@graphql-tools/executor 0.0.1 → 0.0.2-alpha-20221029152711-14f4f7a7

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