Skip to content

Commit 4770fe9

Browse files
committed
feat: compile operations
Add a compiled execution path for validated operations and subscriptions. Benchmarks were run on Node v24.14.1 against 17.x.x. The compiler path shows rough ops/sec wins across the benchmark scenarios: - async root fields: 1,511 vs 638 ops/sec, +137% - field argument values: 11,245 vs 3,595 ops/sec, +213% - introspection query: 70.4 vs 49.9 ops/sec, +41% - async list field: 6,725 vs 3,083 ops/sec, +118% - async non-null list items: 6,853 vs 2,960 ops/sec, +132% - sync list field: 44,583 vs 14,248 ops/sec, +213% - variable field collection: 18,498 vs 5,708 ops/sec, +224%
1 parent 677f230 commit 4770fe9

94 files changed

Lines changed: 16451 additions & 1046 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
import * as execution from 'graphql/execution/index.js';
2+
import { parse } from 'graphql/language/parser.js';
3+
import { buildSchema } from 'graphql/utilities/buildASTSchema.js';
4+
5+
const fieldCount = 1000;
6+
const fieldNames = Array.from(
7+
{ length: fieldCount },
8+
(_, index) => `f${index}`,
9+
);
10+
11+
const schema = buildSchema(
12+
`type Query { ${fieldNames.map((fieldName) => `${fieldName}: Int`).join(' ')} }`,
13+
{ assumeValid: true },
14+
);
15+
16+
const document = parse(`{ ${fieldNames.join(' ')} }`);
17+
18+
const rootValue = Object.fromEntries(
19+
fieldNames.map((fieldName, index) => [
20+
fieldName,
21+
() => Promise.resolve(index),
22+
]),
23+
);
24+
25+
const compiled =
26+
typeof execution.compileExecution === 'function'
27+
? execution.compileExecution({ schema, document })
28+
: undefined;
29+
if (Array.isArray(compiled)) {
30+
throw compiled[0];
31+
}
32+
33+
export const benchmark = {
34+
name: 'Compiled Asynchronous Root Fields',
35+
measure: () => {
36+
const runtimeArgs = { rootValue };
37+
if (compiled !== undefined) {
38+
return 'execute' in compiled
39+
? compiled.execute(runtimeArgs)
40+
: compiled.executeRootSelectionSet(runtimeArgs);
41+
}
42+
43+
const validatedArgs = execution.validateExecutionArgs({
44+
schema,
45+
document,
46+
...runtimeArgs,
47+
});
48+
if (!('schema' in validatedArgs)) {
49+
throw validatedArgs[0];
50+
}
51+
return execution.executeRootSelectionSet(validatedArgs);
52+
},
53+
};
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
import * as execution from 'graphql/execution/index.js';
2+
import { parse } from 'graphql/language/parser.js';
3+
import { buildSchema } from 'graphql/utilities/buildASTSchema.js';
4+
5+
const fieldCount = 100;
6+
const fieldNames = Array.from(
7+
{ length: fieldCount },
8+
(_, index) => `f${index}`,
9+
);
10+
11+
const schema = buildSchema(
12+
`
13+
input FieldInput {
14+
enabled: Boolean
15+
value: Int
16+
}
17+
18+
type Query {
19+
${fieldNames
20+
.map(
21+
(fieldName) => `
22+
${fieldName}(
23+
value: Int!
24+
enabled: Boolean
25+
input: FieldInput
26+
list: [Int]
27+
): Int
28+
`,
29+
)
30+
.join('\n')}
31+
}
32+
`,
33+
{ assumeValid: true },
34+
);
35+
36+
const document = parse(`
37+
query CompiledArgumentValues($value: Int!, $enabled: Boolean!) {
38+
${fieldNames
39+
.map(
40+
(fieldName, index) => `
41+
${fieldName}(
42+
value: $value
43+
enabled: $enabled
44+
input: { enabled: $enabled, value: ${index} }
45+
list: [${index}, $value]
46+
)
47+
`,
48+
)
49+
.join('\n')}
50+
}
51+
`);
52+
53+
const rootValue = Object.fromEntries(
54+
fieldNames.map((fieldName, index) => [
55+
fieldName,
56+
(args) => args.value + args.input.value + args.list[0] + index,
57+
]),
58+
);
59+
60+
const compiled =
61+
typeof execution.compileExecution === 'function'
62+
? execution.compileExecution({ schema, document })
63+
: undefined;
64+
if (Array.isArray(compiled)) {
65+
throw compiled[0];
66+
}
67+
68+
let value = 0;
69+
let enabled = false;
70+
71+
export const benchmark = {
72+
name: 'Compiled Field Argument Values',
73+
measure: () => {
74+
value = (value + 1) % 10;
75+
enabled = !enabled;
76+
const runtimeArgs = {
77+
rootValue,
78+
variableValues: { value, enabled },
79+
};
80+
if (compiled !== undefined) {
81+
return 'execute' in compiled
82+
? compiled.execute(runtimeArgs)
83+
: compiled.executeRootSelectionSet(runtimeArgs);
84+
}
85+
86+
const validatedArgs = execution.validateExecutionArgs({
87+
schema,
88+
document,
89+
...runtimeArgs,
90+
});
91+
if (!('schema' in validatedArgs)) {
92+
throw validatedArgs[0];
93+
}
94+
return execution.executeRootSelectionSet(validatedArgs);
95+
},
96+
};
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import * as execution from 'graphql/execution/index.js';
2+
import { parse } from 'graphql/language/parser.js';
3+
import { buildSchema } from 'graphql/utilities/buildASTSchema.js';
4+
import { getIntrospectionQuery } from 'graphql/utilities/getIntrospectionQuery.js';
5+
6+
import { bigSchemaSDL } from '../fixtures.js';
7+
8+
const schema = buildSchema(bigSchemaSDL, { assumeValid: true });
9+
const document = parse(getIntrospectionQuery());
10+
11+
const compiled =
12+
typeof execution.compileExecution === 'function'
13+
? execution.compileExecution({ schema, document })
14+
: undefined;
15+
if (Array.isArray(compiled)) {
16+
throw compiled[0];
17+
}
18+
19+
export const benchmark = {
20+
name: 'Compiled Execute Introspection Query',
21+
measure: () => {
22+
if (compiled !== undefined) {
23+
return 'execute' in compiled
24+
? compiled.execute()
25+
: compiled.executeRootSelectionSet();
26+
}
27+
28+
return execution.executeSync({ schema, document });
29+
},
30+
};
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
import * as execution from 'graphql/execution/index.js';
2+
import { parse } from 'graphql/language/parser.js';
3+
import { buildSchema } from 'graphql/utilities/buildASTSchema.js';
4+
5+
const schema = buildSchema('type Query { listField: [String] }', {
6+
assumeValid: true,
7+
});
8+
const document = parse('{ listField }');
9+
10+
function listField() {
11+
const results = [];
12+
for (let index = 0; index < 1000; index++) {
13+
results.push(Promise.resolve(index));
14+
}
15+
return results;
16+
}
17+
18+
const rootValue = { listField };
19+
20+
const compiled =
21+
typeof execution.compileExecution === 'function'
22+
? execution.compileExecution({ schema, document })
23+
: undefined;
24+
if (Array.isArray(compiled)) {
25+
throw compiled[0];
26+
}
27+
28+
export const benchmark = {
29+
name: 'Compiled Asynchronous List Field',
30+
measure: () => {
31+
const runtimeArgs = { rootValue };
32+
if (compiled !== undefined) {
33+
return 'execute' in compiled
34+
? compiled.execute(runtimeArgs)
35+
: compiled.executeRootSelectionSet(runtimeArgs);
36+
}
37+
38+
const validatedArgs = execution.validateExecutionArgs({
39+
schema,
40+
document,
41+
...runtimeArgs,
42+
});
43+
if (!('schema' in validatedArgs)) {
44+
throw validatedArgs[0];
45+
}
46+
return execution.executeRootSelectionSet(validatedArgs);
47+
},
48+
};
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
import * as execution from 'graphql/execution/index.js';
2+
import { parse } from 'graphql/language/parser.js';
3+
import { buildSchema } from 'graphql/utilities/buildASTSchema.js';
4+
5+
const schema = buildSchema('type Query { listField: [String!] }', {
6+
assumeValid: true,
7+
});
8+
const document = parse('{ listField }');
9+
10+
function listField() {
11+
const results = [];
12+
for (let index = 0; index < 1000; index++) {
13+
results.push(Promise.resolve(index));
14+
}
15+
return results;
16+
}
17+
18+
const rootValue = { listField };
19+
20+
const compiled =
21+
typeof execution.compileExecution === 'function'
22+
? execution.compileExecution({ schema, document })
23+
: undefined;
24+
if (Array.isArray(compiled)) {
25+
throw compiled[0];
26+
}
27+
28+
export const benchmark = {
29+
name: 'Compiled Asynchronous Non-Null List Items',
30+
measure: () => {
31+
const runtimeArgs = { rootValue };
32+
if (compiled !== undefined) {
33+
return 'execute' in compiled
34+
? compiled.execute(runtimeArgs)
35+
: compiled.executeRootSelectionSet(runtimeArgs);
36+
}
37+
38+
const validatedArgs = execution.validateExecutionArgs({
39+
schema,
40+
document,
41+
...runtimeArgs,
42+
});
43+
if (!('schema' in validatedArgs)) {
44+
throw validatedArgs[0];
45+
}
46+
return execution.executeRootSelectionSet(validatedArgs);
47+
},
48+
};
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
import * as execution from 'graphql/execution/index.js';
2+
import { parse } from 'graphql/language/parser.js';
3+
import { buildSchema } from 'graphql/utilities/buildASTSchema.js';
4+
5+
const schema = buildSchema('type Query { listField: [String] }', {
6+
assumeValid: true,
7+
});
8+
const document = parse('{ listField }');
9+
10+
function listField() {
11+
const results = [];
12+
for (let index = 0; index < 1000; index++) {
13+
results.push(index);
14+
}
15+
return results;
16+
}
17+
18+
const rootValue = { listField };
19+
20+
const compiled =
21+
typeof execution.compileExecution === 'function'
22+
? execution.compileExecution({ schema, document })
23+
: undefined;
24+
if (Array.isArray(compiled)) {
25+
throw compiled[0];
26+
}
27+
28+
export const benchmark = {
29+
name: 'Compiled Synchronous List Field',
30+
measure: () => {
31+
const runtimeArgs = { rootValue };
32+
if (compiled !== undefined) {
33+
return 'execute' in compiled
34+
? compiled.execute(runtimeArgs)
35+
: compiled.executeRootSelectionSet(runtimeArgs);
36+
}
37+
38+
const validatedArgs = execution.validateExecutionArgs({
39+
schema,
40+
document,
41+
...runtimeArgs,
42+
});
43+
if (!('schema' in validatedArgs)) {
44+
throw validatedArgs[0];
45+
}
46+
return execution.executeRootSelectionSet(validatedArgs);
47+
},
48+
};

0 commit comments

Comments
 (0)