grafast 0.1.1-beta.21 → 0.1.1-beta.23
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.
- package/README.md +0 -4
- package/dist/args.js +3 -3
- package/dist/constants.d.ts +79 -0
- package/dist/constants.js +79 -0
- package/dist/engine/LayerPlan.d.ts +71 -8
- package/dist/engine/LayerPlan.js +375 -265
- package/dist/engine/OperationPlan.d.ts +77 -14
- package/dist/engine/OperationPlan.js +1508 -382
- package/dist/engine/OperationPlanTypes.d.ts +66 -0
- package/dist/engine/OperationPlanTypes.js +3 -0
- package/dist/engine/OutputPlan.d.ts +6 -0
- package/dist/engine/OutputPlan.js +138 -82
- package/dist/engine/StepTracker.js +76 -17
- package/dist/engine/executeBucket.js +327 -166
- package/dist/engine/lib/defaultPlanResolver.d.ts +1 -4
- package/dist/engine/lib/defaultPlanResolver.js +1 -5
- package/dist/engine/lib/withGlobalLayerPlan.d.ts +3 -1
- package/dist/engine/lib/withGlobalLayerPlan.js +19 -1
- package/dist/envelop.js +14 -3
- package/dist/error.d.ts +1 -1
- package/dist/error.js +9 -9
- package/dist/establishOperationPlan.d.ts +2 -1
- package/dist/establishOperationPlan.js +10 -10
- package/dist/execute.js +7 -5
- package/dist/global.d.ts +10 -0
- package/dist/global.js +25 -0
- package/dist/grafastGraphql.js +4 -3
- package/dist/grafastPrint.js +36 -4
- package/dist/index.d.ts +76 -8
- package/dist/index.js +37 -33
- package/dist/input.js +20 -1
- package/dist/inspect.js +1 -0
- package/dist/interfaces.d.ts +80 -122
- package/dist/interfaces.js +0 -77
- package/dist/makeGrafastSchema.d.ts +118 -35
- package/dist/makeGrafastSchema.js +197 -29
- package/dist/mermaid.js +198 -97
- package/dist/operationPlan-input.d.ts +1 -1
- package/dist/operationPlan-input.js +15 -5
- package/dist/planJSONInterfaces.d.ts +24 -5
- package/dist/prepare.d.ts +16 -9
- package/dist/prepare.js +54 -51
- package/dist/step.d.ts +45 -9
- package/dist/step.js +139 -22
- package/dist/steps/__flag.d.ts +3 -2
- package/dist/steps/__flag.js +31 -29
- package/dist/steps/__inputObject.d.ts +1 -1
- package/dist/steps/__inputStaticLeaf.d.ts +3 -2
- package/dist/steps/__inputStaticLeaf.js +13 -7
- package/dist/steps/__item.d.ts +1 -1
- package/dist/steps/__item.js +3 -3
- package/dist/steps/__trackedValue.d.ts +6 -3
- package/dist/steps/__trackedValue.js +25 -9
- package/dist/steps/__value.d.ts +2 -1
- package/dist/steps/__value.js +5 -0
- package/dist/steps/access.d.ts +17 -1
- package/dist/steps/access.js +14 -1
- package/dist/steps/applyInput.d.ts +1 -1
- package/dist/steps/applyInput.js +7 -6
- package/dist/steps/applyTransforms.js +9 -7
- package/dist/steps/bakedInput.js +2 -2
- package/dist/steps/coalesce.d.ts +15 -0
- package/dist/steps/coalesce.js +36 -0
- package/dist/steps/constant.js +16 -14
- package/dist/steps/each.d.ts +2 -2
- package/dist/steps/first.d.ts +2 -0
- package/dist/steps/first.js +5 -1
- package/dist/steps/graphqlResolver.d.ts +2 -2
- package/dist/steps/graphqlResolver.js +63 -161
- package/dist/steps/index.d.ts +3 -15
- package/dist/steps/index.js +6 -41
- package/dist/steps/lambda.js +1 -1
- package/dist/steps/last.d.ts +2 -0
- package/dist/steps/last.js +4 -0
- package/dist/steps/listTransform.d.ts +2 -2
- package/dist/steps/listTransform.js +11 -13
- package/dist/steps/load.d.ts +28 -22
- package/dist/steps/load.js +47 -1
- package/dist/steps/node.d.ts +10 -7
- package/dist/steps/node.js +5 -19
- package/dist/steps/object.js +6 -1
- package/dist/steps/proxy.d.ts +0 -6
- package/dist/steps/proxy.js +3 -3
- package/dist/steps/remapKeys.d.ts +1 -1
- package/dist/steps/remapKeys.js +0 -1
- package/dist/utils.d.ts +27 -5
- package/dist/utils.js +235 -15
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +7 -7
- package/dist/polymorphic.d.ts +0 -14
- package/dist/polymorphic.js +0 -72
- package/dist/steps/polymorphicBranch.d.ts +0 -27
- package/dist/steps/polymorphicBranch.js +0 -62
|
@@ -6,12 +6,12 @@ const lru_1 = tslib_1.__importDefault(require("@graphile/lru"));
|
|
|
6
6
|
const graphql = tslib_1.__importStar(require("graphql"));
|
|
7
7
|
const tamedevil_1 = tslib_1.__importDefault(require("tamedevil"));
|
|
8
8
|
const assert = tslib_1.__importStar(require("../assert.js"));
|
|
9
|
+
const constants_js_1 = require("../constants.js");
|
|
9
10
|
const graphqlCollectFields_js_1 = require("../graphqlCollectFields.js");
|
|
10
11
|
const graphqlMergeSelectionSets_js_1 = require("../graphqlMergeSelectionSets.js");
|
|
11
12
|
const index_js_1 = require("../index.js");
|
|
12
13
|
const input_js_1 = require("../input.js");
|
|
13
14
|
const inspect_js_1 = require("../inspect.js");
|
|
14
|
-
const interfaces_js_1 = require("../interfaces.js");
|
|
15
15
|
const operationPlan_input_js_1 = require("../operationPlan-input.js");
|
|
16
16
|
const step_js_1 = require("../step.js");
|
|
17
17
|
const connection_js_1 = require("../steps/connection.js");
|
|
@@ -28,6 +28,7 @@ const StepTracker_js_1 = require("./StepTracker.js");
|
|
|
28
28
|
const atpe = typeof process !== "undefined" && process.env.ALWAYS_THROW_PLANNING_ERRORS;
|
|
29
29
|
const ALWAYS_THROW_PLANNING_ERRORS = atpe === "1";
|
|
30
30
|
const THROW_PLANNING_ERRORS_ON_SIDE_EFFECTS = atpe === "2";
|
|
31
|
+
const DEFAULT_MAX_DEPTH = 100;
|
|
31
32
|
/**
|
|
32
33
|
* Returns true for steps that the system populates automatically without executing.
|
|
33
34
|
*/
|
|
@@ -48,6 +49,7 @@ const { assertObjectType, defaultFieldResolver, getNamedType, getNullableType, i
|
|
|
48
49
|
*/
|
|
49
50
|
let planningTimeoutWarmupMultiplier = 5;
|
|
50
51
|
const EMPTY_ARRAY = Object.freeze([]);
|
|
52
|
+
const EMPTY_SET = new Set();
|
|
51
53
|
exports.POLYMORPHIC_ROOT_PATH = null;
|
|
52
54
|
exports.POLYMORPHIC_ROOT_PATHS = null;
|
|
53
55
|
Object.freeze(exports.POLYMORPHIC_ROOT_PATHS);
|
|
@@ -57,20 +59,20 @@ const REASON_ROOT = Object.freeze({ type: "root" });
|
|
|
57
59
|
const OUTPUT_PLAN_TYPE_NULL = Object.freeze({ mode: "null" });
|
|
58
60
|
const OUTPUT_PLAN_TYPE_ARRAY = Object.freeze({ mode: "array" });
|
|
59
61
|
const newValueStepCallback = (isImmutable) => new index_js_1.__ValueStep(isImmutable);
|
|
60
|
-
const NO_ARGS =
|
|
61
|
-
get() {
|
|
62
|
-
throw new Error(`This field doesn't have any arguments`);
|
|
63
|
-
},
|
|
64
|
-
};
|
|
62
|
+
const NO_ARGS = Object.create(null);
|
|
65
63
|
class OperationPlan {
|
|
66
|
-
constructor(schema, operation, fragments, variableValuesConstraints, variableValues, contextConstraints, context, rootValueConstraints, rootValue,
|
|
64
|
+
constructor(schema, operation, fragments, variableValuesConstraints, variableValues, contextConstraints, context, rootValueConstraints, rootValue, options) {
|
|
67
65
|
this.schema = schema;
|
|
68
66
|
this.operation = operation;
|
|
69
67
|
this.fragments = fragments;
|
|
70
68
|
this.variableValues = variableValues;
|
|
71
69
|
this.context = context;
|
|
72
70
|
this.rootValue = rootValue;
|
|
73
|
-
|
|
71
|
+
/**
|
|
72
|
+
* For use by `inputStep()` only.
|
|
73
|
+
* @internal
|
|
74
|
+
*/
|
|
75
|
+
this._inputStepCache = new Map();
|
|
74
76
|
/**
|
|
75
77
|
* What state is the OpPlan in?
|
|
76
78
|
*
|
|
@@ -95,7 +97,7 @@ class OperationPlan {
|
|
|
95
97
|
/**
|
|
96
98
|
* @internal
|
|
97
99
|
*/
|
|
98
|
-
this.
|
|
100
|
+
this.itemStepIdByListStepIdByParentLayerPlanId = Object.create(null);
|
|
99
101
|
/**
|
|
100
102
|
* If true, then this operation doesn't use (custom) resolvers.
|
|
101
103
|
*/
|
|
@@ -106,6 +108,7 @@ class OperationPlan {
|
|
|
106
108
|
this.optimizeMeta = new Map();
|
|
107
109
|
/** @internal */
|
|
108
110
|
this.valueNodeToStaticValueCache = new Map();
|
|
111
|
+
this.frozenPlanningPaths = index_js_1.isDev ? null : new Set();
|
|
109
112
|
/** @internal Use plan.getStep(id) instead. */
|
|
110
113
|
this.getStep = index_js_1.isDev
|
|
111
114
|
? (id, requestingStep) => {
|
|
@@ -122,14 +125,28 @@ class OperationPlan {
|
|
|
122
125
|
if (step == null) {
|
|
123
126
|
throw new Error(`Programming error: step with id '${id}' no longer exists (attempted access from ${requestingStep}). Most likely this means that ${requestingStep} has an illegal reference to this step, you should only maintain references to steps via dependencies.`);
|
|
124
127
|
}
|
|
125
|
-
return step[
|
|
128
|
+
return step[constants_js_1.$$proxy] ?? step;
|
|
126
129
|
}
|
|
127
130
|
: (id, _requestingStep) => {
|
|
128
131
|
const step = this.stepTracker.getStepById(id);
|
|
129
|
-
return step[
|
|
132
|
+
return step[constants_js_1.$$proxy] ?? step;
|
|
130
133
|
};
|
|
131
|
-
|
|
132
|
-
this.
|
|
134
|
+
// This is the queue of things to be done _IN ORDER_
|
|
135
|
+
this.planningQueue = [];
|
|
136
|
+
// This is the queue of things to be done grouped by their planning path.
|
|
137
|
+
// The result of this is not necessarily in order, but it does save us
|
|
138
|
+
// time and effort in `planPending()`
|
|
139
|
+
this.planningQueueByPlanningPath = new Map();
|
|
140
|
+
this.planFieldBatch = null;
|
|
141
|
+
this._cacheStepStoreByActionKeyByLayerPlan = new Map();
|
|
142
|
+
this._immutableCacheStepStoreAndActionKey = Object.create(null);
|
|
143
|
+
this.planningTimeout = options?.timeouts?.planning ?? null;
|
|
144
|
+
this.maxPlanningDepth = options?.maxPlanningDepth ?? DEFAULT_MAX_DEPTH;
|
|
145
|
+
this.resolveInfoOperationBase = {
|
|
146
|
+
schema,
|
|
147
|
+
operation,
|
|
148
|
+
fragments,
|
|
149
|
+
};
|
|
133
150
|
this.variableValuesConstraints = variableValuesConstraints;
|
|
134
151
|
this.contextConstraints = contextConstraints;
|
|
135
152
|
this.rootValueConstraints = rootValueConstraints;
|
|
@@ -165,7 +182,7 @@ class OperationPlan {
|
|
|
165
182
|
}
|
|
166
183
|
this.operationType = operation.operation;
|
|
167
184
|
this.phase = "plan";
|
|
168
|
-
this.rootLayerPlan = new LayerPlan_js_1.LayerPlan(this,
|
|
185
|
+
this.rootLayerPlan = new LayerPlan_js_1.LayerPlan(this, REASON_ROOT);
|
|
169
186
|
// Set up the shared steps for variables, context and rootValue
|
|
170
187
|
[this.variableValuesStep, this.trackedVariableValuesStep] = this.track(variableValues, this.variableValuesConstraints, this.operation.variableDefinitions);
|
|
171
188
|
[this.contextStep, this.trackedContextStep] = this.track(context, this.contextConstraints);
|
|
@@ -293,8 +310,8 @@ class OperationPlan {
|
|
|
293
310
|
const elapsed = now - this.startTime;
|
|
294
311
|
if (elapsed > this.planningTimeout * planningTimeoutWarmupMultiplier) {
|
|
295
312
|
throw new index_js_1.SafeError("Operation took too long to plan and was aborted. Please simplify the request and try again.", {
|
|
296
|
-
[
|
|
297
|
-
[
|
|
313
|
+
[constants_js_1.$$timeout]: this.planningTimeout,
|
|
314
|
+
[constants_js_1.$$ts]: now,
|
|
298
315
|
});
|
|
299
316
|
}
|
|
300
317
|
}
|
|
@@ -380,7 +397,18 @@ class OperationPlan {
|
|
|
380
397
|
typeName: this.queryType.name,
|
|
381
398
|
}, locationDetails);
|
|
382
399
|
this.rootOutputPlan = outputPlan;
|
|
383
|
-
this.
|
|
400
|
+
this.queueNextLayer(this.planSelectionSet, {
|
|
401
|
+
outputPlan,
|
|
402
|
+
path: [],
|
|
403
|
+
planningPath: rootType.name + ".",
|
|
404
|
+
polymorphicPaths: exports.POLYMORPHIC_ROOT_PATHS,
|
|
405
|
+
parentStep: this.trackedRootValueStep,
|
|
406
|
+
positionType: rootType,
|
|
407
|
+
layerPlan: this.rootLayerPlan,
|
|
408
|
+
selections: this.operation.selectionSet.selections,
|
|
409
|
+
resolverEmulation: true,
|
|
410
|
+
});
|
|
411
|
+
this.planPending();
|
|
384
412
|
if (this.loc !== null)
|
|
385
413
|
this.loc.pop();
|
|
386
414
|
}
|
|
@@ -394,7 +422,6 @@ class OperationPlan {
|
|
|
394
422
|
if (!rootType) {
|
|
395
423
|
throw new index_js_1.SafeError("No mutation type found in schema");
|
|
396
424
|
}
|
|
397
|
-
this.deduplicateSteps();
|
|
398
425
|
const locationDetails = {
|
|
399
426
|
node: this.operation.selectionSet.selections,
|
|
400
427
|
parentTypeName: null,
|
|
@@ -406,7 +433,19 @@ class OperationPlan {
|
|
|
406
433
|
typeName: rootType.name,
|
|
407
434
|
}, locationDetails);
|
|
408
435
|
this.rootOutputPlan = outputPlan;
|
|
409
|
-
this.
|
|
436
|
+
this.queueNextLayer(this.planSelectionSet, {
|
|
437
|
+
outputPlan,
|
|
438
|
+
path: [],
|
|
439
|
+
planningPath: rootType.name + ".",
|
|
440
|
+
polymorphicPaths: exports.POLYMORPHIC_ROOT_PATHS,
|
|
441
|
+
parentStep: this.trackedRootValueStep,
|
|
442
|
+
positionType: rootType,
|
|
443
|
+
layerPlan: this.rootLayerPlan,
|
|
444
|
+
selections: this.operation.selectionSet.selections,
|
|
445
|
+
resolverEmulation: true,
|
|
446
|
+
isMutation: true,
|
|
447
|
+
});
|
|
448
|
+
this.planPending();
|
|
410
449
|
if (this.loc !== null)
|
|
411
450
|
this.loc.pop();
|
|
412
451
|
}
|
|
@@ -420,8 +459,9 @@ class OperationPlan {
|
|
|
420
459
|
if (!rootType) {
|
|
421
460
|
throw new index_js_1.SafeError("No subscription type found in schema");
|
|
422
461
|
}
|
|
462
|
+
const planningPath = rootType.name + ".";
|
|
423
463
|
const selectionSet = this.operation.selectionSet;
|
|
424
|
-
const groupedFieldSet = (0, withGlobalLayerPlan_js_1.withGlobalLayerPlan)(this.rootLayerPlan, exports.POLYMORPHIC_ROOT_PATHS, graphqlCollectFields_js_1.graphqlCollectFields, null, this, this.trackedRootValueStep.id, rootType, selectionSet.selections, (0, graphqlCollectFields_js_1.newSelectionSetDigest)(false));
|
|
464
|
+
const groupedFieldSet = (0, withGlobalLayerPlan_js_1.withGlobalLayerPlan)(this.rootLayerPlan, exports.POLYMORPHIC_ROOT_PATHS, planningPath, graphqlCollectFields_js_1.graphqlCollectFields, null, this, this.trackedRootValueStep.id, rootType, selectionSet.selections, (0, graphqlCollectFields_js_1.newSelectionSetDigest)(false));
|
|
425
465
|
if (groupedFieldSet.deferred !== undefined) {
|
|
426
466
|
throw new index_js_1.SafeError("@defer forbidden on subscription root selection set");
|
|
427
467
|
}
|
|
@@ -452,46 +492,63 @@ class OperationPlan {
|
|
|
452
492
|
const subscriptionPlanResolver = rawSubscriptionPlanResolver;
|
|
453
493
|
const fieldArgsSpec = fieldSpec.args;
|
|
454
494
|
const trackedArguments = fieldArgsSpec.length > 0
|
|
455
|
-
? (0, withGlobalLayerPlan_js_1.withGlobalLayerPlan)(this.rootLayerPlan, exports.POLYMORPHIC_ROOT_PATHS, this.getTrackedArguments, this, fieldArgsSpec, field)
|
|
495
|
+
? (0, withGlobalLayerPlan_js_1.withGlobalLayerPlan)(this.rootLayerPlan, exports.POLYMORPHIC_ROOT_PATHS, planningPath, this.getTrackedArguments, this, fieldArgsSpec, field)
|
|
456
496
|
: NO_ARGS;
|
|
457
497
|
if (subscriptionPlanResolver !== undefined) {
|
|
458
498
|
// PERF: optimize this
|
|
459
|
-
const { haltTree, step: subscribeStep } = this.
|
|
499
|
+
const { haltTree, step: subscribeStep } = this.batchPlanField({
|
|
500
|
+
typeName: rootType.name,
|
|
501
|
+
fieldName,
|
|
502
|
+
layerPlan: this.rootLayerPlan,
|
|
503
|
+
path,
|
|
504
|
+
polymorphicPaths: exports.POLYMORPHIC_ROOT_PATHS,
|
|
505
|
+
planningPath,
|
|
506
|
+
planResolver: subscriptionPlanResolver,
|
|
507
|
+
applyAfterMode: "subscribePlan",
|
|
508
|
+
rawParentStep: this.trackedRootValueStep,
|
|
509
|
+
field: fieldSpec,
|
|
510
|
+
trackedArguments,
|
|
511
|
+
streamDetails: true,
|
|
512
|
+
})();
|
|
460
513
|
if (haltTree) {
|
|
461
514
|
throw new index_js_1.SafeError("Failed to setup subscription");
|
|
462
515
|
}
|
|
463
516
|
this.rootLayerPlan.setRootStep(subscribeStep);
|
|
464
|
-
const subscriptionEventLayerPlan = new LayerPlan_js_1.LayerPlan(this,
|
|
517
|
+
const subscriptionEventLayerPlan = new LayerPlan_js_1.LayerPlan(this, {
|
|
465
518
|
type: "subscription",
|
|
519
|
+
parentLayerPlan: this.rootLayerPlan,
|
|
466
520
|
});
|
|
467
|
-
const $__item = (0, withGlobalLayerPlan_js_1.withGlobalLayerPlan)(subscriptionEventLayerPlan, exports.POLYMORPHIC_ROOT_PATHS, () => new index_js_1.__ItemStep(subscribeStep));
|
|
521
|
+
const $__item = (0, withGlobalLayerPlan_js_1.withGlobalLayerPlan)(subscriptionEventLayerPlan, exports.POLYMORPHIC_ROOT_PATHS, planningPath, () => new index_js_1.__ItemStep(subscribeStep));
|
|
468
522
|
subscriptionEventLayerPlan.setRootStep($__item);
|
|
469
|
-
|
|
470
|
-
? (0, withGlobalLayerPlan_js_1.withGlobalLayerPlan)(subscriptionEventLayerPlan, exports.POLYMORPHIC_ROOT_PATHS, subscribeStep.itemPlan, subscribeStep, $__item)
|
|
523
|
+
const streamItemPlan = (0, utils_js_1.hasItemPlan)(subscribeStep)
|
|
524
|
+
? (0, withGlobalLayerPlan_js_1.withGlobalLayerPlan)(subscriptionEventLayerPlan, exports.POLYMORPHIC_ROOT_PATHS, planningPath, subscribeStep.itemPlan, subscribeStep, $__item)
|
|
471
525
|
: $__item;
|
|
472
|
-
// WE MUST RE-FETCH STEPS AFTER DEDUPLICATION!
|
|
473
|
-
this.deduplicateSteps();
|
|
474
|
-
streamItemPlan = this.stepTracker.getStepById(streamItemPlan.id);
|
|
475
526
|
const outputPlan = new OutputPlan_js_1.OutputPlan(subscriptionEventLayerPlan, this.rootValueStep, { mode: "root", typeName: rootType.name }, locationDetails);
|
|
476
527
|
this.rootOutputPlan = outputPlan;
|
|
477
|
-
this.
|
|
528
|
+
this.queueNextLayer(this.planSelectionSet, {
|
|
529
|
+
outputPlan,
|
|
530
|
+
path: [],
|
|
531
|
+
planningPath,
|
|
532
|
+
polymorphicPaths: exports.POLYMORPHIC_ROOT_PATHS,
|
|
533
|
+
parentStep: streamItemPlan,
|
|
534
|
+
positionType: rootType,
|
|
535
|
+
layerPlan: subscriptionEventLayerPlan,
|
|
536
|
+
selections: selectionSet.selections,
|
|
537
|
+
resolverEmulation: false,
|
|
538
|
+
});
|
|
539
|
+
this.planPending();
|
|
478
540
|
}
|
|
479
541
|
else {
|
|
480
|
-
const subscribeStep = (0, withGlobalLayerPlan_js_1.withGlobalLayerPlan)(this.rootLayerPlan, exports.POLYMORPHIC_ROOT_PATHS, () => {
|
|
481
|
-
const $args = (0, index_js_1.object)(
|
|
482
|
-
memo[arg.name.value] = trackedArguments.get(arg.name.value);
|
|
483
|
-
return memo;
|
|
484
|
-
}, Object.create(null)) ?? Object.create(null));
|
|
542
|
+
const subscribeStep = (0, withGlobalLayerPlan_js_1.withGlobalLayerPlan)(this.rootLayerPlan, exports.POLYMORPHIC_ROOT_PATHS, planningPath, () => {
|
|
543
|
+
const $args = (0, index_js_1.object)(trackedArguments);
|
|
485
544
|
const rawResolver = fieldSpec.resolve;
|
|
486
545
|
const rawSubscriber = fieldSpec.subscribe;
|
|
487
546
|
return (0, graphqlResolver_js_1.graphqlResolver)(rawResolver, rawSubscriber, this.trackedRootValueStep, $args, {
|
|
547
|
+
...this.resolveInfoOperationBase,
|
|
488
548
|
fieldName,
|
|
489
549
|
fieldNodes: fields,
|
|
490
|
-
fragments: this.fragments,
|
|
491
|
-
operation: this.operation,
|
|
492
550
|
parentType: this.subscriptionType,
|
|
493
551
|
returnType: fieldSpec.type,
|
|
494
|
-
schema: this.schema,
|
|
495
552
|
// @ts-ignore
|
|
496
553
|
path: {
|
|
497
554
|
typename: this.subscriptionType.name,
|
|
@@ -503,47 +560,81 @@ class OperationPlan {
|
|
|
503
560
|
subscribeStep._stepOptions.stream = {};
|
|
504
561
|
subscribeStep._stepOptions.walkIterable = true;
|
|
505
562
|
this.rootLayerPlan.setRootStep(subscribeStep);
|
|
506
|
-
const subscriptionEventLayerPlan = new LayerPlan_js_1.LayerPlan(this,
|
|
563
|
+
const subscriptionEventLayerPlan = new LayerPlan_js_1.LayerPlan(this, {
|
|
507
564
|
type: "subscription",
|
|
565
|
+
parentLayerPlan: this.rootLayerPlan,
|
|
508
566
|
});
|
|
509
|
-
const $__item = (0, withGlobalLayerPlan_js_1.withGlobalLayerPlan)(subscriptionEventLayerPlan, exports.POLYMORPHIC_ROOT_PATHS, () => new index_js_1.__ItemStep(subscribeStep));
|
|
567
|
+
const $__item = (0, withGlobalLayerPlan_js_1.withGlobalLayerPlan)(subscriptionEventLayerPlan, exports.POLYMORPHIC_ROOT_PATHS, planningPath, () => new index_js_1.__ItemStep(subscribeStep));
|
|
510
568
|
subscriptionEventLayerPlan.setRootStep($__item);
|
|
511
|
-
|
|
512
|
-
? (0, withGlobalLayerPlan_js_1.withGlobalLayerPlan)(subscriptionEventLayerPlan, exports.POLYMORPHIC_ROOT_PATHS, subscribeStep.itemPlan, subscribeStep, $__item)
|
|
569
|
+
const streamItemPlan = (0, utils_js_1.hasItemPlan)(subscribeStep)
|
|
570
|
+
? (0, withGlobalLayerPlan_js_1.withGlobalLayerPlan)(subscriptionEventLayerPlan, exports.POLYMORPHIC_ROOT_PATHS, planningPath, subscribeStep.itemPlan, subscribeStep, $__item)
|
|
513
571
|
: $__item;
|
|
514
|
-
// WE MUST RE-FETCH STEPS AFTER DEDUPLICATION!
|
|
515
|
-
this.deduplicateSteps();
|
|
516
|
-
streamItemPlan = this.stepTracker.getStepById(streamItemPlan.id);
|
|
517
572
|
const outputPlan = new OutputPlan_js_1.OutputPlan(subscriptionEventLayerPlan, this.rootValueStep, { mode: "root", typeName: rootType.name }, locationDetails);
|
|
518
573
|
this.rootOutputPlan = outputPlan;
|
|
519
|
-
this.
|
|
574
|
+
this.queueNextLayer(this.planSelectionSet, {
|
|
575
|
+
outputPlan,
|
|
576
|
+
path: [],
|
|
577
|
+
planningPath,
|
|
578
|
+
polymorphicPaths: exports.POLYMORPHIC_ROOT_PATHS,
|
|
579
|
+
parentStep: streamItemPlan,
|
|
580
|
+
positionType: rootType,
|
|
581
|
+
layerPlan: subscriptionEventLayerPlan,
|
|
582
|
+
selections: selectionSet.selections,
|
|
583
|
+
resolverEmulation: true,
|
|
584
|
+
});
|
|
585
|
+
this.planPending();
|
|
520
586
|
}
|
|
521
587
|
if (this.loc !== null)
|
|
522
588
|
this.loc.pop();
|
|
523
589
|
}
|
|
590
|
+
getCombinedLayerPlanForLayerPlans(setOfParentLayerPlans) {
|
|
591
|
+
const parentLayerPlans = [...setOfParentLayerPlans];
|
|
592
|
+
// See if one already exists with the same layer plans in the same order
|
|
593
|
+
for (const lp of this.stepTracker.layerPlans) {
|
|
594
|
+
if (lp?.reason.type === "combined" &&
|
|
595
|
+
(0, utils_js_1.arraysMatch)(parentLayerPlans, lp.reason.parentLayerPlans)) {
|
|
596
|
+
return lp;
|
|
597
|
+
}
|
|
598
|
+
}
|
|
599
|
+
return new LayerPlan_js_1.LayerPlan(this, {
|
|
600
|
+
type: "combined",
|
|
601
|
+
parentLayerPlans,
|
|
602
|
+
});
|
|
603
|
+
}
|
|
524
604
|
/**
|
|
525
605
|
* Gets the item plan for a given parent list plan - this ensures we only
|
|
526
606
|
* create one item plan per parent plan.
|
|
527
607
|
*/
|
|
528
|
-
itemStepForListStep(parentLayerPlan, listStep, depth, stream) {
|
|
529
|
-
const
|
|
608
|
+
itemStepForListStep(parentLayerPlan, planningPath, listStep, depth, stream) {
|
|
609
|
+
const itemStepIdByListStepId = (this.itemStepIdByListStepIdByParentLayerPlanId[parentLayerPlan.id] ??=
|
|
610
|
+
Object.create(null));
|
|
611
|
+
const itemStepId = itemStepIdByListStepId[listStep.id];
|
|
530
612
|
if (itemStepId !== undefined) {
|
|
531
|
-
|
|
613
|
+
const itemStep = this.stepTracker.getStepById(itemStepId);
|
|
614
|
+
if (listStep.polymorphicPaths !== null &&
|
|
615
|
+
itemStep.polymorphicPaths !== null) {
|
|
616
|
+
for (const p of listStep.polymorphicPaths) {
|
|
617
|
+
itemStep.polymorphicPaths.add(p);
|
|
618
|
+
}
|
|
619
|
+
}
|
|
620
|
+
return itemStep;
|
|
532
621
|
}
|
|
533
622
|
// Create a new LayerPlan for this list item
|
|
534
|
-
const layerPlan = new LayerPlan_js_1.LayerPlan(this,
|
|
623
|
+
const layerPlan = new LayerPlan_js_1.LayerPlan(this, {
|
|
535
624
|
type: "listItem",
|
|
625
|
+
parentLayerPlan,
|
|
536
626
|
parentStep: listStep,
|
|
537
627
|
stream,
|
|
538
628
|
});
|
|
539
|
-
const
|
|
540
|
-
layerPlan.setRootStep(
|
|
541
|
-
|
|
542
|
-
return
|
|
543
|
-
}
|
|
544
|
-
processGroupedFieldSet(
|
|
545
|
-
|
|
546
|
-
|
|
629
|
+
const itemStep = (0, withGlobalLayerPlan_js_1.withGlobalLayerPlan)(layerPlan, listStep.polymorphicPaths, planningPath, () => new index_js_1.__ItemStep(listStep, depth));
|
|
630
|
+
layerPlan.setRootStep(itemStep);
|
|
631
|
+
itemStepIdByListStepId[listStep.id] = itemStep.id;
|
|
632
|
+
return itemStep;
|
|
633
|
+
}
|
|
634
|
+
*processGroupedFieldSet(details) {
|
|
635
|
+
const { outputPlan, path, planningPath, polymorphicPaths, parentStep, positionType: objectType,
|
|
636
|
+
// layerPlan,
|
|
637
|
+
objectTypeFields, isMutation, groupedFieldSet, } = details;
|
|
547
638
|
// `__typename` shouldn't bump the mutation index since it has no side effects.
|
|
548
639
|
let mutationIndex = -1;
|
|
549
640
|
const $sideEffect = outputPlan.layerPlan.latestSideEffectStep;
|
|
@@ -600,13 +691,12 @@ class OperationPlan {
|
|
|
600
691
|
const resolvedResolver = objectField.resolve;
|
|
601
692
|
const subscriber = objectField.subscribe;
|
|
602
693
|
const usesDefaultResolver = resolvedResolver == null || resolvedResolver === defaultFieldResolver;
|
|
603
|
-
const isPolymorphic = isUnionType(namedReturnType) || isInterfaceType(namedReturnType);
|
|
604
694
|
// We should use a resolver if:
|
|
605
695
|
// 1. they give us a non-default resolver
|
|
606
|
-
// 2. we're emulating resolvers
|
|
696
|
+
// 2. we're emulating resolvers
|
|
607
697
|
const resolver = resolvedResolver && !usesDefaultResolver
|
|
608
698
|
? resolvedResolver
|
|
609
|
-
: resolverEmulation
|
|
699
|
+
: resolverEmulation
|
|
610
700
|
? defaultFieldResolver
|
|
611
701
|
: null;
|
|
612
702
|
// Apply a default plan to fields that do not have a plan nor a resolver.
|
|
@@ -683,16 +773,18 @@ class OperationPlan {
|
|
|
683
773
|
let step;
|
|
684
774
|
let haltTree = false;
|
|
685
775
|
const fieldLayerPlan = isMutation
|
|
686
|
-
? new LayerPlan_js_1.LayerPlan(this,
|
|
776
|
+
? new LayerPlan_js_1.LayerPlan(this, {
|
|
687
777
|
type: "mutationField",
|
|
778
|
+
parentLayerPlan: outputPlan.layerPlan,
|
|
688
779
|
mutationIndex: ++mutationIndex,
|
|
689
780
|
})
|
|
690
781
|
: outputPlan.layerPlan;
|
|
691
782
|
const objectFieldArgs = objectField.args;
|
|
783
|
+
const fieldPath = [...path, responseKey];
|
|
784
|
+
const fieldPlanningPath = planningPath + responseKey;
|
|
692
785
|
const trackedArguments = objectFieldArgs.length > 0
|
|
693
|
-
? (0, withGlobalLayerPlan_js_1.withGlobalLayerPlan)(this.rootLayerPlan, exports.POLYMORPHIC_ROOT_PATHS, this.getTrackedArguments, this, objectFieldArgs, field)
|
|
786
|
+
? (0, withGlobalLayerPlan_js_1.withGlobalLayerPlan)(this.rootLayerPlan, exports.POLYMORPHIC_ROOT_PATHS, fieldPlanningPath, this.getTrackedArguments, this, objectFieldArgs, field)
|
|
694
787
|
: NO_ARGS;
|
|
695
|
-
const fieldPath = [...path, responseKey];
|
|
696
788
|
let streamDetails = null;
|
|
697
789
|
const isList = isListType(getNullableType(fieldType));
|
|
698
790
|
if (isList) {
|
|
@@ -735,7 +827,20 @@ class OperationPlan {
|
|
|
735
827
|
}
|
|
736
828
|
}
|
|
737
829
|
if (typeof planResolver === "function") {
|
|
738
|
-
({ step, haltTree } = this.
|
|
830
|
+
({ step, haltTree } = yield this.batchPlanField({
|
|
831
|
+
typeName: objectType.name,
|
|
832
|
+
fieldName,
|
|
833
|
+
layerPlan: fieldLayerPlan,
|
|
834
|
+
path: fieldPath,
|
|
835
|
+
polymorphicPaths,
|
|
836
|
+
planningPath: fieldPlanningPath,
|
|
837
|
+
planResolver,
|
|
838
|
+
applyAfterMode: "plan",
|
|
839
|
+
rawParentStep: parentStep,
|
|
840
|
+
field: objectField,
|
|
841
|
+
trackedArguments,
|
|
842
|
+
streamDetails: isList ? (streamDetails ?? false) : null,
|
|
843
|
+
}));
|
|
739
844
|
}
|
|
740
845
|
else {
|
|
741
846
|
// No plan resolver (or plan resolver fallback) so there must be a
|
|
@@ -749,25 +854,21 @@ class OperationPlan {
|
|
|
749
854
|
step = parentStep;
|
|
750
855
|
}
|
|
751
856
|
if (resolver !== null) {
|
|
752
|
-
step = (0, withGlobalLayerPlan_js_1.withGlobalLayerPlan)(fieldLayerPlan, polymorphicPaths, () => {
|
|
753
|
-
const $args = (0, index_js_1.object)(
|
|
754
|
-
memo[arg.name.value] = trackedArguments.get(arg.name.value);
|
|
755
|
-
return memo;
|
|
756
|
-
}, Object.create(null)) ?? Object.create(null));
|
|
857
|
+
step = (0, withGlobalLayerPlan_js_1.withGlobalLayerPlan)(fieldLayerPlan, polymorphicPaths, fieldPlanningPath, () => {
|
|
858
|
+
const $args = (0, index_js_1.object)(trackedArguments);
|
|
757
859
|
return (0, graphqlResolver_js_1.graphqlResolver)(resolver, subscriber, step, $args, {
|
|
860
|
+
...this.resolveInfoOperationBase,
|
|
758
861
|
fieldName,
|
|
759
862
|
fieldNodes,
|
|
760
|
-
fragments: this.fragments,
|
|
761
|
-
operation: this.operation,
|
|
762
863
|
parentType: objectType,
|
|
763
864
|
returnType: fieldType,
|
|
764
|
-
schema: this.schema,
|
|
765
865
|
});
|
|
766
866
|
});
|
|
767
867
|
}
|
|
768
868
|
// May have changed due to deduplicate
|
|
769
869
|
step = this.stepTracker.getStepById(step.id);
|
|
770
870
|
if (haltTree) {
|
|
871
|
+
// Very similar to this.handlePlanningError. Should probably use it in future.
|
|
771
872
|
const isNonNull = isNonNullType(fieldType);
|
|
772
873
|
outputPlan.addChild(objectType, responseKey, {
|
|
773
874
|
type: "outputPlan",
|
|
@@ -777,11 +878,31 @@ class OperationPlan {
|
|
|
777
878
|
});
|
|
778
879
|
}
|
|
779
880
|
else {
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
881
|
+
if (index_js_1.isDev && polymorphicPaths) {
|
|
882
|
+
const invalid = [...polymorphicPaths].filter((p) => !stepIsValidInPolyPath(step, p));
|
|
883
|
+
if (invalid.length > 0) {
|
|
884
|
+
throw new Error(`${objectType}.${fieldName} (as ${responseKey}) returned ${step}, but that's not valid in ${invalid.length} out of ${polymorphicPaths.size} of the expected polymorphic paths. Invalid paths: ${invalid}`);
|
|
885
|
+
}
|
|
886
|
+
}
|
|
887
|
+
outputPlan.expectChild(objectType, responseKey);
|
|
888
|
+
this.queueNextLayer(this.planFieldReturnType, {
|
|
889
|
+
outputPlan,
|
|
890
|
+
path: fieldPath,
|
|
891
|
+
planningPath: fieldPlanningPath,
|
|
892
|
+
polymorphicPaths,
|
|
893
|
+
parentStep: step,
|
|
894
|
+
positionType: fieldType,
|
|
895
|
+
layerPlan: fieldLayerPlan,
|
|
896
|
+
// If one field has a selection set, they all have a selection set (guaranteed by validation).
|
|
897
|
+
selections: field.selectionSet != null
|
|
898
|
+
? fieldNodes.flatMap((n) => n.selectionSet.selections)
|
|
899
|
+
: undefined,
|
|
900
|
+
parentObjectType: objectType,
|
|
901
|
+
responseKey,
|
|
902
|
+
locationDetails,
|
|
903
|
+
resolverEmulation,
|
|
904
|
+
streamDetails,
|
|
905
|
+
});
|
|
785
906
|
}
|
|
786
907
|
}
|
|
787
908
|
finally {
|
|
@@ -790,8 +911,9 @@ class OperationPlan {
|
|
|
790
911
|
}
|
|
791
912
|
if (groupedFieldSet.deferred !== undefined) {
|
|
792
913
|
for (const deferred of groupedFieldSet.deferred) {
|
|
793
|
-
const deferredLayerPlan = new LayerPlan_js_1.LayerPlan(this,
|
|
914
|
+
const deferredLayerPlan = new LayerPlan_js_1.LayerPlan(this, {
|
|
794
915
|
type: "defer",
|
|
916
|
+
parentLayerPlan: outputPlan.layerPlan,
|
|
795
917
|
label: deferred.label,
|
|
796
918
|
});
|
|
797
919
|
const deferredOutputPlan = new OutputPlan_js_1.OutputPlan(deferredLayerPlan, outputPlan.rootStep, {
|
|
@@ -805,7 +927,18 @@ class OperationPlan {
|
|
|
805
927
|
const $sideEffect = deferredOutputPlan.layerPlan.latestSideEffectStep;
|
|
806
928
|
try {
|
|
807
929
|
outputPlan.deferredOutputPlans.push(deferredOutputPlan);
|
|
808
|
-
this.processGroupedFieldSet
|
|
930
|
+
this.queueNextLayer(this.processGroupedFieldSet, {
|
|
931
|
+
outputPlan: deferredOutputPlan,
|
|
932
|
+
path,
|
|
933
|
+
planningPath: planningPath + "#",
|
|
934
|
+
polymorphicPaths,
|
|
935
|
+
parentStep,
|
|
936
|
+
positionType: objectType,
|
|
937
|
+
layerPlan: deferredLayerPlan,
|
|
938
|
+
objectTypeFields,
|
|
939
|
+
isMutation,
|
|
940
|
+
groupedFieldSet: deferred,
|
|
941
|
+
});
|
|
809
942
|
}
|
|
810
943
|
finally {
|
|
811
944
|
deferredOutputPlan.layerPlan.latestSideEffectStep = $sideEffect;
|
|
@@ -822,33 +955,432 @@ class OperationPlan {
|
|
|
822
955
|
* @param selections - The GraphQL selections (fields, fragment spreads, inline fragments) to evaluate
|
|
823
956
|
* @param isMutation - If true this selection set should be executed serially rather than in parallel (each field gets its own LayerPlan)
|
|
824
957
|
*/
|
|
825
|
-
planSelectionSet(
|
|
958
|
+
planSelectionSet(details) {
|
|
959
|
+
const { outputPlan, path, planningPath, polymorphicPaths, parentStep, positionType: objectType, layerPlan, selections, resolverEmulation, isMutation = false, } = details;
|
|
826
960
|
if (this.loc !== null) {
|
|
827
|
-
this.loc.push(`planSelectionSet(${objectType.name} @ ${outputPlan.layerPlan.id} @ ${path.join(".")} @ ${
|
|
961
|
+
this.loc.push(`planSelectionSet(${objectType.name} @ ${outputPlan.layerPlan.id} @ ${path.join(".")} @ ${polymorphicPaths ? [...polymorphicPaths] : ""})`);
|
|
828
962
|
}
|
|
829
963
|
if (index_js_1.isDev) {
|
|
830
964
|
assertObjectType(objectType);
|
|
965
|
+
if (outputPlan.layerPlan !== layerPlan) {
|
|
966
|
+
throw new Error(`GrafastInternalError<3ea1a3dd-1e11-4eb7-a31b-e125996d7eb4>: expected ${outputPlan} to have layer plan ${layerPlan}`);
|
|
967
|
+
}
|
|
831
968
|
}
|
|
832
|
-
const groupedFieldSet = (0, withGlobalLayerPlan_js_1.withGlobalLayerPlan)(
|
|
969
|
+
const groupedFieldSet = (0, withGlobalLayerPlan_js_1.withGlobalLayerPlan)(layerPlan, polymorphicPaths, planningPath, graphqlCollectFields_js_1.graphqlCollectFields, null, this, parentStep.id, objectType, selections, (0, graphqlCollectFields_js_1.newSelectionSetDigest)(resolverEmulation), isMutation);
|
|
833
970
|
const objectTypeFields = objectType.getFields();
|
|
834
|
-
this.processGroupedFieldSet
|
|
971
|
+
this.queueNextLayer(this.processGroupedFieldSet, {
|
|
972
|
+
outputPlan,
|
|
973
|
+
path,
|
|
974
|
+
planningPath: planningPath + ">",
|
|
975
|
+
polymorphicPaths,
|
|
976
|
+
parentStep,
|
|
977
|
+
positionType: objectType,
|
|
978
|
+
layerPlan,
|
|
979
|
+
objectTypeFields,
|
|
980
|
+
isMutation,
|
|
981
|
+
groupedFieldSet,
|
|
982
|
+
});
|
|
835
983
|
if (this.loc !== null)
|
|
836
984
|
this.loc.pop();
|
|
837
985
|
}
|
|
986
|
+
queueNextLayer(method, details) {
|
|
987
|
+
const { planningPath } = details;
|
|
988
|
+
if (this.frozenPlanningPaths?.has(planningPath)) {
|
|
989
|
+
throw new Error(`GrafastInternalError<93c64f55-4f3f-442f-a17b-391e28bd3629>: Already processed planning path ${planningPath}`);
|
|
990
|
+
}
|
|
991
|
+
let list = this.planningQueueByPlanningPath.get(planningPath);
|
|
992
|
+
if (!list) {
|
|
993
|
+
list = [];
|
|
994
|
+
this.planningQueueByPlanningPath.set(planningPath, list);
|
|
995
|
+
}
|
|
996
|
+
const tuple = [
|
|
997
|
+
method,
|
|
998
|
+
details,
|
|
999
|
+
this.loc ? [...this.loc] : null,
|
|
1000
|
+
details.layerPlan,
|
|
1001
|
+
details.layerPlan.latestSideEffectStep,
|
|
1002
|
+
];
|
|
1003
|
+
this.planningQueue.push(tuple);
|
|
1004
|
+
list.push(tuple);
|
|
1005
|
+
}
|
|
1006
|
+
planPending() {
|
|
1007
|
+
for (let depth = 0; depth <= this.maxPlanningDepth; depth++) {
|
|
1008
|
+
// Process the next batch
|
|
1009
|
+
const l = this.planningQueue.length;
|
|
1010
|
+
if (l === 0)
|
|
1011
|
+
break;
|
|
1012
|
+
if (depth === this.maxPlanningDepth) {
|
|
1013
|
+
throw new Error(`Query is too complex, Grafast refuses to continue processing at planning depth ${this.maxPlanningDepth}. You can configure this through \`preset.grafast.maxPlanningDepth\``);
|
|
1014
|
+
}
|
|
1015
|
+
// NOTE: `batch` and `todo` are different views of the same information,
|
|
1016
|
+
// specifically: `batch` is stored in the order in which the calls were
|
|
1017
|
+
// made (critical for ensuring the OutputPlans output fields in the
|
|
1018
|
+
// correct order); whereas `todo` is the result of grouping `batch` into
|
|
1019
|
+
// groups where the planning paths match.
|
|
1020
|
+
const batch = this.planningQueue.slice(0, l);
|
|
1021
|
+
const todo = [...this.planningQueueByPlanningPath.entries()];
|
|
1022
|
+
// Now clear the stores ready to start collecting the next lot.
|
|
1023
|
+
this.planningQueue.length = 0;
|
|
1024
|
+
this.planningQueueByPlanningPath.clear();
|
|
1025
|
+
// First, do a planning-path-aware deduplicate
|
|
1026
|
+
this.deduplicateSteps();
|
|
1027
|
+
// Update the step references (and freeze the paths)
|
|
1028
|
+
for (const [planningPath, batch] of todo) {
|
|
1029
|
+
if (this.frozenPlanningPaths?.has(planningPath)) {
|
|
1030
|
+
throw new Error(`GrafastInternalError<dd30288e-9375-4025-91a6-66b64e74cf74>: planning path already processed - ${planningPath}`);
|
|
1031
|
+
}
|
|
1032
|
+
this.frozenPlanningPaths?.add(planningPath);
|
|
1033
|
+
for (const entry of batch) {
|
|
1034
|
+
const step = entry[1].parentStep;
|
|
1035
|
+
const actualStep = this.stepTracker.getStepById(step.id);
|
|
1036
|
+
if (actualStep !== step) {
|
|
1037
|
+
entry[1].parentStep = actualStep;
|
|
1038
|
+
}
|
|
1039
|
+
}
|
|
1040
|
+
}
|
|
1041
|
+
// Then, apply the per-method batch tweaks (such as resolving
|
|
1042
|
+
// polymorphism)
|
|
1043
|
+
this.mutateTodos(todo);
|
|
1044
|
+
const DONE = Symbol("done");
|
|
1045
|
+
const gennies = [];
|
|
1046
|
+
// Finally plan this layer
|
|
1047
|
+
for (const [fn, rawDetails, loc, originalLayerPlan, layerPlanLatestSideEffect,] of batch) {
|
|
1048
|
+
const details = rawDetails;
|
|
1049
|
+
this.withLocLpSE(loc, originalLayerPlan, layerPlanLatestSideEffect, () => {
|
|
1050
|
+
/** Still just genny from the block */
|
|
1051
|
+
const genny = fn.call(this, details);
|
|
1052
|
+
if (genny != null) {
|
|
1053
|
+
gennies.push({
|
|
1054
|
+
genny,
|
|
1055
|
+
loc,
|
|
1056
|
+
layerPlan: details.layerPlan,
|
|
1057
|
+
layerPlanLatestSideEffect: details.layerPlan.latestSideEffectStep,
|
|
1058
|
+
result: undefined,
|
|
1059
|
+
});
|
|
1060
|
+
}
|
|
1061
|
+
});
|
|
1062
|
+
}
|
|
1063
|
+
// And go through all the generators
|
|
1064
|
+
while (gennies.length > 0) {
|
|
1065
|
+
const cbs = [];
|
|
1066
|
+
for (const spec of gennies) {
|
|
1067
|
+
const { genny, loc, layerPlan, layerPlanLatestSideEffect, result } = spec;
|
|
1068
|
+
this.withLocLpSE(loc, layerPlan, layerPlanLatestSideEffect, () => {
|
|
1069
|
+
const r = genny.next(result);
|
|
1070
|
+
if (r.done) {
|
|
1071
|
+
spec.result = DONE;
|
|
1072
|
+
}
|
|
1073
|
+
else {
|
|
1074
|
+
cbs.push({ spec, cb: r.value });
|
|
1075
|
+
}
|
|
1076
|
+
});
|
|
1077
|
+
}
|
|
1078
|
+
for (const { spec, cb } of cbs) {
|
|
1079
|
+
spec.result = cb();
|
|
1080
|
+
}
|
|
1081
|
+
// Remove the generators that are done.
|
|
1082
|
+
for (let i = gennies.length - 1; i >= 0; i--) {
|
|
1083
|
+
if (gennies[i].result === DONE) {
|
|
1084
|
+
gennies.splice(i, 1);
|
|
1085
|
+
}
|
|
1086
|
+
}
|
|
1087
|
+
}
|
|
1088
|
+
}
|
|
1089
|
+
// A final deduplicate
|
|
1090
|
+
this.deduplicateSteps();
|
|
1091
|
+
}
|
|
1092
|
+
withLocLpSE(loc, layerPlan, layerPlanLatestSideEffect, cb) {
|
|
1093
|
+
const $sideEffect = layerPlan.latestSideEffectStep;
|
|
1094
|
+
layerPlan.latestSideEffectStep = layerPlanLatestSideEffect;
|
|
1095
|
+
try {
|
|
1096
|
+
const prevLoc = this.loc;
|
|
1097
|
+
this.loc = loc;
|
|
1098
|
+
cb();
|
|
1099
|
+
this.loc = prevLoc;
|
|
1100
|
+
}
|
|
1101
|
+
finally {
|
|
1102
|
+
layerPlan.latestSideEffectStep = $sideEffect;
|
|
1103
|
+
}
|
|
1104
|
+
}
|
|
1105
|
+
mutateTodos(todo) {
|
|
1106
|
+
for (const [_planningPath, batch] of todo) {
|
|
1107
|
+
const polymorphicResolveTypeEntriesByPolyType = new Map();
|
|
1108
|
+
const planFieldReturnTypeEntriesByStepByLayerPlan = new Map();
|
|
1109
|
+
for (const entry of batch) {
|
|
1110
|
+
const [method, rawArgs] = entry;
|
|
1111
|
+
// Tidy up after dedupe
|
|
1112
|
+
rawArgs.parentStep = this.stepTracker.getStepById(rawArgs.parentStep.id);
|
|
1113
|
+
if (method === this.polymorphicResolveType) {
|
|
1114
|
+
const args = rawArgs;
|
|
1115
|
+
const polyType = args.positionType;
|
|
1116
|
+
if (!isUnionType(polyType) && !isInterfaceType(polyType)) {
|
|
1117
|
+
throw new Error(`GrafastInternalError<b0a276d0-134f-4a26-9c33-00af5ead38e6>: expected ${polyType} to be an interface or union type`);
|
|
1118
|
+
}
|
|
1119
|
+
let list = polymorphicResolveTypeEntriesByPolyType.get(polyType);
|
|
1120
|
+
if (!list) {
|
|
1121
|
+
list = [];
|
|
1122
|
+
polymorphicResolveTypeEntriesByPolyType.set(polyType, list);
|
|
1123
|
+
}
|
|
1124
|
+
list.push(args);
|
|
1125
|
+
}
|
|
1126
|
+
else if (method == this.polymorphicPlanObjectType) {
|
|
1127
|
+
const args = rawArgs;
|
|
1128
|
+
const lp = args.layerPlan;
|
|
1129
|
+
let planFieldReturnTypeEntriesByStep = planFieldReturnTypeEntriesByStepByLayerPlan.get(lp);
|
|
1130
|
+
if (!planFieldReturnTypeEntriesByStep) {
|
|
1131
|
+
planFieldReturnTypeEntriesByStep = new Map();
|
|
1132
|
+
planFieldReturnTypeEntriesByStepByLayerPlan.set(lp, planFieldReturnTypeEntriesByStep);
|
|
1133
|
+
}
|
|
1134
|
+
const step = args.parentStep;
|
|
1135
|
+
let list = planFieldReturnTypeEntriesByStep.get(step);
|
|
1136
|
+
if (list) {
|
|
1137
|
+
list.push(args);
|
|
1138
|
+
}
|
|
1139
|
+
else {
|
|
1140
|
+
list = [args];
|
|
1141
|
+
planFieldReturnTypeEntriesByStep.set(step, list);
|
|
1142
|
+
}
|
|
1143
|
+
}
|
|
1144
|
+
}
|
|
1145
|
+
// Handle calls to `polymorphicResolveType` by performing the combined
|
|
1146
|
+
// layer plan / `planType` shuffle.
|
|
1147
|
+
for (const [graphqlType,
|
|
1148
|
+
// A list of all the `details` argument objects capture for this type
|
|
1149
|
+
detailsRecordList,] of polymorphicResolveTypeEntriesByPolyType) {
|
|
1150
|
+
const firstDetailsRecord = detailsRecordList[0];
|
|
1151
|
+
// All of these properties should be in common
|
|
1152
|
+
// const path = firstDetailsRecord.path;
|
|
1153
|
+
const planningPath = firstDetailsRecord.planningPath;
|
|
1154
|
+
const allPossibleObjectTypes = firstDetailsRecord.allPossibleObjectTypes;
|
|
1155
|
+
// The existence of this is common (i.e. either all have it set, or all
|
|
1156
|
+
// have it null, but the actual contents may differ)
|
|
1157
|
+
const polymorphicPaths = firstDetailsRecord.polymorphicPaths;
|
|
1158
|
+
const combinedPolymorphicPaths = polymorphicPaths
|
|
1159
|
+
? new Set( /* Populated below */)
|
|
1160
|
+
: null;
|
|
1161
|
+
let commonLayerPlan;
|
|
1162
|
+
let $original;
|
|
1163
|
+
let commonStep;
|
|
1164
|
+
const steps = new Set(detailsRecordList.map((t) => t.parentStep));
|
|
1165
|
+
if (steps.size > 1) {
|
|
1166
|
+
$original = null;
|
|
1167
|
+
// Make combined
|
|
1168
|
+
const layerPlans = new Set(detailsRecordList.map((t) => t.layerPlan));
|
|
1169
|
+
const combinedLayerPlan = this.getCombinedLayerPlanForLayerPlans(layerPlans);
|
|
1170
|
+
const toCombine = [];
|
|
1171
|
+
let isUnary = true;
|
|
1172
|
+
for (const detailsRecord of detailsRecordList) {
|
|
1173
|
+
const parentStep = detailsRecord.parentStep;
|
|
1174
|
+
const polymorphicPaths = detailsRecord.polymorphicPaths;
|
|
1175
|
+
const layerPlan = detailsRecord.layerPlan;
|
|
1176
|
+
if (!parentStep._isUnary) {
|
|
1177
|
+
isUnary = false;
|
|
1178
|
+
}
|
|
1179
|
+
if (polymorphicPaths) {
|
|
1180
|
+
for (const path of polymorphicPaths) {
|
|
1181
|
+
combinedPolymorphicPaths.add(path);
|
|
1182
|
+
}
|
|
1183
|
+
}
|
|
1184
|
+
const $data = graphqlType.extensions?.grafast?.toSpecifier
|
|
1185
|
+
? (0, withGlobalLayerPlan_js_1.withGlobalLayerPlan)(layerPlan, polymorphicPaths, planningPath, graphqlType.extensions.grafast.toSpecifier, graphqlType.extensions.grafast, parentStep)
|
|
1186
|
+
: (0, step_js_1.stepHasToSpecifier)(parentStep)
|
|
1187
|
+
? (0, withGlobalLayerPlan_js_1.withGlobalLayerPlan)(layerPlan, polymorphicPaths, planningPath, parentStep.toSpecifier, parentStep)
|
|
1188
|
+
: (0, step_js_1.stepHasToRecord)(parentStep)
|
|
1189
|
+
? (0, withGlobalLayerPlan_js_1.withGlobalLayerPlan)(layerPlan, polymorphicPaths, planningPath, parentStep.toRecord, parentStep)
|
|
1190
|
+
: parentStep;
|
|
1191
|
+
toCombine.push({ step: $data, layerPlan });
|
|
1192
|
+
}
|
|
1193
|
+
// Create a __ValueStep in the new combined layer plan that
|
|
1194
|
+
// represents all of these values
|
|
1195
|
+
const $combined = (0, withGlobalLayerPlan_js_1.withGlobalLayerPlan)(combinedLayerPlan, combinedPolymorphicPaths, planningPath, newValueStepCallback, null, false);
|
|
1196
|
+
if (!isUnary) {
|
|
1197
|
+
$combined._isUnary = false;
|
|
1198
|
+
}
|
|
1199
|
+
// Tell it to populate the __ValuePlan $combined with the combination
|
|
1200
|
+
// of all the values from toCombine.
|
|
1201
|
+
combinedLayerPlan.addCombo(toCombine, $combined);
|
|
1202
|
+
commonLayerPlan = combinedLayerPlan;
|
|
1203
|
+
commonStep = $combined;
|
|
1204
|
+
}
|
|
1205
|
+
else {
|
|
1206
|
+
$original = [...steps][0];
|
|
1207
|
+
const layerPlans = new Set();
|
|
1208
|
+
for (const tuple of detailsRecordList) {
|
|
1209
|
+
layerPlans.add(tuple.layerPlan);
|
|
1210
|
+
}
|
|
1211
|
+
if (layerPlans.size === 1) {
|
|
1212
|
+
commonLayerPlan = [...layerPlans][0];
|
|
1213
|
+
}
|
|
1214
|
+
else {
|
|
1215
|
+
commonLayerPlan =
|
|
1216
|
+
this.getCombinedLayerPlanForLayerPlans(layerPlans);
|
|
1217
|
+
}
|
|
1218
|
+
commonStep = graphqlType.extensions?.grafast?.toSpecifier
|
|
1219
|
+
? (0, withGlobalLayerPlan_js_1.withGlobalLayerPlan)(commonLayerPlan, polymorphicPaths, planningPath, graphqlType.extensions.grafast.toSpecifier, graphqlType.extensions.grafast, $original)
|
|
1220
|
+
: (0, step_js_1.stepHasToSpecifier)($original)
|
|
1221
|
+
? (0, withGlobalLayerPlan_js_1.withGlobalLayerPlan)(commonLayerPlan, polymorphicPaths, planningPath, $original.toSpecifier, $original)
|
|
1222
|
+
: (0, step_js_1.stepHasToRecord)($original)
|
|
1223
|
+
? (0, withGlobalLayerPlan_js_1.withGlobalLayerPlan)(commonLayerPlan, polymorphicPaths, planningPath, $original.toRecord, $original)
|
|
1224
|
+
: $original;
|
|
1225
|
+
for (const detailsRecord of detailsRecordList) {
|
|
1226
|
+
detailsRecord.layerPlan = commonLayerPlan;
|
|
1227
|
+
const polymorphicPaths = detailsRecord.polymorphicPaths;
|
|
1228
|
+
if (polymorphicPaths) {
|
|
1229
|
+
for (const path of polymorphicPaths) {
|
|
1230
|
+
combinedPolymorphicPaths.add(path);
|
|
1231
|
+
}
|
|
1232
|
+
}
|
|
1233
|
+
}
|
|
1234
|
+
}
|
|
1235
|
+
// Call planTypes and plan each of the types?
|
|
1236
|
+
const planType = graphqlType.extensions?.grafast?.planType ?? defaultPlanType;
|
|
1237
|
+
// TODO: revisit this. If planType exists then no need? If resolver emulation then always?
|
|
1238
|
+
const resolverEmulation =
|
|
1239
|
+
// detailsRecordList.some((a) => a.resolverEmulation) && (
|
|
1240
|
+
graphqlType.resolveType != null ||
|
|
1241
|
+
allPossibleObjectTypes.some((t) => t.isTypeOf != null);
|
|
1242
|
+
const info = {
|
|
1243
|
+
abstractType: graphqlType,
|
|
1244
|
+
resolverEmulation,
|
|
1245
|
+
$original,
|
|
1246
|
+
};
|
|
1247
|
+
let polymorphicTypePlanner;
|
|
1248
|
+
try {
|
|
1249
|
+
polymorphicTypePlanner = (0, withGlobalLayerPlan_js_1.withGlobalLayerPlan)(commonLayerPlan, combinedPolymorphicPaths, planningPath, planType, null, commonStep, info);
|
|
1250
|
+
}
|
|
1251
|
+
catch (err) {
|
|
1252
|
+
const $error = this.withRootLayerPlan(() => (0, index_js_1.error)(err));
|
|
1253
|
+
polymorphicTypePlanner = {
|
|
1254
|
+
$__typename: $error,
|
|
1255
|
+
};
|
|
1256
|
+
}
|
|
1257
|
+
const stepForType = new Map();
|
|
1258
|
+
const allTypeNames = allPossibleObjectTypes.map((t) => t.name);
|
|
1259
|
+
const basePaths = [...(combinedPolymorphicPaths ?? [""])];
|
|
1260
|
+
const polymorphicLayerPlan = new LayerPlan_js_1.LayerPlan(this, {
|
|
1261
|
+
type: "polymorphic",
|
|
1262
|
+
parentLayerPlan: commonLayerPlan,
|
|
1263
|
+
polymorphicPaths: new Set(
|
|
1264
|
+
// BUG: this isn't 100% correct, it's possible that this layer
|
|
1265
|
+
// plan might not be used in some of these polymorphic paths (e.g.
|
|
1266
|
+
// if fragment types caused certain fields to not be selected in
|
|
1267
|
+
// certain scenarios). We should instead figure out the concrete
|
|
1268
|
+
// list of polymorphic paths actually seen during planning.
|
|
1269
|
+
allTypeNames.flatMap((t) => basePaths.map((p) => `${p}>${t}`))),
|
|
1270
|
+
typeNames: allTypeNames,
|
|
1271
|
+
parentStep: polymorphicTypePlanner.$__typename,
|
|
1272
|
+
});
|
|
1273
|
+
for (const type of allPossibleObjectTypes) {
|
|
1274
|
+
const polymorphicPaths = new Set(basePaths.map((p) => `${p}>${type.name}`));
|
|
1275
|
+
try {
|
|
1276
|
+
const $stepForType = (polymorphicTypePlanner.planForType
|
|
1277
|
+
? (0, withGlobalLayerPlan_js_1.withGlobalLayerPlan)(polymorphicLayerPlan, polymorphicPaths, planningPath + "?", polymorphicTypePlanner.planForType, polymorphicTypePlanner, type)
|
|
1278
|
+
: type.extensions?.grafast?.planType
|
|
1279
|
+
? (0, withGlobalLayerPlan_js_1.withGlobalLayerPlan)(polymorphicLayerPlan, polymorphicPaths, planningPath + "?", type.extensions.grafast.planType, type.extensions.grafast, commonStep)
|
|
1280
|
+
: commonStep) ??
|
|
1281
|
+
(0, withGlobalLayerPlan_js_1.withGlobalLayerPlan)(polymorphicLayerPlan, polymorphicPaths, planningPath + "?", constant_js_1.constant, null, index_js_1.$$inhibit);
|
|
1282
|
+
stepForType.set(type, $stepForType);
|
|
1283
|
+
if (index_js_1.isDev) {
|
|
1284
|
+
// Check that this plan is compatible with every poly path
|
|
1285
|
+
if ($stepForType.polymorphicPaths === null) {
|
|
1286
|
+
// All good, valid in all paths
|
|
1287
|
+
}
|
|
1288
|
+
else {
|
|
1289
|
+
const missedPaths = [...polymorphicPaths].filter((p) => !stepIsValidInPolyPath($stepForType, p));
|
|
1290
|
+
if (missedPaths.length > 0) {
|
|
1291
|
+
throw new Error(`When planning ${graphqlType}'s planForType for ${type.name}, returned step ${$stepForType} is not valid in ${missedPaths.length} out of ${polymorphicPaths.size} expected paths; missed paths: ${missedPaths}`);
|
|
1292
|
+
}
|
|
1293
|
+
}
|
|
1294
|
+
}
|
|
1295
|
+
}
|
|
1296
|
+
catch (e) {
|
|
1297
|
+
stepForType.set(type, e);
|
|
1298
|
+
}
|
|
1299
|
+
}
|
|
1300
|
+
// Now replace references to layer plan and step
|
|
1301
|
+
for (const detailsRecord of detailsRecordList) {
|
|
1302
|
+
detailsRecord.parentStep = commonStep;
|
|
1303
|
+
detailsRecord.layerPlan = polymorphicLayerPlan;
|
|
1304
|
+
// TODO: do we want to set the polymorphic paths here or not?
|
|
1305
|
+
// detailsRecord.polymorphicPaths = combinedPolymorphicPaths;
|
|
1306
|
+
const { locationDetails, parentObjectType, responseKey, isNonNull, outputPlan: parentOutputPlan, } = detailsRecord;
|
|
1307
|
+
const polymorphicOutputPlan = new OutputPlan_js_1.OutputPlan(commonLayerPlan, polymorphicTypePlanner.$__typename, {
|
|
1308
|
+
mode: "polymorphic",
|
|
1309
|
+
deferLabel: undefined,
|
|
1310
|
+
typeNames: allPossibleObjectTypes.map((t) => t.name),
|
|
1311
|
+
}, locationDetails);
|
|
1312
|
+
detailsRecord.outputPlan = polymorphicOutputPlan;
|
|
1313
|
+
parentOutputPlan.addChild(parentObjectType, responseKey, {
|
|
1314
|
+
type: "outputPlan",
|
|
1315
|
+
outputPlan: polymorphicOutputPlan,
|
|
1316
|
+
isNonNull,
|
|
1317
|
+
locationDetails,
|
|
1318
|
+
});
|
|
1319
|
+
detailsRecord.stepForType = stepForType;
|
|
1320
|
+
}
|
|
1321
|
+
}
|
|
1322
|
+
for (const [parentLayerPlan, planFieldReturnTypeEntriesByStep,] of planFieldReturnTypeEntriesByStepByLayerPlan) {
|
|
1323
|
+
if (planFieldReturnTypeEntriesByStep.size <= 1) {
|
|
1324
|
+
continue;
|
|
1325
|
+
}
|
|
1326
|
+
for (const [step, entries] of planFieldReturnTypeEntriesByStep) {
|
|
1327
|
+
// We already know the planningPath lines up.
|
|
1328
|
+
// We know all `entries` resolved to the same `step`.
|
|
1329
|
+
// We know all `entries` come from the same layer plan.
|
|
1330
|
+
// TODO: I'm not sure if we care if the field result type is the
|
|
1331
|
+
// same or not. I don't think so?
|
|
1332
|
+
// We want to create a polymorphicPartition layer plan for these, if
|
|
1333
|
+
// it makes sense.
|
|
1334
|
+
// It makes sense if there are multiple different groups; which we
|
|
1335
|
+
// checked in the `if` above. So, yes.
|
|
1336
|
+
// TODO: Check assumption: the different groups should relate to
|
|
1337
|
+
// different types.
|
|
1338
|
+
const typeNameSet = new Set();
|
|
1339
|
+
entries.forEach((e) => void typeNameSet.add(e.positionType.name));
|
|
1340
|
+
const typeNames = [...typeNameSet];
|
|
1341
|
+
// TODO: eliminate this
|
|
1342
|
+
const polymorphicPaths = new Set(entries.flatMap((e) => [...(e.polymorphicPaths ?? [])]));
|
|
1343
|
+
const partitionedLayerPlan = parentLayerPlan.getPartition(typeNames, polymorphicPaths);
|
|
1344
|
+
/**
|
|
1345
|
+
* Moves all the steps that match these polymorphic paths only into
|
|
1346
|
+
* the polymorphicPartition layer plan
|
|
1347
|
+
*/
|
|
1348
|
+
const recursivelyMoveSteps = (step) => {
|
|
1349
|
+
if (step.layerPlan !== parentLayerPlan)
|
|
1350
|
+
return;
|
|
1351
|
+
if (!(0, utils_js_1.setsMatch)(step.polymorphicPaths, polymorphicPaths))
|
|
1352
|
+
return;
|
|
1353
|
+
this.stepTracker.moveStepToLayerPlan(step, partitionedLayerPlan);
|
|
1354
|
+
for (const dep of (0, utils_js_1.sudo)(step).dependencies) {
|
|
1355
|
+
recursivelyMoveSteps(dep);
|
|
1356
|
+
}
|
|
1357
|
+
};
|
|
1358
|
+
recursivelyMoveSteps(step);
|
|
1359
|
+
// TODO: Do we need to update the outputPlan.layerPlan too?
|
|
1360
|
+
for (const entry of entries) {
|
|
1361
|
+
entry.layerPlan = partitionedLayerPlan;
|
|
1362
|
+
}
|
|
1363
|
+
}
|
|
1364
|
+
}
|
|
1365
|
+
}
|
|
1366
|
+
}
|
|
838
1367
|
internalDependency($step) {
|
|
839
1368
|
this.stepTracker.internalDependencies.add($step);
|
|
840
1369
|
return $step;
|
|
841
1370
|
}
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
path, polymorphicPath, polymorphicPaths, selections, parentObjectType, responseKey, fieldType, $step, locationDetails, resolverEmulation, listDepth, streamDetails) {
|
|
1371
|
+
planFieldReturnType(details) {
|
|
1372
|
+
return this.planIntoOutputPlan({ ...details, listDepth: 0 });
|
|
1373
|
+
}
|
|
1374
|
+
planIntoOutputPlan(details) {
|
|
1375
|
+
const { outputPlan: parentOutputPlan, path, planningPath, polymorphicPaths, parentStep: $step, positionType: fieldType, layerPlan: parentLayerPlan, selections, parentObjectType, responseKey, locationDetails, resolverEmulation, listDepth, streamDetails, } = details;
|
|
848
1376
|
const nullableFieldType = getNullableType(fieldType);
|
|
849
1377
|
const isNonNull = nullableFieldType !== fieldType;
|
|
850
1378
|
if (isListType(nullableFieldType)) {
|
|
851
|
-
const
|
|
1379
|
+
const listItemPlanningPath = planningPath +
|
|
1380
|
+
`[${streamDetails
|
|
1381
|
+
? `#${streamDetails.initialCount.id}|${streamDetails.if.id}|${streamDetails.label.id}`
|
|
1382
|
+
: ""}]`;
|
|
1383
|
+
const $list = (0, withGlobalLayerPlan_js_1.withGlobalLayerPlan)(parentLayerPlan, polymorphicPaths, listItemPlanningPath, connection_js_1.itemsOrStep, null, $step);
|
|
852
1384
|
if ($list !== $step) {
|
|
853
1385
|
$list._stepOptions.stream = $step._stepOptions.stream;
|
|
854
1386
|
}
|
|
@@ -868,25 +1400,20 @@ class OperationPlan {
|
|
|
868
1400
|
labelStepId: streamDetails.label.id,
|
|
869
1401
|
}
|
|
870
1402
|
: undefined;
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
this.planIntoOutputPlan(listOutputPlan, $item.layerPlan, path, polymorphicPath, polymorphicPaths, selections, null, null, nullableFieldType.ofType, $item, locationDetails, resolverEmulation, listDepth + 1, null);
|
|
886
|
-
}
|
|
887
|
-
finally {
|
|
888
|
-
$__item.layerPlan.latestSideEffectStep = $sideEffect;
|
|
889
|
-
}
|
|
1403
|
+
this.queueNextLayer(this.planListItem, {
|
|
1404
|
+
outputPlan: listOutputPlan,
|
|
1405
|
+
path,
|
|
1406
|
+
planningPath: listItemPlanningPath,
|
|
1407
|
+
polymorphicPaths,
|
|
1408
|
+
parentStep: $list,
|
|
1409
|
+
positionType: nullableFieldType,
|
|
1410
|
+
layerPlan: parentLayerPlan,
|
|
1411
|
+
selections,
|
|
1412
|
+
listDepth,
|
|
1413
|
+
stream,
|
|
1414
|
+
locationDetails,
|
|
1415
|
+
resolverEmulation,
|
|
1416
|
+
});
|
|
890
1417
|
}
|
|
891
1418
|
else if (isScalarType(nullableFieldType)) {
|
|
892
1419
|
const scalarPlanResolver = nullableFieldType.extensions?.grafast?.plan;
|
|
@@ -895,7 +1422,7 @@ class OperationPlan {
|
|
|
895
1422
|
const $sideEffect = parentLayerPlan.latestSideEffectStep;
|
|
896
1423
|
try {
|
|
897
1424
|
const $leaf = typeof scalarPlanResolver === "function"
|
|
898
|
-
? (0, utils_js_1.assertNotPromise)((0, withGlobalLayerPlan_js_1.withGlobalLayerPlan)(parentLayerPlan, polymorphicPaths, scalarPlanResolver, null, $step, this.scalarPlanInfo), scalarPlanResolver, fnDescription)
|
|
1425
|
+
? (0, utils_js_1.assertNotPromise)((0, withGlobalLayerPlan_js_1.withGlobalLayerPlan)(parentLayerPlan, polymorphicPaths, planningPath, scalarPlanResolver, null, $step, this.scalarPlanInfo), scalarPlanResolver, fnDescription)
|
|
899
1426
|
: $step;
|
|
900
1427
|
parentOutputPlan.addChild(parentObjectType, responseKey, {
|
|
901
1428
|
type: "outputPlan",
|
|
@@ -968,8 +1495,9 @@ class OperationPlan {
|
|
|
968
1495
|
objectLayerPlan = match;
|
|
969
1496
|
}
|
|
970
1497
|
else {
|
|
971
|
-
objectLayerPlan = new LayerPlan_js_1.LayerPlan(this,
|
|
1498
|
+
objectLayerPlan = new LayerPlan_js_1.LayerPlan(this, {
|
|
972
1499
|
type: "nullableBoundary",
|
|
1500
|
+
parentLayerPlan,
|
|
973
1501
|
parentStep: $step,
|
|
974
1502
|
});
|
|
975
1503
|
objectLayerPlan.setRootStep($step);
|
|
@@ -988,7 +1516,17 @@ class OperationPlan {
|
|
|
988
1516
|
isNonNull,
|
|
989
1517
|
locationDetails,
|
|
990
1518
|
});
|
|
991
|
-
this.planSelectionSet
|
|
1519
|
+
this.queueNextLayer(this.planSelectionSet, {
|
|
1520
|
+
outputPlan: objectOutputPlan,
|
|
1521
|
+
path,
|
|
1522
|
+
planningPath: planningPath + ".",
|
|
1523
|
+
polymorphicPaths,
|
|
1524
|
+
parentStep: $step,
|
|
1525
|
+
positionType: nullableFieldType,
|
|
1526
|
+
layerPlan: objectLayerPlan,
|
|
1527
|
+
selections: selections,
|
|
1528
|
+
resolverEmulation,
|
|
1529
|
+
});
|
|
992
1530
|
}
|
|
993
1531
|
finally {
|
|
994
1532
|
objectLayerPlan.latestSideEffectStep = $sideEffect;
|
|
@@ -999,7 +1537,8 @@ class OperationPlan {
|
|
|
999
1537
|
const isUnion = isUnionType(nullableFieldType);
|
|
1000
1538
|
const isInterface = isInterfaceType(nullableFieldType);
|
|
1001
1539
|
if (!(isUnion || isInterface)) {
|
|
1002
|
-
|
|
1540
|
+
const never = nullableFieldType;
|
|
1541
|
+
throw new Error(`GrafastInternalError<a54d6d63-d186-4ab9-9299-05f817894300>: Wasn't expecting ${never}`);
|
|
1003
1542
|
}
|
|
1004
1543
|
assert.ok(selections, "GrafastInternalError<d94e281c-1a10-463e-b7f5-2b0a3665d99b>: A polymorphic type with no selections is invalid");
|
|
1005
1544
|
/*
|
|
@@ -1007,10 +1546,11 @@ class OperationPlan {
|
|
|
1007
1546
|
* other types.
|
|
1008
1547
|
*
|
|
1009
1548
|
* First, we figure out the list of `possibleTypes` based on the
|
|
1010
|
-
* union/interface and any other constraints that we know.
|
|
1549
|
+
* union/interface and any other constraints that we know. Note: we can't
|
|
1011
1550
|
* discount a type just because it doesn't have any fragments that apply
|
|
1012
1551
|
* to it - instead we must still plan an empty selection set (or one just
|
|
1013
|
-
* using `{__typename}`), and we need to know it exists
|
|
1552
|
+
* using `{__typename}`), and we need to know it exists (is not null) for
|
|
1553
|
+
* that. See
|
|
1014
1554
|
* https://github.com/graphql/graphql-spec/issues/951#issuecomment-1140957685
|
|
1015
1555
|
*/
|
|
1016
1556
|
const allPossibleObjectTypes = isUnion
|
|
@@ -1027,139 +1567,329 @@ class OperationPlan {
|
|
|
1027
1567
|
});
|
|
1028
1568
|
}
|
|
1029
1569
|
else {
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
mode: "polymorphic",
|
|
1042
|
-
deferLabel: undefined,
|
|
1043
|
-
typeNames: allPossibleObjectTypes.map((t) => t.name),
|
|
1044
|
-
}, locationDetails);
|
|
1045
|
-
parentOutputPlan.addChild(parentObjectType, responseKey, {
|
|
1046
|
-
type: "outputPlan",
|
|
1047
|
-
outputPlan: polymorphicOutputPlan,
|
|
1048
|
-
isNonNull,
|
|
1570
|
+
const polymorphicResolvePlanningPath = planningPath + "<*>";
|
|
1571
|
+
this.queueNextLayer(this.polymorphicResolveType, {
|
|
1572
|
+
outputPlan: parentOutputPlan,
|
|
1573
|
+
path,
|
|
1574
|
+
planningPath: polymorphicResolvePlanningPath,
|
|
1575
|
+
polymorphicPaths,
|
|
1576
|
+
parentStep: $step, // NOTE: This may be batched and turned into a $specifier step
|
|
1577
|
+
positionType: nullableFieldType,
|
|
1578
|
+
layerPlan: parentLayerPlan, // NOTE: This may be batched and turned into a combined layer plan
|
|
1579
|
+
selections,
|
|
1580
|
+
allPossibleObjectTypes,
|
|
1049
1581
|
locationDetails,
|
|
1582
|
+
parentObjectType,
|
|
1583
|
+
responseKey,
|
|
1584
|
+
isNonNull,
|
|
1585
|
+
resolverEmulation,
|
|
1050
1586
|
});
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1587
|
+
}
|
|
1588
|
+
}
|
|
1589
|
+
}
|
|
1590
|
+
/** @internal */
|
|
1591
|
+
planListItem(details) {
|
|
1592
|
+
const { outputPlan: listOutputPlan, path, planningPath: listItemPlanningPath, polymorphicPaths, parentStep: $list, positionType: nullableFieldType, layerPlan: parentLayerPlan, selections, listDepth, stream, locationDetails, resolverEmulation, } = details;
|
|
1593
|
+
const $__item = this.itemStepForListStep(parentLayerPlan, listItemPlanningPath, $list, listDepth, stream);
|
|
1594
|
+
const $sideEffect = $__item.layerPlan.latestSideEffectStep;
|
|
1595
|
+
try {
|
|
1596
|
+
let $item;
|
|
1597
|
+
if ((0, step_js_1.isListCapableStep)($list)) {
|
|
1598
|
+
$item = (0, withGlobalLayerPlan_js_1.withGlobalLayerPlan)($__item.layerPlan, $__item.polymorphicPaths, listItemPlanningPath, $list.listItem, $list, $__item);
|
|
1599
|
+
}
|
|
1600
|
+
else {
|
|
1601
|
+
$item = $__item;
|
|
1602
|
+
}
|
|
1603
|
+
this.queueNextLayer(this.planIntoOutputPlan, {
|
|
1604
|
+
outputPlan: listOutputPlan,
|
|
1605
|
+
path,
|
|
1606
|
+
planningPath: listItemPlanningPath + "^",
|
|
1607
|
+
polymorphicPaths,
|
|
1608
|
+
parentStep: $item,
|
|
1609
|
+
positionType: nullableFieldType.ofType,
|
|
1610
|
+
layerPlan: $item.layerPlan,
|
|
1611
|
+
selections,
|
|
1612
|
+
parentObjectType: null,
|
|
1613
|
+
responseKey: null,
|
|
1614
|
+
locationDetails,
|
|
1615
|
+
resolverEmulation,
|
|
1616
|
+
listDepth: listDepth + 1,
|
|
1617
|
+
streamDetails: null,
|
|
1618
|
+
});
|
|
1619
|
+
}
|
|
1620
|
+
catch (err) {
|
|
1621
|
+
this.handlePlanningError({
|
|
1622
|
+
outputPlan: listOutputPlan,
|
|
1623
|
+
layerPlan: $__item.layerPlan,
|
|
1624
|
+
objectType: null,
|
|
1625
|
+
responseKey: null,
|
|
1626
|
+
positionType: nullableFieldType.ofType,
|
|
1627
|
+
locationDetails,
|
|
1628
|
+
err,
|
|
1629
|
+
});
|
|
1630
|
+
}
|
|
1631
|
+
finally {
|
|
1632
|
+
$__item.layerPlan.latestSideEffectStep = $sideEffect;
|
|
1633
|
+
}
|
|
1634
|
+
}
|
|
1635
|
+
handlePlanningError(details) {
|
|
1636
|
+
const { outputPlan, layerPlan, objectType, responseKey, positionType, locationDetails, err, } = details;
|
|
1637
|
+
const step = this.withRootLayerPlan(() => (0, index_js_1.error)(err));
|
|
1638
|
+
const nullableFieldType = getNullableType(positionType);
|
|
1639
|
+
const isNonNull = nullableFieldType !== positionType;
|
|
1640
|
+
outputPlan.addChild(objectType, responseKey, {
|
|
1641
|
+
type: "outputPlan",
|
|
1642
|
+
outputPlan: new OutputPlan_js_1.OutputPlan(layerPlan, step, OUTPUT_PLAN_TYPE_NULL, locationDetails),
|
|
1643
|
+
isNonNull,
|
|
1644
|
+
locationDetails,
|
|
1645
|
+
});
|
|
1646
|
+
}
|
|
1647
|
+
/** @internal */
|
|
1648
|
+
polymorphicResolveType(details) {
|
|
1649
|
+
const { outputPlan, path, planningPath: polymorphicResolvePlanningPath, polymorphicPaths, layerPlan, selections, allPossibleObjectTypes, locationDetails, isNonNull, resolverEmulation, stepForType, } = details;
|
|
1650
|
+
if (!stepForType) {
|
|
1651
|
+
throw new Error("GrafastInternalError<6afce944-f963-470f-8575-0d0420b4c838>: planForType wasn't set!");
|
|
1652
|
+
}
|
|
1653
|
+
if (outputPlan.type.mode !== "polymorphic") {
|
|
1654
|
+
throw new Error(`GrafastInternalError<21de2f87-45c9-42c6-a1a3-c2c0f6e72ccb>: expected a polymorphic output plan`);
|
|
1655
|
+
}
|
|
1656
|
+
const polymorphicOutputPlan = outputPlan;
|
|
1657
|
+
/*
|
|
1658
|
+
* Now we need to loop through each type and plan it.
|
|
1659
|
+
*/
|
|
1660
|
+
const polyBases = [...(polymorphicPaths ?? [""])];
|
|
1661
|
+
const polymorphicPlanningPath = polymorphicResolvePlanningPath + "!";
|
|
1662
|
+
for (const type of allPossibleObjectTypes) {
|
|
1663
|
+
const $sideEffect = layerPlan.latestSideEffectStep;
|
|
1664
|
+
try {
|
|
1665
|
+
// Bit of a hack, but saves passing it around through all the arguments
|
|
1666
|
+
const newPolymorphicPaths = new Set();
|
|
1667
|
+
for (const polyBase of polyBases) {
|
|
1668
|
+
const newPolymorphicPath = `${polyBase}>${type.name}`;
|
|
1669
|
+
//resolveTypeLayerPlan.reason.polymorphicPaths.add(newPolymorphicPath);
|
|
1670
|
+
newPolymorphicPaths.add(newPolymorphicPath);
|
|
1671
|
+
}
|
|
1672
|
+
const $root = stepForType.get(type);
|
|
1673
|
+
try {
|
|
1674
|
+
if ($root == null) {
|
|
1675
|
+
throw new Error(`${details.positionType}'s planType().planForType(${type}) returned ${$root}`);
|
|
1105
1676
|
}
|
|
1106
|
-
|
|
1107
|
-
|
|
1677
|
+
else if (!($root instanceof index_js_1.Step)) {
|
|
1678
|
+
throw $root;
|
|
1108
1679
|
}
|
|
1109
1680
|
}
|
|
1681
|
+
catch (err) {
|
|
1682
|
+
this.handlePlanningError({
|
|
1683
|
+
outputPlan: polymorphicOutputPlan,
|
|
1684
|
+
layerPlan: layerPlan,
|
|
1685
|
+
objectType: type,
|
|
1686
|
+
responseKey: null,
|
|
1687
|
+
positionType: type,
|
|
1688
|
+
locationDetails,
|
|
1689
|
+
err,
|
|
1690
|
+
});
|
|
1691
|
+
return;
|
|
1692
|
+
}
|
|
1693
|
+
// find all selections compatible with `type`
|
|
1694
|
+
const fieldNodes = (0, graphqlMergeSelectionSets_js_1.fieldSelectionsForType)(this, type, selections);
|
|
1695
|
+
this.queueNextLayer(this.polymorphicPlanObjectType, {
|
|
1696
|
+
outputPlan: polymorphicOutputPlan,
|
|
1697
|
+
path,
|
|
1698
|
+
planningPath: polymorphicPlanningPath,
|
|
1699
|
+
polymorphicPaths: newPolymorphicPaths,
|
|
1700
|
+
parentStep: $root,
|
|
1701
|
+
positionType: type,
|
|
1702
|
+
layerPlan,
|
|
1703
|
+
fieldNodes,
|
|
1704
|
+
locationDetails,
|
|
1705
|
+
isNonNull,
|
|
1706
|
+
resolverEmulation,
|
|
1707
|
+
});
|
|
1708
|
+
}
|
|
1709
|
+
finally {
|
|
1710
|
+
layerPlan.latestSideEffectStep = $sideEffect;
|
|
1110
1711
|
}
|
|
1111
1712
|
}
|
|
1112
1713
|
}
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
if (
|
|
1120
|
-
|
|
1714
|
+
// Before calling this, all the deduplication in the resolveType layer plan
|
|
1715
|
+
// should have taken place, and for each step that survives, a polymorphic
|
|
1716
|
+
// layer plan matching those relevant types should be created, and passed
|
|
1717
|
+
// through here as `polymorphicLayerPlan`.
|
|
1718
|
+
polymorphicPlanObjectType(details) {
|
|
1719
|
+
const { outputPlan, path, planningPath: polymorphicPlanningPath, polymorphicPaths: newPolymorphicPaths, parentStep: $root, positionType: type, layerPlan: polymorphicLayerPlan, fieldNodes, locationDetails, isNonNull, resolverEmulation, } = details;
|
|
1720
|
+
if (outputPlan.type.mode !== "polymorphic") {
|
|
1721
|
+
throw new Error(`GrafastInternalError<4c8d9d82-6cb2-4712-aa1e-fdd2173a0760>: expected a polymorphic output plan`);
|
|
1722
|
+
}
|
|
1723
|
+
const polymorphicOutputPlan = outputPlan;
|
|
1724
|
+
if (polymorphicLayerPlan.reason.type !== "polymorphic" &&
|
|
1725
|
+
polymorphicLayerPlan.reason.type !== "polymorphicPartition") {
|
|
1726
|
+
// NOTE: when queued, this method will be queued with a different layer
|
|
1727
|
+
// plan, but `planPending` should go through and convert it to the
|
|
1728
|
+
// relevant polymorphic layer plans for us.
|
|
1729
|
+
throw new Error(`GrafastInternalError<877eaa1c-30c9-4526-ada4-3ccce020ee0e>: expected ${polymorphicLayerPlan} to be a polymorphic or polymorphicPartition layer plan`);
|
|
1730
|
+
}
|
|
1731
|
+
const objectOutputPlan = new OutputPlan_js_1.OutputPlan(polymorphicLayerPlan, $root, {
|
|
1732
|
+
mode: "object",
|
|
1733
|
+
deferLabel: undefined,
|
|
1734
|
+
typeName: type.name,
|
|
1735
|
+
}, locationDetails);
|
|
1736
|
+
this.planSelectionSet({
|
|
1737
|
+
outputPlan: objectOutputPlan,
|
|
1738
|
+
path,
|
|
1739
|
+
planningPath: polymorphicPlanningPath + ".",
|
|
1740
|
+
polymorphicPaths: newPolymorphicPaths,
|
|
1741
|
+
parentStep: $root,
|
|
1742
|
+
positionType: type,
|
|
1743
|
+
layerPlan: polymorphicLayerPlan,
|
|
1744
|
+
selections: fieldNodes,
|
|
1745
|
+
resolverEmulation,
|
|
1746
|
+
});
|
|
1747
|
+
polymorphicOutputPlan.addChild(type, null, {
|
|
1748
|
+
type: "outputPlan",
|
|
1749
|
+
isNonNull,
|
|
1750
|
+
outputPlan: objectOutputPlan,
|
|
1751
|
+
locationDetails,
|
|
1752
|
+
});
|
|
1753
|
+
}
|
|
1754
|
+
batchPlanField(batchPlanFieldDetails) {
|
|
1755
|
+
let b;
|
|
1756
|
+
if (this.planFieldBatch != null) {
|
|
1757
|
+
b = this.planFieldBatch;
|
|
1758
|
+
}
|
|
1759
|
+
else {
|
|
1760
|
+
b = this.planFieldBatch = {
|
|
1761
|
+
complete: false,
|
|
1762
|
+
batch: [],
|
|
1763
|
+
results: [],
|
|
1764
|
+
};
|
|
1121
1765
|
}
|
|
1122
|
-
const
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
// keeping the plan simpler (and more efficient).
|
|
1128
|
-
const { stepId, layerPlan } = prev;
|
|
1129
|
-
const stepByStepId = this.stepTracker.getStepById(stepId);
|
|
1130
|
-
const stepBy$stepId = this.stepTracker.getStepById($step.id);
|
|
1131
|
-
if (stepByStepId !== stepBy$stepId) {
|
|
1132
|
-
throw new Error(`GrafastInternalError<e01bdc40-7c89-41c6-8d84-56efa22c872a>: unexpected inconsistency when determining the polymorphic LayerPlan to use (pathString = ${pathString}, ${stepByStepId} (${stepId}) != ${stepBy$stepId} (${$step.id}))`);
|
|
1766
|
+
const myIndex = b.batch.length;
|
|
1767
|
+
b.batch.push(batchPlanFieldDetails);
|
|
1768
|
+
return () => {
|
|
1769
|
+
if (!b.complete) {
|
|
1770
|
+
this.processPlanField(b);
|
|
1133
1771
|
}
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1772
|
+
const result = b.results[myIndex];
|
|
1773
|
+
if (result.error) {
|
|
1774
|
+
throw result.error;
|
|
1775
|
+
}
|
|
1776
|
+
return result;
|
|
1777
|
+
};
|
|
1778
|
+
}
|
|
1779
|
+
processPlanField(b) {
|
|
1780
|
+
b.complete = true;
|
|
1781
|
+
this.planFieldBatch = null;
|
|
1782
|
+
const groups = new Map();
|
|
1783
|
+
for (let i = 0, l = b.batch.length; i < l; i++) {
|
|
1784
|
+
const batchPlanFieldDetails = b.batch[i];
|
|
1785
|
+
const { typeName, fieldName, layerPlan,
|
|
1786
|
+
// path,
|
|
1787
|
+
polymorphicPaths, planningPath,
|
|
1788
|
+
// planResolver,
|
|
1789
|
+
// applyAfterMode,
|
|
1790
|
+
rawParentStep,
|
|
1791
|
+
// field,
|
|
1792
|
+
trackedArguments, streamDetails, } = batchPlanFieldDetails;
|
|
1793
|
+
const argsSig = Object.entries(trackedArguments)
|
|
1794
|
+
.map(([key, step]) => `${key}:${step.id}`)
|
|
1795
|
+
.join(",");
|
|
1796
|
+
/**
|
|
1797
|
+
* Our tests don't come up with anywhere where rawParentStep.id needs
|
|
1798
|
+
* incorporation into the signature, but I'm feeling paranoid.
|
|
1799
|
+
*/
|
|
1800
|
+
const benjiesParanoia = `[${rawParentStep.id}]`;
|
|
1801
|
+
const signature = `${planningPath}@${layerPlan.id}${benjiesParanoia}=${typeName}.${fieldName}(${argsSig})`;
|
|
1802
|
+
let entry = groups.get(signature);
|
|
1803
|
+
if (!entry) {
|
|
1804
|
+
entry = {
|
|
1805
|
+
firstDetails: batchPlanFieldDetails,
|
|
1806
|
+
extraDetails: [{ polymorphicPaths }],
|
|
1807
|
+
streamDetails,
|
|
1808
|
+
indexes: [i],
|
|
1809
|
+
};
|
|
1810
|
+
groups.set(signature, entry);
|
|
1811
|
+
}
|
|
1812
|
+
else {
|
|
1813
|
+
if (index_js_1.isDev) {
|
|
1814
|
+
// Check everything lines up as we would expect
|
|
1815
|
+
for (const key of Object.keys(batchPlanFieldDetails)) {
|
|
1816
|
+
const myVal = batchPlanFieldDetails[key];
|
|
1817
|
+
const first = entry.firstDetails[key];
|
|
1818
|
+
if (myVal === first)
|
|
1819
|
+
continue;
|
|
1820
|
+
switch (key) {
|
|
1821
|
+
case "typeName":
|
|
1822
|
+
throw new Error(`GraphileInternalError<15e09f3f-1a83-48a8-822c-1158b9740ef7>: processPlanField signature failure - mismatch typeName`);
|
|
1823
|
+
case "fieldName":
|
|
1824
|
+
throw new Error(`GraphileInternalError<2999cbf9-7143-4677-9592-0bfc52e12cb0>: processPlanField signature failure - mismatch fieldName`);
|
|
1825
|
+
case "layerPlan":
|
|
1826
|
+
throw new Error(`GraphileInternalError<52786d18-cfda-4ed6-a309-9cb31dcd5f34>: processPlanField signature failure - mismatch layerPlan`);
|
|
1827
|
+
case "path":
|
|
1828
|
+
if (!(0, utils_js_1.arraysMatch)(batchPlanFieldDetails.path, entry.firstDetails.path)) {
|
|
1829
|
+
throw new Error(`GraphileInternalError<cb84829d-ee4c-40cd-a3a6-f53d1029ad83>: processPlanField signature failure - mismatch path`);
|
|
1830
|
+
}
|
|
1831
|
+
break;
|
|
1832
|
+
case "polymorphicPaths":
|
|
1833
|
+
// Explicitly differences in polymorphicPaths are allowed
|
|
1834
|
+
break;
|
|
1835
|
+
case "planningPath":
|
|
1836
|
+
throw new Error(`GraphileInternalError<1b708215-1549-47c3-9cf5-8fd8d7eb9bd0>: processPlanField signature failure - mismatch planningPath`);
|
|
1837
|
+
case "planResolver":
|
|
1838
|
+
throw new Error(`GraphileInternalError<7f14700f-2272-4b6a-a927-7600d934fdf0>: processPlanField signature failure - mismatch planResolver`);
|
|
1839
|
+
case "applyAfterMode":
|
|
1840
|
+
throw new Error(`GraphileInternalError<bbddad4f-68aa-49c7-b82c-09ceebf14a3f>: processPlanField signature failure - mismatch applyAfterMode`);
|
|
1841
|
+
case "rawParentStep":
|
|
1842
|
+
throw new Error(`GraphileInternalError<3306994d-7881-4495-89d1-6c9252840369>: processPlanField signature failure - mismatch rawParentStep`);
|
|
1843
|
+
case "field":
|
|
1844
|
+
throw new Error(`GraphileInternalError<67d2a787-2383-4228-8358-6ea9b3321445>: processPlanField signature failure - mismatch field`);
|
|
1845
|
+
case "trackedArguments":
|
|
1846
|
+
if (!(0, utils_js_1.recordsMatch)(batchPlanFieldDetails.trackedArguments, entry.firstDetails.trackedArguments)) {
|
|
1847
|
+
throw new Error(`GraphileInternalError<ec3f1e44-0ab6-445c-a644-a4d276f4b787>: processPlanField signature failure - mismatch trackedArguments`);
|
|
1848
|
+
}
|
|
1849
|
+
break;
|
|
1850
|
+
case "streamDetails":
|
|
1851
|
+
// If any of them don't stream, turn streaming off
|
|
1852
|
+
if (!streamDetails) {
|
|
1853
|
+
entry.streamDetails = null;
|
|
1854
|
+
}
|
|
1855
|
+
break;
|
|
1856
|
+
default: {
|
|
1857
|
+
const never = key;
|
|
1858
|
+
throw new Error(`GraphileInternalError<3f039c33-0b43-47d8-8da8-57873186cd60>: unexpected key '${never}'`);
|
|
1859
|
+
}
|
|
1860
|
+
}
|
|
1861
|
+
}
|
|
1139
1862
|
}
|
|
1863
|
+
entry.indexes.push(i);
|
|
1864
|
+
entry.extraDetails.push({ polymorphicPaths });
|
|
1865
|
+
}
|
|
1866
|
+
}
|
|
1867
|
+
// Loop through the groups and resolve the plan ONCE per group.
|
|
1868
|
+
// We don't care about the signature here; that was just for grouping
|
|
1869
|
+
for (const entry of groups.values()) {
|
|
1870
|
+
const planFieldDetails = {
|
|
1871
|
+
...entry.firstDetails,
|
|
1872
|
+
polymorphicPaths: entry.firstDetails.polymorphicPaths
|
|
1873
|
+
? new Set([
|
|
1874
|
+
...entry.firstDetails.polymorphicPaths,
|
|
1875
|
+
...entry.extraDetails.flatMap((d) => [...d.polymorphicPaths]),
|
|
1876
|
+
])
|
|
1877
|
+
: null,
|
|
1878
|
+
};
|
|
1879
|
+
let result;
|
|
1880
|
+
try {
|
|
1881
|
+
result = this._realPlanField(planFieldDetails);
|
|
1882
|
+
}
|
|
1883
|
+
catch (error) {
|
|
1884
|
+
result = { error };
|
|
1885
|
+
}
|
|
1886
|
+
for (const i of entry.indexes) {
|
|
1887
|
+
b.results[i] = result;
|
|
1140
1888
|
}
|
|
1141
|
-
return layerPlan;
|
|
1142
|
-
}
|
|
1143
|
-
else {
|
|
1144
|
-
const layerPlan = new LayerPlan_js_1.LayerPlan(this, parentLayerPlan, {
|
|
1145
|
-
type: "polymorphic",
|
|
1146
|
-
typeNames: allPossibleObjectTypes.map((t) => t.name),
|
|
1147
|
-
parentStep: $step,
|
|
1148
|
-
polymorphicPaths: new Set(),
|
|
1149
|
-
});
|
|
1150
|
-
polymorphicLayerPlanByPath.set(pathString, {
|
|
1151
|
-
stepId: $step.id,
|
|
1152
|
-
layerPlan,
|
|
1153
|
-
});
|
|
1154
|
-
return layerPlan;
|
|
1155
1889
|
}
|
|
1156
1890
|
}
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
// If 'false' this is a list but it will never stream
|
|
1160
|
-
// If 'null' this is neither subscribe field nor list field
|
|
1161
|
-
// Otherwise, it's a list field that has the `@stream` directive applied
|
|
1162
|
-
streamDetails, deduplicate = true) {
|
|
1891
|
+
_realPlanField(planFieldDetails) {
|
|
1892
|
+
const { typeName, fieldName, layerPlan, path, polymorphicPaths, planningPath, planResolver, applyAfterMode, rawParentStep, field, trackedArguments, streamDetails, } = planFieldDetails;
|
|
1163
1893
|
const coordinate = `${typeName}.${fieldName}`;
|
|
1164
1894
|
// The step may have been de-duped whilst sibling steps were planned
|
|
1165
1895
|
// PERF: this should be handled in the parent?
|
|
@@ -1169,7 +1899,7 @@ class OperationPlan {
|
|
|
1169
1899
|
if (this.loc !== null)
|
|
1170
1900
|
this.loc.push(`planField(${path.join(".")})`);
|
|
1171
1901
|
try {
|
|
1172
|
-
let step = (0, withGlobalLayerPlan_js_1.withGlobalLayerPlan)(layerPlan, polymorphicPaths, operationPlan_input_js_1.withFieldArgsForArguments, null, this, trackedArguments, field, parentStep, applyAfterMode, coordinate, (fieldArgs) => planResolver(parentStep, fieldArgs, {
|
|
1902
|
+
let step = (0, withGlobalLayerPlan_js_1.withGlobalLayerPlan)(layerPlan, polymorphicPaths, planningPath, operationPlan_input_js_1.withFieldArgsForArguments, null, this, trackedArguments, field, parentStep, applyAfterMode, coordinate, (fieldArgs) => planResolver(parentStep, fieldArgs, {
|
|
1173
1903
|
fieldName,
|
|
1174
1904
|
field,
|
|
1175
1905
|
schema: this.schema,
|
|
@@ -1180,7 +1910,7 @@ class OperationPlan {
|
|
|
1180
1910
|
step =
|
|
1181
1911
|
step ||
|
|
1182
1912
|
// `withGlobalLayerPlan(layerPlan, polymorphicPaths, () => constant(null))` but with reduced memory allocation
|
|
1183
|
-
(0, withGlobalLayerPlan_js_1.withGlobalLayerPlan)(layerPlan, polymorphicPaths, constant_js_1.constant, null, null);
|
|
1913
|
+
(0, withGlobalLayerPlan_js_1.withGlobalLayerPlan)(layerPlan, polymorphicPaths, planningPath, constant_js_1.constant, null, null);
|
|
1184
1914
|
haltTree = true;
|
|
1185
1915
|
}
|
|
1186
1916
|
(0, step_js_1.assertExecutableStep)(step);
|
|
@@ -1200,15 +1930,6 @@ class OperationPlan {
|
|
|
1200
1930
|
};
|
|
1201
1931
|
step._stepOptions.walkIterable = true;
|
|
1202
1932
|
}
|
|
1203
|
-
if (deduplicate) {
|
|
1204
|
-
// Now that the field has been planned (including arguments, but NOT
|
|
1205
|
-
// including selection set) we can deduplicate it to see if any of its
|
|
1206
|
-
// peers are identical.
|
|
1207
|
-
this.deduplicateSteps();
|
|
1208
|
-
// After deduplication, this step may have been substituted; get the
|
|
1209
|
-
// updated reference.
|
|
1210
|
-
step = this.stepTracker.getStepById(step.id);
|
|
1211
|
-
}
|
|
1212
1933
|
return { step, haltTree };
|
|
1213
1934
|
}
|
|
1214
1935
|
catch (e) {
|
|
@@ -1231,7 +1952,7 @@ class OperationPlan {
|
|
|
1231
1952
|
console.error(`Cleanup error occurred whilst trying to recover from field planning error: ${e2.stack}`);
|
|
1232
1953
|
throw e;
|
|
1233
1954
|
}
|
|
1234
|
-
const step = (0, withGlobalLayerPlan_js_1.withGlobalLayerPlan)(layerPlan, polymorphicPaths, index_js_1.error, null, e);
|
|
1955
|
+
const step = (0, withGlobalLayerPlan_js_1.withGlobalLayerPlan)(layerPlan, polymorphicPaths, planningPath, index_js_1.error, null, e);
|
|
1235
1956
|
const haltTree = true;
|
|
1236
1957
|
// PERF: consider deleting all steps that were allocated during this. For
|
|
1237
1958
|
// now we'll just rely on tree-shaking.
|
|
@@ -1264,18 +1985,14 @@ class OperationPlan {
|
|
|
1264
1985
|
const argumentPlan = (0, input_js_1.inputStep)(this, argumentType, argumentValue?.value, defaultValue);
|
|
1265
1986
|
trackedArgumentValues[argumentName] = argumentPlan;
|
|
1266
1987
|
}
|
|
1267
|
-
return
|
|
1268
|
-
get(name) {
|
|
1269
|
-
return trackedArgumentValues[name];
|
|
1270
|
-
},
|
|
1271
|
-
};
|
|
1988
|
+
return trackedArgumentValues;
|
|
1272
1989
|
}
|
|
1273
1990
|
/**
|
|
1274
1991
|
* Sets up tracking for the given value (variableValues, context, rootValue).
|
|
1275
1992
|
*/
|
|
1276
1993
|
track(value, constraints, variableDefinitions) {
|
|
1277
|
-
const valueStep = (0, withGlobalLayerPlan_js_1.withGlobalLayerPlan)(this.rootLayerPlan, exports.POLYMORPHIC_ROOT_PATHS, newValueStepCallback, null, variableDefinitions != null);
|
|
1278
|
-
const trackedObjectStep = (0, withGlobalLayerPlan_js_1.withGlobalLayerPlan)(this.rootLayerPlan, exports.POLYMORPHIC_ROOT_PATHS, () => new index_js_1.__TrackedValueStep(value, valueStep, constraints, [], variableDefinitions != null, variableDefinitions));
|
|
1994
|
+
const valueStep = (0, withGlobalLayerPlan_js_1.withGlobalLayerPlan)(this.rootLayerPlan, exports.POLYMORPHIC_ROOT_PATHS, "", newValueStepCallback, null, variableDefinitions != null);
|
|
1995
|
+
const trackedObjectStep = (0, withGlobalLayerPlan_js_1.withGlobalLayerPlan)(this.rootLayerPlan, exports.POLYMORPHIC_ROOT_PATHS, "", () => new index_js_1.__TrackedValueStep(value, valueStep, constraints, [], variableDefinitions != null, variableDefinitions));
|
|
1279
1996
|
return [valueStep, trackedObjectStep];
|
|
1280
1997
|
}
|
|
1281
1998
|
/**
|
|
@@ -1322,7 +2039,7 @@ class OperationPlan {
|
|
|
1322
2039
|
}
|
|
1323
2040
|
}
|
|
1324
2041
|
}
|
|
1325
|
-
const subroutineLayerPlan = step[
|
|
2042
|
+
const subroutineLayerPlan = step[constants_js_1.$$subroutine];
|
|
1326
2043
|
if (subroutineLayerPlan !== null) {
|
|
1327
2044
|
const $root = subroutineLayerPlan.rootStep;
|
|
1328
2045
|
if ($root) {
|
|
@@ -1344,7 +2061,7 @@ class OperationPlan {
|
|
|
1344
2061
|
}
|
|
1345
2062
|
let replacementStep = step;
|
|
1346
2063
|
try {
|
|
1347
|
-
replacementStep = (0, withGlobalLayerPlan_js_1.withGlobalLayerPlan)(step.layerPlan, step.polymorphicPaths, callback, this, step);
|
|
2064
|
+
replacementStep = (0, withGlobalLayerPlan_js_1.withGlobalLayerPlan)(step.layerPlan, step.polymorphicPaths, null, callback, this, step);
|
|
1348
2065
|
}
|
|
1349
2066
|
catch (e) {
|
|
1350
2067
|
console.error(`Error occurred during ${actionDescription}; whilst processing ${step} in ${order} mode an error occurred:`, e);
|
|
@@ -1362,7 +2079,9 @@ class OperationPlan {
|
|
|
1362
2079
|
if (replacementStep !== step) {
|
|
1363
2080
|
this.replaceStep(step, replacementStep);
|
|
1364
2081
|
}
|
|
1365
|
-
|
|
2082
|
+
if (actionDescription !== "deduplicate") {
|
|
2083
|
+
this.deduplicateSteps();
|
|
2084
|
+
}
|
|
1366
2085
|
}
|
|
1367
2086
|
return replacementStep;
|
|
1368
2087
|
}
|
|
@@ -1421,21 +2140,18 @@ class OperationPlan {
|
|
|
1421
2140
|
// Plans with side effects have no peers.
|
|
1422
2141
|
return EMPTY_ARRAY;
|
|
1423
2142
|
}
|
|
1424
|
-
if (step._stepOptions.stream) {
|
|
1425
|
-
// Streams have no peers - we cannot reference the stream more
|
|
1426
|
-
// than once (and we aim to not cache the stream because we want its
|
|
1427
|
-
// entries to be garbage collected).
|
|
1428
|
-
//
|
|
1429
|
-
// HOWEVER! There may be lifecycle parts that need to be called... So
|
|
1430
|
-
// call the function with an empty array; ignore the result.
|
|
1431
|
-
return EMPTY_ARRAY;
|
|
1432
|
-
}
|
|
1433
2143
|
// NOTE: Streams have no peers - we cannot reference the stream more than
|
|
1434
2144
|
// once (and we aim to not cache the stream because we want its entries to
|
|
1435
2145
|
// be garbage collected) - however if we're already fetching the list then
|
|
1436
2146
|
// we shouldn't fetch it again via stream... We should deduplicate a stream
|
|
1437
2147
|
// to return a non-stream.
|
|
1438
2148
|
if (step._stepOptions.stream != null) {
|
|
2149
|
+
// Streams have no peers - we cannot reference the stream more
|
|
2150
|
+
// than once (and we aim to not cache the stream because we want its
|
|
2151
|
+
// entries to be garbage collected).
|
|
2152
|
+
//
|
|
2153
|
+
// HOWEVER! There may be lifecycle parts that need to be called... So
|
|
2154
|
+
// call the function with an empty array; ignore the result.
|
|
1439
2155
|
// TODO: remove this if block when we implement the new stream/defer -
|
|
1440
2156
|
// deduplicating a stream should be fine. (Not subscriptions though - may
|
|
1441
2157
|
// need a check for that!)
|
|
@@ -1446,7 +2162,7 @@ class OperationPlan {
|
|
|
1446
2162
|
return EMPTY_ARRAY;
|
|
1447
2163
|
}
|
|
1448
2164
|
const sstep = (0, utils_js_1.sudo)(step);
|
|
1449
|
-
const { dependencies: deps, dependencyForbiddenFlags: flags, dependencyOnReject: onReject, layerPlan: layerPlan, constructor: stepConstructor, peerKey, } = sstep;
|
|
2165
|
+
const { dependencies: deps, dependencyForbiddenFlags: flags, dependencyOnReject: onReject, dependencyDataOnly: dataOnly, layerPlan: layerPlan, constructor: stepConstructor, peerKey, } = sstep;
|
|
1450
2166
|
// const streamInitialCount = sstep._stepOptions.stream?.initialCount;
|
|
1451
2167
|
const dependencyCount = deps.length;
|
|
1452
2168
|
if (dependencyCount === 0) {
|
|
@@ -1455,7 +2171,7 @@ class OperationPlan {
|
|
|
1455
2171
|
for (const possiblyPeer of stepsWithNoDependencies) {
|
|
1456
2172
|
if (possiblyPeer !== step &&
|
|
1457
2173
|
!possiblyPeer.hasSideEffects &&
|
|
1458
|
-
possiblyPeer.layerPlan
|
|
2174
|
+
isPeerLayerPlan(possiblyPeer.layerPlan, layerPlan) &&
|
|
1459
2175
|
possiblyPeer._stepOptions.stream == null &&
|
|
1460
2176
|
possiblyPeer.peerKey === peerKey
|
|
1461
2177
|
// && possiblyPeer._stepOptions.stream?.initialCount === streamInitialCount
|
|
@@ -1472,8 +2188,9 @@ class OperationPlan {
|
|
|
1472
2188
|
}
|
|
1473
2189
|
else if (dependencyCount === 1) {
|
|
1474
2190
|
// Optimized form for steps that have one dependency (extremely common!)
|
|
2191
|
+
const dependencyIndex = 0;
|
|
1475
2192
|
const { ancestry, deferBoundaryDepth } = layerPlan;
|
|
1476
|
-
const dep = deps[
|
|
2193
|
+
const dep = deps[dependencyIndex];
|
|
1477
2194
|
const dl = dep.dependents.length;
|
|
1478
2195
|
if (dl === 1) {
|
|
1479
2196
|
// We're the only dependent; therefore we have no peers (since peers
|
|
@@ -1483,7 +2200,7 @@ class OperationPlan {
|
|
|
1483
2200
|
const minDepth = Math.max(deferBoundaryDepth, dep.layerPlan.depth);
|
|
1484
2201
|
let allPeers = null;
|
|
1485
2202
|
for (const { dependencyIndex: peerDependencyIndex, step: rawPossiblyPeer, } of dep.dependents) {
|
|
1486
|
-
if (peerDependencyIndex !==
|
|
2203
|
+
if (peerDependencyIndex !== dependencyIndex ||
|
|
1487
2204
|
rawPossiblyPeer === step ||
|
|
1488
2205
|
rawPossiblyPeer.hasSideEffects ||
|
|
1489
2206
|
rawPossiblyPeer._stepOptions.stream != null ||
|
|
@@ -1494,12 +2211,13 @@ class OperationPlan {
|
|
|
1494
2211
|
continue;
|
|
1495
2212
|
}
|
|
1496
2213
|
const possiblyPeer = (0, utils_js_1.sudo)(rawPossiblyPeer);
|
|
1497
|
-
const { layerPlan: peerLayerPlan, dependencyForbiddenFlags: peerFlags, dependencyOnReject: peerOnReject, } = possiblyPeer;
|
|
2214
|
+
const { layerPlan: peerLayerPlan, dependencyForbiddenFlags: peerFlags, dependencyOnReject: peerOnReject, dependencyDataOnly: peerDataOnly, } = possiblyPeer;
|
|
1498
2215
|
if (peerLayerPlan.depth >= minDepth &&
|
|
1499
2216
|
possiblyPeer.dependencies.length === dependencyCount &&
|
|
1500
|
-
peerLayerPlan
|
|
1501
|
-
peerFlags[
|
|
1502
|
-
peerOnReject[
|
|
2217
|
+
isPeerLayerPlan(peerLayerPlan, ancestry[peerLayerPlan.depth]) &&
|
|
2218
|
+
peerFlags[dependencyIndex] === flags[dependencyIndex] &&
|
|
2219
|
+
peerOnReject[dependencyIndex] === onReject[dependencyIndex] &&
|
|
2220
|
+
peerDataOnly[dependencyIndex] === dataOnly[dependencyIndex]) {
|
|
1503
2221
|
if (allPeers === null) {
|
|
1504
2222
|
allPeers = [possiblyPeer];
|
|
1505
2223
|
}
|
|
@@ -1548,11 +2266,12 @@ class OperationPlan {
|
|
|
1548
2266
|
continue;
|
|
1549
2267
|
}
|
|
1550
2268
|
const possiblyPeer = (0, utils_js_1.sudo)(rawPossiblyPeer);
|
|
1551
|
-
const { layerPlan: peerLayerPlan, dependencyForbiddenFlags: peerFlags, dependencyOnReject: peerOnReject, dependencies: peerDependencies, } = possiblyPeer;
|
|
2269
|
+
const { layerPlan: peerLayerPlan, dependencyForbiddenFlags: peerFlags, dependencyOnReject: peerOnReject, dependencyDataOnly: peerDataOnly, dependencies: peerDependencies, } = possiblyPeer;
|
|
1552
2270
|
if (peerDependencies.length === dependencyCount &&
|
|
1553
|
-
peerLayerPlan
|
|
1554
|
-
peerFlags[
|
|
1555
|
-
peerOnReject[
|
|
2271
|
+
isPeerLayerPlan(peerLayerPlan, ancestry[peerLayerPlan.depth]) &&
|
|
2272
|
+
peerFlags[dependencyIndex] === flags[dependencyIndex] &&
|
|
2273
|
+
peerOnReject[dependencyIndex] === onReject[dependencyIndex] &&
|
|
2274
|
+
peerDataOnly[dependencyIndex] === dataOnly[dependencyIndex]) {
|
|
1556
2275
|
possiblePeers.push(possiblyPeer);
|
|
1557
2276
|
}
|
|
1558
2277
|
}
|
|
@@ -1569,10 +2288,17 @@ class OperationPlan {
|
|
|
1569
2288
|
outerloop: for (const possiblyPeer of possiblePeers) {
|
|
1570
2289
|
if (possiblyPeer.layerPlan.depth < minDepth)
|
|
1571
2290
|
continue;
|
|
2291
|
+
const speer = (0, utils_js_1.sudo)(possiblyPeer);
|
|
2292
|
+
// PERF: I'm not sure we strictly require this.
|
|
2293
|
+
if (!(0, utils_js_1.arraysMatch)(sstep._refs, speer._refs, (refA, refB) => refA === refB ||
|
|
2294
|
+
this.stepTracker.getStepById(refA) ===
|
|
2295
|
+
this.stepTracker.getStepById(refB))) {
|
|
2296
|
+
continue;
|
|
2297
|
+
}
|
|
1572
2298
|
// We know the final dependency matches and the dependency count
|
|
1573
2299
|
// matches - check the other dependencies match.
|
|
1574
2300
|
for (let i = 0; i < dependencyCount - 1; i++) {
|
|
1575
|
-
if (deps[i] !==
|
|
2301
|
+
if (deps[i] !== speer.dependencies[i]) {
|
|
1576
2302
|
continue outerloop;
|
|
1577
2303
|
}
|
|
1578
2304
|
}
|
|
@@ -1593,7 +2319,7 @@ class OperationPlan {
|
|
|
1593
2319
|
if (isPrepopulatedStep(step)) {
|
|
1594
2320
|
return true;
|
|
1595
2321
|
}
|
|
1596
|
-
if (step[
|
|
2322
|
+
if (step[constants_js_1.$$subroutine] !== null) {
|
|
1597
2323
|
// Don't hoist steps that are the parent of a subroutine
|
|
1598
2324
|
// PERF: we _should_ be able to hoist, but care must be taken. Currently it causes test failures.
|
|
1599
2325
|
return true;
|
|
@@ -1620,15 +2346,19 @@ class OperationPlan {
|
|
|
1620
2346
|
return true;
|
|
1621
2347
|
}
|
|
1622
2348
|
*/
|
|
1623
|
-
if (step.layerPlan.
|
|
2349
|
+
if (step.layerPlan.reason.type === "root") {
|
|
2350
|
+
// There is no higher layerPlan
|
|
2351
|
+
return;
|
|
2352
|
+
}
|
|
2353
|
+
else if (step.layerPlan.reason.type === "combined") {
|
|
2354
|
+
// Cannot hoist out of a combination
|
|
2355
|
+
return;
|
|
2356
|
+
}
|
|
2357
|
+
else if (step.layerPlan.reason.parentLayerPlan.reason.type === "mutationField") {
|
|
1624
2358
|
// Never hoist into a mutation layer
|
|
1625
2359
|
return;
|
|
1626
2360
|
}
|
|
1627
2361
|
switch (step.layerPlan.reason.type) {
|
|
1628
|
-
case "root": {
|
|
1629
|
-
// There is no higher layerPlan
|
|
1630
|
-
return;
|
|
1631
|
-
}
|
|
1632
2362
|
case "subscription":
|
|
1633
2363
|
case "defer": {
|
|
1634
2364
|
// Should be deferred, don't evaluate early (unless it's cheap to do so)
|
|
@@ -1641,23 +2371,28 @@ class OperationPlan {
|
|
|
1641
2371
|
}
|
|
1642
2372
|
}
|
|
1643
2373
|
case "polymorphic": {
|
|
1644
|
-
//
|
|
1645
|
-
if (step.
|
|
2374
|
+
// Only hoist steps that are executed for all the types
|
|
2375
|
+
if (step.polymorphicPaths === null ||
|
|
1646
2376
|
step.polymorphicPaths.size ===
|
|
1647
2377
|
step.layerPlan.reason.polymorphicPaths.size) {
|
|
1648
|
-
// It
|
|
1649
|
-
// NOTE: I have concerns about whether this is safe or not, but I
|
|
1650
|
-
// have not been able to come up with a counterexample that is
|
|
1651
|
-
// unsafe. Should we do so, we should remove this.
|
|
2378
|
+
// It covers all types, try and hoist it.
|
|
1652
2379
|
break;
|
|
1653
2380
|
}
|
|
1654
2381
|
else if (step instanceof index_js_1.__FlagStep) {
|
|
2382
|
+
// Flag step is cheap, try and hoist
|
|
1655
2383
|
break;
|
|
1656
2384
|
}
|
|
1657
2385
|
else {
|
|
1658
2386
|
return;
|
|
1659
2387
|
}
|
|
1660
2388
|
}
|
|
2389
|
+
case "polymorphicPartition": {
|
|
2390
|
+
// Don't want to hoist out of a polymorphic partition
|
|
2391
|
+
// TODO: revisit this, e.g. global unary steps should be hoistable? But
|
|
2392
|
+
// we should only do that if they're cheap, we don't want to run
|
|
2393
|
+
// expensive stuff at a higher level if only certain types need it.
|
|
2394
|
+
return;
|
|
2395
|
+
}
|
|
1661
2396
|
case "subroutine": {
|
|
1662
2397
|
// Should be safe to hoist.
|
|
1663
2398
|
break;
|
|
@@ -1712,51 +2447,31 @@ class OperationPlan {
|
|
|
1712
2447
|
return;
|
|
1713
2448
|
}
|
|
1714
2449
|
// All our checks passed, hoist it.
|
|
1715
|
-
assert.ok(step.layerPlan.parentLayerPlan !== null, "GrafastInternalError<55c8940f-e8ac-4985-8b34-96fc6f81d62d>: A non-root layer plan had no parent?!");
|
|
1716
2450
|
// 1: adjust polymorphicPaths to fit new layerPlan
|
|
1717
2451
|
if (step.layerPlan.reason.type === "polymorphic") {
|
|
1718
2452
|
// PERF: this is cacheable
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
if (
|
|
2453
|
+
let newPolyPaths = new Set();
|
|
2454
|
+
for (const polyPath of step.polymorphicPaths) {
|
|
2455
|
+
const i = polyPath.lastIndexOf(">");
|
|
2456
|
+
if (i > 0) {
|
|
2457
|
+
const newPath = polyPath.slice(0, i);
|
|
2458
|
+
newPolyPaths.add(newPath);
|
|
2459
|
+
}
|
|
2460
|
+
else if (i === 0) {
|
|
2461
|
+
newPolyPaths = null;
|
|
1723
2462
|
break;
|
|
1724
2463
|
}
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
? ancestor.reason
|
|
1728
|
-
.polymorphicPaths
|
|
1729
|
-
: exports.POLYMORPHIC_ROOT_PATHS;
|
|
1730
|
-
const myPaths = [...step.polymorphicPaths];
|
|
1731
|
-
if (parentPolymorphicPaths?.has(myPaths[0])) {
|
|
1732
|
-
// All the others must be valid too
|
|
1733
|
-
}
|
|
1734
|
-
else if (parentPolymorphicPaths === null) {
|
|
1735
|
-
step.polymorphicPaths = null;
|
|
1736
|
-
}
|
|
1737
|
-
else {
|
|
1738
|
-
const layerPaths = [...step.layerPlan.reason.polymorphicPaths];
|
|
1739
|
-
const newPaths = new Set();
|
|
1740
|
-
for (const path of parentPolymorphicPaths) {
|
|
1741
|
-
const prefix = path + ">";
|
|
1742
|
-
const matches = myPaths.filter((p) => p.startsWith(prefix));
|
|
1743
|
-
const layerMatches = layerPaths.filter((p) => p.startsWith(prefix));
|
|
1744
|
-
if (matches.length !== layerMatches.length) {
|
|
1745
|
-
// Can't hoist because it's not used for all polymorphicPaths of this type
|
|
1746
|
-
return;
|
|
1747
|
-
}
|
|
1748
|
-
else if (matches.length > 0) {
|
|
1749
|
-
newPaths.add(path);
|
|
1750
|
-
}
|
|
2464
|
+
else {
|
|
2465
|
+
throw new Error(`GrafastInternalError<42f1c7e7-e544-46d2-81b3-00db11eb5def>: invalid poly path ${polyPath}`);
|
|
1751
2466
|
}
|
|
1752
|
-
step.polymorphicPaths = newPaths;
|
|
1753
2467
|
}
|
|
2468
|
+
step.polymorphicPaths = newPolyPaths;
|
|
1754
2469
|
}
|
|
1755
2470
|
const $subroutine = step.layerPlan.reason.type === "subroutine"
|
|
1756
2471
|
? step.layerPlan.reason.parentStep
|
|
1757
2472
|
: null;
|
|
1758
2473
|
// 2: move it up a layer
|
|
1759
|
-
this.stepTracker.moveStepToLayerPlan(step, step.layerPlan.parentLayerPlan);
|
|
2474
|
+
this.stepTracker.moveStepToLayerPlan(step, step.layerPlan.reason.parentLayerPlan);
|
|
1760
2475
|
// 3: if it's was in a subroutine, the subroutine parent plan needs to list it as a dependency
|
|
1761
2476
|
if ($subroutine) {
|
|
1762
2477
|
// Naughty naughty
|
|
@@ -1783,12 +2498,16 @@ class OperationPlan {
|
|
|
1783
2498
|
case "subscription":
|
|
1784
2499
|
case "defer":
|
|
1785
2500
|
case "polymorphic":
|
|
2501
|
+
case "polymorphicPartition":
|
|
1786
2502
|
case "subroutine":
|
|
1787
2503
|
case "nullableBoundary":
|
|
1788
2504
|
case "listItem": {
|
|
1789
2505
|
// Fine to push lower
|
|
1790
2506
|
break;
|
|
1791
2507
|
}
|
|
2508
|
+
case "combined": {
|
|
2509
|
+
return step;
|
|
2510
|
+
}
|
|
1792
2511
|
case "mutationField": {
|
|
1793
2512
|
// NOTE: It's the user's responsibility to ensure that steps that have
|
|
1794
2513
|
// side effects are marked as such via `step.hasSideEffects = true`.
|
|
@@ -1830,11 +2549,24 @@ class OperationPlan {
|
|
|
1830
2549
|
const layerPlansByParent = this.stepTracker.layerPlansByParentStep.get(step);
|
|
1831
2550
|
if (layerPlansByParent !== undefined) {
|
|
1832
2551
|
for (const layerPlan of layerPlansByParent) {
|
|
1833
|
-
if (layerPlan.parentLayerPlan === step.layerPlan) {
|
|
2552
|
+
if (layerPlan.reason.parentLayerPlan === step.layerPlan) {
|
|
1834
2553
|
return step;
|
|
1835
2554
|
}
|
|
1836
2555
|
else {
|
|
1837
|
-
dependentLayerPlans.add(layerPlan.parentLayerPlan);
|
|
2556
|
+
dependentLayerPlans.add(layerPlan.reason.parentLayerPlan);
|
|
2557
|
+
}
|
|
2558
|
+
}
|
|
2559
|
+
}
|
|
2560
|
+
const layerPlansByDependent = this.stepTracker.layerPlansByDependentStep.get(step);
|
|
2561
|
+
if (layerPlansByDependent !== undefined) {
|
|
2562
|
+
for (const layerPlan of layerPlansByDependent) {
|
|
2563
|
+
for (const parentLayerPlan of layerPlan.reason.parentLayerPlans) {
|
|
2564
|
+
if (parentLayerPlan === step.layerPlan) {
|
|
2565
|
+
return step;
|
|
2566
|
+
}
|
|
2567
|
+
else if ((0, utils_js_1.layerPlanHeirarchyContains)(parentLayerPlan, step.layerPlan)) {
|
|
2568
|
+
dependentLayerPlans.add(parentLayerPlan);
|
|
2569
|
+
}
|
|
1838
2570
|
}
|
|
1839
2571
|
}
|
|
1840
2572
|
}
|
|
@@ -1858,28 +2590,30 @@ class OperationPlan {
|
|
|
1858
2590
|
const paths = [];
|
|
1859
2591
|
let minPathLength = Infinity;
|
|
1860
2592
|
for (const dependentLayerPlan of dependentLayerPlans) {
|
|
1861
|
-
|
|
1862
|
-
const
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
|
|
1866
|
-
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
path.push(lp);
|
|
2593
|
+
const lp = dependentLayerPlan;
|
|
2594
|
+
const childPaths = (0, utils_js_1.pathsFromAncestorToTargetLayerPlan)(step.layerPlan, lp);
|
|
2595
|
+
if (childPaths.length === 0) {
|
|
2596
|
+
throw new Error(`GrafastInternalError<64c07427-4fe2-43c4-9858-272d33bee0b8>: invalid layer plan heirarchy; step ${step} cannot be found from ${dependentLayerPlan}`);
|
|
2597
|
+
}
|
|
2598
|
+
for (const path of childPaths) {
|
|
2599
|
+
paths.push(path);
|
|
2600
|
+
minPathLength = Math.min(path.length, minPathLength);
|
|
1870
2601
|
}
|
|
1871
|
-
paths.push(path);
|
|
1872
|
-
minPathLength = Math.min(path.length, minPathLength);
|
|
1873
2602
|
}
|
|
1874
2603
|
const dependentLayerPlanCount = dependentLayerPlans.size;
|
|
1875
2604
|
let deepest = step.layerPlan;
|
|
1876
|
-
outerloop: for (let i =
|
|
2605
|
+
outerloop: for (let i = minPathLength - 1; i >= 0; i--) {
|
|
1877
2606
|
const expected = paths[0][i];
|
|
1878
2607
|
if (expected.reason.type === "polymorphic") {
|
|
1879
2608
|
// PERF: reconsider
|
|
1880
2609
|
// Let's not pass polymorphic boundaries for now
|
|
1881
2610
|
break;
|
|
1882
2611
|
}
|
|
2612
|
+
if (expected.reason.type === "polymorphicPartition") {
|
|
2613
|
+
// PERF: reconsider
|
|
2614
|
+
// Let's not pass polymorphic boundaries for now
|
|
2615
|
+
break;
|
|
2616
|
+
}
|
|
1883
2617
|
if (expected.reason.type === "subroutine") {
|
|
1884
2618
|
// PERF: reconsider
|
|
1885
2619
|
// Let's not pass subroutine boundaries for now
|
|
@@ -1974,10 +2708,36 @@ class OperationPlan {
|
|
|
1974
2708
|
const winner = stepsAtMinDepth[0];
|
|
1975
2709
|
if (winner.polymorphicPaths !== null) {
|
|
1976
2710
|
const polymorphicPaths = new Set();
|
|
1977
|
-
|
|
1978
|
-
|
|
1979
|
-
|
|
2711
|
+
// If the paths don't match up we must be in a polymorphicPartition and
|
|
2712
|
+
// need to move the winner out of it
|
|
2713
|
+
tryAgain: for (let attempts = 0; attempts < 2; attempts++) {
|
|
2714
|
+
const layerPolymorphicPaths = polymorphicPathsForLayer(winner.layerPlan);
|
|
2715
|
+
// PERF: this string trimming is hideous
|
|
2716
|
+
for (const s of [step, ...equivalentSteps]) {
|
|
2717
|
+
for (const p of s.polymorphicPaths) {
|
|
2718
|
+
let trimmed = p;
|
|
2719
|
+
let i;
|
|
2720
|
+
while (!layerPolymorphicPaths.has(trimmed) &&
|
|
2721
|
+
(i = trimmed.lastIndexOf(">")) >= 0) {
|
|
2722
|
+
if (i === 0) {
|
|
2723
|
+
const reason = winner.layerPlan.reason;
|
|
2724
|
+
if (reason.type === "polymorphicPartition") {
|
|
2725
|
+
// Hoist winner into the polymorphic layer plan, and restart
|
|
2726
|
+
// the loop
|
|
2727
|
+
this.stepTracker.moveStepToLayerPlan(winner, reason.parentLayerPlan);
|
|
2728
|
+
polymorphicPaths.clear();
|
|
2729
|
+
continue tryAgain;
|
|
2730
|
+
}
|
|
2731
|
+
else {
|
|
2732
|
+
throw new Error(`GrafastInternalError<93da1006-3af9-44dd-a54b-5bf6fe3e791c>: ${s} has polymorphic paths ${[...(s.polymorphicPaths ?? [])]}; but ${p} is not in ${[...layerPolymorphicPaths]}.`);
|
|
2733
|
+
}
|
|
2734
|
+
}
|
|
2735
|
+
trimmed = trimmed.slice(0, i);
|
|
2736
|
+
}
|
|
2737
|
+
polymorphicPaths.add(trimmed);
|
|
2738
|
+
}
|
|
1980
2739
|
}
|
|
2740
|
+
break;
|
|
1981
2741
|
}
|
|
1982
2742
|
winner.polymorphicPaths = polymorphicPaths;
|
|
1983
2743
|
}
|
|
@@ -2041,7 +2801,8 @@ class OperationPlan {
|
|
|
2041
2801
|
this.deduplicateStepsProcess(processed, start, dep);
|
|
2042
2802
|
}
|
|
2043
2803
|
}
|
|
2044
|
-
(0, withGlobalLayerPlan_js_1.withGlobalLayerPlan)(step.layerPlan, step.polymorphicPaths,
|
|
2804
|
+
(0, withGlobalLayerPlan_js_1.withGlobalLayerPlan)(step.layerPlan, step.polymorphicPaths, null, // TODO: can we get the operation path when phase === "plan"?
|
|
2805
|
+
this.phase === "plan" ? this.deduplicateStep : this.hoistAndDeduplicate, this, step);
|
|
2045
2806
|
}
|
|
2046
2807
|
/**
|
|
2047
2808
|
* Gives us a chance to replace nearly-duplicate plans with other existing
|
|
@@ -2054,12 +2815,17 @@ class OperationPlan {
|
|
|
2054
2815
|
* former SELECT additional fields, then transform the results back to what
|
|
2055
2816
|
* our child plans would be expecting.
|
|
2056
2817
|
*/
|
|
2057
|
-
deduplicateSteps(
|
|
2818
|
+
deduplicateSteps() {
|
|
2058
2819
|
const start = this.stepTracker.nextStepIdToDeduplicate;
|
|
2059
|
-
|
|
2060
|
-
|
|
2820
|
+
if (start === this.stepTracker.stepCount) {
|
|
2821
|
+
// No action necessary since there are no new steps
|
|
2061
2822
|
return;
|
|
2062
2823
|
}
|
|
2824
|
+
// Then we deduplicate
|
|
2825
|
+
this._deduplicateStepsInner(start, 0);
|
|
2826
|
+
}
|
|
2827
|
+
_deduplicateStepsInner(start, depth) {
|
|
2828
|
+
const end = this.stepTracker.stepCount;
|
|
2063
2829
|
const processed = new Set();
|
|
2064
2830
|
for (let i = start; i < end; i++) {
|
|
2065
2831
|
const step = this.stepTracker.stepById[i];
|
|
@@ -2080,7 +2846,7 @@ class OperationPlan {
|
|
|
2080
2846
|
.map((s) => String(s))
|
|
2081
2847
|
.join(", ")}.`);
|
|
2082
2848
|
}
|
|
2083
|
-
return this.
|
|
2849
|
+
return this._deduplicateStepsInner(end, depth + 1);
|
|
2084
2850
|
}
|
|
2085
2851
|
}
|
|
2086
2852
|
hoistAndDeduplicate(step) {
|
|
@@ -2204,7 +2970,7 @@ class OperationPlan {
|
|
|
2204
2970
|
for (const dependent of $flag.dependents) {
|
|
2205
2971
|
const { step, dependencyIndex } = dependent;
|
|
2206
2972
|
const $dependent = (0, utils_js_1.sudo)(step);
|
|
2207
|
-
const inlineDetails = $flag.inline($dependent.
|
|
2973
|
+
const inlineDetails = $flag.inline($dependent._getDepOptions(dependencyIndex));
|
|
2208
2974
|
if (inlineDetails === null) {
|
|
2209
2975
|
continue flagLoop;
|
|
2210
2976
|
}
|
|
@@ -2217,11 +2983,13 @@ class OperationPlan {
|
|
|
2217
2983
|
}
|
|
2218
2984
|
// All of them pass the check, let's inline them
|
|
2219
2985
|
for (const todo of toInline) {
|
|
2220
|
-
const { $dependent, dependencyIndex, inlineDetails: { onReject, acceptFlags =
|
|
2986
|
+
const { $dependent, dependencyIndex, inlineDetails: { onReject, acceptFlags = constants_js_1.DEFAULT_ACCEPT_FLAGS, dataOnly = false, }, } = todo;
|
|
2221
2987
|
(0, utils_js_1.writeableArray)($dependent.dependencyOnReject)[dependencyIndex] =
|
|
2222
2988
|
onReject;
|
|
2989
|
+
(0, utils_js_1.writeableArray)($dependent.dependencyDataOnly)[dependencyIndex] =
|
|
2990
|
+
dataOnly;
|
|
2223
2991
|
(0, utils_js_1.writeableArray)($dependent.dependencyForbiddenFlags)[dependencyIndex] =
|
|
2224
|
-
|
|
2992
|
+
constants_js_1.ALL_FLAGS & ~acceptFlags;
|
|
2225
2993
|
}
|
|
2226
2994
|
const $flagDep = (0, utils_js_1.sudo)($flag).dependencies[0];
|
|
2227
2995
|
this.stepTracker.replaceStep($flag, $flagDep);
|
|
@@ -2234,6 +3002,11 @@ class OperationPlan {
|
|
|
2234
3002
|
for (const step of this.stepTracker.activeSteps) {
|
|
2235
3003
|
const wasLocked = index_js_1.isDev && (0, lock_js_1.unlock)(step);
|
|
2236
3004
|
step.finalize();
|
|
3005
|
+
if (step._stepOptions.stream) {
|
|
3006
|
+
// (Potentially) streamed steps aren't sync and safe, we need to
|
|
3007
|
+
// iterate them expensively
|
|
3008
|
+
step.isSyncAndSafe = false;
|
|
3009
|
+
}
|
|
2237
3010
|
if (wasLocked)
|
|
2238
3011
|
(0, lock_js_1.lock)(step);
|
|
2239
3012
|
(0, step_js_1.assertFinalized)(step);
|
|
@@ -2250,6 +3023,9 @@ class OperationPlan {
|
|
|
2250
3023
|
const ensurePlanAvailableInLayer = (dep, layerPlan) => {
|
|
2251
3024
|
let currentLayerPlan = layerPlan;
|
|
2252
3025
|
while (dep.layerPlan !== currentLayerPlan) {
|
|
3026
|
+
if (currentLayerPlan.reason.type === "root") {
|
|
3027
|
+
throw new Error(`GrafastInternalError<7f3ce201-810c-4639-8e69-f44a95221c6d>: reached root whilst ensuring ${dep} is available in ${layerPlan}`);
|
|
3028
|
+
}
|
|
2253
3029
|
if (currentLayerPlan.copyStepIds.includes(dep.id)) {
|
|
2254
3030
|
break;
|
|
2255
3031
|
}
|
|
@@ -2261,21 +3037,208 @@ class OperationPlan {
|
|
|
2261
3037
|
targetStep._isUnaryLocked = true;
|
|
2262
3038
|
}
|
|
2263
3039
|
currentLayerPlan.copyStepIds.push(dep.id);
|
|
2264
|
-
currentLayerPlan
|
|
3040
|
+
if (currentLayerPlan.reason.type === "combined") {
|
|
3041
|
+
const prev = currentLayerPlan;
|
|
3042
|
+
currentLayerPlan = null;
|
|
3043
|
+
// Figure out which of our parent layer plans contains the step
|
|
3044
|
+
for (const parentLayerPlan of prev.reason.parentLayerPlans) {
|
|
3045
|
+
if (dep.layerPlan === parentLayerPlan) {
|
|
3046
|
+
currentLayerPlan = parentLayerPlan;
|
|
3047
|
+
break;
|
|
3048
|
+
}
|
|
3049
|
+
else if ((0, utils_js_1.layerPlanHeirarchyContains)(parentLayerPlan, dep.layerPlan)) {
|
|
3050
|
+
ensurePlanAvailableInLayer(dep, parentLayerPlan);
|
|
3051
|
+
}
|
|
3052
|
+
}
|
|
3053
|
+
if (currentLayerPlan == null) {
|
|
3054
|
+
return;
|
|
3055
|
+
}
|
|
3056
|
+
}
|
|
3057
|
+
else {
|
|
3058
|
+
currentLayerPlan = currentLayerPlan.reason.parentLayerPlan;
|
|
3059
|
+
}
|
|
2265
3060
|
if (!currentLayerPlan) {
|
|
2266
3061
|
throw new Error(`GrafastInternalError<8c1640b9-fa3c-440d-99e5-7693d0d7e5d1>: could not find layer plan for '${dep}' in chain from layer plan ${layerPlan}`);
|
|
2267
3062
|
}
|
|
2268
3063
|
}
|
|
2269
3064
|
};
|
|
3065
|
+
// Track exactly which steps are in which layer plans
|
|
3066
|
+
const phaseTransitionLayerPlans = new Set();
|
|
3067
|
+
const combinedLayerPlans = new Set();
|
|
3068
|
+
const childrenByLayerPlan = new Map();
|
|
3069
|
+
const addParent = (lp, parent) => {
|
|
3070
|
+
let list = childrenByLayerPlan.get(parent);
|
|
3071
|
+
if (!list) {
|
|
3072
|
+
list = [];
|
|
3073
|
+
childrenByLayerPlan.set(parent, list);
|
|
3074
|
+
}
|
|
3075
|
+
list.push(lp);
|
|
3076
|
+
};
|
|
2270
3077
|
for (const layerPlan of this.stepTracker.layerPlans) {
|
|
2271
3078
|
if (!layerPlan) {
|
|
2272
3079
|
continue;
|
|
2273
3080
|
}
|
|
3081
|
+
if ((0, utils_js_1.isPhaseTransitionLayerPlan)(layerPlan)) {
|
|
3082
|
+
phaseTransitionLayerPlans.add(layerPlan);
|
|
3083
|
+
}
|
|
3084
|
+
if (layerPlan.reason.type === "combined") {
|
|
3085
|
+
combinedLayerPlans.add(layerPlan);
|
|
3086
|
+
}
|
|
2274
3087
|
layerPlan.steps = [];
|
|
3088
|
+
switch (layerPlan.reason.type) {
|
|
3089
|
+
case "root":
|
|
3090
|
+
break;
|
|
3091
|
+
case "combined": {
|
|
3092
|
+
for (const parent of layerPlan.reason.parentLayerPlans) {
|
|
3093
|
+
addParent(layerPlan, parent);
|
|
3094
|
+
}
|
|
3095
|
+
break;
|
|
3096
|
+
}
|
|
3097
|
+
default: {
|
|
3098
|
+
addParent(layerPlan, layerPlan.reason.parentLayerPlan);
|
|
3099
|
+
}
|
|
3100
|
+
}
|
|
3101
|
+
}
|
|
3102
|
+
// Go through all the phase transition layer plans and populate their
|
|
3103
|
+
// "outOfBoundsLayerPlanIds". These are "external inputs" to the subgraph
|
|
3104
|
+
// of layer plans starting at the phase transition layer plan. The external
|
|
3105
|
+
// inputs will always be parent nodes of combined layer plans that are
|
|
3106
|
+
// descendents of the phase transition layer plan.
|
|
3107
|
+
for (const phaseTransitionNode of phaseTransitionLayerPlans) {
|
|
3108
|
+
const descendents = getDescendents(phaseTransitionNode, childrenByLayerPlan);
|
|
3109
|
+
for (const combo of combinedLayerPlans) {
|
|
3110
|
+
if (descendents.has(combo)) {
|
|
3111
|
+
for (const parent of combo.reason.parentLayerPlans) {
|
|
3112
|
+
if (!descendents.has(parent)) {
|
|
3113
|
+
phaseTransitionNode.outOfBoundsLayerPlanIds.add(parent.id);
|
|
3114
|
+
}
|
|
3115
|
+
}
|
|
3116
|
+
}
|
|
3117
|
+
}
|
|
2275
3118
|
}
|
|
2276
3119
|
for (const step of this.stepTracker.activeSteps) {
|
|
2277
3120
|
step.layerPlan.steps.push(step);
|
|
2278
3121
|
}
|
|
3122
|
+
// For each layer plan, track the polymorphic types, and mark the steps in
|
|
3123
|
+
// that layer plan as selective if they don't possess the same number of
|
|
3124
|
+
// poly paths.
|
|
3125
|
+
const polyPathsByLayerPlan = new Map();
|
|
3126
|
+
const processPolymorphicPathsInLayerPlan = (layerPlan) => {
|
|
3127
|
+
const existing = polyPathsByLayerPlan.get(layerPlan);
|
|
3128
|
+
if (existing) {
|
|
3129
|
+
return existing;
|
|
3130
|
+
}
|
|
3131
|
+
const parentPolyPaths = layerPlan.reason.type === "root"
|
|
3132
|
+
? EMPTY_SET
|
|
3133
|
+
: layerPlan.reason.type === "combined"
|
|
3134
|
+
? new Set(layerPlan.reason.parentLayerPlans.flatMap((p) => [
|
|
3135
|
+
...processPolymorphicPathsInLayerPlan(p),
|
|
3136
|
+
]))
|
|
3137
|
+
: processPolymorphicPathsInLayerPlan(layerPlan.reason.parentLayerPlan);
|
|
3138
|
+
let polyPaths;
|
|
3139
|
+
const reason = layerPlan.reason;
|
|
3140
|
+
switch (reason.type) {
|
|
3141
|
+
case "root":
|
|
3142
|
+
case "nullableBoundary":
|
|
3143
|
+
case "listItem":
|
|
3144
|
+
case "defer":
|
|
3145
|
+
case "subroutine":
|
|
3146
|
+
case "subscription":
|
|
3147
|
+
case "mutationField": {
|
|
3148
|
+
polyPaths = parentPolyPaths;
|
|
3149
|
+
break;
|
|
3150
|
+
}
|
|
3151
|
+
case "combined": {
|
|
3152
|
+
// Resolve redundant combinations now plans have been deduped/optimized
|
|
3153
|
+
for (const combo of layerPlan.combinations) {
|
|
3154
|
+
const { sources } = combo;
|
|
3155
|
+
let newSources = null;
|
|
3156
|
+
const l = sources.length;
|
|
3157
|
+
// Deliberately miss the first (index=0) item
|
|
3158
|
+
for (let i = l - 1; i > 0; i--) {
|
|
3159
|
+
const source = sources[i];
|
|
3160
|
+
const { layerPlanId, stepId } = source;
|
|
3161
|
+
for (let j = i - 1; j >= 0; j--) {
|
|
3162
|
+
const otherSource = sources[j];
|
|
3163
|
+
if (otherSource.layerPlanId === layerPlanId &&
|
|
3164
|
+
otherSource.stepId === stepId) {
|
|
3165
|
+
if (!newSources)
|
|
3166
|
+
newSources = [...sources];
|
|
3167
|
+
// Duplicate! Remove it!
|
|
3168
|
+
newSources.splice(i, 1);
|
|
3169
|
+
break;
|
|
3170
|
+
}
|
|
3171
|
+
}
|
|
3172
|
+
}
|
|
3173
|
+
if (newSources) {
|
|
3174
|
+
combo.sources = newSources;
|
|
3175
|
+
}
|
|
3176
|
+
}
|
|
3177
|
+
// Populate our final polyPaths
|
|
3178
|
+
const newPolyPaths = new Set();
|
|
3179
|
+
for (const lp of reason.parentLayerPlans) {
|
|
3180
|
+
const paths = processPolymorphicPathsInLayerPlan(lp);
|
|
3181
|
+
for (const p of paths) {
|
|
3182
|
+
newPolyPaths.add(p);
|
|
3183
|
+
}
|
|
3184
|
+
}
|
|
3185
|
+
polyPaths = newPolyPaths;
|
|
3186
|
+
// Check that everything is sensible
|
|
3187
|
+
if (index_js_1.isDev) {
|
|
3188
|
+
// Let's check we're being sensible - each poly path should only be
|
|
3189
|
+
// sourceable from one step, and these steps should only have poly
|
|
3190
|
+
// paths that we understand
|
|
3191
|
+
for (const { sources } of layerPlan.combinations) {
|
|
3192
|
+
const overlapCheck = new Map();
|
|
3193
|
+
for (const source of sources) {
|
|
3194
|
+
const { layerPlanId, stepId } = source;
|
|
3195
|
+
const step = this.stepTracker.getStepById(stepId);
|
|
3196
|
+
const paths = step.polymorphicPaths;
|
|
3197
|
+
if (paths === null) {
|
|
3198
|
+
throw new Error(`GrafastInternalError<170ac297-e7b2-4d15-bf3b-1c0c50a0da40>: Step ${step} shouldn't be used in a combo because it's valid in all polymorphic paths`);
|
|
3199
|
+
}
|
|
3200
|
+
for (const p of paths) {
|
|
3201
|
+
if (overlapCheck.has(p)) {
|
|
3202
|
+
const sourceLp = this.stepTracker.layerPlans[layerPlanId];
|
|
3203
|
+
const dup = overlapCheck.get(p);
|
|
3204
|
+
const dupStep = this.stepTracker.getStepById(dup.stepId);
|
|
3205
|
+
const dupLp = this.stepTracker.layerPlans[dup.layerPlanId];
|
|
3206
|
+
throw new Error(`GrafastInternalError<f2d906fe-7f52-4234-a172-42691613f733>: Overlapping path ${p} in ${layerPlan} found; sourced from both ${step} in ${sourceLp} and ${dupStep} in ${dupLp}`);
|
|
3207
|
+
}
|
|
3208
|
+
if (!newPolyPaths.has(p)) {
|
|
3209
|
+
throw new Error(`GrafastInternalError<c697df8f-e194-42f0-9f73-c510bc2e9b74>: path ${p} in ${layerPlan} not expected; sourced from ${step}`);
|
|
3210
|
+
}
|
|
3211
|
+
overlapCheck.set(p, source);
|
|
3212
|
+
}
|
|
3213
|
+
}
|
|
3214
|
+
}
|
|
3215
|
+
}
|
|
3216
|
+
break;
|
|
3217
|
+
}
|
|
3218
|
+
case "polymorphic":
|
|
3219
|
+
case "polymorphicPartition": {
|
|
3220
|
+
polyPaths = reason.polymorphicPaths;
|
|
3221
|
+
break;
|
|
3222
|
+
}
|
|
3223
|
+
default: {
|
|
3224
|
+
const never = reason;
|
|
3225
|
+
throw new Error(`GrafastInternalError<032aef95-97d8-4900-95f7-edc34a5d3703>: unexpected layer plan reason ${(0, inspect_js_1.inspect)(never)}`);
|
|
3226
|
+
}
|
|
3227
|
+
}
|
|
3228
|
+
for (const step of layerPlan.steps) {
|
|
3229
|
+
if (step.polymorphicPaths !== null &&
|
|
3230
|
+
step.polymorphicPaths.size !== polyPaths.size) {
|
|
3231
|
+
step._isSelectiveStep = true;
|
|
3232
|
+
}
|
|
3233
|
+
}
|
|
3234
|
+
polyPathsByLayerPlan.set(layerPlan, polyPaths);
|
|
3235
|
+
return polyPaths;
|
|
3236
|
+
};
|
|
3237
|
+
for (const layerPlan of this.stepTracker.layerPlans) {
|
|
3238
|
+
if (!layerPlan)
|
|
3239
|
+
continue;
|
|
3240
|
+
processPolymorphicPathsInLayerPlan(layerPlan);
|
|
3241
|
+
}
|
|
2279
3242
|
for (const layerPlan of this.stepTracker.layerPlans) {
|
|
2280
3243
|
if (!layerPlan) {
|
|
2281
3244
|
continue;
|
|
@@ -2284,7 +3247,25 @@ class OperationPlan {
|
|
|
2284
3247
|
const sideEffectSteps = layerPlan.pendingSteps.filter((s) => s.hasSideEffects);
|
|
2285
3248
|
const pending = new Set(layerPlan.pendingSteps);
|
|
2286
3249
|
const processed = new Set();
|
|
2287
|
-
|
|
3250
|
+
const latestSideEffectStepByPolymorphicPath = new Map();
|
|
3251
|
+
const getLatestSideEffectStepFor = (step) => {
|
|
3252
|
+
const polymorphicPaths = [...(step.polymorphicPaths ?? [""])];
|
|
3253
|
+
const latestSideEffectStep = latestSideEffectStepByPolymorphicPath.get(polymorphicPaths[0]);
|
|
3254
|
+
for (let i = 1, l = polymorphicPaths.length; i < l; i++) {
|
|
3255
|
+
const se = latestSideEffectStepByPolymorphicPath.get(polymorphicPaths[i]);
|
|
3256
|
+
if (se !== latestSideEffectStep) {
|
|
3257
|
+
throw new Error(`You shouldn't have side effects in polymorphic positions; ${step} exists in ${polymorphicPaths} but these positions have mixed side effects (${latestSideEffectStep} @ ${polymorphicPaths[0]}, ${se} @ ${polymorphicPaths[i]})`);
|
|
3258
|
+
}
|
|
3259
|
+
}
|
|
3260
|
+
return latestSideEffectStep;
|
|
3261
|
+
};
|
|
3262
|
+
const setLatestSideEffectStep = (step) => {
|
|
3263
|
+
const polymorphicPaths = [...(step.polymorphicPaths ?? [""])];
|
|
3264
|
+
// Store this side effect for use from now on
|
|
3265
|
+
for (let i = 0, l = polymorphicPaths.length; i < l; i++) {
|
|
3266
|
+
latestSideEffectStepByPolymorphicPath.set(polymorphicPaths[i], step);
|
|
3267
|
+
}
|
|
3268
|
+
};
|
|
2288
3269
|
const processSideEffectPlan = (step) => {
|
|
2289
3270
|
if (processed.has(step) || isPrepopulatedStep(step)) {
|
|
2290
3271
|
return;
|
|
@@ -2317,12 +3298,13 @@ class OperationPlan {
|
|
|
2317
3298
|
for (const dep of rest) {
|
|
2318
3299
|
processSideEffectPlan(dep);
|
|
2319
3300
|
}
|
|
2320
|
-
|
|
3301
|
+
const latestSideEffectStep = getLatestSideEffectStepFor(step);
|
|
3302
|
+
if (latestSideEffectStep !== undefined &&
|
|
2321
3303
|
!(0, utils_js_1.stepADependsOnStepB)(sstep, latestSideEffectStep)) {
|
|
2322
3304
|
sstep.implicitSideEffectStep = latestSideEffectStep;
|
|
2323
3305
|
}
|
|
2324
3306
|
if (step.hasSideEffects) {
|
|
2325
|
-
|
|
3307
|
+
setLatestSideEffectStep(step);
|
|
2326
3308
|
}
|
|
2327
3309
|
const phase = /*#__INLINE__*/ newLayerPlanPhase();
|
|
2328
3310
|
phase.checkTimeout = true;
|
|
@@ -2359,11 +3341,14 @@ class OperationPlan {
|
|
|
2359
3341
|
processed.add(step);
|
|
2360
3342
|
pending.delete(step);
|
|
2361
3343
|
const sstep = (0, utils_js_1.sudo)(step);
|
|
2362
|
-
|
|
3344
|
+
const latestSideEffectStep = getLatestSideEffectStepFor(step);
|
|
3345
|
+
if (latestSideEffectStep !== undefined &&
|
|
2363
3346
|
!(0, utils_js_1.stepADependsOnStepB)(sstep, latestSideEffectStep)) {
|
|
2364
3347
|
sstep.implicitSideEffectStep = latestSideEffectStep;
|
|
2365
3348
|
}
|
|
2366
|
-
if (step.isSyncAndSafe &&
|
|
3349
|
+
if (step.isSyncAndSafe &&
|
|
3350
|
+
(0, step_js_1.isUnbatchedStep)(step) &&
|
|
3351
|
+
isSafeForUnbatched(step)) {
|
|
2367
3352
|
if (phase.unbatchedSyncAndSafeSteps !== undefined) {
|
|
2368
3353
|
phase.unbatchedSyncAndSafeSteps.push({
|
|
2369
3354
|
step,
|
|
@@ -2398,7 +3383,8 @@ class OperationPlan {
|
|
|
2398
3383
|
processed.add(step);
|
|
2399
3384
|
pending.delete(step);
|
|
2400
3385
|
const sstep = (0, utils_js_1.sudo)(step);
|
|
2401
|
-
|
|
3386
|
+
const latestSideEffectStep = getLatestSideEffectStepFor(step);
|
|
3387
|
+
if (latestSideEffectStep !== undefined &&
|
|
2402
3388
|
!(0, utils_js_1.stepADependsOnStepB)(sstep, latestSideEffectStep)) {
|
|
2403
3389
|
sstep.implicitSideEffectStep = latestSideEffectStep;
|
|
2404
3390
|
}
|
|
@@ -2464,7 +3450,15 @@ class OperationPlan {
|
|
|
2464
3450
|
// don't need to actually scale it up/down.
|
|
2465
3451
|
//
|
|
2466
3452
|
// If parentSideEffectStep exists then parentLayerPlan must exist.
|
|
2467
|
-
|
|
3453
|
+
if (layerPlan.reason.type === "root") {
|
|
3454
|
+
// No action
|
|
3455
|
+
}
|
|
3456
|
+
else if (layerPlan.reason.type === "combined") {
|
|
3457
|
+
throw new Error(`GrafastInternalError<26f6b639-637b-4db5-980b-294697317e35>: combined layer plan ${layerPlan} is not permitted to reference side effects`);
|
|
3458
|
+
}
|
|
3459
|
+
else {
|
|
3460
|
+
ensurePlanAvailableInLayer($sideEffect, layerPlan.reason.parentLayerPlan);
|
|
3461
|
+
}
|
|
2468
3462
|
}
|
|
2469
3463
|
// Copy polymorphic parentStepId
|
|
2470
3464
|
if (layerPlan.reason.type === "polymorphic") {
|
|
@@ -2474,17 +3468,31 @@ class OperationPlan {
|
|
|
2474
3468
|
// Ensure list is accessible in parent layerPlan
|
|
2475
3469
|
if (layerPlan.reason.type === "listItem") {
|
|
2476
3470
|
const parentStep = layerPlan.reason.parentStep;
|
|
2477
|
-
ensurePlanAvailableInLayer(parentStep, layerPlan.parentLayerPlan);
|
|
3471
|
+
ensurePlanAvailableInLayer(parentStep, layerPlan.reason.parentLayerPlan);
|
|
2478
3472
|
const stream = layerPlan.reason.stream;
|
|
2479
3473
|
if (stream != null) {
|
|
2480
3474
|
if (stream.initialCountStepId) {
|
|
2481
|
-
ensurePlanAvailableInLayer(this.stepTracker.getStepById(stream.initialCountStepId), layerPlan.parentLayerPlan);
|
|
3475
|
+
ensurePlanAvailableInLayer(this.stepTracker.getStepById(stream.initialCountStepId), layerPlan.reason.parentLayerPlan);
|
|
2482
3476
|
}
|
|
2483
3477
|
if (stream.ifStepId) {
|
|
2484
|
-
ensurePlanAvailableInLayer(this.stepTracker.getStepById(stream.ifStepId), layerPlan.parentLayerPlan);
|
|
3478
|
+
ensurePlanAvailableInLayer(this.stepTracker.getStepById(stream.ifStepId), layerPlan.reason.parentLayerPlan);
|
|
2485
3479
|
}
|
|
2486
3480
|
if (stream.labelStepId) {
|
|
2487
|
-
ensurePlanAvailableInLayer(this.stepTracker.getStepById(stream.labelStepId), layerPlan.parentLayerPlan);
|
|
3481
|
+
ensurePlanAvailableInLayer(this.stepTracker.getStepById(stream.labelStepId), layerPlan.reason.parentLayerPlan);
|
|
3482
|
+
}
|
|
3483
|
+
}
|
|
3484
|
+
}
|
|
3485
|
+
if (layerPlan.reason.type === "combined") {
|
|
3486
|
+
// Loop through combinations and ensure source step is available in parent layer plan
|
|
3487
|
+
for (const combo of layerPlan.combinations) {
|
|
3488
|
+
for (const source of combo.sources) {
|
|
3489
|
+
const { stepId, layerPlanId } = source;
|
|
3490
|
+
const sourceLayerPlan = layerPlan.reason.parentLayerPlans.find((p) => p.id === layerPlanId);
|
|
3491
|
+
if (!sourceLayerPlan) {
|
|
3492
|
+
throw new Error(`GrafastInternalError<86d15f1e-7ec8-4095-869a-548daa2cea0e>: Could not find the parent layer plan ${layerPlanId} of ${layerPlan}`);
|
|
3493
|
+
}
|
|
3494
|
+
const step = this.stepTracker.getStepById(stepId);
|
|
3495
|
+
ensurePlanAvailableInLayer(step, sourceLayerPlan);
|
|
2488
3496
|
}
|
|
2489
3497
|
}
|
|
2490
3498
|
}
|
|
@@ -2540,6 +3548,7 @@ class OperationPlan {
|
|
|
2540
3548
|
dependencyIds: sstep.dependencies.map((d) => d.id),
|
|
2541
3549
|
dependencyForbiddenFlags: sstep.dependencyForbiddenFlags.slice(),
|
|
2542
3550
|
dependencyOnReject: sstep.dependencyOnReject.map((or) => or ? String(or) : or),
|
|
3551
|
+
dependencyDataOnly: sstep.dependencyDataOnly.slice(),
|
|
2543
3552
|
polymorphicPaths: step.polymorphicPaths
|
|
2544
3553
|
? [...step.polymorphicPaths]
|
|
2545
3554
|
: undefined,
|
|
@@ -2558,7 +3567,8 @@ class OperationPlan {
|
|
|
2558
3567
|
unbatchedStepIds: phase.unbatchedSyncAndSafeSteps?.map((s) => s.step.id),
|
|
2559
3568
|
};
|
|
2560
3569
|
}
|
|
2561
|
-
function printBucketReason(
|
|
3570
|
+
function printBucketReason(layerPlan) {
|
|
3571
|
+
const { reason } = layerPlan;
|
|
2562
3572
|
switch (reason.type) {
|
|
2563
3573
|
case "root": {
|
|
2564
3574
|
const { type } = reason;
|
|
@@ -2588,15 +3598,37 @@ class OperationPlan {
|
|
|
2588
3598
|
const { type, typeNames, parentStep, polymorphicPaths } = reason;
|
|
2589
3599
|
return {
|
|
2590
3600
|
type,
|
|
2591
|
-
typeNames,
|
|
3601
|
+
typeNames: [...typeNames],
|
|
2592
3602
|
parentStepId: parentStep.id,
|
|
2593
3603
|
polymorphicPaths: [...polymorphicPaths],
|
|
2594
3604
|
};
|
|
2595
3605
|
}
|
|
3606
|
+
case "polymorphicPartition": {
|
|
3607
|
+
const { type, typeNames, polymorphicPaths } = reason;
|
|
3608
|
+
return {
|
|
3609
|
+
type,
|
|
3610
|
+
typeNames: [...typeNames],
|
|
3611
|
+
polymorphicPaths: [...polymorphicPaths],
|
|
3612
|
+
};
|
|
3613
|
+
}
|
|
2596
3614
|
case "subroutine": {
|
|
2597
3615
|
const { type, parentStep } = reason;
|
|
2598
3616
|
return { type, parentStepId: parentStep.id };
|
|
2599
3617
|
}
|
|
3618
|
+
case "combined": {
|
|
3619
|
+
const { type, parentLayerPlans } = reason;
|
|
3620
|
+
return {
|
|
3621
|
+
type,
|
|
3622
|
+
parentLayerPlanIds: [...parentLayerPlans].map((l) => l.id),
|
|
3623
|
+
combinations: layerPlan.combinations.map((c) => ({
|
|
3624
|
+
sources: c.sources.map((f) => ({
|
|
3625
|
+
layerPlanId: f.layerPlanId,
|
|
3626
|
+
stepId: f.stepId,
|
|
3627
|
+
})),
|
|
3628
|
+
targetStepId: c.targetStepId,
|
|
3629
|
+
})),
|
|
3630
|
+
};
|
|
3631
|
+
}
|
|
2600
3632
|
default: {
|
|
2601
3633
|
const never = reason;
|
|
2602
3634
|
throw new Error(`Failed to process layer plan reason ${(0, inspect_js_1.inspect)(never)}`);
|
|
@@ -2604,21 +3636,22 @@ class OperationPlan {
|
|
|
2604
3636
|
}
|
|
2605
3637
|
}
|
|
2606
3638
|
function printBucket(lp) {
|
|
2607
|
-
lp.reason;
|
|
2608
3639
|
return {
|
|
2609
3640
|
id: lp.id,
|
|
2610
|
-
reason: printBucketReason(lp
|
|
3641
|
+
reason: printBucketReason(lp),
|
|
2611
3642
|
parentSideEffectStepId: lp.parentSideEffectStep?.id ?? null,
|
|
2612
3643
|
copyStepIds: lp.copyStepIds,
|
|
2613
3644
|
phases: lp.phases.map(printPhase),
|
|
2614
3645
|
steps: lp.steps.map(printStep),
|
|
2615
|
-
|
|
3646
|
+
childIds: lp.children.map((c) => c.id),
|
|
2616
3647
|
rootStepId: lp.rootStep ? lp.rootStep.id : null,
|
|
2617
3648
|
};
|
|
2618
3649
|
}
|
|
2619
3650
|
return {
|
|
2620
3651
|
version: "v1",
|
|
2621
|
-
|
|
3652
|
+
buckets: this.stepTracker.layerPlans
|
|
3653
|
+
.filter((b) => b != null)
|
|
3654
|
+
.map(printBucket),
|
|
2622
3655
|
};
|
|
2623
3656
|
}
|
|
2624
3657
|
finishSubroutine(subroutineStep, layerPlan) {
|
|
@@ -2672,16 +3705,25 @@ class OperationPlan {
|
|
|
2672
3705
|
* need to regenerate it on future calls, significantly reducing the load on
|
|
2673
3706
|
* deduplication later.
|
|
2674
3707
|
*
|
|
2675
|
-
* Note: automatically extends the cached step into other (relevant)
|
|
2676
|
-
* polymorphic paths; if this shouldn't be the case then don't use cacheStep
|
|
2677
|
-
* and instead rely on deduplication as usual.
|
|
2678
|
-
*
|
|
2679
3708
|
* @experimental
|
|
2680
3709
|
*/
|
|
2681
3710
|
cacheStep(ownerStep, actionKey, cacheKey, cb) {
|
|
2682
3711
|
const layerPlan = (0, withGlobalLayerPlan_js_1.currentLayerPlan)();
|
|
3712
|
+
let cache = this._cacheStepStoreByActionKeyByLayerPlan.get(layerPlan.id);
|
|
3713
|
+
if (!cache) {
|
|
3714
|
+
cache = Object.create(null);
|
|
3715
|
+
this._cacheStepStoreByActionKeyByLayerPlan.set(layerPlan.id, cache);
|
|
3716
|
+
}
|
|
3717
|
+
return this._cacheStep(cache, ownerStep, actionKey, cacheKey, cb);
|
|
3718
|
+
}
|
|
3719
|
+
/** @internal */
|
|
3720
|
+
cacheImmutableStep(actionKey, cacheKey /* Anything suitable to be the key in a Map */, cb) {
|
|
3721
|
+
const cache = this._immutableCacheStepStoreAndActionKey;
|
|
3722
|
+
return this._cacheStep(cache, this.variableValuesStep, actionKey, cacheKey, cb);
|
|
3723
|
+
}
|
|
3724
|
+
_cacheStep(store, ownerStep, actionKey, cacheKey /* Anything suitable to be the key in a Map */, cb) {
|
|
2683
3725
|
const paths = (0, withGlobalLayerPlan_js_1.currentPolymorphicPaths)();
|
|
2684
|
-
const cache = (
|
|
3726
|
+
const cache = (store[`${actionKey}|${ownerStep.id}|${paths == null ? "" : [...paths].join(",")}`] ??= new Map());
|
|
2685
3727
|
const cacheIt = () => {
|
|
2686
3728
|
const stepToCache = cb();
|
|
2687
3729
|
if (!(stepToCache instanceof index_js_1.Step)) {
|
|
@@ -2696,14 +3738,6 @@ class OperationPlan {
|
|
|
2696
3738
|
const cachedStepId = cache.get(cacheKey);
|
|
2697
3739
|
const cachedStep = this.stepTracker.stepById[cachedStepId];
|
|
2698
3740
|
if (cachedStep) {
|
|
2699
|
-
// Fix poly paths
|
|
2700
|
-
if (paths && cachedStep.polymorphicPaths) {
|
|
2701
|
-
const polymorphicPaths = new Set([
|
|
2702
|
-
...cachedStep.polymorphicPaths,
|
|
2703
|
-
...paths,
|
|
2704
|
-
]);
|
|
2705
|
-
cachedStep.polymorphicPaths = polymorphicPaths;
|
|
2706
|
-
}
|
|
2707
3741
|
return cachedStep;
|
|
2708
3742
|
}
|
|
2709
3743
|
else {
|
|
@@ -2715,10 +3749,10 @@ class OperationPlan {
|
|
|
2715
3749
|
* from setting hasSideEffects on an ExecutableStep, among other places.
|
|
2716
3750
|
*/
|
|
2717
3751
|
resetCache() {
|
|
2718
|
-
this.
|
|
3752
|
+
this._cacheStepStoreByActionKeyByLayerPlan.clear();
|
|
2719
3753
|
}
|
|
2720
3754
|
withRootLayerPlan(cb) {
|
|
2721
|
-
return (0, withGlobalLayerPlan_js_1.withGlobalLayerPlan)(this.rootLayerPlan, exports.POLYMORPHIC_ROOT_PATHS, cb);
|
|
3755
|
+
return (0, withGlobalLayerPlan_js_1.withGlobalLayerPlan)(this.rootLayerPlan, exports.POLYMORPHIC_ROOT_PATHS, null, cb);
|
|
2722
3756
|
}
|
|
2723
3757
|
}
|
|
2724
3758
|
exports.OperationPlan = OperationPlan;
|
|
@@ -2832,4 +3866,96 @@ function throwNoNewStepsError(operationPlan, actionDescription, step, previousSt
|
|
|
2832
3866
|
.map((s) => String(s))
|
|
2833
3867
|
.join(", ")}`);
|
|
2834
3868
|
}
|
|
3869
|
+
function isSafeForUnbatched(step) {
|
|
3870
|
+
// Never run (potential) stream steps as unbatched, otherwise they won't be
|
|
3871
|
+
// able to stream!
|
|
3872
|
+
if (step._stepOptions.stream)
|
|
3873
|
+
return false;
|
|
3874
|
+
// Non-unary steps are safe for unbatched execution
|
|
3875
|
+
if (step._isUnary === false)
|
|
3876
|
+
return true;
|
|
3877
|
+
// Unary steps are only safe for unbatched execution _if_ their polymorphic
|
|
3878
|
+
// paths match that of their bucket.
|
|
3879
|
+
// !! search "f4ce2c83"
|
|
3880
|
+
if (step.polymorphicPaths === null)
|
|
3881
|
+
return true;
|
|
3882
|
+
// PERF: this can probably be optimized further
|
|
3883
|
+
return false;
|
|
3884
|
+
}
|
|
3885
|
+
function defaultPlanType($stepOrSpecifier, info) {
|
|
3886
|
+
const $__typename = $stepOrSpecifier.toTypename?.() ??
|
|
3887
|
+
(info.resolverEmulation
|
|
3888
|
+
? (0, graphqlResolver_js_1.graphqlResolveType)($stepOrSpecifier, info)
|
|
3889
|
+
: (0, index_js_1.get)($stepOrSpecifier, "__typename"));
|
|
3890
|
+
return { $__typename };
|
|
3891
|
+
}
|
|
3892
|
+
function polymorphicPathsForLayer(layer) {
|
|
3893
|
+
switch (layer.reason.type) {
|
|
3894
|
+
case "polymorphic":
|
|
3895
|
+
case "polymorphicPartition": {
|
|
3896
|
+
return layer.reason.polymorphicPaths;
|
|
3897
|
+
}
|
|
3898
|
+
case "combined": {
|
|
3899
|
+
const set = new Set();
|
|
3900
|
+
for (const lp of layer.reason.parentLayerPlans) {
|
|
3901
|
+
for (const p of polymorphicPathsForLayer(lp)) {
|
|
3902
|
+
set.add(p);
|
|
3903
|
+
}
|
|
3904
|
+
}
|
|
3905
|
+
return set;
|
|
3906
|
+
}
|
|
3907
|
+
case "root": {
|
|
3908
|
+
return null;
|
|
3909
|
+
}
|
|
3910
|
+
default: {
|
|
3911
|
+
return polymorphicPathsForLayer(layer.reason.parentLayerPlan);
|
|
3912
|
+
}
|
|
3913
|
+
}
|
|
3914
|
+
}
|
|
3915
|
+
function stepIsValidInPolyPath($step, polyPath) {
|
|
3916
|
+
if (!$step.polymorphicPaths)
|
|
3917
|
+
return true;
|
|
3918
|
+
let trimmed = polyPath;
|
|
3919
|
+
do {
|
|
3920
|
+
if ($step.polymorphicPaths.has(trimmed))
|
|
3921
|
+
return true;
|
|
3922
|
+
const i = trimmed.lastIndexOf(">");
|
|
3923
|
+
trimmed = trimmed.slice(0, i);
|
|
3924
|
+
} while (trimmed.length > 0 && trimmed[0] === ">");
|
|
3925
|
+
return false;
|
|
3926
|
+
}
|
|
3927
|
+
function isPeerLayerPlan(lp1, lp2) {
|
|
3928
|
+
if (lp1 == null || lp2 == null) {
|
|
3929
|
+
return false;
|
|
3930
|
+
}
|
|
3931
|
+
if (lp1 === lp2)
|
|
3932
|
+
return true;
|
|
3933
|
+
if (lp1.reason.type === "polymorphicPartition" &&
|
|
3934
|
+
lp2.reason.type === "polymorphicPartition" &&
|
|
3935
|
+
lp1.reason.parentLayerPlan === lp2.reason.parentLayerPlan) {
|
|
3936
|
+
return true;
|
|
3937
|
+
}
|
|
3938
|
+
return false;
|
|
3939
|
+
}
|
|
3940
|
+
/**
|
|
3941
|
+
* NOTE: includes `start` itself, so it's not _truly_ descendents
|
|
3942
|
+
*/
|
|
3943
|
+
function getDescendents(start, childrenByLayerPlan) {
|
|
3944
|
+
const descendents = new Set();
|
|
3945
|
+
const queue = [start];
|
|
3946
|
+
while (queue.length > 0) {
|
|
3947
|
+
const current = queue.pop();
|
|
3948
|
+
// Already seen
|
|
3949
|
+
if (descendents.has(current))
|
|
3950
|
+
continue;
|
|
3951
|
+
descendents.add(current);
|
|
3952
|
+
const children = childrenByLayerPlan.get(current);
|
|
3953
|
+
if (children) {
|
|
3954
|
+
for (const child of children) {
|
|
3955
|
+
queue.push(child);
|
|
3956
|
+
}
|
|
3957
|
+
}
|
|
3958
|
+
}
|
|
3959
|
+
return descendents;
|
|
3960
|
+
}
|
|
2835
3961
|
//# sourceMappingURL=OperationPlan.js.map
|