@graphql-tools/executor 0.0.2-alpha-20221029195929-bc9be579 → 0.0.2-alpha-20221029200225-c09daca7
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 +109 -656
- package/cjs/execution/subscribe.js +158 -0
- package/cjs/index.js +0 -1
- package/esm/execution/execute.js +108 -653
- package/esm/execution/subscribe.js +153 -0
- package/esm/index.js +0 -1
- package/package.json +2 -2
- package/typings/execution/execute.d.cts +22 -167
- package/typings/execution/execute.d.ts +22 -167
- package/typings/execution/subscribe.d.cts +59 -0
- package/typings/execution/subscribe.d.ts +59 -0
- package/typings/index.d.cts +0 -1
- package/typings/index.d.ts +0 -1
- package/cjs/directives/defer.js +0 -23
- package/cjs/directives/index.js +0 -5
- package/cjs/directives/stream.js +0 -28
- package/cjs/execution/AccumulatorMap.js +0 -21
- package/cjs/execution/collectFields.js +0 -126
- package/cjs/execution/flattenAsyncIterable.js +0 -91
- package/cjs/execution/invariant.js +0 -9
- package/cjs/execution/promiseForObject.js +0 -21
- package/esm/directives/defer.js +0 -20
- package/esm/directives/index.js +0 -2
- package/esm/directives/stream.js +0 -25
- package/esm/execution/AccumulatorMap.js +0 -17
- package/esm/execution/collectFields.js +0 -122
- package/esm/execution/flattenAsyncIterable.js +0 -87
- package/esm/execution/invariant.js +0 -5
- package/esm/execution/promiseForObject.js +0 -17
- package/typings/directives/defer.d.cts +0 -5
- package/typings/directives/defer.d.ts +0 -5
- package/typings/directives/index.d.cts +0 -2
- package/typings/directives/index.d.ts +0 -2
- package/typings/directives/stream.d.cts +0 -5
- package/typings/directives/stream.d.ts +0 -5
- package/typings/execution/AccumulatorMap.d.cts +0 -7
- package/typings/execution/AccumulatorMap.d.ts +0 -7
- package/typings/execution/collectFields.d.cts +0 -32
- package/typings/execution/collectFields.d.ts +0 -32
- package/typings/execution/flattenAsyncIterable.d.cts +0 -7
- package/typings/execution/flattenAsyncIterable.d.ts +0 -7
- package/typings/execution/invariant.d.cts +0 -1
- package/typings/execution/invariant.d.ts +0 -1
- package/typings/execution/promiseForObject.d.cts +0 -12
- package/typings/execution/promiseForObject.d.ts +0 -12
package/cjs/execution/execute.js
CHANGED
|
@@ -1,21 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.getFieldDef = exports.createSourceEventStream = exports.
|
|
3
|
+
exports.getFieldDef = exports.createSourceEventStream = exports.subscribe = exports.defaultFieldResolver = exports.defaultTypeResolver = exports.buildResolveInfo = exports.buildExecutionContext = exports.assertValidExecutionArguments = exports.executeSync = exports.execute = void 0;
|
|
4
4
|
const graphql_1 = require("graphql");
|
|
5
5
|
const utils_1 = require("@graphql-tools/utils");
|
|
6
6
|
const values_js_1 = require("./values.js");
|
|
7
|
-
const promiseForObject_js_1 = require("./promiseForObject.js");
|
|
8
|
-
const flattenAsyncIterable_js_1 = require("./flattenAsyncIterable.js");
|
|
9
|
-
const collectFields_js_1 = require("./collectFields.js");
|
|
10
|
-
const index_js_1 = require("../directives/index.js");
|
|
11
|
-
const invariant_js_1 = require("./invariant.js");
|
|
12
|
-
/**
|
|
13
|
-
* A memoized collection of relevant subfields with regard to the return
|
|
14
|
-
* type. Memoizing ensures the subfields are not repeatedly calculated, which
|
|
15
|
-
* saves overhead when resolving lists of values.
|
|
16
|
-
*/
|
|
17
|
-
const collectSubfields = (0, utils_1.memoize3)((exeContext, returnType, fieldNodes) => (0, collectFields_js_1.collectSubfields)(exeContext.schema, exeContext.fragments, exeContext.variableValues, returnType, fieldNodes));
|
|
18
|
-
const UNEXPECTED_MULTIPLE_PAYLOADS = 'Executing this GraphQL operation would unexpectedly produce multiple payloads (due to @defer or @stream directive)';
|
|
19
7
|
/**
|
|
20
8
|
* Implements the "Executing requests" section of the GraphQL specification.
|
|
21
9
|
*
|
|
@@ -25,44 +13,8 @@ const UNEXPECTED_MULTIPLE_PAYLOADS = 'Executing this GraphQL operation would une
|
|
|
25
13
|
*
|
|
26
14
|
* If the arguments to this function do not result in a legal execution context,
|
|
27
15
|
* a GraphQLError will be thrown immediately explaining the invalid input.
|
|
28
|
-
*
|
|
29
|
-
* This function does not support incremental delivery (`@defer` and `@stream`).
|
|
30
|
-
* If an operation which would defer or stream data is executed with this
|
|
31
|
-
* function, it will throw or resolve to an object containing an error instead.
|
|
32
|
-
* Use `experimentalExecuteIncrementally` if you want to support incremental
|
|
33
|
-
* delivery.
|
|
34
16
|
*/
|
|
35
17
|
function execute(args) {
|
|
36
|
-
const result = experimentalExecuteIncrementally(args);
|
|
37
|
-
if (!(0, utils_1.isPromise)(result)) {
|
|
38
|
-
if ('initialResult' in result) {
|
|
39
|
-
throw new Error(UNEXPECTED_MULTIPLE_PAYLOADS);
|
|
40
|
-
}
|
|
41
|
-
return result;
|
|
42
|
-
}
|
|
43
|
-
return result.then(incrementalResult => {
|
|
44
|
-
if ('initialResult' in incrementalResult) {
|
|
45
|
-
return {
|
|
46
|
-
errors: [(0, utils_1.createGraphQLError)(UNEXPECTED_MULTIPLE_PAYLOADS)],
|
|
47
|
-
};
|
|
48
|
-
}
|
|
49
|
-
return incrementalResult;
|
|
50
|
-
});
|
|
51
|
-
}
|
|
52
|
-
exports.execute = execute;
|
|
53
|
-
/**
|
|
54
|
-
* Implements the "Executing requests" section of the GraphQL specification,
|
|
55
|
-
* including `@defer` and `@stream` as proposed in
|
|
56
|
-
* https://github.com/graphql/graphql-spec/pull/742
|
|
57
|
-
*
|
|
58
|
-
* This function returns a Promise of an ExperimentalIncrementalExecutionResults
|
|
59
|
-
* object. This object either consists of a single ExecutionResult, or an
|
|
60
|
-
* object containing an `initialResult` and a stream of `subsequentResults`.
|
|
61
|
-
*
|
|
62
|
-
* If the arguments to this function do not result in a legal execution context,
|
|
63
|
-
* a GraphQLError will be thrown immediately explaining the invalid input.
|
|
64
|
-
*/
|
|
65
|
-
function experimentalExecuteIncrementally(args) {
|
|
66
18
|
// If a valid execution context cannot be created due to incorrect arguments,
|
|
67
19
|
// a "Response" with only errors is returned.
|
|
68
20
|
const exeContext = buildExecutionContext(args);
|
|
@@ -72,7 +24,7 @@ function experimentalExecuteIncrementally(args) {
|
|
|
72
24
|
}
|
|
73
25
|
return executeImpl(exeContext);
|
|
74
26
|
}
|
|
75
|
-
exports.
|
|
27
|
+
exports.execute = execute;
|
|
76
28
|
function executeImpl(exeContext) {
|
|
77
29
|
// Return a Promise that will eventually resolve to the data described by
|
|
78
30
|
// The "Response" section of the GraphQL specification.
|
|
@@ -88,34 +40,12 @@ function executeImpl(exeContext) {
|
|
|
88
40
|
try {
|
|
89
41
|
const result = executeOperation(exeContext);
|
|
90
42
|
if ((0, utils_1.isPromise)(result)) {
|
|
91
|
-
return result.then(data => {
|
|
92
|
-
const initialResult = buildResponse(data, exeContext.errors);
|
|
93
|
-
if (exeContext.subsequentPayloads.size > 0) {
|
|
94
|
-
return {
|
|
95
|
-
initialResult: {
|
|
96
|
-
...initialResult,
|
|
97
|
-
hasNext: true,
|
|
98
|
-
},
|
|
99
|
-
subsequentResults: yieldSubsequentPayloads(exeContext),
|
|
100
|
-
};
|
|
101
|
-
}
|
|
102
|
-
return initialResult;
|
|
103
|
-
}, error => {
|
|
43
|
+
return result.then(data => buildResponse(data, exeContext.errors), error => {
|
|
104
44
|
exeContext.errors.push(error);
|
|
105
45
|
return buildResponse(null, exeContext.errors);
|
|
106
46
|
});
|
|
107
47
|
}
|
|
108
|
-
|
|
109
|
-
if (exeContext.subsequentPayloads.size > 0) {
|
|
110
|
-
return {
|
|
111
|
-
initialResult: {
|
|
112
|
-
...initialResult,
|
|
113
|
-
hasNext: true,
|
|
114
|
-
},
|
|
115
|
-
subsequentResults: yieldSubsequentPayloads(exeContext),
|
|
116
|
-
};
|
|
117
|
-
}
|
|
118
|
-
return initialResult;
|
|
48
|
+
return buildResponse(result, exeContext.errors);
|
|
119
49
|
}
|
|
120
50
|
catch (error) {
|
|
121
51
|
exeContext.errors.push(error);
|
|
@@ -128,9 +58,9 @@ function executeImpl(exeContext) {
|
|
|
128
58
|
* that all field resolvers are also synchronous.
|
|
129
59
|
*/
|
|
130
60
|
function executeSync(args) {
|
|
131
|
-
const result =
|
|
61
|
+
const result = execute(args);
|
|
132
62
|
// Assert that the execution was synchronous.
|
|
133
|
-
if ((0, utils_1.isPromise)(result)
|
|
63
|
+
if ((0, utils_1.isPromise)(result)) {
|
|
134
64
|
throw new Error('GraphQL execution failed to complete synchronously.');
|
|
135
65
|
}
|
|
136
66
|
return result;
|
|
@@ -218,7 +148,6 @@ function buildExecutionContext(args) {
|
|
|
218
148
|
fieldResolver: fieldResolver !== null && fieldResolver !== void 0 ? fieldResolver : exports.defaultFieldResolver,
|
|
219
149
|
typeResolver: typeResolver !== null && typeResolver !== void 0 ? typeResolver : exports.defaultTypeResolver,
|
|
220
150
|
subscribeFieldResolver: subscribeFieldResolver !== null && subscribeFieldResolver !== void 0 ? subscribeFieldResolver : exports.defaultFieldResolver,
|
|
221
|
-
subsequentPayloads: new Set(),
|
|
222
151
|
errors: [],
|
|
223
152
|
};
|
|
224
153
|
}
|
|
@@ -227,7 +156,6 @@ function buildPerEventExecutionContext(exeContext, payload) {
|
|
|
227
156
|
return {
|
|
228
157
|
...exeContext,
|
|
229
158
|
rootValue: payload,
|
|
230
|
-
subsequentPayloads: new Set(),
|
|
231
159
|
errors: [],
|
|
232
160
|
};
|
|
233
161
|
}
|
|
@@ -237,32 +165,26 @@ function buildPerEventExecutionContext(exeContext, payload) {
|
|
|
237
165
|
function executeOperation(exeContext) {
|
|
238
166
|
const { operation, schema, fragments, variableValues, rootValue } = exeContext;
|
|
239
167
|
const rootType = (0, utils_1.getDefinedRootType)(schema, operation.operation, [operation]);
|
|
240
|
-
|
|
241
|
-
(0, utils_1.createGraphQLError)(`Schema is not configured to execute ${operation.operation} operation.`, {
|
|
242
|
-
nodes: operation,
|
|
243
|
-
});
|
|
244
|
-
}
|
|
245
|
-
const { fields: rootFields, patches } = (0, collectFields_js_1.collectFields)(schema, fragments, variableValues, rootType, operation.selectionSet);
|
|
168
|
+
const rootFields = (0, utils_1.collectFields)(schema, fragments, variableValues, rootType, operation.selectionSet);
|
|
246
169
|
const path = undefined;
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
}
|
|
258
|
-
return result;
|
|
170
|
+
switch (operation.operation) {
|
|
171
|
+
case 'query':
|
|
172
|
+
return executeFields(exeContext, rootType, rootValue, path, rootFields);
|
|
173
|
+
case 'mutation':
|
|
174
|
+
return executeFieldsSerially(exeContext, rootType, rootValue, path, rootFields);
|
|
175
|
+
case 'subscription':
|
|
176
|
+
// TODO: deprecate `subscribe` and move all logic here
|
|
177
|
+
// Temporary solution until we finish merging execute and subscribe together
|
|
178
|
+
return executeFields(exeContext, rootType, rootValue, path, rootFields);
|
|
179
|
+
}
|
|
180
|
+
throw new Error(`Can only execute queries, mutations and subscriptions, got "${operation.operation}".`);
|
|
259
181
|
}
|
|
260
182
|
/**
|
|
261
183
|
* Implements the "Executing selection sets" section of the spec
|
|
262
184
|
* for fields that must be executed serially.
|
|
263
185
|
*/
|
|
264
186
|
function executeFieldsSerially(exeContext, parentType, sourceValue, path, fields) {
|
|
265
|
-
return (0, utils_1.promiseReduce)(fields, (results, [responseName, fieldNodes]) => {
|
|
187
|
+
return (0, utils_1.promiseReduce)(fields.entries(), (results, [responseName, fieldNodes]) => {
|
|
266
188
|
const fieldPath = (0, utils_1.addPath)(path, responseName, parentType.name);
|
|
267
189
|
const result = executeField(exeContext, parentType, sourceValue, fieldNodes, fieldPath);
|
|
268
190
|
if (result === undefined) {
|
|
@@ -282,30 +204,19 @@ function executeFieldsSerially(exeContext, parentType, sourceValue, path, fields
|
|
|
282
204
|
* Implements the "Executing selection sets" section of the spec
|
|
283
205
|
* for fields that may be executed in parallel.
|
|
284
206
|
*/
|
|
285
|
-
function executeFields(exeContext, parentType, sourceValue, path, fields
|
|
207
|
+
function executeFields(exeContext, parentType, sourceValue, path, fields) {
|
|
286
208
|
const results = Object.create(null);
|
|
287
209
|
let containsPromise = false;
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
containsPromise = true;
|
|
296
|
-
}
|
|
210
|
+
for (const [responseName, fieldNodes] of fields.entries()) {
|
|
211
|
+
const fieldPath = (0, utils_1.addPath)(path, responseName, parentType.name);
|
|
212
|
+
const result = executeField(exeContext, parentType, sourceValue, fieldNodes, fieldPath);
|
|
213
|
+
if (result !== undefined) {
|
|
214
|
+
results[responseName] = result;
|
|
215
|
+
if ((0, utils_1.isPromise)(result)) {
|
|
216
|
+
containsPromise = true;
|
|
297
217
|
}
|
|
298
218
|
}
|
|
299
219
|
}
|
|
300
|
-
catch (error) {
|
|
301
|
-
if (containsPromise) {
|
|
302
|
-
// Ensure that any promises returned by other fields are handled, as they may also reject.
|
|
303
|
-
return (0, promiseForObject_js_1.promiseForObject)(results).finally(() => {
|
|
304
|
-
throw error;
|
|
305
|
-
});
|
|
306
|
-
}
|
|
307
|
-
throw error;
|
|
308
|
-
}
|
|
309
220
|
// If there are no promises, we can just return the object
|
|
310
221
|
if (!containsPromise) {
|
|
311
222
|
return results;
|
|
@@ -313,7 +224,13 @@ function executeFields(exeContext, parentType, sourceValue, path, fields, asyncP
|
|
|
313
224
|
// Otherwise, results is a map from field name to the result of resolving that
|
|
314
225
|
// field, which is possibly a promise. Return a promise that will return this
|
|
315
226
|
// same map, but with any promises replaced with the values they resolved to.
|
|
316
|
-
return (
|
|
227
|
+
return Promise.all(Object.values(results)).then(resolvedValues => {
|
|
228
|
+
const resolvedObject = Object.create(null);
|
|
229
|
+
for (const [i, key] of Object.keys(results).entries()) {
|
|
230
|
+
resolvedObject[key] = resolvedValues[i];
|
|
231
|
+
}
|
|
232
|
+
return resolvedObject;
|
|
233
|
+
});
|
|
317
234
|
}
|
|
318
235
|
/**
|
|
319
236
|
* Implements the "Executing fields" section of the spec
|
|
@@ -321,15 +238,14 @@ function executeFields(exeContext, parentType, sourceValue, path, fields, asyncP
|
|
|
321
238
|
* calling its resolve function, then calls completeValue to complete promises,
|
|
322
239
|
* serialize scalars, or execute the sub-selection-set for objects.
|
|
323
240
|
*/
|
|
324
|
-
function executeField(exeContext, parentType, source, fieldNodes, path
|
|
325
|
-
var _a
|
|
326
|
-
const errors = (_a = asyncPayloadRecord === null || asyncPayloadRecord === void 0 ? void 0 : asyncPayloadRecord.errors) !== null && _a !== void 0 ? _a : exeContext.errors;
|
|
241
|
+
function executeField(exeContext, parentType, source, fieldNodes, path) {
|
|
242
|
+
var _a;
|
|
327
243
|
const fieldDef = getFieldDef(exeContext.schema, parentType, fieldNodes[0]);
|
|
328
244
|
if (!fieldDef) {
|
|
329
245
|
return;
|
|
330
246
|
}
|
|
331
247
|
const returnType = fieldDef.type;
|
|
332
|
-
const resolveFn = (
|
|
248
|
+
const resolveFn = (_a = fieldDef.resolve) !== null && _a !== void 0 ? _a : exeContext.fieldResolver;
|
|
333
249
|
const info = buildResolveInfo(exeContext, fieldDef, fieldNodes, parentType, path);
|
|
334
250
|
// Get the resolve function, regardless of if its result is normal or abrupt (error).
|
|
335
251
|
try {
|
|
@@ -344,28 +260,24 @@ function executeField(exeContext, parentType, source, fieldNodes, path, asyncPay
|
|
|
344
260
|
const result = resolveFn(source, args, contextValue, info);
|
|
345
261
|
let completed;
|
|
346
262
|
if ((0, utils_1.isPromise)(result)) {
|
|
347
|
-
completed = result.then(resolved => completeValue(exeContext, returnType, fieldNodes, info, path, resolved
|
|
263
|
+
completed = result.then(resolved => completeValue(exeContext, returnType, fieldNodes, info, path, resolved));
|
|
348
264
|
}
|
|
349
265
|
else {
|
|
350
|
-
completed = completeValue(exeContext, returnType, fieldNodes, info, path, result
|
|
266
|
+
completed = completeValue(exeContext, returnType, fieldNodes, info, path, result);
|
|
351
267
|
}
|
|
352
268
|
if ((0, utils_1.isPromise)(completed)) {
|
|
353
269
|
// Note: we don't rely on a `catch` method, but we do expect "thenable"
|
|
354
270
|
// to take a second callback for the error case.
|
|
355
271
|
return completed.then(undefined, rawError => {
|
|
356
272
|
const error = (0, graphql_1.locatedError)(rawError, fieldNodes, (0, utils_1.pathToArray)(path));
|
|
357
|
-
|
|
358
|
-
filterSubsequentPayloads(exeContext, path, asyncPayloadRecord);
|
|
359
|
-
return handledError;
|
|
273
|
+
return handleFieldError(error, returnType, exeContext);
|
|
360
274
|
});
|
|
361
275
|
}
|
|
362
276
|
return completed;
|
|
363
277
|
}
|
|
364
278
|
catch (rawError) {
|
|
365
279
|
const error = (0, graphql_1.locatedError)(rawError, fieldNodes, (0, utils_1.pathToArray)(path));
|
|
366
|
-
|
|
367
|
-
filterSubsequentPayloads(exeContext, path, asyncPayloadRecord);
|
|
368
|
-
return handledError;
|
|
280
|
+
return handleFieldError(error, returnType, exeContext);
|
|
369
281
|
}
|
|
370
282
|
}
|
|
371
283
|
/**
|
|
@@ -389,7 +301,7 @@ function buildResolveInfo(exeContext, fieldDef, fieldNodes, parentType, path) {
|
|
|
389
301
|
};
|
|
390
302
|
}
|
|
391
303
|
exports.buildResolveInfo = buildResolveInfo;
|
|
392
|
-
function handleFieldError(error, returnType,
|
|
304
|
+
function handleFieldError(error, returnType, exeContext) {
|
|
393
305
|
// If the field type is non-nullable, then it is resolved without any
|
|
394
306
|
// protection from errors, however it still properly locates the error.
|
|
395
307
|
if ((0, graphql_1.isNonNullType)(returnType)) {
|
|
@@ -397,7 +309,7 @@ function handleFieldError(error, returnType, errors) {
|
|
|
397
309
|
}
|
|
398
310
|
// Otherwise, error protection is applied, logging the error and resolving
|
|
399
311
|
// a null value for this field if one is encountered.
|
|
400
|
-
errors.push(error);
|
|
312
|
+
exeContext.errors.push(error);
|
|
401
313
|
return null;
|
|
402
314
|
}
|
|
403
315
|
/**
|
|
@@ -421,7 +333,7 @@ function handleFieldError(error, returnType, errors) {
|
|
|
421
333
|
* Otherwise, the field type expects a sub-selection set, and will complete the
|
|
422
334
|
* value by executing all sub-selections.
|
|
423
335
|
*/
|
|
424
|
-
function completeValue(exeContext, returnType, fieldNodes, info, path, result
|
|
336
|
+
function completeValue(exeContext, returnType, fieldNodes, info, path, result) {
|
|
425
337
|
// If result is an Error, throw a located error.
|
|
426
338
|
if (result instanceof Error) {
|
|
427
339
|
throw result;
|
|
@@ -429,7 +341,7 @@ function completeValue(exeContext, returnType, fieldNodes, info, path, result, a
|
|
|
429
341
|
// If field type is NonNull, complete for inner type, and throw field error
|
|
430
342
|
// if result is null.
|
|
431
343
|
if ((0, graphql_1.isNonNullType)(returnType)) {
|
|
432
|
-
const completed = completeValue(exeContext, returnType.ofType, fieldNodes, info, path, result
|
|
344
|
+
const completed = completeValue(exeContext, returnType.ofType, fieldNodes, info, path, result);
|
|
433
345
|
if (completed === null) {
|
|
434
346
|
throw new Error(`Cannot return null for non-nullable field ${info.parentType.name}.${info.fieldName}.`);
|
|
435
347
|
}
|
|
@@ -441,7 +353,7 @@ function completeValue(exeContext, returnType, fieldNodes, info, path, result, a
|
|
|
441
353
|
}
|
|
442
354
|
// If field type is List, complete each item in the list with the inner type
|
|
443
355
|
if ((0, graphql_1.isListType)(returnType)) {
|
|
444
|
-
return completeListValue(exeContext, returnType, fieldNodes, info, path, result
|
|
356
|
+
return completeListValue(exeContext, returnType, fieldNodes, info, path, result);
|
|
445
357
|
}
|
|
446
358
|
// If field type is a leaf type, Scalar or Enum, serialize to a valid value,
|
|
447
359
|
// returning null if serialization is not possible.
|
|
@@ -451,74 +363,51 @@ function completeValue(exeContext, returnType, fieldNodes, info, path, result, a
|
|
|
451
363
|
// If field type is an abstract type, Interface or Union, determine the
|
|
452
364
|
// runtime Object type and complete for that type.
|
|
453
365
|
if ((0, graphql_1.isAbstractType)(returnType)) {
|
|
454
|
-
return completeAbstractValue(exeContext, returnType, fieldNodes, info, path, result
|
|
366
|
+
return completeAbstractValue(exeContext, returnType, fieldNodes, info, path, result);
|
|
455
367
|
}
|
|
456
368
|
// If field type is Object, execute and complete all sub-selections.
|
|
457
369
|
if ((0, graphql_1.isObjectType)(returnType)) {
|
|
458
|
-
return completeObjectValue(exeContext, returnType, fieldNodes, info, path, result
|
|
370
|
+
return completeObjectValue(exeContext, returnType, fieldNodes, info, path, result);
|
|
459
371
|
}
|
|
460
372
|
/* c8 ignore next 6 */
|
|
461
373
|
// Not reachable, all possible output types have been considered.
|
|
462
374
|
console.assert(false, 'Cannot complete value of unexpected output type: ' + (0, utils_1.inspect)(returnType));
|
|
463
375
|
}
|
|
464
|
-
/**
|
|
465
|
-
* Returns an object containing the `@stream` arguments if a field should be
|
|
466
|
-
* streamed based on the experimental flag, stream directive present and
|
|
467
|
-
* not disabled by the "if" argument.
|
|
468
|
-
*/
|
|
469
|
-
function getStreamValues(exeContext, fieldNodes, path) {
|
|
470
|
-
// do not stream inner lists of multi-dimensional lists
|
|
471
|
-
if (typeof path.key === 'number') {
|
|
472
|
-
return;
|
|
473
|
-
}
|
|
474
|
-
// validation only allows equivalent streams on multiple fields, so it is
|
|
475
|
-
// safe to only check the first fieldNode for the stream directive
|
|
476
|
-
const stream = (0, graphql_1.getDirectiveValues)(index_js_1.GraphQLStreamDirective, fieldNodes[0], exeContext.variableValues);
|
|
477
|
-
if (!stream) {
|
|
478
|
-
return;
|
|
479
|
-
}
|
|
480
|
-
if (stream['if'] === false) {
|
|
481
|
-
return;
|
|
482
|
-
}
|
|
483
|
-
(0, invariant_js_1.invariant)(typeof stream['initialCount'] === 'number', 'initialCount must be a number');
|
|
484
|
-
(0, invariant_js_1.invariant)(stream['initialCount'] >= 0, 'initialCount must be a positive integer');
|
|
485
|
-
return {
|
|
486
|
-
initialCount: stream['initialCount'],
|
|
487
|
-
label: typeof stream['label'] === 'string' ? stream['label'] : undefined,
|
|
488
|
-
};
|
|
489
|
-
}
|
|
490
376
|
/**
|
|
491
377
|
* Complete a async iterator value by completing the result and calling
|
|
492
378
|
* recursively until all the results are completed.
|
|
493
379
|
*/
|
|
494
|
-
async function completeAsyncIteratorValue(exeContext, itemType, fieldNodes, info, path, iterator
|
|
495
|
-
var _a;
|
|
496
|
-
const errors = (_a = asyncPayloadRecord === null || asyncPayloadRecord === void 0 ? void 0 : asyncPayloadRecord.errors) !== null && _a !== void 0 ? _a : exeContext.errors;
|
|
497
|
-
const stream = getStreamValues(exeContext, fieldNodes, path);
|
|
380
|
+
async function completeAsyncIteratorValue(exeContext, itemType, fieldNodes, info, path, iterator) {
|
|
498
381
|
let containsPromise = false;
|
|
499
382
|
const completedResults = [];
|
|
500
383
|
let index = 0;
|
|
501
384
|
while (true) {
|
|
502
|
-
|
|
503
|
-
executeStreamIterator(index, iterator, exeContext, fieldNodes, info, itemType, path, stream.label, asyncPayloadRecord);
|
|
504
|
-
break;
|
|
505
|
-
}
|
|
506
|
-
const itemPath = (0, utils_1.addPath)(path, index, undefined);
|
|
507
|
-
let iteration;
|
|
385
|
+
const fieldPath = (0, utils_1.addPath)(path, index, undefined);
|
|
508
386
|
try {
|
|
509
|
-
|
|
510
|
-
if (
|
|
387
|
+
const { value, done } = await iterator.next();
|
|
388
|
+
if (done) {
|
|
511
389
|
break;
|
|
512
390
|
}
|
|
391
|
+
try {
|
|
392
|
+
// TODO can the error checking logic be consolidated with completeListValue?
|
|
393
|
+
const completedItem = completeValue(exeContext, itemType, fieldNodes, info, fieldPath, value);
|
|
394
|
+
if ((0, utils_1.isPromise)(completedItem)) {
|
|
395
|
+
containsPromise = true;
|
|
396
|
+
}
|
|
397
|
+
completedResults.push(completedItem);
|
|
398
|
+
}
|
|
399
|
+
catch (rawError) {
|
|
400
|
+
completedResults.push(null);
|
|
401
|
+
const error = (0, graphql_1.locatedError)(rawError, fieldNodes, (0, utils_1.pathToArray)(fieldPath));
|
|
402
|
+
handleFieldError(error, itemType, exeContext);
|
|
403
|
+
}
|
|
513
404
|
}
|
|
514
405
|
catch (rawError) {
|
|
515
|
-
|
|
516
|
-
|
|
406
|
+
completedResults.push(null);
|
|
407
|
+
const error = (0, graphql_1.locatedError)(rawError, fieldNodes, (0, utils_1.pathToArray)(fieldPath));
|
|
408
|
+
handleFieldError(error, itemType, exeContext);
|
|
517
409
|
break;
|
|
518
410
|
}
|
|
519
|
-
if (completeListItemValue(iteration.value, completedResults, errors, exeContext, itemType, fieldNodes, info, itemPath, asyncPayloadRecord)) {
|
|
520
|
-
containsPromise = true;
|
|
521
|
-
}
|
|
522
411
|
index += 1;
|
|
523
412
|
}
|
|
524
413
|
return containsPromise ? Promise.all(completedResults) : completedResults;
|
|
@@ -527,75 +416,48 @@ async function completeAsyncIteratorValue(exeContext, itemType, fieldNodes, info
|
|
|
527
416
|
* Complete a list value by completing each item in the list with the
|
|
528
417
|
* inner type
|
|
529
418
|
*/
|
|
530
|
-
function completeListValue(exeContext, returnType, fieldNodes, info, path, result
|
|
531
|
-
var _a;
|
|
419
|
+
function completeListValue(exeContext, returnType, fieldNodes, info, path, result) {
|
|
532
420
|
const itemType = returnType.ofType;
|
|
533
|
-
const errors = (_a = asyncPayloadRecord === null || asyncPayloadRecord === void 0 ? void 0 : asyncPayloadRecord.errors) !== null && _a !== void 0 ? _a : exeContext.errors;
|
|
534
421
|
if ((0, utils_1.isAsyncIterable)(result)) {
|
|
535
422
|
const iterator = result[Symbol.asyncIterator]();
|
|
536
|
-
return completeAsyncIteratorValue(exeContext, itemType, fieldNodes, info, path, iterator
|
|
423
|
+
return completeAsyncIteratorValue(exeContext, itemType, fieldNodes, info, path, iterator);
|
|
537
424
|
}
|
|
538
425
|
if (!(0, utils_1.isIterableObject)(result)) {
|
|
539
426
|
throw (0, utils_1.createGraphQLError)(`Expected Iterable, but did not find one for field "${info.parentType.name}.${info.fieldName}".`);
|
|
540
427
|
}
|
|
541
|
-
const stream = getStreamValues(exeContext, fieldNodes, path);
|
|
542
428
|
// This is specified as a simple map, however we're optimizing the path
|
|
543
429
|
// where the list contains no Promises by avoiding creating another Promise.
|
|
544
430
|
let containsPromise = false;
|
|
545
|
-
|
|
546
|
-
const completedResults = [];
|
|
547
|
-
let index = 0;
|
|
548
|
-
for (const item of result) {
|
|
431
|
+
const completedResults = Array.from(result, (item, index) => {
|
|
549
432
|
// No need to modify the info object containing the path,
|
|
550
433
|
// since from here on it is not ever accessed by resolver functions.
|
|
551
434
|
const itemPath = (0, utils_1.addPath)(path, index, undefined);
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
435
|
+
try {
|
|
436
|
+
let completedItem;
|
|
437
|
+
if ((0, utils_1.isPromise)(item)) {
|
|
438
|
+
completedItem = item.then(resolved => completeValue(exeContext, itemType, fieldNodes, info, itemPath, resolved));
|
|
439
|
+
}
|
|
440
|
+
else {
|
|
441
|
+
completedItem = completeValue(exeContext, itemType, fieldNodes, info, itemPath, item);
|
|
442
|
+
}
|
|
443
|
+
if ((0, utils_1.isPromise)(completedItem)) {
|
|
444
|
+
containsPromise = true;
|
|
445
|
+
// Note: we don't rely on a `catch` method, but we do expect "thenable"
|
|
446
|
+
// to take a second callback for the error case.
|
|
447
|
+
return completedItem.then(undefined, rawError => {
|
|
448
|
+
const error = (0, graphql_1.locatedError)(rawError, fieldNodes, (0, utils_1.pathToArray)(itemPath));
|
|
449
|
+
return handleFieldError(error, itemType, exeContext);
|
|
450
|
+
});
|
|
451
|
+
}
|
|
452
|
+
return completedItem;
|
|
556
453
|
}
|
|
557
|
-
|
|
558
|
-
|
|
454
|
+
catch (rawError) {
|
|
455
|
+
const error = (0, graphql_1.locatedError)(rawError, fieldNodes, (0, utils_1.pathToArray)(itemPath));
|
|
456
|
+
return handleFieldError(error, itemType, exeContext);
|
|
559
457
|
}
|
|
560
|
-
|
|
561
|
-
}
|
|
458
|
+
});
|
|
562
459
|
return containsPromise ? Promise.all(completedResults) : completedResults;
|
|
563
460
|
}
|
|
564
|
-
/**
|
|
565
|
-
* Complete a list item value by adding it to the completed results.
|
|
566
|
-
*
|
|
567
|
-
* Returns true if the value is a Promise.
|
|
568
|
-
*/
|
|
569
|
-
function completeListItemValue(item, completedResults, errors, exeContext, itemType, fieldNodes, info, itemPath, asyncPayloadRecord) {
|
|
570
|
-
try {
|
|
571
|
-
let completedItem;
|
|
572
|
-
if ((0, utils_1.isPromise)(item)) {
|
|
573
|
-
completedItem = item.then(resolved => completeValue(exeContext, itemType, fieldNodes, info, itemPath, resolved, asyncPayloadRecord));
|
|
574
|
-
}
|
|
575
|
-
else {
|
|
576
|
-
completedItem = completeValue(exeContext, itemType, fieldNodes, info, itemPath, item, asyncPayloadRecord);
|
|
577
|
-
}
|
|
578
|
-
if ((0, utils_1.isPromise)(completedItem)) {
|
|
579
|
-
// Note: we don't rely on a `catch` method, but we do expect "thenable"
|
|
580
|
-
// to take a second callback for the error case.
|
|
581
|
-
completedResults.push(completedItem.then(undefined, rawError => {
|
|
582
|
-
const error = (0, graphql_1.locatedError)(rawError, fieldNodes, (0, utils_1.pathToArray)(itemPath));
|
|
583
|
-
const handledError = handleFieldError(error, itemType, errors);
|
|
584
|
-
filterSubsequentPayloads(exeContext, itemPath, asyncPayloadRecord);
|
|
585
|
-
return handledError;
|
|
586
|
-
}));
|
|
587
|
-
return true;
|
|
588
|
-
}
|
|
589
|
-
completedResults.push(completedItem);
|
|
590
|
-
}
|
|
591
|
-
catch (rawError) {
|
|
592
|
-
const error = (0, graphql_1.locatedError)(rawError, fieldNodes, (0, utils_1.pathToArray)(itemPath));
|
|
593
|
-
const handledError = handleFieldError(error, itemType, errors);
|
|
594
|
-
filterSubsequentPayloads(exeContext, itemPath, asyncPayloadRecord);
|
|
595
|
-
completedResults.push(handledError);
|
|
596
|
-
}
|
|
597
|
-
return false;
|
|
598
|
-
}
|
|
599
461
|
/**
|
|
600
462
|
* Complete a Scalar or Enum by serializing to a valid value, returning
|
|
601
463
|
* null if serialization is not possible.
|
|
@@ -612,15 +474,15 @@ function completeLeafValue(returnType, result) {
|
|
|
612
474
|
* Complete a value of an abstract type by determining the runtime object type
|
|
613
475
|
* of that value, then complete the value for that type.
|
|
614
476
|
*/
|
|
615
|
-
function completeAbstractValue(exeContext, returnType, fieldNodes, info, path, result
|
|
477
|
+
function completeAbstractValue(exeContext, returnType, fieldNodes, info, path, result) {
|
|
616
478
|
var _a;
|
|
617
479
|
const resolveTypeFn = (_a = returnType.resolveType) !== null && _a !== void 0 ? _a : exeContext.typeResolver;
|
|
618
480
|
const contextValue = exeContext.contextValue;
|
|
619
481
|
const runtimeType = resolveTypeFn(result, contextValue, info, returnType);
|
|
620
482
|
if ((0, utils_1.isPromise)(runtimeType)) {
|
|
621
|
-
return runtimeType.then(resolvedRuntimeType => completeObjectValue(exeContext, ensureValidRuntimeType(resolvedRuntimeType, exeContext, returnType, fieldNodes, info, result), fieldNodes, info, path, result
|
|
483
|
+
return runtimeType.then(resolvedRuntimeType => completeObjectValue(exeContext, ensureValidRuntimeType(resolvedRuntimeType, exeContext, returnType, fieldNodes, info, result), fieldNodes, info, path, result));
|
|
622
484
|
}
|
|
623
|
-
return completeObjectValue(exeContext, ensureValidRuntimeType(runtimeType, exeContext, returnType, fieldNodes, info, result), fieldNodes, info, path, result
|
|
485
|
+
return completeObjectValue(exeContext, ensureValidRuntimeType(runtimeType, exeContext, returnType, fieldNodes, info, result), fieldNodes, info, path, result);
|
|
624
486
|
}
|
|
625
487
|
function ensureValidRuntimeType(runtimeTypeName, exeContext, returnType, fieldNodes, info, result) {
|
|
626
488
|
if (runtimeTypeName == null) {
|
|
@@ -650,7 +512,9 @@ function ensureValidRuntimeType(runtimeTypeName, exeContext, returnType, fieldNo
|
|
|
650
512
|
/**
|
|
651
513
|
* Complete an Object value by executing all sub-selections.
|
|
652
514
|
*/
|
|
653
|
-
function completeObjectValue(exeContext, returnType, fieldNodes, info, path, result
|
|
515
|
+
function completeObjectValue(exeContext, returnType, fieldNodes, info, path, result) {
|
|
516
|
+
// Collect sub-fields to execute to complete this value.
|
|
517
|
+
const subFieldNodes = (0, utils_1.collectSubFields)(exeContext.schema, exeContext.fragments, exeContext.variableValues, returnType, fieldNodes);
|
|
654
518
|
// If there is an isTypeOf predicate function, call it with the
|
|
655
519
|
// current result. If isTypeOf returns false, then raise an error rather
|
|
656
520
|
// than continuing execution.
|
|
@@ -661,30 +525,20 @@ function completeObjectValue(exeContext, returnType, fieldNodes, info, path, res
|
|
|
661
525
|
if (!resolvedIsTypeOf) {
|
|
662
526
|
throw invalidReturnTypeError(returnType, result, fieldNodes);
|
|
663
527
|
}
|
|
664
|
-
return
|
|
528
|
+
return executeFields(exeContext, returnType, result, path, subFieldNodes);
|
|
665
529
|
});
|
|
666
530
|
}
|
|
667
531
|
if (!isTypeOf) {
|
|
668
532
|
throw invalidReturnTypeError(returnType, result, fieldNodes);
|
|
669
533
|
}
|
|
670
534
|
}
|
|
671
|
-
return
|
|
535
|
+
return executeFields(exeContext, returnType, result, path, subFieldNodes);
|
|
672
536
|
}
|
|
673
537
|
function invalidReturnTypeError(returnType, result, fieldNodes) {
|
|
674
538
|
return (0, utils_1.createGraphQLError)(`Expected value of type "${returnType.name}" but got: ${(0, utils_1.inspect)(result)}.`, {
|
|
675
539
|
nodes: fieldNodes,
|
|
676
540
|
});
|
|
677
541
|
}
|
|
678
|
-
function collectAndExecuteSubfields(exeContext, returnType, fieldNodes, path, result, asyncPayloadRecord) {
|
|
679
|
-
// Collect sub-fields to execute to complete this value.
|
|
680
|
-
const { fields: subFieldNodes, patches: subPatches } = collectSubfields(exeContext, returnType, fieldNodes);
|
|
681
|
-
const subFields = executeFields(exeContext, returnType, result, path, subFieldNodes, asyncPayloadRecord);
|
|
682
|
-
for (const subPatch of subPatches) {
|
|
683
|
-
const { label, fields: subPatchFieldNodes } = subPatch;
|
|
684
|
-
executeDeferredFragment(exeContext, returnType, result, subPatchFieldNodes, label, path, asyncPayloadRecord);
|
|
685
|
-
}
|
|
686
|
-
return subFields;
|
|
687
|
-
}
|
|
688
542
|
/**
|
|
689
543
|
* If a resolveType function is not given, then a default resolve behavior is
|
|
690
544
|
* used which attempts two strategies:
|
|
@@ -752,78 +606,19 @@ exports.defaultFieldResolver = defaultFieldResolver;
|
|
|
752
606
|
* is not an async iterable.
|
|
753
607
|
*
|
|
754
608
|
* If the client-provided arguments to this function do not result in a
|
|
755
|
-
* compliant subscription, a GraphQL Response (ExecutionResult) with
|
|
756
|
-
* errors and no data will be returned.
|
|
609
|
+
* compliant subscription, a GraphQL Response (ExecutionResult) with
|
|
610
|
+
* descriptive errors and no data will be returned.
|
|
757
611
|
*
|
|
758
|
-
* If the source stream could not be created due to faulty subscription
|
|
759
|
-
* logic or underlying systems, the promise will resolve to a single
|
|
612
|
+
* If the source stream could not be created due to faulty subscription
|
|
613
|
+
* resolver logic or underlying systems, the promise will resolve to a single
|
|
760
614
|
* ExecutionResult containing `errors` and no `data`.
|
|
761
615
|
*
|
|
762
616
|
* If the operation succeeded, the promise resolves to an AsyncIterator, which
|
|
763
617
|
* yields a stream of ExecutionResults representing the response stream.
|
|
764
618
|
*
|
|
765
|
-
*
|
|
766
|
-
* If an operation which would defer or stream data is executed with this
|
|
767
|
-
* function, each `InitialIncrementalExecutionResult` and
|
|
768
|
-
* `SubsequentIncrementalExecutionResult` in the result stream will be replaced
|
|
769
|
-
* with an `ExecutionResult` with a single error stating that defer/stream is
|
|
770
|
-
* not supported. Use `experimentalSubscribeIncrementally` if you want to
|
|
771
|
-
* support incremental delivery.
|
|
772
|
-
*
|
|
773
|
-
* Accepts an object with named arguments.
|
|
619
|
+
* Accepts either an object with named arguments, or individual arguments.
|
|
774
620
|
*/
|
|
775
621
|
function subscribe(args) {
|
|
776
|
-
const maybePromise = experimentalSubscribeIncrementally(args);
|
|
777
|
-
if ((0, utils_1.isPromise)(maybePromise)) {
|
|
778
|
-
return maybePromise.then(resultOrIterable => (0, utils_1.isAsyncIterable)(resultOrIterable)
|
|
779
|
-
? (0, utils_1.mapAsyncIterator)(resultOrIterable, ensureSingleExecutionResult)
|
|
780
|
-
: resultOrIterable);
|
|
781
|
-
}
|
|
782
|
-
return (0, utils_1.isAsyncIterable)(maybePromise) ? (0, utils_1.mapAsyncIterator)(maybePromise, ensureSingleExecutionResult) : maybePromise;
|
|
783
|
-
}
|
|
784
|
-
exports.subscribe = subscribe;
|
|
785
|
-
function ensureSingleExecutionResult(result) {
|
|
786
|
-
if ('hasNext' in result) {
|
|
787
|
-
return {
|
|
788
|
-
errors: [(0, utils_1.createGraphQLError)(UNEXPECTED_MULTIPLE_PAYLOADS)],
|
|
789
|
-
};
|
|
790
|
-
}
|
|
791
|
-
return result;
|
|
792
|
-
}
|
|
793
|
-
/**
|
|
794
|
-
* Implements the "Subscribe" algorithm described in the GraphQL specification,
|
|
795
|
-
* including `@defer` and `@stream` as proposed in
|
|
796
|
-
* https://github.com/graphql/graphql-spec/pull/742
|
|
797
|
-
*
|
|
798
|
-
* Returns a Promise which resolves to either an AsyncIterator (if successful)
|
|
799
|
-
* or an ExecutionResult (error). The promise will be rejected if the schema or
|
|
800
|
-
* other arguments to this function are invalid, or if the resolved event stream
|
|
801
|
-
* is not an async iterable.
|
|
802
|
-
*
|
|
803
|
-
* If the client-provided arguments to this function do not result in a
|
|
804
|
-
* compliant subscription, a GraphQL Response (ExecutionResult) with descriptive
|
|
805
|
-
* errors and no data will be returned.
|
|
806
|
-
*
|
|
807
|
-
* If the source stream could not be created due to faulty subscription resolver
|
|
808
|
-
* logic or underlying systems, the promise will resolve to a single
|
|
809
|
-
* ExecutionResult containing `errors` and no `data`.
|
|
810
|
-
*
|
|
811
|
-
* If the operation succeeded, the promise resolves to an AsyncIterator, which
|
|
812
|
-
* yields a stream of result representing the response stream.
|
|
813
|
-
*
|
|
814
|
-
* Each result may be an ExecutionResult with no `hasNext` (if executing the
|
|
815
|
-
* event did not use `@defer` or `@stream`), or an
|
|
816
|
-
* `InitialIncrementalExecutionResult` or `SubsequentIncrementalExecutionResult`
|
|
817
|
-
* (if executing the event used `@defer` or `@stream`). In the case of
|
|
818
|
-
* incremental execution results, each event produces a single
|
|
819
|
-
* `InitialIncrementalExecutionResult` followed by one or more
|
|
820
|
-
* `SubsequentIncrementalExecutionResult`s; all but the last have `hasNext: true`,
|
|
821
|
-
* and the last has `hasNext: false`. There is no interleaving between results
|
|
822
|
-
* generated from the same original event.
|
|
823
|
-
*
|
|
824
|
-
* Accepts an object with named arguments.
|
|
825
|
-
*/
|
|
826
|
-
function experimentalSubscribeIncrementally(args) {
|
|
827
622
|
// If a valid execution context cannot be created due to incorrect arguments,
|
|
828
623
|
// a "Response" with only errors is returned.
|
|
829
624
|
const exeContext = buildExecutionContext(args);
|
|
@@ -837,16 +632,7 @@ function experimentalSubscribeIncrementally(args) {
|
|
|
837
632
|
}
|
|
838
633
|
return mapSourceToResponse(exeContext, resultOrStream);
|
|
839
634
|
}
|
|
840
|
-
exports.
|
|
841
|
-
async function* ensureAsyncIterable(someExecutionResult) {
|
|
842
|
-
if ('initialResult' in someExecutionResult) {
|
|
843
|
-
yield someExecutionResult.initialResult;
|
|
844
|
-
yield* someExecutionResult.subsequentResults;
|
|
845
|
-
}
|
|
846
|
-
else {
|
|
847
|
-
yield someExecutionResult;
|
|
848
|
-
}
|
|
849
|
-
}
|
|
635
|
+
exports.subscribe = subscribe;
|
|
850
636
|
function mapSourceToResponse(exeContext, resultOrStream) {
|
|
851
637
|
if (!(0, utils_1.isAsyncIterable)(resultOrStream)) {
|
|
852
638
|
return resultOrStream;
|
|
@@ -857,7 +643,7 @@ function mapSourceToResponse(exeContext, resultOrStream) {
|
|
|
857
643
|
// the GraphQL specification. The `execute` function provides the
|
|
858
644
|
// "ExecuteSubscriptionEvent" algorithm, as it is nearly identical to the
|
|
859
645
|
// "ExecuteQuery" algorithm, for which `execute` is also used.
|
|
860
|
-
return (0,
|
|
646
|
+
return (0, utils_1.mapAsyncIterator)(resultOrStream[Symbol.asyncIterator](), (payload) => executeImpl(buildPerEventExecutionContext(exeContext, payload)));
|
|
861
647
|
}
|
|
862
648
|
/**
|
|
863
649
|
* Implements the "CreateSourceEventStream" algorithm described in the
|
|
@@ -917,7 +703,7 @@ function executeSubscription(exeContext) {
|
|
|
917
703
|
if (rootType == null) {
|
|
918
704
|
throw (0, utils_1.createGraphQLError)('Schema is not configured to execute subscription operation.', { nodes: operation });
|
|
919
705
|
}
|
|
920
|
-
const
|
|
706
|
+
const rootFields = (0, utils_1.collectFields)(schema, fragments, variableValues, rootType, operation.selectionSet);
|
|
921
707
|
const [responseName, fieldNodes] = [...rootFields.entries()][0];
|
|
922
708
|
const fieldName = fieldNodes[0].name.value;
|
|
923
709
|
const fieldDef = getFieldDef(schema, rootType, fieldNodes[0]);
|
|
@@ -961,339 +747,6 @@ function assertEventStream(result) {
|
|
|
961
747
|
}
|
|
962
748
|
return result;
|
|
963
749
|
}
|
|
964
|
-
function executeDeferredFragment(exeContext, parentType, sourceValue, fields, label, path, parentContext) {
|
|
965
|
-
const asyncPayloadRecord = new DeferredFragmentRecord({
|
|
966
|
-
label,
|
|
967
|
-
path,
|
|
968
|
-
parentContext,
|
|
969
|
-
exeContext,
|
|
970
|
-
});
|
|
971
|
-
let promiseOrData;
|
|
972
|
-
try {
|
|
973
|
-
promiseOrData = executeFields(exeContext, parentType, sourceValue, path, fields, asyncPayloadRecord);
|
|
974
|
-
if ((0, utils_1.isPromise)(promiseOrData)) {
|
|
975
|
-
promiseOrData = promiseOrData.then(null, e => {
|
|
976
|
-
asyncPayloadRecord.errors.push(e);
|
|
977
|
-
return null;
|
|
978
|
-
});
|
|
979
|
-
}
|
|
980
|
-
}
|
|
981
|
-
catch (e) {
|
|
982
|
-
asyncPayloadRecord.errors.push(e);
|
|
983
|
-
promiseOrData = null;
|
|
984
|
-
}
|
|
985
|
-
asyncPayloadRecord.addData(promiseOrData);
|
|
986
|
-
}
|
|
987
|
-
function executeStreamField(path, itemPath, item, exeContext, fieldNodes, info, itemType, label, parentContext) {
|
|
988
|
-
const asyncPayloadRecord = new StreamRecord({
|
|
989
|
-
label,
|
|
990
|
-
path: itemPath,
|
|
991
|
-
parentContext,
|
|
992
|
-
exeContext,
|
|
993
|
-
});
|
|
994
|
-
let completedItem;
|
|
995
|
-
try {
|
|
996
|
-
try {
|
|
997
|
-
if ((0, utils_1.isPromise)(item)) {
|
|
998
|
-
completedItem = item.then(resolved => completeValue(exeContext, itemType, fieldNodes, info, itemPath, resolved, asyncPayloadRecord));
|
|
999
|
-
}
|
|
1000
|
-
else {
|
|
1001
|
-
completedItem = completeValue(exeContext, itemType, fieldNodes, info, itemPath, item, asyncPayloadRecord);
|
|
1002
|
-
}
|
|
1003
|
-
if ((0, utils_1.isPromise)(completedItem)) {
|
|
1004
|
-
// Note: we don't rely on a `catch` method, but we do expect "thenable"
|
|
1005
|
-
// to take a second callback for the error case.
|
|
1006
|
-
completedItem = completedItem.then(undefined, rawError => {
|
|
1007
|
-
const error = (0, graphql_1.locatedError)(rawError, fieldNodes, (0, utils_1.pathToArray)(itemPath));
|
|
1008
|
-
const handledError = handleFieldError(error, itemType, asyncPayloadRecord.errors);
|
|
1009
|
-
filterSubsequentPayloads(exeContext, itemPath, asyncPayloadRecord);
|
|
1010
|
-
return handledError;
|
|
1011
|
-
});
|
|
1012
|
-
}
|
|
1013
|
-
}
|
|
1014
|
-
catch (rawError) {
|
|
1015
|
-
const error = (0, graphql_1.locatedError)(rawError, fieldNodes, (0, utils_1.pathToArray)(itemPath));
|
|
1016
|
-
completedItem = handleFieldError(error, itemType, asyncPayloadRecord.errors);
|
|
1017
|
-
filterSubsequentPayloads(exeContext, itemPath, asyncPayloadRecord);
|
|
1018
|
-
}
|
|
1019
|
-
}
|
|
1020
|
-
catch (error) {
|
|
1021
|
-
asyncPayloadRecord.errors.push(error);
|
|
1022
|
-
filterSubsequentPayloads(exeContext, path, asyncPayloadRecord);
|
|
1023
|
-
asyncPayloadRecord.addItems(null);
|
|
1024
|
-
return asyncPayloadRecord;
|
|
1025
|
-
}
|
|
1026
|
-
let completedItems;
|
|
1027
|
-
if ((0, utils_1.isPromise)(completedItem)) {
|
|
1028
|
-
completedItems = completedItem.then(value => [value], error => {
|
|
1029
|
-
asyncPayloadRecord.errors.push(error);
|
|
1030
|
-
filterSubsequentPayloads(exeContext, path, asyncPayloadRecord);
|
|
1031
|
-
return null;
|
|
1032
|
-
});
|
|
1033
|
-
}
|
|
1034
|
-
else {
|
|
1035
|
-
completedItems = [completedItem];
|
|
1036
|
-
}
|
|
1037
|
-
asyncPayloadRecord.addItems(completedItems);
|
|
1038
|
-
return asyncPayloadRecord;
|
|
1039
|
-
}
|
|
1040
|
-
async function executeStreamIteratorItem(iterator, exeContext, fieldNodes, info, itemType, asyncPayloadRecord, itemPath) {
|
|
1041
|
-
let item;
|
|
1042
|
-
try {
|
|
1043
|
-
const { value, done } = await iterator.next();
|
|
1044
|
-
if (done) {
|
|
1045
|
-
asyncPayloadRecord.setIsCompletedIterator();
|
|
1046
|
-
return { done, value: undefined };
|
|
1047
|
-
}
|
|
1048
|
-
item = value;
|
|
1049
|
-
}
|
|
1050
|
-
catch (rawError) {
|
|
1051
|
-
const error = (0, graphql_1.locatedError)(rawError, fieldNodes, (0, utils_1.pathToArray)(itemPath));
|
|
1052
|
-
const value = handleFieldError(error, itemType, asyncPayloadRecord.errors);
|
|
1053
|
-
// don't continue if iterator throws
|
|
1054
|
-
return { done: true, value };
|
|
1055
|
-
}
|
|
1056
|
-
let completedItem;
|
|
1057
|
-
try {
|
|
1058
|
-
completedItem = completeValue(exeContext, itemType, fieldNodes, info, itemPath, item, asyncPayloadRecord);
|
|
1059
|
-
if ((0, utils_1.isPromise)(completedItem)) {
|
|
1060
|
-
completedItem = completedItem.then(undefined, rawError => {
|
|
1061
|
-
const error = (0, graphql_1.locatedError)(rawError, fieldNodes, (0, utils_1.pathToArray)(itemPath));
|
|
1062
|
-
const handledError = handleFieldError(error, itemType, asyncPayloadRecord.errors);
|
|
1063
|
-
filterSubsequentPayloads(exeContext, itemPath, asyncPayloadRecord);
|
|
1064
|
-
return handledError;
|
|
1065
|
-
});
|
|
1066
|
-
}
|
|
1067
|
-
return { done: false, value: completedItem };
|
|
1068
|
-
}
|
|
1069
|
-
catch (rawError) {
|
|
1070
|
-
const error = (0, graphql_1.locatedError)(rawError, fieldNodes, (0, utils_1.pathToArray)(itemPath));
|
|
1071
|
-
const value = handleFieldError(error, itemType, asyncPayloadRecord.errors);
|
|
1072
|
-
filterSubsequentPayloads(exeContext, itemPath, asyncPayloadRecord);
|
|
1073
|
-
return { done: false, value };
|
|
1074
|
-
}
|
|
1075
|
-
}
|
|
1076
|
-
async function executeStreamIterator(initialIndex, iterator, exeContext, fieldNodes, info, itemType, path, label, parentContext) {
|
|
1077
|
-
let index = initialIndex;
|
|
1078
|
-
let previousAsyncPayloadRecord = parentContext !== null && parentContext !== void 0 ? parentContext : undefined;
|
|
1079
|
-
while (true) {
|
|
1080
|
-
const itemPath = (0, utils_1.addPath)(path, index, undefined);
|
|
1081
|
-
const asyncPayloadRecord = new StreamRecord({
|
|
1082
|
-
label,
|
|
1083
|
-
path: itemPath,
|
|
1084
|
-
parentContext: previousAsyncPayloadRecord,
|
|
1085
|
-
iterator,
|
|
1086
|
-
exeContext,
|
|
1087
|
-
});
|
|
1088
|
-
let iteration;
|
|
1089
|
-
try {
|
|
1090
|
-
iteration = await executeStreamIteratorItem(iterator, exeContext, fieldNodes, info, itemType, asyncPayloadRecord, itemPath);
|
|
1091
|
-
}
|
|
1092
|
-
catch (error) {
|
|
1093
|
-
asyncPayloadRecord.errors.push(error);
|
|
1094
|
-
filterSubsequentPayloads(exeContext, path, asyncPayloadRecord);
|
|
1095
|
-
asyncPayloadRecord.addItems(null);
|
|
1096
|
-
// entire stream has errored and bubbled upwards
|
|
1097
|
-
if (iterator === null || iterator === void 0 ? void 0 : iterator.return) {
|
|
1098
|
-
iterator.return().catch(() => {
|
|
1099
|
-
// ignore errors
|
|
1100
|
-
});
|
|
1101
|
-
}
|
|
1102
|
-
return;
|
|
1103
|
-
}
|
|
1104
|
-
const { done, value: completedItem } = iteration;
|
|
1105
|
-
let completedItems;
|
|
1106
|
-
if ((0, utils_1.isPromise)(completedItem)) {
|
|
1107
|
-
completedItems = completedItem.then(value => [value], error => {
|
|
1108
|
-
asyncPayloadRecord.errors.push(error);
|
|
1109
|
-
filterSubsequentPayloads(exeContext, path, asyncPayloadRecord);
|
|
1110
|
-
return null;
|
|
1111
|
-
});
|
|
1112
|
-
}
|
|
1113
|
-
else {
|
|
1114
|
-
completedItems = [completedItem];
|
|
1115
|
-
}
|
|
1116
|
-
asyncPayloadRecord.addItems(completedItems);
|
|
1117
|
-
if (done) {
|
|
1118
|
-
break;
|
|
1119
|
-
}
|
|
1120
|
-
previousAsyncPayloadRecord = asyncPayloadRecord;
|
|
1121
|
-
index++;
|
|
1122
|
-
}
|
|
1123
|
-
}
|
|
1124
|
-
function filterSubsequentPayloads(exeContext, nullPath, currentAsyncRecord) {
|
|
1125
|
-
const nullPathArray = (0, utils_1.pathToArray)(nullPath);
|
|
1126
|
-
exeContext.subsequentPayloads.forEach(asyncRecord => {
|
|
1127
|
-
var _a;
|
|
1128
|
-
if (asyncRecord === currentAsyncRecord) {
|
|
1129
|
-
// don't remove payload from where error originates
|
|
1130
|
-
return;
|
|
1131
|
-
}
|
|
1132
|
-
for (let i = 0; i < nullPathArray.length; i++) {
|
|
1133
|
-
if (asyncRecord.path[i] !== nullPathArray[i]) {
|
|
1134
|
-
// asyncRecord points to a path unaffected by this payload
|
|
1135
|
-
return;
|
|
1136
|
-
}
|
|
1137
|
-
}
|
|
1138
|
-
// asyncRecord path points to nulled error field
|
|
1139
|
-
if (isStreamPayload(asyncRecord) && ((_a = asyncRecord.iterator) === null || _a === void 0 ? void 0 : _a.return)) {
|
|
1140
|
-
asyncRecord.iterator.return().catch(() => {
|
|
1141
|
-
// ignore error
|
|
1142
|
-
});
|
|
1143
|
-
}
|
|
1144
|
-
exeContext.subsequentPayloads.delete(asyncRecord);
|
|
1145
|
-
});
|
|
1146
|
-
}
|
|
1147
|
-
function getCompletedIncrementalResults(exeContext) {
|
|
1148
|
-
const incrementalResults = [];
|
|
1149
|
-
for (const asyncPayloadRecord of exeContext.subsequentPayloads) {
|
|
1150
|
-
const incrementalResult = {};
|
|
1151
|
-
if (!asyncPayloadRecord.isCompleted) {
|
|
1152
|
-
continue;
|
|
1153
|
-
}
|
|
1154
|
-
exeContext.subsequentPayloads.delete(asyncPayloadRecord);
|
|
1155
|
-
if (isStreamPayload(asyncPayloadRecord)) {
|
|
1156
|
-
const items = asyncPayloadRecord.items;
|
|
1157
|
-
if (asyncPayloadRecord.isCompletedIterator) {
|
|
1158
|
-
// async iterable resolver just finished but there may be pending payloads
|
|
1159
|
-
continue;
|
|
1160
|
-
}
|
|
1161
|
-
incrementalResult.items = items;
|
|
1162
|
-
}
|
|
1163
|
-
else {
|
|
1164
|
-
const data = asyncPayloadRecord.data;
|
|
1165
|
-
incrementalResult.data = data !== null && data !== void 0 ? data : null;
|
|
1166
|
-
}
|
|
1167
|
-
incrementalResult.path = asyncPayloadRecord.path;
|
|
1168
|
-
if (asyncPayloadRecord.label) {
|
|
1169
|
-
incrementalResult.label = asyncPayloadRecord.label;
|
|
1170
|
-
}
|
|
1171
|
-
if (asyncPayloadRecord.errors.length > 0) {
|
|
1172
|
-
incrementalResult.errors = asyncPayloadRecord.errors;
|
|
1173
|
-
}
|
|
1174
|
-
incrementalResults.push(incrementalResult);
|
|
1175
|
-
}
|
|
1176
|
-
return incrementalResults;
|
|
1177
|
-
}
|
|
1178
|
-
function yieldSubsequentPayloads(exeContext) {
|
|
1179
|
-
let isDone = false;
|
|
1180
|
-
async function next() {
|
|
1181
|
-
if (isDone) {
|
|
1182
|
-
return { value: undefined, done: true };
|
|
1183
|
-
}
|
|
1184
|
-
await Promise.race(Array.from(exeContext.subsequentPayloads).map(p => p.promise));
|
|
1185
|
-
if (isDone) {
|
|
1186
|
-
// a different call to next has exhausted all payloads
|
|
1187
|
-
return { value: undefined, done: true };
|
|
1188
|
-
}
|
|
1189
|
-
const incremental = getCompletedIncrementalResults(exeContext);
|
|
1190
|
-
const hasNext = exeContext.subsequentPayloads.size > 0;
|
|
1191
|
-
if (!incremental.length && hasNext) {
|
|
1192
|
-
return next();
|
|
1193
|
-
}
|
|
1194
|
-
if (!hasNext) {
|
|
1195
|
-
isDone = true;
|
|
1196
|
-
}
|
|
1197
|
-
return {
|
|
1198
|
-
value: incremental.length ? { incremental, hasNext } : { hasNext },
|
|
1199
|
-
done: false,
|
|
1200
|
-
};
|
|
1201
|
-
}
|
|
1202
|
-
function returnStreamIterators() {
|
|
1203
|
-
const promises = [];
|
|
1204
|
-
exeContext.subsequentPayloads.forEach(asyncPayloadRecord => {
|
|
1205
|
-
var _a;
|
|
1206
|
-
if (isStreamPayload(asyncPayloadRecord) && ((_a = asyncPayloadRecord.iterator) === null || _a === void 0 ? void 0 : _a.return)) {
|
|
1207
|
-
promises.push(asyncPayloadRecord.iterator.return());
|
|
1208
|
-
}
|
|
1209
|
-
});
|
|
1210
|
-
return Promise.all(promises);
|
|
1211
|
-
}
|
|
1212
|
-
return {
|
|
1213
|
-
[Symbol.asyncIterator]() {
|
|
1214
|
-
return this;
|
|
1215
|
-
},
|
|
1216
|
-
next,
|
|
1217
|
-
async return() {
|
|
1218
|
-
await returnStreamIterators();
|
|
1219
|
-
isDone = true;
|
|
1220
|
-
return { value: undefined, done: true };
|
|
1221
|
-
},
|
|
1222
|
-
async throw(error) {
|
|
1223
|
-
await returnStreamIterators();
|
|
1224
|
-
isDone = true;
|
|
1225
|
-
return Promise.reject(error);
|
|
1226
|
-
},
|
|
1227
|
-
};
|
|
1228
|
-
}
|
|
1229
|
-
class DeferredFragmentRecord {
|
|
1230
|
-
constructor(opts) {
|
|
1231
|
-
this.type = 'defer';
|
|
1232
|
-
this.label = opts.label;
|
|
1233
|
-
this.path = (0, utils_1.pathToArray)(opts.path);
|
|
1234
|
-
this.parentContext = opts.parentContext;
|
|
1235
|
-
this.errors = [];
|
|
1236
|
-
this._exeContext = opts.exeContext;
|
|
1237
|
-
this._exeContext.subsequentPayloads.add(this);
|
|
1238
|
-
this.isCompleted = false;
|
|
1239
|
-
this.data = null;
|
|
1240
|
-
this.promise = new Promise(resolve => {
|
|
1241
|
-
this._resolve = MaybePromise => {
|
|
1242
|
-
resolve(MaybePromise);
|
|
1243
|
-
};
|
|
1244
|
-
}).then(data => {
|
|
1245
|
-
this.data = data;
|
|
1246
|
-
this.isCompleted = true;
|
|
1247
|
-
});
|
|
1248
|
-
}
|
|
1249
|
-
addData(data) {
|
|
1250
|
-
var _a, _b, _c;
|
|
1251
|
-
const parentData = (_a = this.parentContext) === null || _a === void 0 ? void 0 : _a.promise;
|
|
1252
|
-
if (parentData) {
|
|
1253
|
-
(_b = this._resolve) === null || _b === void 0 ? void 0 : _b.call(this, parentData.then(() => data));
|
|
1254
|
-
return;
|
|
1255
|
-
}
|
|
1256
|
-
(_c = this._resolve) === null || _c === void 0 ? void 0 : _c.call(this, data);
|
|
1257
|
-
}
|
|
1258
|
-
}
|
|
1259
|
-
class StreamRecord {
|
|
1260
|
-
constructor(opts) {
|
|
1261
|
-
this.type = 'stream';
|
|
1262
|
-
this.items = null;
|
|
1263
|
-
this.label = opts.label;
|
|
1264
|
-
this.path = (0, utils_1.pathToArray)(opts.path);
|
|
1265
|
-
this.parentContext = opts.parentContext;
|
|
1266
|
-
this.iterator = opts.iterator;
|
|
1267
|
-
this.errors = [];
|
|
1268
|
-
this._exeContext = opts.exeContext;
|
|
1269
|
-
this._exeContext.subsequentPayloads.add(this);
|
|
1270
|
-
this.isCompleted = false;
|
|
1271
|
-
this.items = null;
|
|
1272
|
-
this.promise = new Promise(resolve => {
|
|
1273
|
-
this._resolve = MaybePromise => {
|
|
1274
|
-
resolve(MaybePromise);
|
|
1275
|
-
};
|
|
1276
|
-
}).then(items => {
|
|
1277
|
-
this.items = items;
|
|
1278
|
-
this.isCompleted = true;
|
|
1279
|
-
});
|
|
1280
|
-
}
|
|
1281
|
-
addItems(items) {
|
|
1282
|
-
var _a, _b, _c;
|
|
1283
|
-
const parentData = (_a = this.parentContext) === null || _a === void 0 ? void 0 : _a.promise;
|
|
1284
|
-
if (parentData) {
|
|
1285
|
-
(_b = this._resolve) === null || _b === void 0 ? void 0 : _b.call(this, parentData.then(() => items));
|
|
1286
|
-
return;
|
|
1287
|
-
}
|
|
1288
|
-
(_c = this._resolve) === null || _c === void 0 ? void 0 : _c.call(this, items);
|
|
1289
|
-
}
|
|
1290
|
-
setIsCompletedIterator() {
|
|
1291
|
-
this.isCompletedIterator = true;
|
|
1292
|
-
}
|
|
1293
|
-
}
|
|
1294
|
-
function isStreamPayload(asyncPayload) {
|
|
1295
|
-
return asyncPayload.type === 'stream';
|
|
1296
|
-
}
|
|
1297
750
|
/**
|
|
1298
751
|
* This method looks up the field on the given type definition.
|
|
1299
752
|
* It has special casing for the three introspection fields,
|