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