diff --git a/benchmarks/large/raw-sync.ts b/benchmarks/array/graphql-js/async.ts similarity index 85% rename from benchmarks/large/raw-sync.ts rename to benchmarks/array/graphql-js/async.ts index 79f376c76..bac241fbc 100644 --- a/benchmarks/large/raw-sync.ts +++ b/benchmarks/array/graphql-js/async.ts @@ -8,34 +8,34 @@ import { GraphQLList, } from "graphql"; -import { runBenchmark, ARRAY_ITEMS } from "./run"; +import { runBenchmark, ARRAY_ITEMS } from "../run"; const SampleObjectType: GraphQLObjectType = new GraphQLObjectType({ name: "SampleObject", fields: () => ({ sampleField: { type: new GraphQLNonNull(GraphQLString), - resolve: (source) => { + resolve: async source => { return source.sampleField; - } + }, }, numberField: { type: new GraphQLNonNull(GraphQLInt), - resolve: (source) => { + resolve: async source => { return source.numberField; - } + }, }, booleanField: { type: new GraphQLNonNull(GraphQLBoolean), - resolve: (source) => { + resolve: async source => { return source.booleanField; - } + }, }, nestedField: { type: SampleObjectType, - resolve: (source) => { + resolve: async source => { return source.nestedField; - } + }, }, }), }); diff --git a/benchmarks/array/graphql-js.ts b/benchmarks/array/graphql-js/standard.ts similarity index 95% rename from benchmarks/array/graphql-js.ts rename to benchmarks/array/graphql-js/standard.ts index cbb121e63..7b590a86d 100644 --- a/benchmarks/array/graphql-js.ts +++ b/benchmarks/array/graphql-js/standard.ts @@ -8,7 +8,7 @@ import { GraphQLList, } from "graphql"; -import { runBenchmark, ARRAY_ITEMS } from "./run"; +import { runBenchmark, ARRAY_ITEMS } from "../run"; const SampleObjectType: GraphQLObjectType = new GraphQLObjectType({ name: "SampleObject", diff --git a/benchmarks/array/results.txt b/benchmarks/array/results.txt index 8c1a3f8ac..6453b1a22 100644 --- a/benchmarks/array/results.txt +++ b/benchmarks/array/results.txt @@ -1,15 +1,34 @@ Core i7 2700K @ 3.5GHz Windows 10 x64 -10 000 array items | 100 iterations +25 000 array items | 50 iterations +Node.js v13.5 ----- -Node.js v13.2 +TypeGraphQL standard -- 42.551s +- 15.518s + +using sync field resolvers +- 18.180s + +using async field resolvers +- 39.934s + +using getters +- 31.207s + +standard with global middleware +- 62.664s with `simpleResolvers: true` -- 11.841s +- 14.980s + +----- +`graphql-js` + +standard +- 13.276s -graphql-js -- 9.963s +async field resolvers +- 25.630s diff --git a/benchmarks/array/run.ts b/benchmarks/array/run.ts index 608631c39..d9e70a115 100644 --- a/benchmarks/array/run.ts +++ b/benchmarks/array/run.ts @@ -1,8 +1,8 @@ import { GraphQLSchema, execute } from "graphql"; import { gql } from "apollo-server"; -const BENCHMARK_ITERATIONS = 100; -export const ARRAY_ITEMS = 10000; +const BENCHMARK_ITERATIONS = 50; +export const ARRAY_ITEMS = 25000; export async function runBenchmark(schema: GraphQLSchema) { const multipleNestedObjectsQuery = gql` diff --git a/benchmarks/large/tg-async.ts b/benchmarks/array/type-graphql/async-field-resolvers.ts similarity index 87% rename from benchmarks/large/tg-async.ts rename to benchmarks/array/type-graphql/async-field-resolvers.ts index a7ef96098..e69011b7a 100644 --- a/benchmarks/large/tg-async.ts +++ b/benchmarks/array/type-graphql/async-field-resolvers.ts @@ -1,7 +1,16 @@ import "reflect-metadata"; -import { buildSchema, Field, ObjectType, Resolver, Query, Int, FieldResolver, Root } from "../../build/package"; +import { + buildSchema, + Field, + ObjectType, + Resolver, + Query, + Int, + FieldResolver, + Root, +} from "../../../build/package/dist"; -import { runBenchmark, ARRAY_ITEMS } from "./run"; +import { runBenchmark, ARRAY_ITEMS } from "../run"; @ObjectType() class SampleObject { diff --git a/benchmarks/array/type-graphql.ts b/benchmarks/array/type-graphql/simple-resolvers.ts similarity index 68% rename from benchmarks/array/type-graphql.ts rename to benchmarks/array/type-graphql/simple-resolvers.ts index ea5ab82fa..f2a97750d 100644 --- a/benchmarks/array/type-graphql.ts +++ b/benchmarks/array/type-graphql/simple-resolvers.ts @@ -1,7 +1,15 @@ import "reflect-metadata"; -import { buildSchema, Field, ObjectType, Resolver, Query, Int } from "../../build/package"; +import { + buildSchema, + Field, + ObjectType, + Resolver, + Query, + Int, + MiddlewareFn, +} from "../../../build/package/dist"; -import { runBenchmark, ARRAY_ITEMS } from "./run"; +import { runBenchmark, ARRAY_ITEMS } from "../run"; @ObjectType({ simpleResolvers: true }) class SampleObject { @@ -38,9 +46,17 @@ class SampleResolver { } } +const log = (...args: any[]) => void 0; // noop + +const loggingMiddleware: MiddlewareFn = ({ info }, next) => { + log(`${info.parentType.name}.${info.fieldName} accessed`); + return next(); +}; + async function main() { const schema = await buildSchema({ resolvers: [SampleResolver], + globalMiddlewares: [loggingMiddleware], }); await runBenchmark(schema); diff --git a/benchmarks/large/tg-basic.ts b/benchmarks/array/type-graphql/standard.ts similarity index 91% rename from benchmarks/large/tg-basic.ts rename to benchmarks/array/type-graphql/standard.ts index ac3b1b999..36d5fbb9c 100644 --- a/benchmarks/large/tg-basic.ts +++ b/benchmarks/array/type-graphql/standard.ts @@ -1,7 +1,7 @@ import "reflect-metadata"; -import { buildSchema, Field, ObjectType, Resolver, Query, Int } from "../../build/package"; +import { buildSchema, Field, ObjectType, Resolver, Query, Int } from "../../../build/package/dist"; -import { runBenchmark, ARRAY_ITEMS } from "./run"; +import { runBenchmark, ARRAY_ITEMS } from "../run"; @ObjectType() class SampleObject { diff --git a/benchmarks/large/tg-sync.ts b/benchmarks/array/type-graphql/sync-field-resolvers.ts similarity index 86% rename from benchmarks/large/tg-sync.ts rename to benchmarks/array/type-graphql/sync-field-resolvers.ts index 007e5216b..b672d0909 100644 --- a/benchmarks/large/tg-sync.ts +++ b/benchmarks/array/type-graphql/sync-field-resolvers.ts @@ -1,7 +1,16 @@ import "reflect-metadata"; -import { buildSchema, Field, ObjectType, Resolver, Query, Int, FieldResolver, Root } from "../../build/package"; +import { + buildSchema, + Field, + ObjectType, + Resolver, + Query, + Int, + FieldResolver, + Root, +} from "../../../build/package/dist"; -import { runBenchmark, ARRAY_ITEMS } from "./run"; +import { runBenchmark, ARRAY_ITEMS } from "../../large/run"; @ObjectType() class SampleObject { diff --git a/benchmarks/array/type-graphql/sync-getters.ts b/benchmarks/array/type-graphql/sync-getters.ts new file mode 100644 index 000000000..4b3337547 --- /dev/null +++ b/benchmarks/array/type-graphql/sync-getters.ts @@ -0,0 +1,62 @@ +import "reflect-metadata"; +import { buildSchema, Field, ObjectType, Resolver, Query, Int } from "../../../build/package/dist"; + +import { runBenchmark, ARRAY_ITEMS } from "../../large/run"; + +@ObjectType() +class SampleObject { + stringField!: string; + @Field({ name: "stringField" }) + get getStringField(): string { + return this.stringField; + } + + numberField!: number; + @Field(type => Int, { name: "numberField" }) + get getNumberField(): number { + return this.numberField; + } + + booleanField!: boolean; + @Field({ name: "booleanField" }) + get getBooleanField(): boolean { + return this.booleanField; + } + + nestedField?: SampleObject; + @Field(type => SampleObject, { name: "nestedField", nullable: true }) + get getNestedField(): SampleObject | undefined { + return this.nestedField; + } +} + +@Resolver(SampleObject) +class SampleResolver { + @Query(returns => [SampleObject]) + multipleNestedObjects(): SampleObject[] { + return Array.from( + { length: ARRAY_ITEMS }, + (_, index): SampleObject => + ({ + stringField: "stringField", + booleanField: true, + numberField: index, + nestedField: { + stringField: "stringField", + booleanField: true, + numberField: index, + } as SampleObject, + } as SampleObject), + ); + } +} + +async function main() { + const schema = await buildSchema({ + resolvers: [SampleResolver], + }); + + await runBenchmark(schema); +} + +main().catch(console.error); diff --git a/benchmarks/array/type-graphql/with-global-middleware.ts b/benchmarks/array/type-graphql/with-global-middleware.ts new file mode 100644 index 000000000..2b63a22dc --- /dev/null +++ b/benchmarks/array/type-graphql/with-global-middleware.ts @@ -0,0 +1,65 @@ +import "reflect-metadata"; +import { + buildSchema, + Field, + ObjectType, + Resolver, + Query, + Int, + MiddlewareFn, +} from "../../../build/package/dist"; + +import { runBenchmark, ARRAY_ITEMS } from "../run"; + +@ObjectType() +class SampleObject { + @Field() + stringField!: string; + + @Field(type => Int) + numberField!: number; + + @Field() + booleanField!: boolean; + + @Field({ nullable: true }) + nestedField?: SampleObject; +} + +@Resolver() +class SampleResolver { + @Query(returns => [SampleObject]) + multipleNestedObjects(): SampleObject[] { + return Array.from( + { length: ARRAY_ITEMS }, + (_, index): SampleObject => ({ + stringField: "stringField", + booleanField: true, + numberField: index, + nestedField: { + stringField: "stringField", + booleanField: true, + numberField: index, + }, + }), + ); + } +} + +const log = (...args: any[]) => void 0; // noop + +const loggingMiddleware: MiddlewareFn = ({ info }, next) => { + log(`${info.parentType.name}.${info.fieldName} accessed`); + return next(); +}; + +async function main() { + const schema = await buildSchema({ + resolvers: [SampleResolver], + globalMiddlewares: [loggingMiddleware], + }); + + await runBenchmark(schema); +} + +main().catch(console.error); diff --git a/benchmarks/large/raw-async.ts b/benchmarks/large/raw-async.ts deleted file mode 100644 index 9adb5ea08..000000000 --- a/benchmarks/large/raw-async.ts +++ /dev/null @@ -1,65 +0,0 @@ -import { - GraphQLSchema, - GraphQLObjectType, - GraphQLString, - GraphQLNonNull, - GraphQLBoolean, - GraphQLInt, - GraphQLList, -} from "graphql"; - -import { runBenchmark, ARRAY_ITEMS } from "./run"; - -const SampleObjectType: GraphQLObjectType = new GraphQLObjectType({ - name: "SampleObject", - fields: () => ({ - sampleField: { - type: new GraphQLNonNull(GraphQLString), - resolve: async (source) => { - return source.sampleField; - } - }, - numberField: { - type: new GraphQLNonNull(GraphQLInt), - resolve: async (source) => { - return source.numberField; - } - }, - booleanField: { - type: new GraphQLNonNull(GraphQLBoolean), - resolve: async (source) => { - return source.booleanField; - } - }, - nestedField: { - type: SampleObjectType, - resolve: async (source) => { - return source.nestedField; - } - }, - }), -}); - -const schema = new GraphQLSchema({ - query: new GraphQLObjectType({ - name: "Query", - fields: { - multipleNestedObjects: { - type: new GraphQLNonNull(new GraphQLList(new GraphQLNonNull(SampleObjectType))), - resolve: () => - Array.from({ length: ARRAY_ITEMS }, (_, index) => ({ - stringField: "stringField", - booleanField: true, - numberField: index, - nestedField: { - stringField: "stringField", - booleanField: true, - numberField: index, - }, - })), - }, - }, - }), -}); - -runBenchmark(schema).catch(console.error); diff --git a/benchmarks/large/raw-basic.ts b/benchmarks/large/raw-basic.ts deleted file mode 100644 index cbb121e63..000000000 --- a/benchmarks/large/raw-basic.ts +++ /dev/null @@ -1,53 +0,0 @@ -import { - GraphQLSchema, - GraphQLObjectType, - GraphQLString, - GraphQLNonNull, - GraphQLBoolean, - GraphQLInt, - GraphQLList, -} from "graphql"; - -import { runBenchmark, ARRAY_ITEMS } from "./run"; - -const SampleObjectType: GraphQLObjectType = new GraphQLObjectType({ - name: "SampleObject", - fields: () => ({ - sampleField: { - type: new GraphQLNonNull(GraphQLString), - }, - numberField: { - type: new GraphQLNonNull(GraphQLInt), - }, - booleanField: { - type: new GraphQLNonNull(GraphQLBoolean), - }, - nestedField: { - type: SampleObjectType, - }, - }), -}); - -const schema = new GraphQLSchema({ - query: new GraphQLObjectType({ - name: "Query", - fields: { - multipleNestedObjects: { - type: new GraphQLNonNull(new GraphQLList(new GraphQLNonNull(SampleObjectType))), - resolve: () => - Array.from({ length: ARRAY_ITEMS }, (_, index) => ({ - stringField: "stringField", - booleanField: true, - numberField: index, - nestedField: { - stringField: "stringField", - booleanField: true, - numberField: index, - }, - })), - }, - }, - }), -}); - -runBenchmark(schema).catch(console.error); diff --git a/benchmarks/large/results.txt b/benchmarks/large/results.txt deleted file mode 100644 index 8b3f710b1..000000000 --- a/benchmarks/large/results.txt +++ /dev/null @@ -1,24 +0,0 @@ -Core i7 2700K @ 3.5GHz -Windows 10 x64 -10 000 array items | 100 iterations - ------ -Node.js v13.3 - -GraphQL-js async: -- 19.765s - -GraphQL-js sync: -- 10.031s - -TypeGraphQL async field resolvers: -- 30.749s - -TypeGraphQL sync field resolvers: -- 16.441s - -TypeGraphQL implicit fields: -- 13.784s - -TypeGraphQL simple resolvers: -- 11.814s diff --git a/benchmarks/large/run.ts b/benchmarks/large/run.ts deleted file mode 100644 index 608631c39..000000000 --- a/benchmarks/large/run.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { GraphQLSchema, execute } from "graphql"; -import { gql } from "apollo-server"; - -const BENCHMARK_ITERATIONS = 100; -export const ARRAY_ITEMS = 10000; - -export async function runBenchmark(schema: GraphQLSchema) { - const multipleNestedObjectsQuery = gql` - query { - multipleNestedObjects { - stringField - booleanField - numberField - nestedField { - stringField - booleanField - numberField - } - } - } - `; - console.time("multipleNestedObjects"); - for (let i = 0; i < BENCHMARK_ITERATIONS; i++) { - const result = await execute({ schema, document: multipleNestedObjectsQuery }); - console.assert(result.data !== undefined, "result data is undefined"); - console.assert( - result.data!.multipleNestedObjects.length === ARRAY_ITEMS, - "result data is not a proper array", - ); - console.assert( - result.data!.multipleNestedObjects[0].nestedField.booleanField === true, - "data nestedField are incorrect", - ); - } - console.timeEnd("multipleNestedObjects"); -}