grafast 0.1.1-beta.0 → 0.1.1-beta.2

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 (81) hide show
  1. package/README.md +1 -2
  2. package/dist/args.js +62 -0
  3. package/dist/assert.js +24 -0
  4. package/dist/bucket.js +4 -0
  5. package/dist/config.js +99 -0
  6. package/dist/constraints.js +72 -0
  7. package/dist/deferred.js +25 -0
  8. package/dist/dev.js +10 -0
  9. package/dist/engine/LayerPlan.js +536 -0
  10. package/dist/engine/OperationPlan.js +2543 -0
  11. package/dist/engine/OutputPlan.js +1059 -0
  12. package/dist/engine/StepTracker.js +524 -0
  13. package/dist/engine/executeBucket.js +700 -0
  14. package/dist/engine/executeOutputPlan.js +21 -0
  15. package/dist/engine/lib/withGlobalLayerPlan.js +36 -0
  16. package/dist/envelop.js +73 -5
  17. package/dist/error.js +62 -0
  18. package/dist/establishOperationPlan.js +186 -0
  19. package/dist/execute.js +80 -0
  20. package/dist/exportAs.js +57 -0
  21. package/dist/global.js +13 -0
  22. package/dist/grafastGraphql.js +133 -0
  23. package/dist/grafastPrint.js +177 -0
  24. package/dist/graphqlCollectFields.js +217 -0
  25. package/dist/graphqlMergeSelectionSets.js +60 -0
  26. package/dist/index.d.ts +161 -2
  27. package/dist/index.js +255 -499
  28. package/dist/input.js +159 -0
  29. package/dist/inspect.js +20 -0
  30. package/dist/interfaces.d.ts +3 -160
  31. package/dist/interfaces.js +63 -0
  32. package/dist/makeGrafastSchema.js +174 -0
  33. package/dist/mermaid.js +290 -7
  34. package/dist/operationPlan-input.js +449 -0
  35. package/dist/planJSONInterfaces.js +3 -0
  36. package/dist/polymorphic.js +73 -0
  37. package/dist/prepare.js +763 -0
  38. package/dist/step.js +396 -0
  39. package/dist/steps/__inputDynamicScalar.js +125 -0
  40. package/dist/steps/__inputList.js +110 -0
  41. package/dist/steps/__inputObject.js +128 -0
  42. package/dist/steps/__inputStaticLeaf.js +43 -0
  43. package/dist/steps/__item.js +50 -0
  44. package/dist/steps/__trackedValue.js +257 -0
  45. package/dist/steps/__value.js +47 -0
  46. package/dist/steps/access.js +183 -0
  47. package/dist/steps/applyTransforms.js +151 -0
  48. package/dist/steps/connection.js +315 -0
  49. package/dist/steps/constant.js +72 -0
  50. package/dist/steps/each.js +64 -0
  51. package/dist/steps/error.js +32 -0
  52. package/dist/steps/filter.js +32 -0
  53. package/dist/steps/first.js +49 -0
  54. package/dist/steps/graphqlResolver.js +260 -0
  55. package/dist/steps/groupBy.js +40 -0
  56. package/dist/steps/index.js +117 -0
  57. package/dist/steps/lambda.js +58 -0
  58. package/dist/steps/last.js +41 -0
  59. package/dist/steps/list.js +75 -0
  60. package/dist/steps/listTransform.js +185 -0
  61. package/dist/steps/listen.js +61 -0
  62. package/dist/steps/load.d.ts +4 -4
  63. package/dist/steps/load.js +310 -0
  64. package/dist/steps/node.d.ts +6 -6
  65. package/dist/steps/node.js +107 -0
  66. package/dist/steps/object.js +195 -0
  67. package/dist/steps/partitionByIndex.js +86 -0
  68. package/dist/steps/proxy.js +114 -0
  69. package/dist/steps/remapKeys.js +84 -0
  70. package/dist/steps/reverse.js +52 -0
  71. package/dist/steps/setter.js +28 -0
  72. package/dist/stringifyPayload.js +59 -0
  73. package/dist/stripAnsi.js +14 -0
  74. package/dist/subscribe.js +14 -0
  75. package/dist/thereCanBeOnlyOne.js +21 -0
  76. package/dist/timeSource.js +8 -0
  77. package/dist/utils.js +698 -0
  78. package/dist/version.d.ts +1 -1
  79. package/dist/version.js +6 -0
  80. package/package.json +9 -4
  81. package/dist/LICENSES.txt +0 -300
@@ -0,0 +1,700 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.newBucket = exports.executeBucket = void 0;
4
+ const tslib_1 = require("tslib");
5
+ const iterall_1 = require("iterall");
6
+ const assert = tslib_1.__importStar(require("../assert.js"));
7
+ const dev_js_1 = require("../dev.js");
8
+ const error_js_1 = require("../error.js");
9
+ const inspect_js_1 = require("../inspect.js");
10
+ const interfaces_js_1 = require("../interfaces.js");
11
+ const step_js_1 = require("../step.js");
12
+ const timeSource_js_1 = require("../timeSource.js");
13
+ const utils_js_1 = require("../utils.js");
14
+ const DEBUG_POLYMORPHISM = false;
15
+ /** Path to use when there's no polymorphic paths. */
16
+ const NO_POLY_PATH = "";
17
+ // TODO: the handling of polymorphism via POLY_SKIPPED is distasteful. Find a
18
+ // better approach.
19
+ // An error that indicates this entry was skipped because it didn't match
20
+ // polymorphicPath.
21
+ const POLY_SKIPPED = (0, error_js_1.newGrafastError)(new Error("GrafastInternalError<757b99f9-cb4d-4141-895d-8c687b2048fd>: Polymorphic skipped; you should never see this"), null);
22
+ 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 })));
23
+ function noop() {
24
+ /*noop*/
25
+ }
26
+ /**
27
+ * Takes a list of `results` (shorter than `resultCount`) and an object with
28
+ * errors and indexes; returns a list of length `resultCount` with the results
29
+ * from `results` but with errors injected at the indexes specified in
30
+ * `errors`.
31
+ *
32
+ * ASSERT: `results.length + Object.values(errors).length === resultCount`
33
+ *
34
+ * @internal
35
+ */
36
+ function mergeErrorsBackIn(results, errors, resultCount) {
37
+ const finalResults = [];
38
+ let resultIndex = 0;
39
+ for (let i = 0; i < resultCount; i++) {
40
+ const error = errors[i];
41
+ if (error !== undefined) {
42
+ finalResults[i] = error;
43
+ }
44
+ else {
45
+ finalResults[i] = results[resultIndex++];
46
+ }
47
+ }
48
+ return finalResults;
49
+ }
50
+ /** @internal */
51
+ function executeBucket(bucket, requestContext) {
52
+ /**
53
+ * Execute the step directly; since there's no errors we can pass the
54
+ * dependencies through verbatim!
55
+ */
56
+ const reallyExecuteStepWithNoErrors = executeOrStream;
57
+ const { stopTime, eventEmitter } = requestContext;
58
+ const { metaByMetaKey, size, store, layerPlan: { phases, children: childLayerPlans }, } = bucket;
59
+ const phaseCount = phases.length;
60
+ let sideEffectStepsWithErrors = null;
61
+ // Like a `for(i = 0; i < phaseCount; i++)` loop with some `await`s in it, except it does promise
62
+ // handling manually so that it can complete synchronously (no promises) if
63
+ // possible.
64
+ const nextPhase = (phaseIndex) => {
65
+ if (phaseIndex >= phaseCount) {
66
+ return;
67
+ }
68
+ const phase = phases[phaseIndex];
69
+ const { _allSteps } = phase;
70
+ /**
71
+ * To ensure we don't enter a situation where an "unhandled" promise
72
+ * rejection causes Node to exit, we must process each completed step during the
73
+ * same tick in which it completes.
74
+ */
75
+ let indexesPendingLoopOver = [];
76
+ let executePromises = null;
77
+ let sideEffectSteps = null;
78
+ let executePromiseResultIndex = null;
79
+ const results = [];
80
+ if (phase.checkTimeout &&
81
+ stopTime !== null &&
82
+ timeSource_js_1.timeSource.now() >= stopTime) {
83
+ // ABORT!
84
+ if (phase.normalSteps !== undefined) {
85
+ const normalSteps = phase.normalSteps;
86
+ for (let normalStepIndex = 0, l = normalSteps.length; normalStepIndex < l; normalStepIndex++) {
87
+ const step = normalSteps[normalStepIndex].step;
88
+ const r = (0, error_js_1.newGrafastError)(timeoutError, step.id);
89
+ const result = (0, utils_js_1.arrayOfLength)(bucket.size, r);
90
+ results[normalStepIndex] = result;
91
+ indexesPendingLoopOver.push(normalStepIndex);
92
+ bucket.hasErrors = true;
93
+ }
94
+ }
95
+ }
96
+ else if (phase.normalSteps !== undefined) {
97
+ const normalSteps = phase.normalSteps;
98
+ for (let normalStepIndex = 0, l = normalSteps.length; normalStepIndex < l; normalStepIndex++) {
99
+ const step = normalSteps[normalStepIndex].step;
100
+ if (step.hasSideEffects) {
101
+ if (sideEffectSteps === null) {
102
+ sideEffectSteps = [step];
103
+ }
104
+ else {
105
+ sideEffectSteps.push(step);
106
+ }
107
+ }
108
+ try {
109
+ const r = executeStep(step);
110
+ if ((0, utils_js_1.isPromiseLike)(r)) {
111
+ results[normalStepIndex] = undefined /* will populate shortly */;
112
+ if (!executePromises) {
113
+ executePromises = [r];
114
+ executePromiseResultIndex = [normalStepIndex];
115
+ }
116
+ else {
117
+ const newIndex = executePromises.push(r) - 1;
118
+ executePromiseResultIndex[newIndex] = normalStepIndex;
119
+ }
120
+ }
121
+ else {
122
+ results[normalStepIndex] = r;
123
+ indexesPendingLoopOver.push(normalStepIndex);
124
+ }
125
+ }
126
+ catch (e) {
127
+ const r = (0, error_js_1.newGrafastError)(e, step.id);
128
+ const result = (0, utils_js_1.arrayOfLength)(bucket.size, r);
129
+ results[normalStepIndex] = result;
130
+ indexesPendingLoopOver.push(normalStepIndex);
131
+ bucket.hasErrors = true;
132
+ }
133
+ }
134
+ }
135
+ const handleSideEffectSteps = () => {
136
+ if (!sideEffectStepsWithErrors) {
137
+ sideEffectStepsWithErrors = bucket.polymorphicPathList.reduce((memo, path) => {
138
+ memo[path ?? NO_POLY_PATH] = [];
139
+ return memo;
140
+ }, Object.create(null));
141
+ }
142
+ for (const step of sideEffectSteps) {
143
+ if (step.polymorphicPaths) {
144
+ for (const path of step.polymorphicPaths) {
145
+ sideEffectStepsWithErrors[path].push(step);
146
+ }
147
+ }
148
+ else {
149
+ sideEffectStepsWithErrors[NO_POLY_PATH].push(step);
150
+ }
151
+ }
152
+ };
153
+ const next = () => {
154
+ return nextPhase(phaseIndex + 1);
155
+ };
156
+ /**
157
+ * Loops over (and resets) the indexesPendingLoopOver array, ensuring that
158
+ * all errors are handled.
159
+ */
160
+ const loopOverResults = () => {
161
+ if (indexesPendingLoopOver.length === 0)
162
+ return;
163
+ const indexesToProcess = indexesPendingLoopOver;
164
+ indexesPendingLoopOver = [];
165
+ // Validate executed steps
166
+ for (const allStepsIndex of indexesToProcess) {
167
+ const result = results[allStepsIndex];
168
+ const finishedStep = _allSteps[allStepsIndex];
169
+ const resultLength = result?.length;
170
+ if (resultLength !== size) {
171
+ if (!Array.isArray(result)) {
172
+ throw new Error(`Result from ${finishedStep} should be an array, instead received ${(0, inspect_js_1.inspect)(result, { colors: true })}`);
173
+ }
174
+ throw new Error(`Result array from ${finishedStep} should have length ${size}, instead it had length ${result.length}`);
175
+ }
176
+ bucket.store.set(finishedStep.id, (0, utils_js_1.arrayOfLength)(size));
177
+ }
178
+ // Need to complete promises, check for errors, etc.
179
+ // **DO NOT THROW, DO NOT ALLOW AN ERROR TO BE RAISED!**
180
+ // **USE DEFENSIVE PROGRAMMING HERE!**
181
+ /** PROMISES ADDED HERE MUST NOT REJECT */
182
+ let promises;
183
+ let pendingPromises;
184
+ let pendingPromiseIndexes;
185
+ const success = (finishedStep, finalResult, resultIndex, value) => {
186
+ let proto;
187
+ if (
188
+ // Fast-lane for non-objects
189
+ typeof value !== "object" ||
190
+ value === null) {
191
+ finalResult[resultIndex] = value;
192
+ return;
193
+ }
194
+ let valueIsAsyncIterable;
195
+ if (
196
+ // Are we streaming this? If so, we need an iterable or async
197
+ // iterable.
198
+ finishedStep._stepOptions.stream &&
199
+ ((valueIsAsyncIterable = (0, iterall_1.isAsyncIterable)(value)) || (0, iterall_1.isIterable)(value))) {
200
+ const streamOptions = finishedStep._stepOptions.stream;
201
+ const initialCount = streamOptions
202
+ ? streamOptions.initialCount
203
+ : Infinity;
204
+ const iterator = valueIsAsyncIterable
205
+ ? value[Symbol.asyncIterator]()
206
+ : value[Symbol.iterator]();
207
+ // Here we track the iterator via the bucket, this allows us to
208
+ // ensure that the iterator is terminated even if the stream is never
209
+ // consumed (e.g. if an error is thrown/caught during execution of
210
+ // the output plan).
211
+ if (!bucket.iterators[resultIndex]) {
212
+ bucket.iterators[resultIndex] = new Set();
213
+ }
214
+ bucket.iterators[resultIndex].add(iterator);
215
+ if (initialCount === 0) {
216
+ // Optimization - defer everything
217
+ const arr = [];
218
+ arr[interfaces_js_1.$$streamMore] = iterator;
219
+ finalResult[resultIndex] = arr;
220
+ }
221
+ else {
222
+ // Evaluate the first initialCount entries, rest is streamed.
223
+ const promise = (async () => {
224
+ try {
225
+ let valuesSeen = 0;
226
+ const arr = [];
227
+ /*
228
+ * We need to "shift" a few entries off the top of the
229
+ * iterator, but still keep it iterable for the later
230
+ * stream. To accomplish this we have to do manual
231
+ * looping
232
+ */
233
+ let resultPromise;
234
+ while ((resultPromise = iterator.next())) {
235
+ const finalResult = await resultPromise;
236
+ if (finalResult.done) {
237
+ break;
238
+ }
239
+ arr.push(await finalResult.value);
240
+ if (++valuesSeen >= initialCount) {
241
+ // This is safe to do in the `while` since we checked
242
+ // the `0` entries condition in the optimization
243
+ // above.
244
+ arr[interfaces_js_1.$$streamMore] = iterator;
245
+ break;
246
+ }
247
+ }
248
+ finalResult[resultIndex] = arr;
249
+ }
250
+ catch (e) {
251
+ bucket.hasErrors = true;
252
+ finalResult[resultIndex] = (0, error_js_1.newGrafastError)(e, finishedStep.id);
253
+ }
254
+ })();
255
+ if (!promises) {
256
+ promises = [promise];
257
+ }
258
+ else {
259
+ promises.push(promise);
260
+ }
261
+ }
262
+ }
263
+ else if ((proto = Object.getPrototypeOf(value)) === null ||
264
+ proto === Object.prototype) {
265
+ finalResult[resultIndex] = value;
266
+ }
267
+ else if (value instanceof Error) {
268
+ const e = error_js_1.$$error in value ? value : (0, error_js_1.newGrafastError)(value, finishedStep.id);
269
+ finalResult[resultIndex] = e;
270
+ bucket.hasErrors = true;
271
+ }
272
+ else {
273
+ finalResult[resultIndex] = value;
274
+ }
275
+ };
276
+ for (const allStepsIndex of indexesToProcess) {
277
+ const step = _allSteps[allStepsIndex];
278
+ const result = results[allStepsIndex];
279
+ const storeEntry = bucket.store.get(step.id);
280
+ for (let dataIndex = 0; dataIndex < size; dataIndex++) {
281
+ const val = result[dataIndex];
282
+ if (step.isSyncAndSafe || !(0, utils_js_1.isPromiseLike)(val)) {
283
+ success(step, storeEntry, dataIndex, val);
284
+ }
285
+ else {
286
+ if (!pendingPromises) {
287
+ pendingPromises = [val];
288
+ pendingPromiseIndexes = [{ s: allStepsIndex, i: dataIndex }];
289
+ }
290
+ else {
291
+ pendingPromises.push(val);
292
+ pendingPromiseIndexes.push({ s: allStepsIndex, i: dataIndex });
293
+ }
294
+ }
295
+ }
296
+ }
297
+ if (pendingPromises !== undefined) {
298
+ return Promise.allSettled(pendingPromises)
299
+ .then((resultSettledResult) => {
300
+ for (let i = 0, pendingPromisesLength = resultSettledResult.length; i < pendingPromisesLength; i++) {
301
+ const settledResult = resultSettledResult[i];
302
+ const { s: allStepsIndex, i: dataIndex } = pendingPromiseIndexes[i];
303
+ const finishedStep = _allSteps[allStepsIndex];
304
+ const storeEntry = bucket.store.get(finishedStep.id);
305
+ if (settledResult.status === "fulfilled") {
306
+ success(finishedStep, storeEntry, dataIndex, settledResult.value);
307
+ }
308
+ else {
309
+ bucket.hasErrors = true;
310
+ storeEntry[dataIndex] = (0, error_js_1.newGrafastError)(settledResult.reason, finishedStep.id);
311
+ }
312
+ }
313
+ if (bucket.hasErrors && sideEffectSteps) {
314
+ handleSideEffectSteps();
315
+ }
316
+ return promises ? Promise.all(promises) : undefined;
317
+ })
318
+ .then(null, (e) => {
319
+ // THIS SHOULD NEVER HAPPEN!
320
+ console.error(`GrafastInternalError<1e9731b4-005e-4b0e-bc61-43baa62e6444>: this error should never occur! Please file an issue against grafast. Details: ${e}`);
321
+ bucket.hasErrors = true;
322
+ for (let i = 0, pendingPromisesLength = pendingPromises.length; i < pendingPromisesLength; i++) {
323
+ const { s: allStepsIndex, i: dataIndex } = pendingPromiseIndexes[i];
324
+ const finishedStep = _allSteps[allStepsIndex];
325
+ const storeEntry = bucket.store.get(finishedStep.id);
326
+ storeEntry[dataIndex] = (0, error_js_1.newGrafastError)(new Error(`GrafastInternalError<1e9731b4-005e-4b0e-bc61-43baa62e6444>: error occurred whilst performing completedStep(${finishedStep.id})`), finishedStep.id);
327
+ }
328
+ });
329
+ }
330
+ else {
331
+ if (bucket.hasErrors && sideEffectSteps) {
332
+ handleSideEffectSteps();
333
+ }
334
+ return promises ? Promise.all(promises) : undefined;
335
+ }
336
+ };
337
+ const runSyncSteps = () => {
338
+ const executedLength = results.length;
339
+ if (dev_js_1.isDev) {
340
+ assert.strictEqual(executedLength, phase.normalSteps?.length ?? 0, "Expected only and all normalSteps to have executed");
341
+ }
342
+ if (!phase.unbatchedSyncAndSafeSteps) {
343
+ return next();
344
+ }
345
+ const allStepsLength = _allSteps.length;
346
+ const extras = [];
347
+ for (let allStepsIndex = executedLength; allStepsIndex < allStepsLength; allStepsIndex++) {
348
+ const step = _allSteps[allStepsIndex];
349
+ const meta = step.metaKey !== undefined ? metaByMetaKey[step.metaKey] : undefined;
350
+ extras[allStepsIndex] = {
351
+ stopTime,
352
+ meta,
353
+ eventEmitter,
354
+ _bucket: bucket,
355
+ _requestContext: requestContext,
356
+ };
357
+ bucket.store.set(step.id, (0, utils_js_1.arrayOfLength)(size));
358
+ }
359
+ outerLoop: for (let dataIndex = 0; dataIndex < size; dataIndex++) {
360
+ if (sideEffectStepsWithErrors) {
361
+ const currentPolymorphicPath = bucket.polymorphicPathList[dataIndex];
362
+ for (const dep of sideEffectStepsWithErrors[currentPolymorphicPath ?? NO_POLY_PATH]) {
363
+ const depVal = bucket.store.get(dep.id)[dataIndex];
364
+ if (depVal === POLY_SKIPPED ||
365
+ (dev_js_1.isDev && depVal?.$$error === POLY_SKIPPED)) {
366
+ /* noop */
367
+ }
368
+ else if ((0, error_js_1.isGrafastError)(depVal)) {
369
+ for (let allStepsIndex = executedLength; allStepsIndex < allStepsLength; allStepsIndex++) {
370
+ const step = _allSteps[allStepsIndex];
371
+ const storeEntry = bucket.store.get(step.id);
372
+ storeEntry[dataIndex] = depVal;
373
+ }
374
+ continue outerLoop;
375
+ }
376
+ }
377
+ }
378
+ stepLoop: for (let allStepsIndex = executedLength; allStepsIndex < allStepsLength; allStepsIndex++) {
379
+ const step = _allSteps[allStepsIndex];
380
+ const storeEntry = bucket.store.get(step.id);
381
+ try {
382
+ const deps = [];
383
+ for (const $dep of step.dependencies) {
384
+ const depVal = bucket.store.get($dep.id)[dataIndex];
385
+ if (bucket.hasErrors && (0, error_js_1.isGrafastError)(depVal)) {
386
+ storeEntry[dataIndex] = depVal;
387
+ continue stepLoop;
388
+ }
389
+ deps.push(depVal);
390
+ }
391
+ storeEntry[dataIndex] = step.unbatchedExecute(extras[allStepsIndex], ...deps);
392
+ }
393
+ catch (e) {
394
+ bucket.hasErrors = true;
395
+ storeEntry[dataIndex] = (0, error_js_1.newGrafastError)(e, step.id);
396
+ }
397
+ }
398
+ }
399
+ return next();
400
+ };
401
+ if (executePromises !== null) {
402
+ const processedPromises = [];
403
+ if (indexesPendingLoopOver.length > 0) {
404
+ // This **must be done in the same tick**
405
+ const promiseOrNot = loopOverResults();
406
+ if ((0, utils_js_1.isPromiseLike)(promiseOrNot)) {
407
+ processedPromises.push(promiseOrNot);
408
+ }
409
+ }
410
+ for (let i = 0, l = executePromises.length; i < l; i++) {
411
+ const executePromise = executePromises[i];
412
+ const index = executePromiseResultIndex[i];
413
+ processedPromises.push(executePromise.then((promiseResult) => {
414
+ results[index] = promiseResult;
415
+ indexesPendingLoopOver.push(index);
416
+ // We must loop over the results in the same tick in which the
417
+ // promise resolved.
418
+ return loopOverResults();
419
+ }));
420
+ }
421
+ return Promise.all(processedPromises).then(runSyncSteps);
422
+ }
423
+ else {
424
+ const promiseOrNot = loopOverResults();
425
+ if ((0, utils_js_1.isPromiseLike)(promiseOrNot)) {
426
+ return promiseOrNot.then(runSyncSteps);
427
+ }
428
+ else {
429
+ return runSyncSteps();
430
+ }
431
+ }
432
+ };
433
+ const promise = nextPhase(0);
434
+ if ((0, utils_js_1.isPromiseLike)(promise)) {
435
+ return promise.then(executeSamePhaseChildren);
436
+ }
437
+ else {
438
+ return executeSamePhaseChildren();
439
+ }
440
+ // Function definitions below here
441
+ function executeOrStream(step, dependencies, extra) {
442
+ if (step._stepOptions.stream && (0, step_js_1.isStreamableStep)(step)) {
443
+ return step.stream(size, dependencies, extra, step._stepOptions.stream);
444
+ }
445
+ else {
446
+ return step.execute(size, dependencies, extra);
447
+ }
448
+ }
449
+ // Slow mode...
450
+ /**
451
+ * Execute the step, filtering out errors and entries with non-matching
452
+ * polymorphicPaths from the input dependencies and then padding the lists
453
+ * back out at the end.
454
+ */
455
+ function reallyExecuteStepWithErrorsOrSelective(step, dependenciesIncludingSideEffects, polymorphicPathList, extra) {
456
+ const errors = Object.create(null);
457
+ /** If there's errors, we must manipulate the arrays being passed into the step execution */
458
+ let foundErrors = false;
459
+ /** If all we see is errors, there's no need to execute! */
460
+ let needsNoExecution = true;
461
+ const stepPolymorphicPaths = step.polymorphicPaths;
462
+ for (let index = 0, l = polymorphicPathList.length; index < l; index++) {
463
+ const polymorphicPath = polymorphicPathList[index];
464
+ if (stepPolymorphicPaths !== null &&
465
+ !stepPolymorphicPaths.has(polymorphicPath)) {
466
+ foundErrors = true;
467
+ const e = dev_js_1.isDev && DEBUG_POLYMORPHISM
468
+ ? Object.assign((0, error_js_1.newGrafastError)(new Error(`GrafastInternalError<00d52055-06b0-4b25-abeb-311b800ea284>: step ${step.id} (polymorphicPaths ${[
469
+ ...stepPolymorphicPaths,
470
+ ]}) has no match for '${polymorphicPath}'`), step.id), { $$error: POLY_SKIPPED })
471
+ : POLY_SKIPPED;
472
+ errors[index] = e;
473
+ }
474
+ else if (extra._bucket.hasErrors) {
475
+ let noError = true;
476
+ for (const depList of dependenciesIncludingSideEffects) {
477
+ const v = depList[index];
478
+ if ((0, error_js_1.isGrafastError)(v)) {
479
+ if (!errors[index]) {
480
+ noError = false;
481
+ foundErrors = true;
482
+ errors[index] = v;
483
+ break;
484
+ }
485
+ }
486
+ }
487
+ if (noError) {
488
+ needsNoExecution = false;
489
+ }
490
+ }
491
+ else {
492
+ needsNoExecution = false;
493
+ }
494
+ }
495
+ // Trim the side-effect dependencies back out again
496
+ const dependencies = sideEffectStepsWithErrors
497
+ ? dependenciesIncludingSideEffects.slice(0, step.dependencies.length)
498
+ : dependenciesIncludingSideEffects;
499
+ if (needsNoExecution) {
500
+ // Everything is errors; we can skip execution
501
+ return Object.values(errors);
502
+ }
503
+ else if (foundErrors) {
504
+ const dependenciesWithoutErrors = dependencies.map((depList) => depList.filter((_, index) => !errors[index]));
505
+ const resultWithoutErrors = executeOrStream(step, dependenciesWithoutErrors, extra);
506
+ if ((0, utils_js_1.isPromiseLike)(resultWithoutErrors)) {
507
+ return resultWithoutErrors.then((r) => mergeErrorsBackIn(r, errors, dependencies[0].length));
508
+ }
509
+ else {
510
+ return mergeErrorsBackIn(resultWithoutErrors, errors, dependencies[0].length);
511
+ }
512
+ }
513
+ else {
514
+ return reallyExecuteStepWithNoErrors(step, dependencies, extra);
515
+ }
516
+ }
517
+ /**
518
+ * This function MIGHT throw or reject, so be sure to handle that.
519
+ */
520
+ function executeStep(step) {
521
+ try {
522
+ const meta = step.metaKey !== undefined ? metaByMetaKey[step.metaKey] : undefined;
523
+ const extra = {
524
+ stopTime,
525
+ meta,
526
+ eventEmitter,
527
+ _bucket: bucket,
528
+ _requestContext: requestContext,
529
+ };
530
+ const dependencies = [];
531
+ const depCount = step.dependencies.length;
532
+ if (depCount > 0 || sideEffectStepsWithErrors !== null) {
533
+ for (let i = 0, l = depCount; i < l; i++) {
534
+ const $dep = step.dependencies[i];
535
+ dependencies[i] = store.get($dep.id);
536
+ }
537
+ if (sideEffectStepsWithErrors !== null) {
538
+ if (step.polymorphicPaths) {
539
+ for (const path of step.polymorphicPaths) {
540
+ for (const sideEffectStep of sideEffectStepsWithErrors[path]) {
541
+ const sideEffectStoreEntry = store.get(sideEffectStep.id);
542
+ if (!dependencies.includes(sideEffectStoreEntry)) {
543
+ dependencies.push(sideEffectStoreEntry);
544
+ }
545
+ }
546
+ }
547
+ }
548
+ else {
549
+ for (const sideEffectStep of sideEffectStepsWithErrors[NO_POLY_PATH]) {
550
+ const sideEffectStoreEntry = store.get(sideEffectStep.id);
551
+ if (!dependencies.includes(sideEffectStoreEntry)) {
552
+ dependencies.push(sideEffectStoreEntry);
553
+ }
554
+ }
555
+ }
556
+ }
557
+ }
558
+ if (dev_js_1.isDev &&
559
+ step.layerPlan.reason.type === "polymorphic" &&
560
+ step.polymorphicPaths === null) {
561
+ throw new Error(`GrafastInternalError<c33328fe-6758-4699-8ac6-7be41ce58bfb>: a step without polymorphic paths cannot belong to a polymorphic bucket`);
562
+ }
563
+ const isSelectiveStep = step.layerPlan.reason.type === "polymorphic" &&
564
+ step.polymorphicPaths.size !==
565
+ step.layerPlan.reason.polymorphicPaths.size;
566
+ const result = bucket.hasErrors || isSelectiveStep
567
+ ? reallyExecuteStepWithErrorsOrSelective(step, dependencies, bucket.polymorphicPathList, extra)
568
+ : reallyExecuteStepWithNoErrors(step, dependencies, extra);
569
+ if ((0, utils_js_1.isPromiseLike)(result)) {
570
+ return result.then(null, (error) => {
571
+ // bucket.hasErrors = true;
572
+ return (0, utils_js_1.arrayOfLength)(size, error);
573
+ });
574
+ }
575
+ else {
576
+ return result;
577
+ }
578
+ }
579
+ catch (error) {
580
+ // bucket.hasErrors = true;
581
+ return (0, utils_js_1.arrayOfLength)(size, error);
582
+ }
583
+ }
584
+ function executeSamePhaseChildren() {
585
+ // PERF: create a JIT factory for this at planning time
586
+ const childPromises = [];
587
+ // This promise should never reject
588
+ let mutationQueue = null;
589
+ /**
590
+ * Ensures that callback is only called once all other enqueued callbacks
591
+ * are called.
592
+ */
593
+ const enqueue = (callback) => {
594
+ const result = (mutationQueue ?? Promise.resolve()).then(callback);
595
+ mutationQueue = result.then(noop, noop);
596
+ return result;
597
+ };
598
+ loop: for (const childLayerPlan of childLayerPlans) {
599
+ switch (childLayerPlan.reason.type) {
600
+ case "nullableBoundary":
601
+ case "listItem":
602
+ case "polymorphic": {
603
+ const childBucket = childLayerPlan.newBucket(bucket);
604
+ if (childBucket !== null) {
605
+ // Execute
606
+ const result = executeBucket(childBucket, requestContext);
607
+ if ((0, utils_js_1.isPromiseLike)(result)) {
608
+ childPromises.push(result);
609
+ }
610
+ }
611
+ break;
612
+ }
613
+ case "mutationField": {
614
+ const childBucket = childLayerPlan.newBucket(bucket);
615
+ if (childBucket !== null) {
616
+ // Enqueue for execution (mutations must run in order)
617
+ const promise = enqueue(() => executeBucket(childBucket, requestContext));
618
+ childPromises.push(promise);
619
+ }
620
+ break;
621
+ }
622
+ case "subroutine":
623
+ case "subscription":
624
+ case "defer": {
625
+ // Ignore; these are handled elsewhere
626
+ continue loop;
627
+ }
628
+ case "root": {
629
+ throw new Error(
630
+ // *confused emoji*
631
+ "GrafastInternalError<05fb7069-81b5-43f7-ae71-f62547d2c2b7>: root cannot be not the root (...)");
632
+ }
633
+ default: {
634
+ const never = childLayerPlan.reason;
635
+ throw new Error(`GrafastInternalError<c6984a96-050e-4d40-ab18-a8c5dc7e239b>: unhandled reason '${(0, inspect_js_1.inspect)(never)}'`);
636
+ }
637
+ }
638
+ }
639
+ if (childPromises.length > 0) {
640
+ return Promise.all(childPromises).then(() => {
641
+ bucket.isComplete = true;
642
+ return;
643
+ });
644
+ }
645
+ else {
646
+ bucket.isComplete = true;
647
+ return;
648
+ }
649
+ }
650
+ }
651
+ exports.executeBucket = executeBucket;
652
+ /** @internal */
653
+ function newBucket(spec, parentMetaByMetaKey) {
654
+ if (dev_js_1.isDev) {
655
+ // Some validations
656
+ if (!(spec.size > 0)) {
657
+ throw new Error("GrafastInternalError<eb5c962d-c748-4759-95e3-52c50c873593>: No need to create an empty bucket!");
658
+ }
659
+ assert.strictEqual(spec.polymorphicPathList.length, spec.size, "polymorphicPathList length must match bucket size");
660
+ /*
661
+ for (let i = 0, l = spec.size; i < l; i++) {
662
+ const p = spec.polymorphicPathList[i];
663
+ assert.strictEqual(
664
+ typeof p,
665
+ "string",
666
+ `Entry ${i} in polymorphicPathList for bucket for ${spec.layerPlan} was not a string`,
667
+ );
668
+ }
669
+ */
670
+ for (const [key, list] of spec.store.entries()) {
671
+ assert.ok(Array.isArray(list), `Store entry for step '${key}' for layerPlan '${spec.layerPlan.id}' should be a list`);
672
+ assert.strictEqual(list.length, spec.size, `Store entry for step '${key}' for layerPlan '${spec.layerPlan.id}' should have same length as bucket`);
673
+ }
674
+ if (!spec.iterators) {
675
+ throw new Error(`newBucket called but no iterators array was specified`);
676
+ }
677
+ }
678
+ const type = spec.layerPlan.reason.type;
679
+ const metaByMetaKey = parentMetaByMetaKey === null ||
680
+ type === "root" ||
681
+ type === "mutationField" ||
682
+ type === "subscription"
683
+ ? // Reset the metaByMetaKey
684
+ spec.layerPlan.operationPlan.makeMetaByMetaKey()
685
+ : parentMetaByMetaKey;
686
+ return {
687
+ // Copy from spec
688
+ layerPlan: spec.layerPlan,
689
+ store: spec.store,
690
+ size: spec.size,
691
+ hasErrors: spec.hasErrors,
692
+ polymorphicPathList: spec.polymorphicPathList,
693
+ iterators: spec.iterators,
694
+ metaByMetaKey,
695
+ isComplete: false,
696
+ children: Object.create(null),
697
+ };
698
+ }
699
+ exports.newBucket = newBucket;
700
+ //# sourceMappingURL=executeBucket.js.map