@graphql-tools/executor 0.0.2 → 0.0.3-alpha-20221031181646-cd48ed2f

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