grafast 0.1.1-beta.21 → 0.1.1-beta.22

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 (94) hide show
  1. package/README.md +0 -4
  2. package/dist/args.js +3 -3
  3. package/dist/constants.d.ts +79 -0
  4. package/dist/constants.js +79 -0
  5. package/dist/engine/LayerPlan.d.ts +71 -8
  6. package/dist/engine/LayerPlan.js +375 -265
  7. package/dist/engine/OperationPlan.d.ts +77 -14
  8. package/dist/engine/OperationPlan.js +1508 -382
  9. package/dist/engine/OperationPlanTypes.d.ts +66 -0
  10. package/dist/engine/OperationPlanTypes.js +3 -0
  11. package/dist/engine/OutputPlan.d.ts +6 -0
  12. package/dist/engine/OutputPlan.js +138 -82
  13. package/dist/engine/StepTracker.js +76 -17
  14. package/dist/engine/executeBucket.js +327 -166
  15. package/dist/engine/lib/defaultPlanResolver.d.ts +1 -4
  16. package/dist/engine/lib/defaultPlanResolver.js +1 -5
  17. package/dist/engine/lib/withGlobalLayerPlan.d.ts +3 -1
  18. package/dist/engine/lib/withGlobalLayerPlan.js +19 -1
  19. package/dist/envelop.js +14 -3
  20. package/dist/error.d.ts +1 -1
  21. package/dist/error.js +9 -9
  22. package/dist/establishOperationPlan.d.ts +2 -1
  23. package/dist/establishOperationPlan.js +10 -10
  24. package/dist/execute.js +7 -5
  25. package/dist/global.d.ts +10 -0
  26. package/dist/global.js +25 -0
  27. package/dist/grafastGraphql.js +4 -3
  28. package/dist/grafastPrint.js +36 -4
  29. package/dist/index.d.ts +76 -8
  30. package/dist/index.js +37 -33
  31. package/dist/input.js +20 -1
  32. package/dist/inspect.js +1 -0
  33. package/dist/interfaces.d.ts +80 -122
  34. package/dist/interfaces.js +0 -77
  35. package/dist/makeGrafastSchema.d.ts +118 -35
  36. package/dist/makeGrafastSchema.js +197 -29
  37. package/dist/mermaid.js +198 -97
  38. package/dist/operationPlan-input.d.ts +1 -1
  39. package/dist/operationPlan-input.js +15 -5
  40. package/dist/planJSONInterfaces.d.ts +24 -5
  41. package/dist/prepare.d.ts +16 -9
  42. package/dist/prepare.js +54 -51
  43. package/dist/step.d.ts +45 -9
  44. package/dist/step.js +139 -22
  45. package/dist/steps/__flag.d.ts +3 -2
  46. package/dist/steps/__flag.js +31 -29
  47. package/dist/steps/__inputObject.d.ts +1 -1
  48. package/dist/steps/__inputStaticLeaf.d.ts +3 -2
  49. package/dist/steps/__inputStaticLeaf.js +13 -7
  50. package/dist/steps/__item.d.ts +1 -1
  51. package/dist/steps/__item.js +3 -3
  52. package/dist/steps/__trackedValue.d.ts +6 -3
  53. package/dist/steps/__trackedValue.js +25 -9
  54. package/dist/steps/__value.d.ts +2 -1
  55. package/dist/steps/__value.js +5 -0
  56. package/dist/steps/access.d.ts +17 -1
  57. package/dist/steps/access.js +14 -1
  58. package/dist/steps/applyInput.d.ts +1 -1
  59. package/dist/steps/applyInput.js +7 -6
  60. package/dist/steps/applyTransforms.js +9 -7
  61. package/dist/steps/bakedInput.js +2 -2
  62. package/dist/steps/coalesce.d.ts +15 -0
  63. package/dist/steps/coalesce.js +36 -0
  64. package/dist/steps/constant.js +16 -14
  65. package/dist/steps/each.d.ts +2 -2
  66. package/dist/steps/first.d.ts +2 -0
  67. package/dist/steps/first.js +5 -1
  68. package/dist/steps/graphqlResolver.d.ts +2 -2
  69. package/dist/steps/graphqlResolver.js +63 -161
  70. package/dist/steps/index.d.ts +3 -15
  71. package/dist/steps/index.js +6 -41
  72. package/dist/steps/lambda.js +1 -1
  73. package/dist/steps/last.d.ts +2 -0
  74. package/dist/steps/last.js +4 -0
  75. package/dist/steps/listTransform.d.ts +2 -2
  76. package/dist/steps/listTransform.js +11 -13
  77. package/dist/steps/load.d.ts +28 -22
  78. package/dist/steps/load.js +47 -1
  79. package/dist/steps/node.d.ts +10 -7
  80. package/dist/steps/node.js +5 -19
  81. package/dist/steps/object.js +6 -1
  82. package/dist/steps/proxy.d.ts +0 -6
  83. package/dist/steps/proxy.js +3 -3
  84. package/dist/steps/remapKeys.d.ts +1 -1
  85. package/dist/steps/remapKeys.js +0 -1
  86. package/dist/utils.d.ts +27 -5
  87. package/dist/utils.js +235 -15
  88. package/dist/version.d.ts +1 -1
  89. package/dist/version.js +1 -1
  90. package/package.json +6 -6
  91. package/dist/polymorphic.d.ts +0 -14
  92. package/dist/polymorphic.js +0 -72
  93. package/dist/steps/polymorphicBranch.d.ts +0 -27
  94. package/dist/steps/polymorphicBranch.js +0 -62
@@ -8,13 +8,15 @@ exports.unaryExecutionValue = unaryExecutionValue;
8
8
  const tslib_1 = require("tslib");
9
9
  const iterall_1 = require("iterall");
10
10
  const assert = tslib_1.__importStar(require("../assert.js"));
11
+ const constants_js_1 = require("../constants.js");
11
12
  const dev_js_1 = require("../dev.js");
12
13
  const error_js_1 = require("../error.js");
13
14
  const inspect_js_1 = require("../inspect.js");
14
- const interfaces_js_1 = require("../interfaces.js");
15
15
  const timeSource_js_1 = require("../timeSource.js");
16
16
  const utils_js_1 = require("../utils.js");
17
- const timeoutError = Object.freeze(new error_js_1.SafeError("Execution timeout exceeded, please simplify or add limits to your request.", Object.freeze({ [interfaces_js_1.$$timeout]: true })));
17
+ /** Default recoverable/trappable flags (excluding NULL) */
18
+ const INHIBIT_OR_ERROR_FLAGS = constants_js_1.FLAG_INHIBITED | constants_js_1.FLAG_ERROR;
19
+ const timeoutError = Object.freeze(new error_js_1.SafeError("Execution timeout exceeded, please simplify or add limits to your request.", Object.freeze({ [constants_js_1.$$timeout]: true })));
18
20
  function noop() {
19
21
  /*noop*/
20
22
  }
@@ -55,7 +57,7 @@ function executeBucket(bucket, requestContext) {
55
57
  */
56
58
  function reallyExecuteStepWithoutFiltering(size, step, dependencies, extra) {
57
59
  const results = executeOrStream(size, step, dependencies, extra);
58
- const flags = (0, utils_js_1.arrayOfLength)(size, interfaces_js_1.NO_FLAGS);
60
+ const flags = (0, utils_js_1.arrayOfLength)(size, constants_js_1.NO_FLAGS);
59
61
  if ((0, utils_js_1.isPromiseLike)(results)) {
60
62
  return results.then((results) => ({ flags, results }));
61
63
  }
@@ -65,7 +67,7 @@ function executeBucket(bucket, requestContext) {
65
67
  }
66
68
  const { stopTime, eventEmitter, args } = requestContext;
67
69
  const { middleware } = args;
68
- const { metaByMetaKey, size, store, layerPlan: { phases, children: childLayerPlans }, } = bucket;
70
+ const { metaByMetaKey, size, store, layerPlan: { phases }, } = bucket;
69
71
  const phaseCount = phases.length;
70
72
  // Like a `for(i = 0; i < phaseCount; i++)` loop with some `await`s in it, except it does promise
71
73
  // handling manually so that it can complete synchronously (no promises) if
@@ -96,11 +98,11 @@ function executeBucket(bucket, requestContext) {
96
98
  const stepSize = step._isUnary ? 1 : bucket.size;
97
99
  const r = timeoutError;
98
100
  const results = (0, utils_js_1.arrayOfLength)(stepSize, r);
99
- const flags = (0, utils_js_1.arrayOfLength)(stepSize, interfaces_js_1.FLAG_ERROR);
101
+ const flags = (0, utils_js_1.arrayOfLength)(stepSize, constants_js_1.FLAG_ERROR);
100
102
  resultList[normalStepIndex] = { flags, results };
101
103
  indexesPendingLoopOver.push(normalStepIndex);
102
104
  // TODO: I believe we can remove this line?
103
- bucket.flagUnion |= interfaces_js_1.FLAG_ERROR;
105
+ bucket.flagUnion |= constants_js_1.FLAG_ERROR;
104
106
  }
105
107
  }
106
108
  }
@@ -130,11 +132,11 @@ function executeBucket(bucket, requestContext) {
130
132
  catch (e) {
131
133
  const r = e;
132
134
  const results = (0, utils_js_1.arrayOfLength)(stepSize, r);
133
- const flags = (0, utils_js_1.arrayOfLength)(stepSize, interfaces_js_1.FLAG_ERROR);
135
+ const flags = (0, utils_js_1.arrayOfLength)(stepSize, constants_js_1.FLAG_ERROR);
134
136
  resultList[normalStepIndex] = { flags, results };
135
137
  indexesPendingLoopOver.push(normalStepIndex);
136
138
  // TODO: I believe we can remove this line?
137
- bucket.flagUnion |= interfaces_js_1.FLAG_ERROR;
139
+ bucket.flagUnion |= constants_js_1.FLAG_ERROR;
138
140
  }
139
141
  }
140
142
  }
@@ -184,15 +186,15 @@ function executeBucket(bucket, requestContext) {
184
186
  // hang of defers? In the mean time... Don't throw any errors here!
185
187
  const success = (finishedStep, bucket, resultIndex, value, flags) => {
186
188
  // Fast lanes
187
- if (typeof value !== "object") {
188
- // non-objects
189
- bucket.setResult(finishedStep, resultIndex, value, flags);
189
+ if (value == null) {
190
+ // null / undefined
191
+ const finalFlags = flags | constants_js_1.FLAG_NULL;
192
+ bucket.setResult(finishedStep, resultIndex, value, finalFlags);
190
193
  return;
191
194
  }
192
- else if (value === null) {
193
- // nulls
194
- const finalFlags = flags | interfaces_js_1.FLAG_NULL;
195
- bucket.setResult(finishedStep, resultIndex, null, finalFlags);
195
+ else if (typeof value !== "object") {
196
+ // non-objects
197
+ bucket.setResult(finishedStep, resultIndex, value, flags);
196
198
  return;
197
199
  }
198
200
  else if ((0, error_js_1.isFlaggedValue)(value)) {
@@ -207,10 +209,47 @@ function executeBucket(bucket, requestContext) {
207
209
  ((valueIsAsyncIterable = (0, iterall_1.isAsyncIterable)(value)) || (0, iterall_1.isIterable)(value))) {
208
210
  // PERF: we've already calculated this once; can we reference that again here?
209
211
  const stream = evaluateStream(bucket, finishedStep);
212
+ if (!stream && !valueIsAsyncIterable && Array.isArray(value)) {
213
+ // Fast mode
214
+ const valueCount = value.length;
215
+ /** We only create a duplicate array if the source array contains promises */
216
+ let replacement = null;
217
+ for (let i = 0; i < valueCount; i++) {
218
+ const item = value[i];
219
+ if ((0, utils_js_1.isPromiseLike)(item)) {
220
+ if (replacement === null) {
221
+ // Copy up to here!
222
+ replacement = value.slice(0, i);
223
+ }
224
+ replacement[i] = null;
225
+ const index = i;
226
+ const promise = item.then((v) => void (replacement[index] = v), (e) => void (replacement[index] = (0, error_js_1.flagError)(e)));
227
+ if (!promises) {
228
+ promises = [promise];
229
+ }
230
+ else {
231
+ promises.push(promise);
232
+ }
233
+ }
234
+ else if (replacement !== null) {
235
+ replacement[i] = item;
236
+ }
237
+ }
238
+ const list = replacement === null ? value : replacement;
239
+ bucket.setResult(finishedStep, resultIndex, list, flags);
240
+ return;
241
+ }
210
242
  const initialCount = stream?.initialCount ?? Infinity;
211
- const iterator = valueIsAsyncIterable
212
- ? value[Symbol.asyncIterator]()
213
- : value[Symbol.iterator]();
243
+ let iterator;
244
+ try {
245
+ iterator = valueIsAsyncIterable
246
+ ? value[Symbol.asyncIterator]()
247
+ : value[Symbol.iterator]();
248
+ }
249
+ catch (e) {
250
+ bucket.setResult(finishedStep, resultIndex, e, flags | constants_js_1.FLAG_ERROR);
251
+ return;
252
+ }
214
253
  // Here we track the iterator via the bucket, this allows us to
215
254
  // ensure that the iterator is terminated even if the stream is never
216
255
  // consumed (e.g. if an error is thrown/caught during execution of
@@ -222,7 +261,7 @@ function executeBucket(bucket, requestContext) {
222
261
  if (initialCount === 0) {
223
262
  // Optimization - defer everything
224
263
  const arr = [];
225
- arr[interfaces_js_1.$$streamMore] = iterator;
264
+ arr[constants_js_1.$$streamMore] = iterator;
226
265
  bucket.setResult(finishedStep, resultIndex, arr, flags);
227
266
  }
228
267
  else {
@@ -243,19 +282,30 @@ function executeBucket(bucket, requestContext) {
243
282
  if (resolvedResult.done) {
244
283
  break;
245
284
  }
246
- arr.push(await resolvedResult.value);
285
+ try {
286
+ const v = resolvedResult.value;
287
+ if ((0, utils_js_1.isPromiseLike)(v)) {
288
+ arr.push(await v);
289
+ }
290
+ else {
291
+ arr.push(v);
292
+ }
293
+ }
294
+ catch (e) {
295
+ arr.push((0, error_js_1.flagError)(e));
296
+ }
247
297
  if (++valuesSeen >= initialCount) {
248
298
  // This is safe to do in the `while` since we checked
249
299
  // the `0` entries condition in the optimization
250
300
  // above.
251
- arr[interfaces_js_1.$$streamMore] = iterator;
301
+ arr[constants_js_1.$$streamMore] = iterator;
252
302
  break;
253
303
  }
254
304
  }
255
305
  bucket.setResult(finishedStep, resultIndex, arr, flags);
256
306
  }
257
307
  catch (e) {
258
- bucket.setResult(finishedStep, resultIndex, e, flags | interfaces_js_1.FLAG_ERROR);
308
+ bucket.setResult(finishedStep, resultIndex, e, flags | constants_js_1.FLAG_ERROR);
259
309
  }
260
310
  })();
261
311
  if (!promises) {
@@ -306,11 +356,11 @@ function executeBucket(bucket, requestContext) {
306
356
  const { s: allStepsIndex, i: dataIndex } = pendingPromiseIndexes[i];
307
357
  const finishedStep = _allSteps[allStepsIndex];
308
358
  if (settledResult.status === "fulfilled") {
309
- success(finishedStep, bucket, dataIndex, settledResult.value, interfaces_js_1.NO_FLAGS);
359
+ success(finishedStep, bucket, dataIndex, settledResult.value, constants_js_1.NO_FLAGS);
310
360
  }
311
361
  else {
312
362
  const error = settledResult.reason;
313
- bucket.setResult(finishedStep, dataIndex, error, interfaces_js_1.FLAG_ERROR);
363
+ bucket.setResult(finishedStep, dataIndex, error, constants_js_1.FLAG_ERROR);
314
364
  }
315
365
  }
316
366
  return promises ? Promise.all(promises) : undefined;
@@ -318,12 +368,12 @@ function executeBucket(bucket, requestContext) {
318
368
  .then(null, (e) => {
319
369
  // THIS SHOULD NEVER HAPPEN!
320
370
  console.error(`GrafastInternalError<1e9731b4-005e-4b0e-bc61-43baa62e6444>: this error should never occur! Please file an issue against grafast. Details: ${e}`);
321
- bucket.flagUnion |= interfaces_js_1.FLAG_ERROR;
371
+ bucket.flagUnion |= constants_js_1.FLAG_ERROR;
322
372
  for (let i = 0, pendingPromisesLength = pendingPromises.length; i < pendingPromisesLength; i++) {
323
373
  const { s: allStepsIndex, i: dataIndex } = pendingPromiseIndexes[i];
324
374
  const finishedStep = _allSteps[allStepsIndex];
325
375
  const error = new Error(`GrafastInternalError<1e9731b4-005e-4b0e-bc61-43baa62e6444>: error occurred whilst performing completedStep(${finishedStep.id})`);
326
- bucket.setResult(finishedStep, dataIndex, error, interfaces_js_1.FLAG_ERROR);
376
+ bucket.setResult(finishedStep, dataIndex, error, constants_js_1.FLAG_ERROR);
327
377
  }
328
378
  });
329
379
  }
@@ -379,10 +429,10 @@ function executeBucket(bucket, requestContext) {
379
429
  throw new Error(`GrafastInternalError<fcc8d302-ac66-40e8-aaea-ee2c7e2b30b2>: failed to get result for side effect ${$sideEffect} which impacts ${step}`);
380
430
  }
381
431
  const depFlags = depExecutionValue._flagsAt(dataIndex);
382
- if (depFlags & interfaces_js_1.FLAG_POLY_SKIPPED) {
432
+ if (depFlags & constants_js_1.FLAG_POLY_SKIPPED) {
383
433
  /* noop */
384
434
  }
385
- else if (depFlags & interfaces_js_1.FLAG_ERROR) {
435
+ else if (depFlags & constants_js_1.FLAG_ERROR) {
386
436
  if (step._isUnary) {
387
437
  // COPY the unary value
388
438
  bucket.store.set(step.id, depExecutionValue);
@@ -401,70 +451,92 @@ function executeBucket(bucket, requestContext) {
401
451
  const extra = extras[allStepsIndex];
402
452
  let forceIndexValue = undefined;
403
453
  let rejectValue = undefined;
404
- let indexFlags = interfaces_js_1.NO_FLAGS;
405
- for (let i = 0, l = step.dependencies.length; i < l; i++) {
406
- const $dep = step.dependencies[i];
407
- const forbiddenFlags = step.dependencyForbiddenFlags[i];
408
- const onReject = step.dependencyOnReject[i];
409
- const depExecutionVal = bucket.store.get($dep.id);
410
- // Search for "f2b3b1b3" for similar block
411
- const flags = depExecutionVal._flagsAt(dataIndex);
412
- const disallowedFlags = flags & forbiddenFlags;
413
- if (disallowedFlags) {
414
- indexFlags |= disallowedFlags;
415
- // If there's a reject behavior and we're FRESHLY rejected (weren't
416
- // already inhibited), use that as a fallback.
417
- // TODO: validate this.
418
- // If dep is inhibited and we don't allow inhibited, copy through (null or error).
419
- // If dep is inhibited and we do allow inhibited, but we're disallowed, use our onReject.
420
- // If dep is not inhibited, but we're disallowed, use our onReject.
421
- if (onReject !== undefined &&
422
- (disallowedFlags & (interfaces_js_1.FLAG_INHIBITED | interfaces_js_1.FLAG_ERROR)) === interfaces_js_1.NO_FLAGS) {
423
- rejectValue ||= onReject;
454
+ let indexFlags = constants_js_1.NO_FLAGS;
455
+ // Check polymorphism matches
456
+ const stepPolymorphicPaths = step.polymorphicPaths;
457
+ if (stepPolymorphicPaths !== null &&
458
+ (step._isUnary
459
+ ? /*
460
+ * already asserted that it matches;
461
+ * !! search "f4ce2c83"
462
+ */
463
+ false
464
+ : /* batch check */
465
+ !stepPolymorphicPaths.has(bucket.polymorphicPathList[dataIndex]))) {
466
+ indexFlags |= constants_js_1.FLAG_POLY_SKIPPED;
467
+ forceIndexValue = null;
468
+ }
469
+ else {
470
+ for (let i = 0, l = step.dependencies.length; i < l; i++) {
471
+ const $dep = step.dependencies[i];
472
+ const forbiddenFlags = step.dependencyForbiddenFlags[i];
473
+ const onReject = step.dependencyOnReject[i];
474
+ const depExecutionVal = bucket.store.get($dep.id);
475
+ if (depExecutionVal === undefined) {
476
+ throw new Error(`GrafastInternalError<480e7c98-a777-4efb-b826-c339129ccff8>: could not find value in ${bucket} for ${$dep}, dependency ${i} of ${step}`);
424
477
  }
425
- if (forceIndexValue == null) {
426
- if ((flags & interfaces_js_1.FLAG_ERROR) !== 0) {
427
- const v = depExecutionVal.at(dataIndex);
428
- forceIndexValue = v;
478
+ // Search for "f2b3b1b3" for similar block
479
+ const flags = depExecutionVal._flagsAt(dataIndex);
480
+ const disallowedFlags = flags & forbiddenFlags;
481
+ if (disallowedFlags) {
482
+ indexFlags |= disallowedFlags;
483
+ // If there's a reject behavior and we're FRESHLY rejected (weren't
484
+ // already inhibited), use that as a fallback.
485
+ // TODO: validate this.
486
+ // If dep is inhibited and we don't allow inhibited, copy through (null or error).
487
+ // If dep is inhibited and we do allow inhibited, but we're disallowed, use our onReject.
488
+ // If dep is not inhibited, but we're disallowed, use our onReject.
489
+ if (onReject !== undefined &&
490
+ (disallowedFlags & INHIBIT_OR_ERROR_FLAGS) === constants_js_1.NO_FLAGS) {
491
+ rejectValue ||= onReject;
492
+ }
493
+ if (forceIndexValue == null) {
494
+ if ((flags & constants_js_1.FLAG_ERROR) !== constants_js_1.NO_FLAGS) {
495
+ const v = depExecutionVal.at(dataIndex);
496
+ forceIndexValue = v;
497
+ }
498
+ else {
499
+ forceIndexValue = null;
500
+ }
429
501
  }
430
502
  else {
431
- forceIndexValue = null;
503
+ // First error wins, ignore this second error.
432
504
  }
505
+ // End "f2b3b1b3" block
433
506
  }
434
- else {
435
- // First error wins, ignore this second error.
436
- }
437
- // End "f2b3b1b3" block
438
- }
439
- else if (forceIndexValue === undefined) {
440
- const depVal = depExecutionVal.at(dataIndex);
441
- let depFlags;
442
- if ((bucket.flagUnion & interfaces_js_1.FLAG_ERROR) === interfaces_js_1.FLAG_ERROR &&
443
- ((depFlags = depExecutionVal._flagsAt(dataIndex)) &
444
- interfaces_js_1.FLAG_ERROR) ===
445
- interfaces_js_1.FLAG_ERROR) {
446
- if (step._isUnary) {
447
- // COPY the unary value
448
- bucket.store.set(step.id, depExecutionVal);
449
- bucket.flagUnion |= depFlags;
450
- }
451
- else {
452
- bucket.setResult(step, dataIndex, depVal, interfaces_js_1.FLAG_ERROR);
507
+ else if (forceIndexValue === undefined) {
508
+ const depVal = depExecutionVal.at(dataIndex);
509
+ let depFlags;
510
+ if ((bucket.flagUnion & constants_js_1.FLAG_ERROR) === constants_js_1.FLAG_ERROR &&
511
+ ((depFlags = depExecutionVal._flagsAt(dataIndex)) &
512
+ constants_js_1.FLAG_ERROR) ===
513
+ constants_js_1.FLAG_ERROR) {
514
+ if (step._isUnary) {
515
+ // COPY the unary value
516
+ bucket.store.set(step.id, depExecutionVal);
517
+ bucket.flagUnion |= depFlags;
518
+ }
519
+ else {
520
+ bucket.setResult(step, dataIndex, depVal, constants_js_1.FLAG_ERROR);
521
+ }
522
+ continue stepLoop;
453
523
  }
454
- continue stepLoop;
524
+ deps.push(depVal);
455
525
  }
456
- deps.push(depVal);
457
526
  }
458
527
  }
459
528
  let stepResult, stepFlags;
460
529
  if (forceIndexValue !== undefined) {
461
530
  // Search for "17217999b7a7" for similar block
462
- if (forceIndexValue == null && rejectValue != null) {
463
- indexFlags |= interfaces_js_1.FLAG_ERROR;
531
+ if ((indexFlags & constants_js_1.FLAG_POLY_SKIPPED) === constants_js_1.FLAG_POLY_SKIPPED) {
532
+ // Already skipped
533
+ }
534
+ else if (forceIndexValue == null && rejectValue != null) {
535
+ indexFlags |= constants_js_1.FLAG_ERROR;
464
536
  forceIndexValue = rejectValue;
465
537
  }
466
538
  else {
467
- indexFlags |= interfaces_js_1.FLAG_INHIBITED;
539
+ indexFlags |= constants_js_1.FLAG_INHIBITED;
468
540
  }
469
541
  // End "17217999b7a7" block
470
542
  stepResult = forceIndexValue;
@@ -480,7 +552,7 @@ function executeBucket(bucket, requestContext) {
480
552
  }
481
553
  else {
482
554
  stepResult = rawStepResult;
483
- stepFlags = rawStepResult == null ? interfaces_js_1.FLAG_NULL : interfaces_js_1.NO_FLAGS;
555
+ stepFlags = rawStepResult == null ? constants_js_1.FLAG_NULL : constants_js_1.NO_FLAGS;
484
556
  }
485
557
  }
486
558
  // TODO: what if stepResult is _returned_ error (as opposed to
@@ -492,7 +564,7 @@ function executeBucket(bucket, requestContext) {
492
564
  bucket.setResult(step, dataIndex, stepResult, stepFlags);
493
565
  }
494
566
  catch (e) {
495
- bucket.setResult(step, dataIndex, e, interfaces_js_1.FLAG_ERROR);
567
+ bucket.setResult(step, dataIndex, e, constants_js_1.FLAG_ERROR);
496
568
  }
497
569
  }
498
570
  }
@@ -539,11 +611,13 @@ function executeBucket(bucket, requestContext) {
539
611
  }
540
612
  // Function definitions below here
541
613
  function executeOrStream(count, step, values, extra) {
542
- if (dev_js_1.isDev && step._isUnary && count !== 1) {
543
- throw new Error(`GrafastInternalError<84a6cdfa-e8fe-4dea-85fe-9426a6a78027>: ${step} is a unary step, but we're attempting to pass it ${count} (!= 1) values`);
544
- }
545
- if (step.execute.length > 1) {
546
- throw new Error(`${step} is using a legacy form of 'execute' which accepts multiple arguments, please see https://err.red/gev2`);
614
+ if (dev_js_1.isDev) {
615
+ if (step._isUnary && count !== 1) {
616
+ throw new Error(`GrafastInternalError<84a6cdfa-e8fe-4dea-85fe-9426a6a78027>: ${step} is a unary step, but we're attempting to pass it ${count} (!= 1) values`);
617
+ }
618
+ if (step.execute.length > 1) {
619
+ throw new Error(`${step} is using a legacy form of 'execute' which accepts multiple arguments, please see https://err.red/gev2`);
620
+ }
547
621
  }
548
622
  const executeDetails = {
549
623
  indexMap: makeIndexMap(count),
@@ -579,6 +653,7 @@ function executeBucket(bucket, requestContext) {
579
653
  let needsTransform = false;
580
654
  /** If all we see is errors, there's no need to execute! */
581
655
  let newSize = 0;
656
+ const newPolymorphicPathList = [];
582
657
  let stepPolymorphicPaths = step.polymorphicPaths;
583
658
  const legitDepsCount = (0, utils_js_1.sudo)(step).dependencies.length;
584
659
  const dependenciesIncludingSideEffectsCount = dependenciesIncludingSideEffects.length;
@@ -604,14 +679,14 @@ function executeBucket(bucket, requestContext) {
604
679
  : null;
605
680
  let rejectValue = undefined;
606
681
  let indexFlags = hasPolyMatch
607
- ? interfaces_js_1.NO_FLAGS
608
- : interfaces_js_1.FLAG_POLY_SKIPPED;
682
+ ? constants_js_1.NO_FLAGS
683
+ : constants_js_1.FLAG_POLY_SKIPPED;
609
684
  if (stepPolymorphicPaths !== null &&
610
685
  !stepPolymorphicPaths.has(polymorphicPathList[dataIndex])) {
611
- indexFlags |= interfaces_js_1.FLAG_POLY_SKIPPED;
686
+ indexFlags |= constants_js_1.FLAG_POLY_SKIPPED;
612
687
  forceIndexValue = null;
613
688
  }
614
- else if (extra._bucket.flagUnion) {
689
+ else if (extra._bucket.flagUnion !== 0) {
615
690
  for (let i = 0; i < dependenciesIncludingSideEffectsCount; i++) {
616
691
  const depExecutionVal = dependenciesIncludingSideEffects[i];
617
692
  const forbiddenFlags = dependencyForbiddenFlags[i];
@@ -628,11 +703,11 @@ function executeBucket(bucket, requestContext) {
628
703
  // If dep is inhibited and we do allow inhibited, but we're disallowed, use our onReject.
629
704
  // If dep is not inhibited, but we're disallowed, use our onReject.
630
705
  if (onReject !== undefined &&
631
- (disallowedFlags & (interfaces_js_1.FLAG_INHIBITED | interfaces_js_1.FLAG_ERROR)) === interfaces_js_1.NO_FLAGS) {
706
+ (disallowedFlags & (constants_js_1.FLAG_INHIBITED | constants_js_1.FLAG_ERROR)) === constants_js_1.NO_FLAGS) {
632
707
  rejectValue ||= onReject;
633
708
  }
634
709
  if (forceIndexValue == null) {
635
- if ((flags & interfaces_js_1.FLAG_ERROR) !== 0) {
710
+ if ((flags & constants_js_1.FLAG_ERROR) !== 0) {
636
711
  const v = depExecutionVal.at(dataIndex);
637
712
  forceIndexValue = v;
638
713
  }
@@ -664,18 +739,19 @@ function executeBucket(bucket, requestContext) {
664
739
  }
665
740
  // Search for "17217999b7a7" for similar block
666
741
  if (forceIndexValue == null && rejectValue != null) {
667
- indexFlags |= interfaces_js_1.FLAG_ERROR;
742
+ indexFlags |= constants_js_1.FLAG_ERROR;
668
743
  forceIndexValue = rejectValue;
669
744
  }
670
745
  else {
671
- indexFlags |= interfaces_js_1.FLAG_INHIBITED;
746
+ indexFlags |= constants_js_1.FLAG_INHIBITED;
672
747
  }
673
748
  // End "17217999b7a7" block
674
749
  forcedValues.flags[dataIndex] = indexFlags;
675
750
  forcedValues.results[dataIndex] = forceIndexValue;
676
751
  }
677
752
  else {
678
- newSize++;
753
+ const newIndex = newSize++;
754
+ newPolymorphicPathList[newIndex] = polymorphicPathList[dataIndex];
679
755
  if (needsTransform) {
680
756
  // dependenciesWithoutErrors has limited content; add this non-error value
681
757
  for (let depListIndex = 0; depListIndex < legitDepsCount; depListIndex++) {
@@ -763,16 +839,12 @@ function executeBucket(bucket, requestContext) {
763
839
  }
764
840
  }
765
841
  if (dev_js_1.isDev &&
766
- step.layerPlan.reason.type === "polymorphic" &&
842
+ (step.layerPlan.reason.type === "polymorphic" ||
843
+ step.layerPlan.reason.type === "polymorphicPartition") &&
767
844
  step.polymorphicPaths === null) {
768
845
  throw new Error(`GrafastInternalError<c33328fe-6758-4699-8ac6-7be41ce58bfb>: a step without polymorphic paths cannot belong to a polymorphic bucket`);
769
846
  }
770
- if (!needsFiltering) {
771
- const isSelectiveStep = step.layerPlan.reason.type === "polymorphic" &&
772
- step.polymorphicPaths.size !==
773
- step.layerPlan.reason.polymorphicPaths.size;
774
- needsFiltering ||= isSelectiveStep;
775
- }
847
+ needsFiltering ||= step._isSelectiveStep;
776
848
  const result = needsFiltering
777
849
  ? reallyExecuteStepWithFiltering(step, dependencies, _rawForbiddenFlags, _rawOnReject, bucket.polymorphicPathList, extra)
778
850
  : reallyExecuteStepWithoutFiltering(size, step, $sideEffect ? dependencies.slice(0, depCount) : dependencies, extra);
@@ -782,7 +854,7 @@ function executeBucket(bucket, requestContext) {
782
854
  // ExecutionValue is created:
783
855
  // bucket.hasNonZeroStatus = true;
784
856
  return {
785
- flags: (0, utils_js_1.arrayOfLength)(size, interfaces_js_1.FLAG_ERROR | interfaces_js_1.FLAG_STOPPED),
857
+ flags: (0, utils_js_1.arrayOfLength)(size, constants_js_1.FLAG_ERROR | constants_js_1.FLAG_STOPPED),
786
858
  results: (0, utils_js_1.arrayOfLength)(size, error),
787
859
  };
788
860
  });
@@ -796,84 +868,167 @@ function executeBucket(bucket, requestContext) {
796
868
  // ExecutionValue is created:
797
869
  // bucket.hasNonZeroStatus = true;
798
870
  return {
799
- flags: (0, utils_js_1.arrayOfLength)(size, interfaces_js_1.FLAG_ERROR | interfaces_js_1.FLAG_STOPPED),
871
+ flags: (0, utils_js_1.arrayOfLength)(size, constants_js_1.FLAG_ERROR | constants_js_1.FLAG_STOPPED),
800
872
  results: (0, utils_js_1.arrayOfLength)(size, error),
801
873
  };
802
874
  }
803
875
  }
804
876
  function executeSamePhaseChildren() {
805
- // PERF: create a JIT factory for this at planning time
806
- const childPromises = [];
807
- // This promise should never reject
808
- let mutationQueue = null;
809
- /**
810
- * Ensures that callback is only called once all other enqueued callbacks
811
- * are called.
812
- */
813
- const enqueue = (callback) => {
814
- const result = mutationQueue ? mutationQueue.then(callback) : callback();
815
- if ((0, utils_js_1.isPromiseLike)(result)) {
816
- mutationQueue = result.then(noop, noop);
877
+ const result = completeBucketAndExecuteSamePhaseChildren(bucket, requestContext);
878
+ if (result != null) {
879
+ return result.then(() => {
880
+ // PERF: this seems like a bad idea! We're forcing the bucket to be
881
+ // retained in this closure? Why?
882
+ bucket.isComplete = true;
883
+ return;
884
+ });
885
+ }
886
+ else {
887
+ bucket.isComplete = true;
888
+ return;
889
+ }
890
+ }
891
+ }
892
+ function completeBucketAndExecuteSamePhaseChildren(bucket, requestContext) {
893
+ const { layerPlan, sharedState } = bucket;
894
+ const result = markLayerPlanAsDone(requestContext, sharedState, layerPlan, bucket);
895
+ bucket.sharedState.release(bucket);
896
+ return result;
897
+ }
898
+ function markLayerPlanAsDone(requestContext, sharedState, layerPlan, bucket) {
899
+ if (sharedState._doneBucketIds.has(layerPlan.id)) {
900
+ throw new Error(`${bucket} has already completed, it cannot complete again!`);
901
+ }
902
+ sharedState._doneBucketIds.add(layerPlan.id);
903
+ const childPromises = [];
904
+ // This promise should never reject
905
+ let mutationQueue = null;
906
+ /**
907
+ * Ensures that callback is only called once all other enqueued callbacks
908
+ * are called.
909
+ */
910
+ const enqueue = (callback) => {
911
+ const result = mutationQueue ? mutationQueue.then(callback) : callback();
912
+ if ((0, utils_js_1.isPromiseLike)(result)) {
913
+ mutationQueue = result.then(noop, noop);
914
+ }
915
+ return result;
916
+ };
917
+ const { children: childLayerPlans } = layerPlan;
918
+ // PERF: create a JIT factory for this at planning time
919
+ loop: for (const childLayerPlan of childLayerPlans) {
920
+ switch (childLayerPlan.reason.type) {
921
+ case "nullableBoundary":
922
+ case "listItem":
923
+ case "polymorphic":
924
+ case "polymorphicPartition": {
925
+ const childBucket = bucket == null ? null : childLayerPlan.newBucket(bucket);
926
+ // Execute
927
+ const result = childBucket !== null
928
+ ? executeBucket(childBucket, requestContext)
929
+ : markLayerPlanAsDone(requestContext, sharedState, childLayerPlan, null);
930
+ if ((0, utils_js_1.isPromiseLike)(result)) {
931
+ childPromises.push(result);
932
+ }
933
+ break;
817
934
  }
818
- return result;
819
- };
820
- loop: for (const childLayerPlan of childLayerPlans) {
821
- switch (childLayerPlan.reason.type) {
822
- case "nullableBoundary":
823
- case "listItem":
824
- case "polymorphic": {
825
- const childBucket = childLayerPlan.newBucket(bucket);
826
- if (childBucket !== null) {
827
- // Execute
828
- const result = executeBucket(childBucket, requestContext);
829
- if ((0, utils_js_1.isPromiseLike)(result)) {
830
- childPromises.push(result);
831
- }
832
- }
833
- break;
935
+ case "mutationField": {
936
+ const childBucket = bucket == null ? null : childLayerPlan.newBucket(bucket);
937
+ // Enqueue for execution (mutations must run in order)
938
+ const promise = enqueue(() => childBucket !== null
939
+ ? executeBucket(childBucket, requestContext)
940
+ : markLayerPlanAsDone(requestContext, sharedState, childLayerPlan, null));
941
+ if ((0, utils_js_1.isPromiseLike)(promise)) {
942
+ childPromises.push(promise);
834
943
  }
835
- case "mutationField": {
836
- const childBucket = childLayerPlan.newBucket(bucket);
837
- if (childBucket !== null) {
838
- // Enqueue for execution (mutations must run in order)
839
- const promise = enqueue(() => executeBucket(childBucket, requestContext));
840
- if ((0, utils_js_1.isPromiseLike)(promise)) {
841
- childPromises.push(promise);
842
- }
944
+ break;
945
+ }
946
+ case "combined": {
947
+ // First, see if _all_ parent layer plans are ready
948
+ let allParentLayerPlansAreReady = true;
949
+ for (const lp of childLayerPlan.reason.parentLayerPlans) {
950
+ if (lp === layerPlan)
951
+ continue;
952
+ if (!sharedState._doneBucketIds.has(lp.id)) {
953
+ allParentLayerPlansAreReady = false;
954
+ break;
843
955
  }
844
- break;
845
956
  }
846
- case "subroutine":
847
- case "subscription":
848
- case "defer": {
849
- // Ignore; these are handled elsewhere
957
+ if (!allParentLayerPlansAreReady) {
958
+ // The last parent layer plan to complete will handle it.
959
+ // Make sure we're retained so it can use our data!
960
+ // Will be released inside the "combined" branch in childLayerPlan.newBucket
961
+ if (bucket != null) {
962
+ bucket.sharedState.retain(bucket);
963
+ }
964
+ // TODO: MAKE SURE CANCELLED BUCKETS ARE HANDLED!
850
965
  continue loop;
851
966
  }
852
- case "root": {
853
- throw new Error(
854
- // *confused emoji*
855
- "GrafastInternalError<05fb7069-81b5-43f7-ae71-f62547d2c2b7>: root cannot be not the root (...)");
856
- }
857
- default: {
858
- const never = childLayerPlan.reason;
859
- throw new Error(`GrafastInternalError<c6984a96-050e-4d40-ab18-a8c5dc7e239b>: unhandled reason '${(0, inspect_js_1.inspect)(never)}'`);
967
+ const childBucket = childLayerPlan.newCombinedBucket({ sharedState });
968
+ if (childBucket !== null) {
969
+ // Execute
970
+ const result = executeBucket(childBucket, requestContext);
971
+ if ((0, utils_js_1.isPromiseLike)(result)) {
972
+ childPromises.push(result);
973
+ }
860
974
  }
975
+ break;
976
+ }
977
+ case "subroutine":
978
+ case "subscription":
979
+ case "defer": {
980
+ // Ignore; these are handled elsewhere
981
+ continue loop;
982
+ }
983
+ case "root": {
984
+ throw new Error(
985
+ // *confused emoji*
986
+ "GrafastInternalError<05fb7069-81b5-43f7-ae71-f62547d2c2b7>: root cannot be not the root (...)");
987
+ }
988
+ default: {
989
+ const never = childLayerPlan.reason;
990
+ throw new Error(`GrafastInternalError<c6984a96-050e-4d40-ab18-a8c5dc7e239b>: unhandled reason '${(0, inspect_js_1.inspect)(never)}'`);
861
991
  }
862
- }
863
- if (childPromises.length > 0) {
864
- return Promise.all(childPromises).then(() => {
865
- bucket.isComplete = true;
866
- return;
867
- });
868
- }
869
- else {
870
- bucket.isComplete = true;
871
- return;
872
992
  }
873
993
  }
994
+ if (childPromises.length > 0) {
995
+ // These should never reject; rejections will bubble up through the promise chain
996
+ return Promise.all(childPromises).then(noop);
997
+ }
998
+ else {
999
+ return;
1000
+ }
1001
+ }
1002
+ function makeSharedState(layerPlan) {
1003
+ // This is from a stream/defer/similar.
1004
+ // There might be combined layer plans in it.
1005
+ // These combined layer plans might reference other layer plans which will
1006
+ // never execute (they're outside of our tree).
1007
+ // We should mark these other layer plans as "done".
1008
+ const _doneBucketIds = new Set(layerPlan.outOfBoundsLayerPlanIds);
1009
+ return {
1010
+ _doneBucketIds,
1011
+ _retainedBuckets: new Map(),
1012
+ retain(bucket) {
1013
+ this._retainedBuckets.set(bucket.layerPlan.id, bucket);
1014
+ bucket.retainCount++;
1015
+ },
1016
+ release(bucket) {
1017
+ bucket.retainCount--;
1018
+ if (bucket.retainCount <= 0) {
1019
+ this._retainedBuckets.delete(bucket.layerPlan.id);
1020
+ }
1021
+ },
1022
+ };
874
1023
  }
875
1024
  /** @internal */
876
- function newBucket(spec, parentMetaByMetaKey) {
1025
+ function newBucket(parent, spec) {
1026
+ const parentMetaByMetaKey = parent?.metaByMetaKey;
1027
+ const sharedState =
1028
+ // Do not copy state across phase transitions
1029
+ (0, utils_js_1.isPhaseTransitionLayerPlan)(spec.layerPlan)
1030
+ ? makeSharedState(spec.layerPlan)
1031
+ : (parent?.sharedState ?? makeSharedState(spec.layerPlan));
877
1032
  if (dev_js_1.isDev) {
878
1033
  // Some validations
879
1034
  if (!(spec.size > 0)) {
@@ -901,7 +1056,7 @@ function newBucket(spec, parentMetaByMetaKey) {
901
1056
  }
902
1057
  }
903
1058
  const type = spec.layerPlan.reason.type;
904
- const metaByMetaKey = parentMetaByMetaKey === null ||
1059
+ const metaByMetaKey = parentMetaByMetaKey == null ||
905
1060
  type === "root" ||
906
1061
  type === "mutationField" ||
907
1062
  type === "subscription"
@@ -909,15 +1064,18 @@ function newBucket(spec, parentMetaByMetaKey) {
909
1064
  spec.layerPlan.operationPlan.makeMetaByMetaKey()
910
1065
  : parentMetaByMetaKey;
911
1066
  // Copy from spec
912
- const { layerPlan, store, size, flagUnion, polymorphicPathList, iterators } = spec;
1067
+ const { layerPlan, store, size, flagUnion, polymorphicPathList, polymorphicType, iterators, } = spec;
913
1068
  const children = Object.create(null);
914
- return {
1069
+ const bucket = {
1070
+ sharedState,
1071
+ retainCount: 0,
915
1072
  toString: bucketToString,
916
1073
  layerPlan,
917
1074
  store,
918
1075
  size,
919
1076
  flagUnion,
920
1077
  polymorphicPathList,
1078
+ polymorphicType,
921
1079
  iterators,
922
1080
  metaByMetaKey,
923
1081
  isComplete: false,
@@ -956,6 +1114,9 @@ function newBucket(spec, parentMetaByMetaKey) {
956
1114
  }
957
1115
  },
958
1116
  };
1117
+ // Will be released when setDone is called
1118
+ sharedState.retain(bucket);
1119
+ return bucket;
959
1120
  }
960
1121
  function bucketToString() {
961
1122
  return `Bucket<${this.layerPlan}>`;
@@ -1003,7 +1164,7 @@ function batchThrowNotUnary() {
1003
1164
  }
1004
1165
  function batchGetStateUnion() {
1005
1166
  if (this._cachedStateUnion === null) {
1006
- let u = interfaces_js_1.NO_FLAGS;
1167
+ let u = constants_js_1.NO_FLAGS;
1007
1168
  for (const flag of this._flags) {
1008
1169
  u = u | flag;
1009
1170
  }