Skip to content

Commit c4efead

Browse files
authored
extract IncrementalExecutor from Executor (#4545)
such that `IncrementalExecutor` extends a base Executor class that ignores the incremental directives. In contrast, the `ExecutorThrowingOnIncremental` subclass should throw on encountering incremental directives, to be used in the standard `execute` function, signaling that these directives are disabled unless used intentionally with the new experimental behavior via the new function. Tests are reorganized/moved, not changed.
1 parent bf84048 commit c4efead

File tree

13 files changed

+2182
-1730
lines changed

13 files changed

+2182
-1730
lines changed

src/execution/Executor.ts

Lines changed: 90 additions & 812 deletions
Large diffs are not rendered by default.
Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
import { invariant } from '../jsutils/invariant.js';
2+
import type { ObjMap } from '../jsutils/ObjMap.js';
3+
import type { Path } from '../jsutils/Path.js';
4+
import type { PromiseOrValue } from '../jsutils/PromiseOrValue.js';
5+
6+
import { OperationTypeNode } from '../language/ast.js';
7+
8+
import type {
9+
GraphQLList,
10+
GraphQLObjectType,
11+
GraphQLOutputType,
12+
} from '../type/index.js';
13+
14+
import type {
15+
DeferUsage,
16+
FieldDetailsList,
17+
GroupedFieldSet,
18+
} from './collectFields.js';
19+
import { Executor, getStreamUsage } from './Executor.js';
20+
import type { ResolveInfo } from './ResolveInfo.js';
21+
22+
const UNEXPECTED_MULTIPLE_PAYLOADS =
23+
'Executing this GraphQL operation would unexpectedly produce multiple payloads (due to @defer or @stream directive)';
24+
25+
/** @internal */
26+
export class ExecutorThrowingOnIncremental extends Executor {
27+
override executeCollectedRootFields(
28+
operation: OperationTypeNode,
29+
rootType: GraphQLObjectType,
30+
rootValue: unknown,
31+
originalGroupedFieldSet: GroupedFieldSet,
32+
newDeferUsages: ReadonlyArray<DeferUsage>,
33+
): PromiseOrValue<ObjMap<unknown>> {
34+
if (newDeferUsages.length > 0) {
35+
invariant(
36+
this.validatedExecutionArgs.operation.operation !==
37+
OperationTypeNode.SUBSCRIPTION,
38+
'`@defer` directive not supported on subscription operations. Disable `@defer` by setting the `if` argument to `false`.',
39+
);
40+
const reason = new Error(UNEXPECTED_MULTIPLE_PAYLOADS);
41+
this.cancel(reason);
42+
throw reason;
43+
}
44+
return this.executeRootGroupedFieldSet(
45+
operation,
46+
rootType,
47+
rootValue,
48+
originalGroupedFieldSet,
49+
undefined,
50+
);
51+
}
52+
53+
override executeCollectedSubfields(
54+
parentType: GraphQLObjectType,
55+
sourceValue: unknown,
56+
path: Path | undefined,
57+
originalGroupedFieldSet: GroupedFieldSet,
58+
newDeferUsages: ReadonlyArray<DeferUsage>,
59+
): PromiseOrValue<ObjMap<unknown>> {
60+
if (newDeferUsages.length > 0) {
61+
invariant(
62+
this.validatedExecutionArgs.operation.operation !==
63+
OperationTypeNode.SUBSCRIPTION,
64+
'`@defer` directive not supported on subscription operations. Disable `@defer` by setting the `if` argument to `false`.',
65+
);
66+
const reason = new Error(UNEXPECTED_MULTIPLE_PAYLOADS);
67+
this.cancel(reason);
68+
throw reason;
69+
}
70+
71+
return this.executeFields(
72+
parentType,
73+
sourceValue,
74+
path,
75+
originalGroupedFieldSet,
76+
undefined,
77+
);
78+
}
79+
80+
// eslint-disable-next-line max-params
81+
override completeListValue(
82+
returnType: GraphQLList<GraphQLOutputType>,
83+
fieldDetailsList: FieldDetailsList,
84+
info: ResolveInfo,
85+
path: Path,
86+
result: unknown,
87+
positionContext: undefined,
88+
): PromiseOrValue<ReadonlyArray<unknown>> {
89+
const streamUsage = getStreamUsage(
90+
this.validatedExecutionArgs,
91+
fieldDetailsList,
92+
);
93+
if (streamUsage !== undefined) {
94+
invariant(
95+
this.validatedExecutionArgs.operation.operation !==
96+
OperationTypeNode.SUBSCRIPTION,
97+
'`@stream` directive not supported on subscription operations. Disable `@stream` by setting the `if` argument to `false`.',
98+
);
99+
100+
const reason = new Error(UNEXPECTED_MULTIPLE_PAYLOADS);
101+
this.cancel(reason);
102+
throw reason;
103+
}
104+
105+
return super.completeListValue(
106+
returnType,
107+
fieldDetailsList,
108+
info,
109+
path,
110+
result,
111+
positionContext,
112+
);
113+
}
114+
}

0 commit comments

Comments
 (0)