@graphql-tools/executor 4.1.1 → 4.1.2-alpha-20261020170708-72d61a1bbfbf64a0a9d61e801c80001b7ea79dc3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/cjs/execution/execute.js +94 -86
- package/cjs/execution/getBySet.js +13 -0
- package/cjs/execution/incremental.js +157 -4
- package/cjs/execution/incrementalCollect.js +194 -0
- package/cjs/execution/isSameSet.js +15 -0
- package/esm/execution/execute.js +91 -82
- package/esm/execution/getBySet.js +10 -0
- package/esm/execution/incremental.js +153 -4
- package/esm/execution/incrementalCollect.js +185 -0
- package/esm/execution/isSameSet.js +12 -0
- package/package.json +1 -1
- package/typings/execution/execute.d.cts +7 -19
- package/typings/execution/execute.d.ts +7 -19
- package/typings/execution/getBySet.d.cts +2 -0
- package/typings/execution/getBySet.d.ts +2 -0
- package/typings/execution/incremental.d.cts +25 -0
- package/typings/execution/incremental.d.ts +25 -0
- package/typings/execution/incrementalCollect.d.cts +35 -0
- package/typings/execution/incrementalCollect.d.ts +35 -0
- package/typings/execution/isSameSet.d.cts +2 -0
- package/typings/execution/isSameSet.d.ts +2 -0
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.collectIncrementalFields = collectIncrementalFields;
|
|
4
|
+
exports.collectIncrementalSubfields = collectIncrementalSubfields;
|
|
5
|
+
exports.buildExecutionPlan = buildExecutionPlan;
|
|
6
|
+
exports.deferUsageForFieldNode = deferUsageForFieldNode;
|
|
7
|
+
exports.groupedFieldSetToFieldMap = groupedFieldSetToFieldMap;
|
|
8
|
+
exports.rootDeferUsage = rootDeferUsage;
|
|
9
|
+
exports.labelForDeferUsageSet = labelForDeferUsageSet;
|
|
10
|
+
const graphql_1 = require("graphql");
|
|
11
|
+
const utils_1 = require("@graphql-tools/utils");
|
|
12
|
+
const getBySet_js_1 = require("./getBySet.js");
|
|
13
|
+
const isSameSet_js_1 = require("./isSameSet.js");
|
|
14
|
+
class FieldDetailsMap extends Map {
|
|
15
|
+
add(key, item) {
|
|
16
|
+
const group = this.get(key);
|
|
17
|
+
if (group === undefined) {
|
|
18
|
+
this.set(key, [item]);
|
|
19
|
+
}
|
|
20
|
+
else {
|
|
21
|
+
group.push(item);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
function collectIncrementalFields(schema, fragments, variableValues, runtimeType, selectionSet, parentDeferUsage) {
|
|
26
|
+
const groupedFieldSet = new FieldDetailsMap();
|
|
27
|
+
const newDeferUsages = [];
|
|
28
|
+
const context = {
|
|
29
|
+
schema,
|
|
30
|
+
fragments,
|
|
31
|
+
variableValues,
|
|
32
|
+
runtimeType,
|
|
33
|
+
visitedFragmentNames: new Map(),
|
|
34
|
+
};
|
|
35
|
+
collectFieldsImpl(context, selectionSet, groupedFieldSet, newDeferUsages, parentDeferUsage);
|
|
36
|
+
return { groupedFieldSet, newDeferUsages };
|
|
37
|
+
}
|
|
38
|
+
const deferUsageByFieldNode = new WeakMap();
|
|
39
|
+
function collectIncrementalSubfields(schema, fragments, variableValues, returnType, fieldNodes, parentDeferUsage) {
|
|
40
|
+
const groupedFieldSet = new FieldDetailsMap();
|
|
41
|
+
const newDeferUsages = [];
|
|
42
|
+
const context = {
|
|
43
|
+
schema,
|
|
44
|
+
fragments,
|
|
45
|
+
variableValues,
|
|
46
|
+
runtimeType: returnType,
|
|
47
|
+
visitedFragmentNames: new Map(),
|
|
48
|
+
};
|
|
49
|
+
for (const node of fieldNodes) {
|
|
50
|
+
if (node.selectionSet) {
|
|
51
|
+
const deferUsage = deferUsageByFieldNode.has(node)
|
|
52
|
+
? deferUsageByFieldNode.get(node)
|
|
53
|
+
: parentDeferUsage;
|
|
54
|
+
collectFieldsImpl(context, node.selectionSet, groupedFieldSet, newDeferUsages, deferUsage);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
return { groupedFieldSet, newDeferUsages };
|
|
58
|
+
}
|
|
59
|
+
function collectFieldsImpl(context, selectionSet, groupedFieldSet, newDeferUsages, deferUsage) {
|
|
60
|
+
const { schema, fragments, variableValues, runtimeType, visitedFragmentNames } = context;
|
|
61
|
+
for (const selection of selectionSet.selections) {
|
|
62
|
+
switch (selection.kind) {
|
|
63
|
+
case graphql_1.Kind.FIELD: {
|
|
64
|
+
if (!(0, utils_1.shouldIncludeNode)(variableValues, selection)) {
|
|
65
|
+
continue;
|
|
66
|
+
}
|
|
67
|
+
groupedFieldSet.add((0, utils_1.getFieldEntryKey)(selection), {
|
|
68
|
+
node: selection,
|
|
69
|
+
deferUsage,
|
|
70
|
+
});
|
|
71
|
+
break;
|
|
72
|
+
}
|
|
73
|
+
case graphql_1.Kind.INLINE_FRAGMENT: {
|
|
74
|
+
if (!(0, utils_1.shouldIncludeNode)(variableValues, selection) ||
|
|
75
|
+
!(0, utils_1.doesFragmentConditionMatch)(schema, selection, runtimeType)) {
|
|
76
|
+
continue;
|
|
77
|
+
}
|
|
78
|
+
const newDeferUsage = getDeferUsage(variableValues, selection, deferUsage);
|
|
79
|
+
if (!newDeferUsage) {
|
|
80
|
+
collectFieldsImpl(context, selection.selectionSet, groupedFieldSet, newDeferUsages, deferUsage);
|
|
81
|
+
}
|
|
82
|
+
else {
|
|
83
|
+
newDeferUsages.push(newDeferUsage);
|
|
84
|
+
collectFieldsImpl(context, selection.selectionSet, groupedFieldSet, newDeferUsages, newDeferUsage);
|
|
85
|
+
}
|
|
86
|
+
break;
|
|
87
|
+
}
|
|
88
|
+
case graphql_1.Kind.FRAGMENT_SPREAD: {
|
|
89
|
+
const fragName = selection.name.value;
|
|
90
|
+
if (!(0, utils_1.shouldIncludeNode)(variableValues, selection)) {
|
|
91
|
+
continue;
|
|
92
|
+
}
|
|
93
|
+
const fragment = fragments[fragName];
|
|
94
|
+
if (!fragment || !(0, utils_1.doesFragmentConditionMatch)(schema, fragment, runtimeType)) {
|
|
95
|
+
continue;
|
|
96
|
+
}
|
|
97
|
+
const newDeferUsage = getDeferUsage(variableValues, selection, deferUsage);
|
|
98
|
+
const visitedAsDeferred = visitedFragmentNames.get(fragName);
|
|
99
|
+
let maybeNewDeferUsage;
|
|
100
|
+
if (!newDeferUsage) {
|
|
101
|
+
if (visitedAsDeferred === false) {
|
|
102
|
+
continue;
|
|
103
|
+
}
|
|
104
|
+
visitedFragmentNames.set(fragName, false);
|
|
105
|
+
maybeNewDeferUsage = deferUsage;
|
|
106
|
+
}
|
|
107
|
+
else {
|
|
108
|
+
if (visitedAsDeferred !== undefined) {
|
|
109
|
+
continue;
|
|
110
|
+
}
|
|
111
|
+
visitedFragmentNames.set(fragName, true);
|
|
112
|
+
newDeferUsages.push(newDeferUsage);
|
|
113
|
+
maybeNewDeferUsage = newDeferUsage;
|
|
114
|
+
}
|
|
115
|
+
collectFieldsImpl(context, fragment.selectionSet, groupedFieldSet, newDeferUsages, maybeNewDeferUsage);
|
|
116
|
+
break;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
function getDeferUsage(variableValues, node, parentDeferUsage) {
|
|
122
|
+
const defer = (0, utils_1.getDirectiveValues)(utils_1.GraphQLDeferDirective, node, variableValues);
|
|
123
|
+
if (!defer || defer['if'] === false) {
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
return {
|
|
127
|
+
label: typeof defer['label'] === 'string' ? defer['label'] : undefined,
|
|
128
|
+
parentDeferUsage,
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
function buildExecutionPlan(originalGroupedFieldSet, parentDeferUsages = new Set()) {
|
|
132
|
+
const groupedFieldSet = new Map();
|
|
133
|
+
const newGroupedFieldSets = new Map();
|
|
134
|
+
for (const [responseKey, fieldDetailsList] of originalGroupedFieldSet) {
|
|
135
|
+
const filteredDeferUsageSet = getFilteredDeferUsageSet(fieldDetailsList);
|
|
136
|
+
if ((0, isSameSet_js_1.isSameSet)(filteredDeferUsageSet, parentDeferUsages)) {
|
|
137
|
+
groupedFieldSet.set(responseKey, fieldDetailsList);
|
|
138
|
+
continue;
|
|
139
|
+
}
|
|
140
|
+
let newGroupedFieldSet = (0, getBySet_js_1.getBySet)(newGroupedFieldSets, filteredDeferUsageSet);
|
|
141
|
+
if (newGroupedFieldSet === undefined) {
|
|
142
|
+
newGroupedFieldSet = new Map();
|
|
143
|
+
newGroupedFieldSets.set(filteredDeferUsageSet, newGroupedFieldSet);
|
|
144
|
+
}
|
|
145
|
+
newGroupedFieldSet.set(responseKey, fieldDetailsList);
|
|
146
|
+
}
|
|
147
|
+
return { groupedFieldSet, newGroupedFieldSets };
|
|
148
|
+
}
|
|
149
|
+
function getFilteredDeferUsageSet(fieldDetailsList) {
|
|
150
|
+
const filteredDeferUsageSet = new Set();
|
|
151
|
+
for (const fieldDetails of fieldDetailsList) {
|
|
152
|
+
const deferUsage = fieldDetails.deferUsage;
|
|
153
|
+
if (deferUsage === undefined) {
|
|
154
|
+
filteredDeferUsageSet.clear();
|
|
155
|
+
return filteredDeferUsageSet;
|
|
156
|
+
}
|
|
157
|
+
filteredDeferUsageSet.add(deferUsage);
|
|
158
|
+
}
|
|
159
|
+
for (const deferUsage of filteredDeferUsageSet) {
|
|
160
|
+
let parentDeferUsage = deferUsage.parentDeferUsage;
|
|
161
|
+
while (parentDeferUsage !== undefined) {
|
|
162
|
+
if (filteredDeferUsageSet.has(parentDeferUsage)) {
|
|
163
|
+
filteredDeferUsageSet.delete(deferUsage);
|
|
164
|
+
break;
|
|
165
|
+
}
|
|
166
|
+
parentDeferUsage = parentDeferUsage.parentDeferUsage;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
return filteredDeferUsageSet;
|
|
170
|
+
}
|
|
171
|
+
function deferUsageForFieldNode(node) {
|
|
172
|
+
return deferUsageByFieldNode.get(node);
|
|
173
|
+
}
|
|
174
|
+
function groupedFieldSetToFieldMap(groupedFieldSet) {
|
|
175
|
+
const fields = new Map();
|
|
176
|
+
for (const [responseKey, fieldDetailsList] of groupedFieldSet) {
|
|
177
|
+
fields.set(responseKey, fieldDetailsList.map(details => {
|
|
178
|
+
deferUsageByFieldNode.set(details.node, details.deferUsage);
|
|
179
|
+
return details.node;
|
|
180
|
+
}));
|
|
181
|
+
}
|
|
182
|
+
return fields;
|
|
183
|
+
}
|
|
184
|
+
function rootDeferUsage(deferUsageSet) {
|
|
185
|
+
for (const usage of deferUsageSet) {
|
|
186
|
+
if (usage.parentDeferUsage == null || !deferUsageSet.has(usage.parentDeferUsage)) {
|
|
187
|
+
return usage;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
return undefined;
|
|
191
|
+
}
|
|
192
|
+
function labelForDeferUsageSet(deferUsageSet) {
|
|
193
|
+
return rootDeferUsage(deferUsageSet)?.label;
|
|
194
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.isSameSet = isSameSet;
|
|
4
|
+
/** @internal */
|
|
5
|
+
function isSameSet(setA, setB) {
|
|
6
|
+
if (setA.size !== setB.size) {
|
|
7
|
+
return false;
|
|
8
|
+
}
|
|
9
|
+
for (const item of setA) {
|
|
10
|
+
if (!setB.has(item)) {
|
|
11
|
+
return false;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
return true;
|
|
15
|
+
}
|
package/esm/execution/execute.js
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
|
-
import { assertValidSchema, getArgumentValues, getVariableValues, GraphQLError, isAbstractType, isLeafType, isListType, isNonNullType, isObjectType, Kind, SchemaMetaFieldDef, TypeMetaFieldDef, TypeNameMetaFieldDef, versionInfo, } from 'graphql';
|
|
1
|
+
import { assertValidSchema, defaultFieldResolver, defaultTypeResolver, getArgumentValues, getVariableValues, GraphQLError, isAbstractType, isLeafType, isListType, isNonNullType, isObjectType, Kind, SchemaMetaFieldDef, TypeMetaFieldDef, TypeNameMetaFieldDef, versionInfo, } from 'graphql';
|
|
2
2
|
import { collectSubFields as _collectSubfields, addPath, collectFields, getDefinedRootType, getDirectiveValues, GraphQLStreamDirective, inspect, isAsyncIterable, isIterableObject, isObjectLike, locatedError, memoize2, memoize3, pathToArray, promiseReduce, } from '@graphql-tools/utils';
|
|
3
3
|
import { DisposableSymbols } from '@whatwg-node/disposablestack';
|
|
4
4
|
import { fakePromise, handleMaybePromise, isPromise, mapAsyncIterator, } from '@whatwg-node/promise-helpers';
|
|
5
5
|
import { coerceError } from './coerceError.js';
|
|
6
6
|
import { flattenAsyncIterable } from './flattenAsyncIterable.js';
|
|
7
|
-
import { collectInitialPending, createIncrementalPublisherState, createStreamGroupIfV02, DeferredFragmentRecord,
|
|
7
|
+
import { cancelAsyncPayload, collectInitialPending, createIncrementalPublisherState, createStreamGroupIfV02, DeferredFragmentRecord, isAtOrUnderNulledPath, pathStartsWith, StreamRecord, yieldSubsequentPayloads, } from './incremental.js';
|
|
8
|
+
import { buildExecutionPlan, collectIncrementalFields, collectIncrementalSubfields, deferUsageForFieldNode, groupedFieldSetToFieldMap, labelForDeferUsageSet, rootDeferUsage, } from './incrementalCollect.js';
|
|
8
9
|
import { invariant } from './invariant.js';
|
|
9
10
|
import { promiseForObject } from './promiseForObject.js';
|
|
11
|
+
export { defaultFieldResolver, defaultTypeResolver };
|
|
10
12
|
const EMPTY_ARGS = Object.freeze(Object.create(null));
|
|
11
13
|
const isGraphQL17 = versionInfo.major >= 17;
|
|
12
14
|
/**
|
|
@@ -387,18 +389,52 @@ function executeOperation(exeContext) {
|
|
|
387
389
|
const { fields: rootFields, patches } = collectFields(schema, fragments, variableValues, rootType, operation.selectionSet);
|
|
388
390
|
const path = undefined;
|
|
389
391
|
let result;
|
|
392
|
+
if (patches.length === 0) {
|
|
393
|
+
if (operation.operation === 'mutation') {
|
|
394
|
+
result = executeFieldsSerially(exeContext, rootType, rootValue, path, rootFields);
|
|
395
|
+
}
|
|
396
|
+
else {
|
|
397
|
+
result = executeFields(exeContext, rootType, rootValue, path, rootFields);
|
|
398
|
+
}
|
|
399
|
+
return result;
|
|
400
|
+
}
|
|
401
|
+
exeContext.nulledPaths ??= [];
|
|
402
|
+
const { groupedFieldSet } = collectIncrementalFields(schema, fragments, variableValues, rootType, operation.selectionSet);
|
|
403
|
+
const { groupedFieldSet: initialFields, newGroupedFieldSets } = buildExecutionPlan(groupedFieldSet);
|
|
404
|
+
const plannedRootFields = groupedFieldSetToFieldMap(initialFields);
|
|
390
405
|
if (operation.operation === 'mutation') {
|
|
391
|
-
result = executeFieldsSerially(exeContext, rootType, rootValue, path,
|
|
406
|
+
result = executeFieldsSerially(exeContext, rootType, rootValue, path, plannedRootFields);
|
|
392
407
|
}
|
|
393
408
|
else {
|
|
394
|
-
result = executeFields(exeContext, rootType, rootValue, path,
|
|
395
|
-
}
|
|
396
|
-
for (const patch of patches) {
|
|
397
|
-
const { label, fields: patchFields, patches: nestedPatches } = patch;
|
|
398
|
-
executeDeferredFragment(exeContext, rootType, rootValue, patchFields, label, path, undefined, nestedPatches);
|
|
409
|
+
result = executeFields(exeContext, rootType, rootValue, path, plannedRootFields);
|
|
399
410
|
}
|
|
411
|
+
executeDeferredGroups(exeContext, rootType, rootValue, path, newGroupedFieldSets, undefined);
|
|
400
412
|
return result;
|
|
401
413
|
}
|
|
414
|
+
function executeDeferredGroups(exeContext, parentType, sourceValue, path, newGroupedFieldSets, parentContext) {
|
|
415
|
+
if (isAtOrUnderNulledPath(pathToArray(path), exeContext.nulledPaths)) {
|
|
416
|
+
return;
|
|
417
|
+
}
|
|
418
|
+
const records = new Map();
|
|
419
|
+
const groups = [...newGroupedFieldSets.entries()].sort(([a], [b]) => deferUsageDepth(rootDeferUsage(a)) - deferUsageDepth(rootDeferUsage(b)));
|
|
420
|
+
for (const [deferUsageSet, groupedFieldSet] of groups) {
|
|
421
|
+
const usage = rootDeferUsage(deferUsageSet);
|
|
422
|
+
const deliveryParent = (usage?.parentDeferUsage && records.get(usage.parentDeferUsage)) ?? parentContext;
|
|
423
|
+
const record = executeDeferredFragment(exeContext, parentType, sourceValue, groupedFieldSetToFieldMap(groupedFieldSet), labelForDeferUsageSet(deferUsageSet), path, parentContext, undefined, deliveryParent, usage);
|
|
424
|
+
if (usage) {
|
|
425
|
+
records.set(usage, record);
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
function deferUsageDepth(usage) {
|
|
430
|
+
let depth = 0;
|
|
431
|
+
let current = usage;
|
|
432
|
+
while (current?.parentDeferUsage) {
|
|
433
|
+
depth++;
|
|
434
|
+
current = current.parentDeferUsage;
|
|
435
|
+
}
|
|
436
|
+
return depth;
|
|
437
|
+
}
|
|
402
438
|
/**
|
|
403
439
|
* Implements the "Executing selection sets" section of the spec
|
|
404
440
|
* for fields that must be executed serially.
|
|
@@ -872,69 +908,29 @@ function invalidReturnTypeError(returnType, result, fieldNodes) {
|
|
|
872
908
|
function collectAndExecuteSubfields(exeContext, returnType, fieldNodes, path, result, asyncPayloadRecord) {
|
|
873
909
|
// Collect sub-fields to execute to complete this value.
|
|
874
910
|
const { fields: subFieldNodes, patches: subPatches } = collectSubfields(exeContext, returnType, fieldNodes);
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
* isTypeOf for the object being coerced, returning the first type that matches.
|
|
891
|
-
*/
|
|
892
|
-
export const defaultTypeResolver = function (value, contextValue, info, abstractType) {
|
|
893
|
-
// First, look for `__typename`.
|
|
894
|
-
if (isObjectLike(value) && typeof value['__typename'] === 'string') {
|
|
895
|
-
return value['__typename'];
|
|
896
|
-
}
|
|
897
|
-
// Otherwise, test each possible type.
|
|
898
|
-
const possibleTypes = info.schema.getPossibleTypes(abstractType);
|
|
899
|
-
const promisedIsTypeOfResults = [];
|
|
900
|
-
for (let i = 0; i < possibleTypes.length; i++) {
|
|
901
|
-
const type = possibleTypes[i];
|
|
902
|
-
if (type.isTypeOf) {
|
|
903
|
-
const isTypeOfResult = type.isTypeOf(value, contextValue, info);
|
|
904
|
-
if (isPromise(isTypeOfResult)) {
|
|
905
|
-
promisedIsTypeOfResults[i] = isTypeOfResult;
|
|
906
|
-
}
|
|
907
|
-
else if (isTypeOfResult) {
|
|
908
|
-
return type.name;
|
|
909
|
-
}
|
|
910
|
-
}
|
|
911
|
-
}
|
|
912
|
-
if (promisedIsTypeOfResults.length) {
|
|
913
|
-
return Promise.all(promisedIsTypeOfResults).then(isTypeOfResults => {
|
|
914
|
-
for (let i = 0; i < isTypeOfResults.length; i++) {
|
|
915
|
-
if (isTypeOfResults[i]) {
|
|
916
|
-
return possibleTypes[i].name;
|
|
917
|
-
}
|
|
911
|
+
if (subPatches.length === 0 && exeContext.nulledPaths == null) {
|
|
912
|
+
return executeFields(exeContext, returnType, result, path, subFieldNodes, asyncPayloadRecord);
|
|
913
|
+
}
|
|
914
|
+
exeContext.nulledPaths ??= [];
|
|
915
|
+
const parentDeferUsage = asyncPayloadRecord?.type === 'defer' ? asyncPayloadRecord.deferUsage : undefined;
|
|
916
|
+
const { groupedFieldSet } = collectIncrementalSubfields(exeContext.schema, exeContext.fragments, exeContext.variableValues, returnType, fieldNodes, parentDeferUsage);
|
|
917
|
+
const parentDeferUsages = new Set();
|
|
918
|
+
if (parentDeferUsage) {
|
|
919
|
+
parentDeferUsages.add(parentDeferUsage);
|
|
920
|
+
}
|
|
921
|
+
else if (asyncPayloadRecord?.type === 'stream') {
|
|
922
|
+
for (const node of fieldNodes) {
|
|
923
|
+
const usage = deferUsageForFieldNode(node);
|
|
924
|
+
if (usage) {
|
|
925
|
+
parentDeferUsages.add(usage);
|
|
918
926
|
}
|
|
919
|
-
});
|
|
920
|
-
}
|
|
921
|
-
};
|
|
922
|
-
/**
|
|
923
|
-
* If a resolve function is not given, then a default resolve behavior is used
|
|
924
|
-
* which takes the property of the source object of the same name as the field
|
|
925
|
-
* and returns it as the result, or if it's a function, returns the result
|
|
926
|
-
* of calling that function while passing along args and context value.
|
|
927
|
-
*/
|
|
928
|
-
export const defaultFieldResolver = function (source, args, contextValue, info) {
|
|
929
|
-
// ensure source is a value for which property access is acceptable.
|
|
930
|
-
if (isObjectLike(source) || typeof source === 'function') {
|
|
931
|
-
const property = source[info.fieldName];
|
|
932
|
-
if (typeof property === 'function') {
|
|
933
|
-
return source[info.fieldName](args, contextValue, info);
|
|
934
927
|
}
|
|
935
|
-
return property;
|
|
936
928
|
}
|
|
937
|
-
};
|
|
929
|
+
const { groupedFieldSet: initialFields, newGroupedFieldSets } = buildExecutionPlan(groupedFieldSet, parentDeferUsages);
|
|
930
|
+
const subFields = executeFields(exeContext, returnType, result, path, groupedFieldSetToFieldMap(initialFields), asyncPayloadRecord);
|
|
931
|
+
executeDeferredGroups(exeContext, returnType, result, path, newGroupedFieldSets, asyncPayloadRecord);
|
|
932
|
+
return subFields;
|
|
933
|
+
}
|
|
938
934
|
/**
|
|
939
935
|
* Implements the "Subscribe" algorithm described in the GraphQL specification,
|
|
940
936
|
* including `@defer` and `@stream` as proposed in
|
|
@@ -1142,13 +1138,14 @@ function assertEventStream(result, signal, onSignalAbort) {
|
|
|
1142
1138
|
}
|
|
1143
1139
|
return result;
|
|
1144
1140
|
}
|
|
1145
|
-
function executeDeferredFragment(exeContext, parentType, sourceValue, fields, label, path, parentContext, nestedPatches, deliveryParent) {
|
|
1141
|
+
function executeDeferredFragment(exeContext, parentType, sourceValue, fields, label, path, parentContext, nestedPatches, deliveryParent, deferUsage) {
|
|
1146
1142
|
const asyncPayloadRecord = new DeferredFragmentRecord({
|
|
1147
1143
|
label,
|
|
1148
1144
|
path,
|
|
1149
1145
|
parentContext,
|
|
1150
1146
|
deliveryParent: deliveryParent ?? parentContext,
|
|
1151
1147
|
exeContext,
|
|
1148
|
+
deferUsage,
|
|
1152
1149
|
});
|
|
1153
1150
|
let promiseOrData;
|
|
1154
1151
|
try {
|
|
@@ -1172,6 +1169,7 @@ function executeDeferredFragment(exeContext, parentType, sourceValue, fields, la
|
|
|
1172
1169
|
parentContext, nested.patches, asyncPayloadRecord);
|
|
1173
1170
|
}
|
|
1174
1171
|
}
|
|
1172
|
+
return asyncPayloadRecord;
|
|
1175
1173
|
}
|
|
1176
1174
|
function executeStreamField(path, itemPath, item, exeContext, fieldNodes, info, itemType, label, parentContext, streamGroup) {
|
|
1177
1175
|
const asyncPayloadRecord = new StreamRecord({
|
|
@@ -1181,6 +1179,10 @@ function executeStreamField(path, itemPath, item, exeContext, fieldNodes, info,
|
|
|
1181
1179
|
exeContext,
|
|
1182
1180
|
streamGroup,
|
|
1183
1181
|
});
|
|
1182
|
+
if (isAtOrUnderNulledPath(asyncPayloadRecord.path, exeContext.nulledPaths)) {
|
|
1183
|
+
cancelAsyncPayload(exeContext, asyncPayloadRecord);
|
|
1184
|
+
return asyncPayloadRecord;
|
|
1185
|
+
}
|
|
1184
1186
|
let completedItem;
|
|
1185
1187
|
try {
|
|
1186
1188
|
try {
|
|
@@ -1283,6 +1285,15 @@ async function executeStreamIterator(initialIndex, iterator, exeContext, fieldNo
|
|
|
1283
1285
|
exeContext,
|
|
1284
1286
|
streamGroup,
|
|
1285
1287
|
});
|
|
1288
|
+
if (isAtOrUnderNulledPath(asyncPayloadRecord.path, exeContext.nulledPaths)) {
|
|
1289
|
+
cancelAsyncPayload(exeContext, asyncPayloadRecord);
|
|
1290
|
+
if (iterator.return) {
|
|
1291
|
+
iterator.return().catch(() => {
|
|
1292
|
+
// ignore errors
|
|
1293
|
+
});
|
|
1294
|
+
}
|
|
1295
|
+
break;
|
|
1296
|
+
}
|
|
1286
1297
|
let iteration;
|
|
1287
1298
|
try {
|
|
1288
1299
|
iteration = await executeStreamIteratorItem(iterator, exeContext, fieldNodes, info, itemType, asyncPayloadRecord, itemPath);
|
|
@@ -1324,24 +1335,22 @@ async function executeStreamIterator(initialIndex, iterator, exeContext, fieldNo
|
|
|
1324
1335
|
}
|
|
1325
1336
|
function filterSubsequentPayloads(exeContext, nullPath, currentAsyncRecord) {
|
|
1326
1337
|
const nullPathArray = pathToArray(nullPath);
|
|
1338
|
+
if (exeContext.nulledPaths) {
|
|
1339
|
+
exeContext.nulledPaths.push(nullPathArray);
|
|
1340
|
+
}
|
|
1341
|
+
else if (exeContext.subsequentPayloads.size === 0) {
|
|
1342
|
+
return;
|
|
1343
|
+
}
|
|
1327
1344
|
exeContext.subsequentPayloads.forEach(asyncRecord => {
|
|
1328
|
-
if (asyncRecord === currentAsyncRecord) {
|
|
1345
|
+
if (asyncRecord === currentAsyncRecord || asyncRecord.cancelled) {
|
|
1329
1346
|
// don't remove payload from where error originates
|
|
1330
1347
|
return;
|
|
1331
1348
|
}
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
return;
|
|
1336
|
-
}
|
|
1337
|
-
}
|
|
1338
|
-
// asyncRecord path points to nulled error field
|
|
1339
|
-
if (isStreamPayload(asyncRecord) && asyncRecord.iterator?.return) {
|
|
1340
|
-
asyncRecord.iterator.return().catch(() => {
|
|
1341
|
-
// ignore error
|
|
1342
|
-
});
|
|
1349
|
+
if (!pathStartsWith(asyncRecord.path, nullPathArray)) {
|
|
1350
|
+
// ancestor or a different branch: ancestor patches are pruned at yield
|
|
1351
|
+
return;
|
|
1343
1352
|
}
|
|
1344
|
-
|
|
1353
|
+
cancelAsyncPayload(exeContext, asyncRecord);
|
|
1345
1354
|
});
|
|
1346
1355
|
}
|
|
1347
1356
|
/**
|