grafast 0.1.1-beta.0 → 0.1.1-beta.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -2
- package/dist/args.js +62 -0
- package/dist/assert.js +24 -0
- package/dist/bucket.js +4 -0
- package/dist/config.js +99 -0
- package/dist/constraints.js +72 -0
- package/dist/deferred.js +25 -0
- package/dist/dev.js +10 -0
- package/dist/engine/LayerPlan.js +536 -0
- package/dist/engine/OperationPlan.js +2543 -0
- package/dist/engine/OutputPlan.js +1059 -0
- package/dist/engine/StepTracker.js +524 -0
- package/dist/engine/executeBucket.js +700 -0
- package/dist/engine/executeOutputPlan.js +21 -0
- package/dist/engine/lib/withGlobalLayerPlan.js +36 -0
- package/dist/envelop.js +73 -5
- package/dist/error.js +62 -0
- package/dist/establishOperationPlan.js +186 -0
- package/dist/execute.js +80 -0
- package/dist/exportAs.js +57 -0
- package/dist/global.js +13 -0
- package/dist/grafastGraphql.js +133 -0
- package/dist/grafastPrint.js +177 -0
- package/dist/graphqlCollectFields.js +217 -0
- package/dist/graphqlMergeSelectionSets.js +60 -0
- package/dist/index.d.ts +161 -2
- package/dist/index.js +255 -499
- package/dist/input.js +159 -0
- package/dist/inspect.js +20 -0
- package/dist/interfaces.d.ts +3 -160
- package/dist/interfaces.js +63 -0
- package/dist/makeGrafastSchema.js +174 -0
- package/dist/mermaid.js +290 -7
- package/dist/operationPlan-input.js +449 -0
- package/dist/planJSONInterfaces.js +3 -0
- package/dist/polymorphic.js +73 -0
- package/dist/prepare.js +763 -0
- package/dist/step.js +396 -0
- package/dist/steps/__inputDynamicScalar.js +125 -0
- package/dist/steps/__inputList.js +110 -0
- package/dist/steps/__inputObject.js +128 -0
- package/dist/steps/__inputStaticLeaf.js +43 -0
- package/dist/steps/__item.js +50 -0
- package/dist/steps/__trackedValue.js +257 -0
- package/dist/steps/__value.js +47 -0
- package/dist/steps/access.js +183 -0
- package/dist/steps/applyTransforms.js +151 -0
- package/dist/steps/connection.js +315 -0
- package/dist/steps/constant.js +72 -0
- package/dist/steps/each.js +64 -0
- package/dist/steps/error.js +32 -0
- package/dist/steps/filter.js +32 -0
- package/dist/steps/first.js +49 -0
- package/dist/steps/graphqlResolver.js +260 -0
- package/dist/steps/groupBy.js +40 -0
- package/dist/steps/index.js +117 -0
- package/dist/steps/lambda.js +58 -0
- package/dist/steps/last.js +41 -0
- package/dist/steps/list.js +75 -0
- package/dist/steps/listTransform.js +185 -0
- package/dist/steps/listen.js +61 -0
- package/dist/steps/load.d.ts +4 -4
- package/dist/steps/load.js +310 -0
- package/dist/steps/node.d.ts +6 -6
- package/dist/steps/node.js +107 -0
- package/dist/steps/object.js +195 -0
- package/dist/steps/partitionByIndex.js +86 -0
- package/dist/steps/proxy.js +114 -0
- package/dist/steps/remapKeys.js +84 -0
- package/dist/steps/reverse.js +52 -0
- package/dist/steps/setter.js +28 -0
- package/dist/stringifyPayload.js +59 -0
- package/dist/stripAnsi.js +14 -0
- package/dist/subscribe.js +14 -0
- package/dist/thereCanBeOnlyOne.js +21 -0
- package/dist/timeSource.js +8 -0
- package/dist/utils.js +698 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +6 -0
- package/package.json +9 -4
- package/dist/LICENSES.txt +0 -300
|
@@ -0,0 +1,1059 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getChildBucketAndIndex = exports.nonNullError = exports.coerceError = exports.OutputPlan = void 0;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const lru_1 = tslib_1.__importDefault(require("@graphile/lru"));
|
|
6
|
+
const graphql = tslib_1.__importStar(require("graphql"));
|
|
7
|
+
const tamedevil_1 = tslib_1.__importStar(require("tamedevil"));
|
|
8
|
+
const assert = tslib_1.__importStar(require("../assert.js"));
|
|
9
|
+
const dev_js_1 = require("../dev.js");
|
|
10
|
+
const error_js_1 = require("../error.js");
|
|
11
|
+
const index_js_1 = require("../index.js");
|
|
12
|
+
const inspect_js_1 = require("../inspect.js");
|
|
13
|
+
const interfaces_js_1 = require("../interfaces.js");
|
|
14
|
+
const polymorphic_js_1 = require("../polymorphic.js");
|
|
15
|
+
const access_js_1 = require("../steps/access.js");
|
|
16
|
+
const { executeSync, GraphQLBoolean, GraphQLError, GraphQLFloat, GraphQLID, GraphQLInt, GraphQLString, isObjectType, Kind, OperationTypeNode, } = graphql;
|
|
17
|
+
const ref_$$error = tamedevil_1.default.ref(error_js_1.$$error, "$$error");
|
|
18
|
+
const ref_coerceError = tamedevil_1.default.ref(coerceError, "coerceError");
|
|
19
|
+
const ref_nonNullError = tamedevil_1.default.ref(nonNullError, "nonNullError");
|
|
20
|
+
const ref_stringifyString = tamedevil_1.default.ref(tamedevil_1.stringifyString, "stringifyString");
|
|
21
|
+
const ref_stringifyJSON = tamedevil_1.default.ref(tamedevil_1.stringifyJSON, "stringifyJSON");
|
|
22
|
+
const ref_isPolymorphicData = tamedevil_1.default.ref(polymorphic_js_1.isPolymorphicData, "isPolymorphicData");
|
|
23
|
+
const ref_$$concreteType = tamedevil_1.default.ref(interfaces_js_1.$$concreteType, "$$concreteType");
|
|
24
|
+
const ref_assert = tamedevil_1.default.ref(assert, "assert");
|
|
25
|
+
const ref_getChildBucketAndIndex = tamedevil_1.default.ref(getChildBucketAndIndex, "getChildBucketAndIndex");
|
|
26
|
+
const ref_inspect = tamedevil_1.default.ref(inspect_js_1.inspect, "inspect");
|
|
27
|
+
const ref_$$streamMore = tamedevil_1.default.ref(interfaces_js_1.$$streamMore, "$$streamMore");
|
|
28
|
+
const te_String = (0, tamedevil_1.default) `String`;
|
|
29
|
+
const te_nullIsFineComment = (0, tamedevil_1.default) `// root/introspection, null is fine`;
|
|
30
|
+
const te_nullString = (0, tamedevil_1.default) `"null"`;
|
|
31
|
+
const te_null = (0, tamedevil_1.default) `null`;
|
|
32
|
+
const te_childBucket = (0, tamedevil_1.default) `childBucket`;
|
|
33
|
+
const te_childBucketIndex = (0, tamedevil_1.default) `childBucketIndex`;
|
|
34
|
+
const te_executeString = (0, tamedevil_1.default) `executeString`;
|
|
35
|
+
const te_execute = (0, tamedevil_1.default) `execute`;
|
|
36
|
+
const te_polymorphic = (0, tamedevil_1.default) `polymorphic`;
|
|
37
|
+
const te_letStringLbrace = (0, tamedevil_1.default) `let string = "{";`;
|
|
38
|
+
const te_stringPlusEquals = (0, tamedevil_1.default) `string +=`;
|
|
39
|
+
const te_stringPlusEqualsRbrace = (0, tamedevil_1.default) ` string += "}";\n`;
|
|
40
|
+
const te_stringPlusEqualsRbracket = (0, tamedevil_1.default) ` string += "]";\n`;
|
|
41
|
+
const te_constObjEqualsObjectCreateNull = (0, tamedevil_1.default) `const obj = Object.create(null);`;
|
|
42
|
+
const te_comma = (0, tamedevil_1.default) `,`;
|
|
43
|
+
const te_specDotLocationDetails = (0, tamedevil_1.default) `spec.locationDetails`;
|
|
44
|
+
const te_thisDotLocationDetails = (0, tamedevil_1.default) `this.locationDetails`;
|
|
45
|
+
const te_specDotOutputPlan = (0, tamedevil_1.default) `spec.outputPlan`;
|
|
46
|
+
const te_bucket = (0, tamedevil_1.default) `bucket`;
|
|
47
|
+
const te_bucketIndex = (0, tamedevil_1.default) `bucketIndex`;
|
|
48
|
+
const te_handleDeferred = (0, tamedevil_1.default) `
|
|
49
|
+
// Everything seems okay; queue any deferred payloads
|
|
50
|
+
for (const defer of this.deferredOutputPlans) {
|
|
51
|
+
root.queue.push({
|
|
52
|
+
root,
|
|
53
|
+
path: mutablePath.slice(1),
|
|
54
|
+
bucket,
|
|
55
|
+
bucketIndex,
|
|
56
|
+
outputPlan: defer,
|
|
57
|
+
label: defer.type.deferLabel,
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
`;
|
|
61
|
+
const te_string = (0, tamedevil_1.default) `string`;
|
|
62
|
+
const te_object = (0, tamedevil_1.default) `object`;
|
|
63
|
+
const te_obj = (0, tamedevil_1.default) `obj`;
|
|
64
|
+
const te_data = (0, tamedevil_1.default) `data`;
|
|
65
|
+
const te_commonErrorHandler = tamedevil_1.default.ref(commonErrorHandler, "handleError");
|
|
66
|
+
const te_questionDot = (0, tamedevil_1.default) `?.`;
|
|
67
|
+
const te_childBucketCBIDC = (0, tamedevil_1.default) `, childBucket, childBucketIndex, directChild`;
|
|
68
|
+
const te_letString = (0, tamedevil_1.default) `let string;`;
|
|
69
|
+
const te_constDataEqualsEmptyArray = (0, tamedevil_1.default) `const data = [];`;
|
|
70
|
+
const te_stringEqualsEmptyArrayString = (0, tamedevil_1.default) ` string = "[]";`;
|
|
71
|
+
const te_stringEqualsLeftSquareBraceString = (0, tamedevil_1.default) ` string = "[";\n`;
|
|
72
|
+
const te_noopComment = (0, tamedevil_1.default) ` /* noop */`;
|
|
73
|
+
const te_ifIGt0StrPlusEqualComma = (0, tamedevil_1.default) `\n if (i > 0) { string += ","; }\n`;
|
|
74
|
+
const te_dataIEquals = (0, tamedevil_1.default) `data[i] =`;
|
|
75
|
+
const te_childOutputPlan = (0, tamedevil_1.default) `childOutputPlan`;
|
|
76
|
+
const te_underscoreNonNull = (0, tamedevil_1.default) `_nonNull`;
|
|
77
|
+
const te_underscoreStream = (0, tamedevil_1.default) `_stream`;
|
|
78
|
+
/**
|
|
79
|
+
* Defines a way of taking a layerPlan and converting it into an output value.
|
|
80
|
+
*
|
|
81
|
+
* The result of executing an output plan will be the following:
|
|
82
|
+
*
|
|
83
|
+
* - data?: the data for this layer, could be object, array or leaf (see OutputPlanMode)
|
|
84
|
+
* - errors: a list of errors that occurred (if any), including path details _within the output plan_
|
|
85
|
+
* - streams: a list of streams that were created
|
|
86
|
+
*/
|
|
87
|
+
class OutputPlan {
|
|
88
|
+
constructor(layerPlan,
|
|
89
|
+
/**
|
|
90
|
+
* For root, this should always be an object.
|
|
91
|
+
*
|
|
92
|
+
* For object this could represent an object or null.
|
|
93
|
+
*
|
|
94
|
+
* For polymorphic this could represent a polymorphic object or null.
|
|
95
|
+
*
|
|
96
|
+
* For array it's the list itself (or null) and dictates the length of the result.
|
|
97
|
+
*
|
|
98
|
+
* For leaf, it's the leaf plan itself.
|
|
99
|
+
*
|
|
100
|
+
* For `introspection`, `null` it's irrelevant. Use `constant(null)` or whatever.
|
|
101
|
+
*/
|
|
102
|
+
rootStep, type, locationDetails) {
|
|
103
|
+
this.layerPlan = layerPlan;
|
|
104
|
+
this.type = type;
|
|
105
|
+
/**
|
|
106
|
+
* Appended to the root step when accessed to avoid the need for AccessSteps
|
|
107
|
+
*/
|
|
108
|
+
this.processRoot = null;
|
|
109
|
+
/**
|
|
110
|
+
* For root/object output plans, the keys to set on the resulting object
|
|
111
|
+
* grouped by the concrete object type name.
|
|
112
|
+
*
|
|
113
|
+
* IMPORTANT: the order of these keys is significant, they MUST match the
|
|
114
|
+
* order in the request otherwise we break GraphQL spec compliance!
|
|
115
|
+
*/
|
|
116
|
+
this.keys = Object.create(null);
|
|
117
|
+
/**
|
|
118
|
+
* For list output plans, the output plan that describes the list children.
|
|
119
|
+
*/
|
|
120
|
+
this.child = null;
|
|
121
|
+
this.childIsNonNull = false;
|
|
122
|
+
/**
|
|
123
|
+
* For object output plan types only.
|
|
124
|
+
*/
|
|
125
|
+
this.deferredOutputPlans = [];
|
|
126
|
+
this.locationDetails = locationDetails;
|
|
127
|
+
this.rootStep = rootStep;
|
|
128
|
+
layerPlan.operationPlan.stepTracker.addOutputPlan(this);
|
|
129
|
+
this.childByTypeName =
|
|
130
|
+
this.type.mode === "polymorphic" ? Object.create(null) : undefined;
|
|
131
|
+
}
|
|
132
|
+
print() {
|
|
133
|
+
const type = this.type;
|
|
134
|
+
switch (type.mode) {
|
|
135
|
+
case "root":
|
|
136
|
+
case "object": {
|
|
137
|
+
return `${this.toString()}\n${Object.entries(this.keys)
|
|
138
|
+
.map(([fieldName, val]) => {
|
|
139
|
+
return `.${fieldName}: ${val.type === "__typename" ? "" : val.isNonNull ? "!" : "?"}${val.type === "__typename"
|
|
140
|
+
? `__typename(${type.typeName})`
|
|
141
|
+
: val.outputPlan.print().replace(/\n/g, "\n ")}`;
|
|
142
|
+
})
|
|
143
|
+
.join("\n")}`;
|
|
144
|
+
}
|
|
145
|
+
case "polymorphic": {
|
|
146
|
+
return `${this.toString()}\n${Object.entries(this.childByTypeName)
|
|
147
|
+
.map(([typeName, outputPlan]) => {
|
|
148
|
+
return `? ${typeName}: ${outputPlan
|
|
149
|
+
.print()
|
|
150
|
+
.replace(/\n/g, "\n ")}`;
|
|
151
|
+
})
|
|
152
|
+
.join("\n")}`;
|
|
153
|
+
}
|
|
154
|
+
case "array": {
|
|
155
|
+
return `${this.toString()}\n ${this.childIsNonNull ? "!" : "?"}${this.child.print().replace(/\n/g, "\n ")}`;
|
|
156
|
+
}
|
|
157
|
+
default: {
|
|
158
|
+
return this.toString();
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
toString() {
|
|
163
|
+
return `OutputPlan<${this.type.mode}∈${this.layerPlan.id}!${this.rootStep.id}>`;
|
|
164
|
+
}
|
|
165
|
+
addChild(type, key, child) {
|
|
166
|
+
if (this.type.mode === "root" || this.type.mode === "object") {
|
|
167
|
+
if (dev_js_1.isDev) {
|
|
168
|
+
if (typeof key !== "string") {
|
|
169
|
+
throw new Error(`GrafastInternalError<7334ec50-23dc-442a-8ffa-19664c9eb79f>: Key must be provided in ${this.type.mode} OutputPlan mode`);
|
|
170
|
+
}
|
|
171
|
+
if (type == null) {
|
|
172
|
+
throw new Error(`GrafastInternalError<638cebef-4ec6-49f4-b681-2f390fb1c0fc>: Type must be provided in ${this.type.mode} OutputPlan mode.`);
|
|
173
|
+
}
|
|
174
|
+
if (!isObjectType(type)) {
|
|
175
|
+
throw new Error(`GrafastInternalError<eaa87576-1d50-49be-990a-345a9b57b998>: Type must provided in ${this.type.mode} OutputPlan mode must be an object type, instead saw '${type}'.`);
|
|
176
|
+
}
|
|
177
|
+
assert.ok(["root", "object"].includes(this.type.mode), "Can only addChild on root/object output plans");
|
|
178
|
+
if (this.keys[key] !== undefined) {
|
|
179
|
+
throw new Error(`GrafastInternalError<5ceecb19-8c2c-4797-9be5-9be1b207fa45>: child already set for key '${key}'`);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
this.keys[key] =
|
|
183
|
+
child.type === "outputPlan"
|
|
184
|
+
? {
|
|
185
|
+
...child,
|
|
186
|
+
layerPlanId: child.outputPlan.layerPlan.id,
|
|
187
|
+
}
|
|
188
|
+
: child;
|
|
189
|
+
}
|
|
190
|
+
else if (this.type.mode === "array") {
|
|
191
|
+
if (dev_js_1.isDev) {
|
|
192
|
+
if (key != null) {
|
|
193
|
+
throw new Error(`GrafastInternalError<7de67325-a02f-4619-b118-61bb2d84f33b>: Key must not be provided in ${this.type.mode} OutputPlan mode`);
|
|
194
|
+
}
|
|
195
|
+
assert.ok(type == null, "Array should not specify type");
|
|
196
|
+
if (this.child !== null) {
|
|
197
|
+
throw new Error(`GrafastInternalError<07059d9d-a47d-441f-b834-683cca1d856a>: child already set`);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
if (child.type === "outputPlan") {
|
|
201
|
+
this.child = child.outputPlan;
|
|
202
|
+
this.childIsNonNull = child.isNonNull;
|
|
203
|
+
}
|
|
204
|
+
else {
|
|
205
|
+
throw new Error(`GrafastInternalError<7525c854-9145-4c6d-8d60-79c14f040519>: Array child must be an outputPlan`);
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
else if (this.type.mode === "polymorphic") {
|
|
209
|
+
if (dev_js_1.isDev) {
|
|
210
|
+
assert.ok(type && this.type.typeNames.includes(type.name), "GrafastInternalError<566a34ac-1138-4dbf-943e-f704819431dd>: polymorphic output plan can only addChild for a matching type");
|
|
211
|
+
assert.strictEqual(key, null, "GrafastInternalError<4346ebda-a02d-4489-b767-7a6d621a73c7>: addChild for polymorphic OutputPlan should not specify a key");
|
|
212
|
+
assert.ok(child.type === "outputPlan", "GrafastInternalError<b29285da-fb07-4943-9038-708edc785041>: polymorphic OutputPlan child must be an outputPlan");
|
|
213
|
+
assert.ok(child.outputPlan.type.mode === "object", "GrafastInternalError<203469c6-4bfa-4cd1-ae82-cc5d0132ca16>: polymorphic OutputPlan child must be an object outputPlan");
|
|
214
|
+
}
|
|
215
|
+
this.childByTypeName[type.name] = child.outputPlan;
|
|
216
|
+
}
|
|
217
|
+
else {
|
|
218
|
+
throw new Error(`GrafastInternalError<5667df5f-30b7-48d3-be3f-a0065ed9c05c>: Doesn't make sense to set a child in mode '${this.type.mode}'`);
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
getLayerPlans(layerPlans = new Set()) {
|
|
222
|
+
// Find all the layerPlans referenced
|
|
223
|
+
layerPlans.add(this.layerPlan);
|
|
224
|
+
if (this.child !== null) {
|
|
225
|
+
if (this.child.layerPlan != this.layerPlan) {
|
|
226
|
+
this.child.getLayerPlans(layerPlans);
|
|
227
|
+
}
|
|
228
|
+
else {
|
|
229
|
+
throw new Error("GrafastInternalError<4013e05f-b8ed-41ea-a869-204232d02763>: how could the child be in the same layer?");
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
for (const key in this.keys) {
|
|
233
|
+
const spec = this.keys[key];
|
|
234
|
+
if (spec.type === "outputPlan") {
|
|
235
|
+
if (spec.outputPlan.layerPlan !== this.layerPlan) {
|
|
236
|
+
spec.outputPlan.getLayerPlans(layerPlans);
|
|
237
|
+
layerPlans.add(spec.outputPlan.layerPlan);
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
return layerPlans;
|
|
242
|
+
}
|
|
243
|
+
makeNextStepByLayerPlan() {
|
|
244
|
+
const layerPlans = this.getLayerPlans();
|
|
245
|
+
const map = Object.create(null);
|
|
246
|
+
for (const layerPlan of layerPlans) {
|
|
247
|
+
map[layerPlan.id] = [];
|
|
248
|
+
}
|
|
249
|
+
return map;
|
|
250
|
+
}
|
|
251
|
+
// This gets replaced with a mode-specific executor
|
|
252
|
+
execute(_root,
|
|
253
|
+
// By just reusing the same path over and over we don't need to allocate
|
|
254
|
+
// more memory for more arrays; but we must be _incredibly_ careful to
|
|
255
|
+
// ensure any changes to it are reversed.
|
|
256
|
+
_mutablePath, _bucket, _bucketIndex) {
|
|
257
|
+
throw new Error(`OutputPlan.execute has yet to be built!`);
|
|
258
|
+
}
|
|
259
|
+
// This gets replaced with a mode-specific executor
|
|
260
|
+
executeString(_root,
|
|
261
|
+
// By just reusing the same path over and over we don't need to allocate
|
|
262
|
+
// more memory for more arrays; but we must be _incredibly_ careful to
|
|
263
|
+
// ensure any changes to it are reversed.
|
|
264
|
+
_mutablePath, _bucket, _bucketIndex) {
|
|
265
|
+
throw new Error(`OutputPlan.executeString has yet to be built!`);
|
|
266
|
+
}
|
|
267
|
+
optimize() {
|
|
268
|
+
const $root = this.layerPlan.operationPlan.dangerouslyGetStep(this.rootStep.id);
|
|
269
|
+
if ($root instanceof index_js_1.AccessStep && $root.fallback === undefined) {
|
|
270
|
+
const expressionDetails = $root.unbatchedExecute[access_js_1.expressionSymbol];
|
|
271
|
+
if (expressionDetails !== undefined) {
|
|
272
|
+
// @ts-ignore
|
|
273
|
+
const $parent = $root.getDep(0);
|
|
274
|
+
this.layerPlan.operationPlan.stepTracker.setOutputPlanRootStep(this, $parent);
|
|
275
|
+
const [path, fallback] = expressionDetails;
|
|
276
|
+
withFastExpression(path, fallback, (fn) => {
|
|
277
|
+
this.processRoot = fn;
|
|
278
|
+
});
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
finalize() {
|
|
283
|
+
// Build the executor
|
|
284
|
+
switch (this.type.mode) {
|
|
285
|
+
case "null": {
|
|
286
|
+
this.execute = nullExecutor;
|
|
287
|
+
this.executeString = nullExecutorString;
|
|
288
|
+
break;
|
|
289
|
+
}
|
|
290
|
+
case "leaf": {
|
|
291
|
+
this.execute = leafExecutor;
|
|
292
|
+
if (this.type.graphqlType.serialize === GraphQLID.serialize ||
|
|
293
|
+
this.type.graphqlType.serialize === GraphQLString.serialize) {
|
|
294
|
+
// String types
|
|
295
|
+
this.executeString = stringLeafExecutorString;
|
|
296
|
+
}
|
|
297
|
+
else if (this.type.graphqlType.serialize === GraphQLInt.serialize) {
|
|
298
|
+
this.executeString = intLeafExecutorString;
|
|
299
|
+
}
|
|
300
|
+
else if (this.type.graphqlType.serialize === GraphQLFloat.serialize) {
|
|
301
|
+
this.executeString = floatLeafExecutorString;
|
|
302
|
+
}
|
|
303
|
+
else if (this.type.graphqlType.serialize === GraphQLBoolean.serialize) {
|
|
304
|
+
// Boolean type
|
|
305
|
+
this.executeString = booleanLeafExecutorString;
|
|
306
|
+
}
|
|
307
|
+
else {
|
|
308
|
+
// PERF: we could probably optimize enums too
|
|
309
|
+
this.executeString = leafExecutorString;
|
|
310
|
+
}
|
|
311
|
+
break;
|
|
312
|
+
}
|
|
313
|
+
case "introspection": {
|
|
314
|
+
this.execute = introspectionExecutor;
|
|
315
|
+
this.executeString = introspectionExecutorString;
|
|
316
|
+
break;
|
|
317
|
+
}
|
|
318
|
+
case "polymorphic": {
|
|
319
|
+
this.execute = polymorphicExecutor;
|
|
320
|
+
this.executeString = polymorphicExecutorString;
|
|
321
|
+
break;
|
|
322
|
+
}
|
|
323
|
+
case "array": {
|
|
324
|
+
if (!this.child) {
|
|
325
|
+
throw new Error("GrafastInternalError<48fabdc8-ce84-45ec-ac20-35a2af9098e0>: No child output plan for list bucket?");
|
|
326
|
+
}
|
|
327
|
+
const childIsNonNull = this.childIsNonNull;
|
|
328
|
+
let directLayerPlanChild = this.child.layerPlan;
|
|
329
|
+
while (directLayerPlanChild.parentLayerPlan !== this.layerPlan) {
|
|
330
|
+
const parent = directLayerPlanChild.parentLayerPlan;
|
|
331
|
+
if (!parent) {
|
|
332
|
+
throw new Error(`GrafastInternalError<d43e06d8-c533-4e7b-b3e7-af399f19c83f>: Invalid heirarchy - could not find direct layerPlan child of ${this}`);
|
|
333
|
+
}
|
|
334
|
+
directLayerPlanChild = parent;
|
|
335
|
+
}
|
|
336
|
+
const canStream = directLayerPlanChild.reason.type === "listItem" &&
|
|
337
|
+
!!directLayerPlanChild.reason.stream;
|
|
338
|
+
if (childIsNonNull) {
|
|
339
|
+
if (canStream) {
|
|
340
|
+
this.execute = arrayExecutor_nonNullable_streaming;
|
|
341
|
+
this.executeString = arrayExecutorString_nonNullable_streaming;
|
|
342
|
+
}
|
|
343
|
+
else {
|
|
344
|
+
this.execute = arrayExecutor_nonNullable;
|
|
345
|
+
this.executeString = arrayExecutorString_nonNullable;
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
else {
|
|
349
|
+
if (canStream) {
|
|
350
|
+
this.execute = arrayExecutor_nullable_streaming;
|
|
351
|
+
this.executeString = arrayExecutorString_nullable_streaming;
|
|
352
|
+
}
|
|
353
|
+
else {
|
|
354
|
+
this.execute = arrayExecutor_nullable;
|
|
355
|
+
this.executeString = arrayExecutorString_nullable;
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
break;
|
|
359
|
+
}
|
|
360
|
+
case "root":
|
|
361
|
+
case "object": {
|
|
362
|
+
const type = this.type;
|
|
363
|
+
const digestFieldTypes = Object.create(null);
|
|
364
|
+
for (const [responseKey, spec] of Object.entries(this.keys)) {
|
|
365
|
+
digestFieldTypes[responseKey] = {
|
|
366
|
+
fieldType: spec.type === "__typename"
|
|
367
|
+
? "__typename"
|
|
368
|
+
: spec.isNonNull
|
|
369
|
+
? "outputPlan!"
|
|
370
|
+
: "outputPlan?",
|
|
371
|
+
sameBucket: spec.type === "__typename" ||
|
|
372
|
+
spec.outputPlan.layerPlan.id === this.layerPlan.id,
|
|
373
|
+
};
|
|
374
|
+
}
|
|
375
|
+
makeObjectExecutor(type.typeName, digestFieldTypes, this.deferredOutputPlans.length > 0, type.mode === "root", false, (fn) => {
|
|
376
|
+
this.execute = fn;
|
|
377
|
+
});
|
|
378
|
+
makeObjectExecutor(type.typeName, digestFieldTypes, this.deferredOutputPlans.length > 0, type.mode === "root", true, (fn) => {
|
|
379
|
+
this.executeString = fn;
|
|
380
|
+
});
|
|
381
|
+
break;
|
|
382
|
+
}
|
|
383
|
+
default: {
|
|
384
|
+
const never = this.type;
|
|
385
|
+
throw new Error(`GrafastInternalError<e88531b2-d9af-4d3a-8cd5-e9f034324341>: Could not build executor for OutputPlan with type ${(0, inspect_js_1.inspect)(never)}}`);
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
exports.OutputPlan = OutputPlan;
|
|
391
|
+
function coerceError(error, locationDetails, path) {
|
|
392
|
+
// Ensure it's a GraphQL error
|
|
393
|
+
if (error instanceof GraphQLError) {
|
|
394
|
+
if (error.path !== undefined) {
|
|
395
|
+
return error;
|
|
396
|
+
}
|
|
397
|
+
else {
|
|
398
|
+
return new GraphQLError(error.message, locationDetails.node, null, null, path, error.originalError ?? error, error.extensions);
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
else {
|
|
402
|
+
return new GraphQLError(error.message, locationDetails.node, null, null, path, error, null);
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
exports.coerceError = coerceError;
|
|
406
|
+
function nonNullError(locationDetails, path) {
|
|
407
|
+
const { parentTypeName, fieldName, node } = locationDetails;
|
|
408
|
+
if (!parentTypeName || !fieldName) {
|
|
409
|
+
return new GraphQLError(`GrafastInternalError<a3706bba-4f88-4643-8a47-2fe2eaaadbea>: null bubbled to root`, node, null, null, path, null, null);
|
|
410
|
+
}
|
|
411
|
+
return new GraphQLError(`Cannot return null for non-nullable field ${parentTypeName}.${fieldName}.`, node, null, null, path, null, null);
|
|
412
|
+
}
|
|
413
|
+
exports.nonNullError = nonNullError;
|
|
414
|
+
/**
|
|
415
|
+
* We're currently running OutputPlan `outputPlan` in bucket `bucket` at index
|
|
416
|
+
* `bucketIndex`. If this is an array OutputPlan then we're looping over the
|
|
417
|
+
* entries in our list and we're currently at index `inArrayIndex` (otherwise
|
|
418
|
+
* this is null).
|
|
419
|
+
*
|
|
420
|
+
* Now we want to run `childOutputPlan`, but to do so we need to find the
|
|
421
|
+
* related `childBucket` and `childBucketIndex`.
|
|
422
|
+
*
|
|
423
|
+
* @internal
|
|
424
|
+
*/
|
|
425
|
+
function getChildBucketAndIndex(childOutputPlan, outputPlan, bucket, bucketIndex, arrayIndex = null) {
|
|
426
|
+
if ((arrayIndex == null) ===
|
|
427
|
+
(outputPlan != null && outputPlan.type.mode === "array")) {
|
|
428
|
+
throw new Error("GrafastInternalError<83d0e3cc-7eec-4185-85b4-846540288162>: arrayIndex must be supplied iff outputPlan is an array");
|
|
429
|
+
}
|
|
430
|
+
if (outputPlan && childOutputPlan.layerPlan === bucket.layerPlan) {
|
|
431
|
+
// Same layer; straightforward
|
|
432
|
+
return [bucket, bucketIndex];
|
|
433
|
+
}
|
|
434
|
+
const reversePath = [childOutputPlan.layerPlan];
|
|
435
|
+
let current = childOutputPlan.layerPlan;
|
|
436
|
+
while (!bucket.children[current.id]) {
|
|
437
|
+
current = current.parentLayerPlan;
|
|
438
|
+
if (!current) {
|
|
439
|
+
return null;
|
|
440
|
+
}
|
|
441
|
+
reversePath.push(current);
|
|
442
|
+
}
|
|
443
|
+
let currentBucket = bucket;
|
|
444
|
+
let currentIndex = bucketIndex;
|
|
445
|
+
for (let l = reversePath.length, i = l - 1; i >= 0; i--) {
|
|
446
|
+
const layerPlan = reversePath[i];
|
|
447
|
+
const child = currentBucket.children[layerPlan.id];
|
|
448
|
+
if (!child) {
|
|
449
|
+
return null;
|
|
450
|
+
}
|
|
451
|
+
const out = child.map.get(currentIndex);
|
|
452
|
+
if (out == null) {
|
|
453
|
+
return null;
|
|
454
|
+
}
|
|
455
|
+
/*
|
|
456
|
+
* TEST: I think this '|| i !== l - 1' check is saying that an array can
|
|
457
|
+
* only occur at the furthest ancestor and everything since then must be
|
|
458
|
+
* non-array. Presumably in the case of nested arrays there would be an
|
|
459
|
+
* intermediary bucket, hence why this check is allowed, but that should be
|
|
460
|
+
* tested. Also, are there any confounding factors when it comes to steps
|
|
461
|
+
* themselves using arrays for object values - for example pgSelectSingle is
|
|
462
|
+
* represented by an array (tuple), but that doesn't make it a list so it should
|
|
463
|
+
* be fine. Use tests to validate this is all fine.
|
|
464
|
+
*/
|
|
465
|
+
if (arrayIndex == null || i !== l - 1) {
|
|
466
|
+
if (Array.isArray(out)) {
|
|
467
|
+
throw new Error("GrafastInternalError<db189d32-bf8f-4e58-b55f-5c5ac3bb2381>: Was expecting an arrayIndex, but none was provided");
|
|
468
|
+
}
|
|
469
|
+
currentBucket = child.bucket;
|
|
470
|
+
currentIndex = out;
|
|
471
|
+
}
|
|
472
|
+
else {
|
|
473
|
+
if (!Array.isArray(out)) {
|
|
474
|
+
throw new Error(`GrafastInternalError<8190d09f-dc75-46ec-8162-b20ad516de41>: Cannot access array index in non-array ${(0, inspect_js_1.inspect)(out)}`);
|
|
475
|
+
}
|
|
476
|
+
if (!(out.length > arrayIndex)) {
|
|
477
|
+
throw new Error(`GrafastInternalError<1f596c22-368b-4d0d-94df-fb3df632b064>: Attempted to retrieve array index '${arrayIndex}' which is out of bounds of array with length '${out.length}'`);
|
|
478
|
+
}
|
|
479
|
+
currentBucket = child.bucket;
|
|
480
|
+
currentIndex = out[arrayIndex];
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
if (currentIndex == null) {
|
|
484
|
+
return null;
|
|
485
|
+
}
|
|
486
|
+
return [currentBucket, currentIndex];
|
|
487
|
+
}
|
|
488
|
+
exports.getChildBucketAndIndex = getChildBucketAndIndex;
|
|
489
|
+
function makeExecutorExpression(options) {
|
|
490
|
+
const { inner, nameExtra, asString, skipNullHandling = false, preamble = tamedevil_1.default.blank, } = options;
|
|
491
|
+
return (0, tamedevil_1.default) `\
|
|
492
|
+
(function compiledOutputPlan${asString ? te_String : tamedevil_1.default.blank}_${nameExtra}(
|
|
493
|
+
root,
|
|
494
|
+
mutablePath,
|
|
495
|
+
bucket,
|
|
496
|
+
bucketIndex,
|
|
497
|
+
rawBucketRootValue = bucket.store.get(this.rootStep.id)[bucketIndex]
|
|
498
|
+
) {
|
|
499
|
+
const bucketRootValue = this.processRoot !== null ? this.processRoot(rawBucketRootValue) : rawBucketRootValue;
|
|
500
|
+
${preamble}\
|
|
501
|
+
${skipNullHandling
|
|
502
|
+
? dev_js_1.isDev
|
|
503
|
+
? te_nullIsFineComment
|
|
504
|
+
: tamedevil_1.default.blank
|
|
505
|
+
: (0, tamedevil_1.default) `if (bucketRootValue == null) return ${asString ? te_nullString : te_null};`}
|
|
506
|
+
if (bucketRootValue${skipNullHandling ? te_questionDot : tamedevil_1.default.blank}[${ref_$$error}]) {
|
|
507
|
+
throw ${ref_coerceError}(bucketRootValue.originalError, this.locationDetails, mutablePath.slice(1));
|
|
508
|
+
}
|
|
509
|
+
${inner}
|
|
510
|
+
})`;
|
|
511
|
+
}
|
|
512
|
+
function makeExecutor(options, callback) {
|
|
513
|
+
const expression = makeExecutorExpression(options);
|
|
514
|
+
if (callback !== undefined) {
|
|
515
|
+
tamedevil_1.default.runInBatch(expression, callback);
|
|
516
|
+
}
|
|
517
|
+
else {
|
|
518
|
+
return tamedevil_1.default.run((0, tamedevil_1.default) `return ${expression}`);
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
function makeExecuteChildPlanCode(setTargetOrReturn, locationDetails, childOutputPlan, isNonNull, asString, childBucket = te_childBucket, childBucketIndex = te_childBucketIndex) {
|
|
522
|
+
const te_childOutputPlanExecute = (0, tamedevil_1.default) `${childOutputPlan}.${asString ? te_executeString : te_execute}(root, mutablePath, ${childBucket}, ${childBucketIndex}, ${childBucket}.rootStep === this.rootStep ? rawBucketRootValue : undefined)`;
|
|
523
|
+
// This is the code that changes based on if the field is nullable or not
|
|
524
|
+
if (isNonNull) {
|
|
525
|
+
// No need to catch error
|
|
526
|
+
return (0, tamedevil_1.default) `\
|
|
527
|
+
${childBucket === te_bucket
|
|
528
|
+
? tamedevil_1.default.blank
|
|
529
|
+
: (0, tamedevil_1.default) `if (${childBucket} == null) {
|
|
530
|
+
throw ${ref_nonNullError}(${locationDetails}, mutablePath.slice(1));
|
|
531
|
+
}
|
|
532
|
+
`}fieldResult = ${te_childOutputPlanExecute};
|
|
533
|
+
if (fieldResult == ${asString ? te_nullString : te_null}) {
|
|
534
|
+
throw ${ref_nonNullError}(${locationDetails}, mutablePath.slice(1));
|
|
535
|
+
}
|
|
536
|
+
${setTargetOrReturn} fieldResult;`;
|
|
537
|
+
}
|
|
538
|
+
else {
|
|
539
|
+
// Need to catch error and set null
|
|
540
|
+
return (0, tamedevil_1.default) `\
|
|
541
|
+
{
|
|
542
|
+
const streamCount = root.streams.length;
|
|
543
|
+
const queueCount = root.queue.length;
|
|
544
|
+
try {
|
|
545
|
+
${setTargetOrReturn} ${childBucket === te_bucket
|
|
546
|
+
? tamedevil_1.default.blank
|
|
547
|
+
: (0, tamedevil_1.default) `${childBucket} == null ? ${asString ? te_nullString : te_null} : `}${te_childOutputPlanExecute};
|
|
548
|
+
} catch (e) {
|
|
549
|
+
${te_commonErrorHandler}(e, ${locationDetails}, mutablePath, mutablePathIndex, root, streamCount, queueCount);
|
|
550
|
+
${setTargetOrReturn} ${asString ? te_nullString : te_null};
|
|
551
|
+
}
|
|
552
|
+
}`;
|
|
553
|
+
}
|
|
554
|
+
}
|
|
555
|
+
function commonErrorHandler(e, locationDetails, mutablePath, mutablePathIndex, root, streamCount, queueCount) {
|
|
556
|
+
if (root.streams.length > streamCount) {
|
|
557
|
+
root.streams.splice(streamCount);
|
|
558
|
+
}
|
|
559
|
+
if (root.queue.length > queueCount) {
|
|
560
|
+
root.queue.splice(queueCount);
|
|
561
|
+
}
|
|
562
|
+
const error = coerceError(e, locationDetails, mutablePath.slice(1));
|
|
563
|
+
const pathLengthTarget = mutablePathIndex + 1;
|
|
564
|
+
const overSize = mutablePath.length - pathLengthTarget;
|
|
565
|
+
if (overSize > 0) {
|
|
566
|
+
mutablePath.splice(pathLengthTarget, overSize);
|
|
567
|
+
}
|
|
568
|
+
root.errors.push(error);
|
|
569
|
+
}
|
|
570
|
+
/*
|
|
571
|
+
* Below here we create the executors that can be shared across many different
|
|
572
|
+
* OutputPlans without having to be recreated (thus saving significant memory,
|
|
573
|
+
* and increasing the probability of optimization).
|
|
574
|
+
*/
|
|
575
|
+
const nullExecutor = makeExecutor({
|
|
576
|
+
inner: tamedevil_1.default.cache ` return null;`,
|
|
577
|
+
nameExtra: tamedevil_1.default.cache `null`,
|
|
578
|
+
asString: false,
|
|
579
|
+
});
|
|
580
|
+
const nullExecutorString = makeExecutor({
|
|
581
|
+
inner: tamedevil_1.default.cache ` return "null";`,
|
|
582
|
+
nameExtra: tamedevil_1.default.cache `null`,
|
|
583
|
+
asString: true,
|
|
584
|
+
});
|
|
585
|
+
/* This is what leafExecutor should use if insideGraphQL (which isn't currently
|
|
586
|
+
* supported)
|
|
587
|
+
`\
|
|
588
|
+
if (root.insideGraphQL) {
|
|
589
|
+
// Don't serialize to avoid the double serialization problem
|
|
590
|
+
return bucketRootValue;
|
|
591
|
+
} else {
|
|
592
|
+
return this.type.graphqlType.serialize(bucketRootValue);
|
|
593
|
+
}
|
|
594
|
+
` */
|
|
595
|
+
const leafExecutor = makeExecutor({
|
|
596
|
+
inner: (0, tamedevil_1.default) `\
|
|
597
|
+
return this.type.graphqlType.serialize(bucketRootValue);
|
|
598
|
+
`,
|
|
599
|
+
nameExtra: tamedevil_1.default.cache `leaf`,
|
|
600
|
+
asString: false,
|
|
601
|
+
});
|
|
602
|
+
const leafExecutorString = makeExecutor({
|
|
603
|
+
inner: (0, tamedevil_1.default) `\
|
|
604
|
+
return ${ref_stringifyJSON}(this.type.graphqlType.serialize(bucketRootValue));
|
|
605
|
+
`,
|
|
606
|
+
nameExtra: tamedevil_1.default.cache `leaf`,
|
|
607
|
+
asString: true,
|
|
608
|
+
});
|
|
609
|
+
const booleanLeafExecutorString = makeExecutor({
|
|
610
|
+
inner: (0, tamedevil_1.default) `\
|
|
611
|
+
const val = this.type.graphqlType.serialize(bucketRootValue);
|
|
612
|
+
return val === true ? 'true' : 'false';
|
|
613
|
+
`,
|
|
614
|
+
nameExtra: tamedevil_1.default.cache `booleanLeaf`,
|
|
615
|
+
asString: true,
|
|
616
|
+
skipNullHandling: false,
|
|
617
|
+
preamble: (0, tamedevil_1.default) `\
|
|
618
|
+
if (bucketRootValue === true) return 'true';
|
|
619
|
+
if (bucketRootValue === false) return 'false';
|
|
620
|
+
`,
|
|
621
|
+
});
|
|
622
|
+
const intLeafExecutorString = makeExecutor({
|
|
623
|
+
inner: (0, tamedevil_1.default) `\
|
|
624
|
+
return '' + this.type.graphqlType.serialize(bucketRootValue);
|
|
625
|
+
`,
|
|
626
|
+
nameExtra: tamedevil_1.default.cache `intLeaf`,
|
|
627
|
+
asString: true,
|
|
628
|
+
skipNullHandling: false,
|
|
629
|
+
// Fast check to see if number is 32 bit integer
|
|
630
|
+
preamble: (0, tamedevil_1.default) `\
|
|
631
|
+
if ((bucketRootValue | 0) === bucketRootValue) {
|
|
632
|
+
return '' + bucketRootValue;
|
|
633
|
+
}
|
|
634
|
+
`,
|
|
635
|
+
});
|
|
636
|
+
const floatLeafExecutorString = makeExecutor({
|
|
637
|
+
inner: (0, tamedevil_1.default) `\
|
|
638
|
+
return String(this.type.graphqlType.serialize(bucketRootValue));
|
|
639
|
+
`,
|
|
640
|
+
nameExtra: tamedevil_1.default.cache `floatLeaf`,
|
|
641
|
+
asString: true,
|
|
642
|
+
skipNullHandling: false,
|
|
643
|
+
preamble: (0, tamedevil_1.default) `\
|
|
644
|
+
if (Number.isFinite(bucketRootValue)) {
|
|
645
|
+
return '' + bucketRootValue;
|
|
646
|
+
}
|
|
647
|
+
`,
|
|
648
|
+
});
|
|
649
|
+
const stringLeafExecutorString = makeExecutor({
|
|
650
|
+
inner: (0, tamedevil_1.default) `\
|
|
651
|
+
return ${ref_stringifyString}(this.type.graphqlType.serialize(bucketRootValue));
|
|
652
|
+
`,
|
|
653
|
+
nameExtra: tamedevil_1.default.cache `stringLeaf`,
|
|
654
|
+
asString: true,
|
|
655
|
+
skipNullHandling: false,
|
|
656
|
+
preamble: (0, tamedevil_1.default) `\
|
|
657
|
+
if (typeof bucketRootValue === 'string') {
|
|
658
|
+
return ${ref_stringifyString}(bucketRootValue);
|
|
659
|
+
}
|
|
660
|
+
`,
|
|
661
|
+
});
|
|
662
|
+
// NOTE: the reference to $$concreteType here is a (temporary) optimization; it
|
|
663
|
+
// should be `resolveType(bucketRootValue)` but it's not worth the function
|
|
664
|
+
// call overhead. Longer term it should just be read directly from a different
|
|
665
|
+
// store.
|
|
666
|
+
function makePolymorphicExecutor(asString) {
|
|
667
|
+
return makeExecutor({
|
|
668
|
+
inner: (0, tamedevil_1.default) `\
|
|
669
|
+
${dev_js_1.isDev
|
|
670
|
+
? (0, tamedevil_1.default) `\
|
|
671
|
+
if (!${ref_isPolymorphicData}(bucketRootValue)) {
|
|
672
|
+
throw ${ref_coerceError}(
|
|
673
|
+
new Error(
|
|
674
|
+
"GrafastInternalError<db7fcda5-dc39-4568-a7ce-ee8acb88806b>: Expected polymorphic data",
|
|
675
|
+
),
|
|
676
|
+
this.locationDetails,
|
|
677
|
+
mutablePath.slice(1),
|
|
678
|
+
);
|
|
679
|
+
}
|
|
680
|
+
`
|
|
681
|
+
: tamedevil_1.default.blank}\
|
|
682
|
+
const typeName = bucketRootValue[${ref_$$concreteType}];
|
|
683
|
+
const childOutputPlan = this.childByTypeName[typeName];
|
|
684
|
+
${dev_js_1.isDev
|
|
685
|
+
? (0, tamedevil_1.default) `{
|
|
686
|
+
${ref_assert}.ok(
|
|
687
|
+
typeName,
|
|
688
|
+
"GrafastInternalError<fd3f3cf0-0789-4c74-a6cd-839c808896ed>: Could not determine concreteType for object",
|
|
689
|
+
);
|
|
690
|
+
${ref_assert}.ok(
|
|
691
|
+
childOutputPlan,
|
|
692
|
+
\`GrafastInternalError<a46999ef-41ff-4a22-bae9-fa37ff6e5f7f>: Could not determine the OutputPlan to use for '\${typeName}' from '\${bucket.layerPlan}'\`,
|
|
693
|
+
);
|
|
694
|
+
}`
|
|
695
|
+
: tamedevil_1.default.blank}
|
|
696
|
+
|
|
697
|
+
const directChild = bucket.children[childOutputPlan.layerPlan.id];
|
|
698
|
+
if (directChild !== undefined) {
|
|
699
|
+
return childOutputPlan.${asString ? te_executeString : te_execute}(root, mutablePath, directChild.bucket, directChild.map.get(bucketIndex));
|
|
700
|
+
} else {
|
|
701
|
+
const c = ${ref_getChildBucketAndIndex}(
|
|
702
|
+
childOutputPlan,
|
|
703
|
+
this,
|
|
704
|
+
bucket,
|
|
705
|
+
bucketIndex,
|
|
706
|
+
);
|
|
707
|
+
if (!c) {
|
|
708
|
+
throw new Error("GrafastInternalError<691509d8-31fa-4cfe-a6df-dcba21bd521f>: polymorphic executor couldn't determine child bucket");
|
|
709
|
+
}
|
|
710
|
+
const [childBucket, childBucketIndex] = c;
|
|
711
|
+
return childOutputPlan.${asString ? te_executeString : te_execute}(root, mutablePath, childBucket, childBucketIndex);
|
|
712
|
+
}
|
|
713
|
+
`,
|
|
714
|
+
nameExtra: te_polymorphic,
|
|
715
|
+
asString,
|
|
716
|
+
});
|
|
717
|
+
}
|
|
718
|
+
const polymorphicExecutor = makePolymorphicExecutor(false);
|
|
719
|
+
const polymorphicExecutorString = makePolymorphicExecutor(true);
|
|
720
|
+
function makeArrayExecutor(childIsNonNull, canStream, asString) {
|
|
721
|
+
return makeExecutor({
|
|
722
|
+
inner: (0, tamedevil_1.default) `\
|
|
723
|
+
if (!Array.isArray(bucketRootValue)) {
|
|
724
|
+
console.warn(\`Hit fallback for value \${${ref_inspect}(bucketRootValue)} coercion to mode 'array'\`);
|
|
725
|
+
return ${asString ? te_nullString : te_null};
|
|
726
|
+
}
|
|
727
|
+
|
|
728
|
+
const childOutputPlan = this.child;
|
|
729
|
+
const l = bucketRootValue.length;
|
|
730
|
+
let fieldResult;
|
|
731
|
+
${asString ? te_letString : te_constDataEqualsEmptyArray}
|
|
732
|
+
if (l === 0) {
|
|
733
|
+
${asString ? te_stringEqualsEmptyArrayString : te_noopComment}
|
|
734
|
+
} else {
|
|
735
|
+
${asString ? te_stringEqualsLeftSquareBraceString : tamedevil_1.default.blank}\
|
|
736
|
+
const mutablePathIndex = mutablePath.push(-1) - 1;
|
|
737
|
+
|
|
738
|
+
// Now to populate the children...
|
|
739
|
+
const directChild = bucket.children[childOutputPlan.layerPlan.id];
|
|
740
|
+
let childBucket, childBucketIndex, lookup;
|
|
741
|
+
if (directChild !== undefined) {
|
|
742
|
+
childBucket = directChild.bucket;
|
|
743
|
+
lookup = directChild.map.get(bucketIndex)
|
|
744
|
+
}
|
|
745
|
+
for (let i = 0; i < l; i++) {
|
|
746
|
+
if (directChild !== undefined) {
|
|
747
|
+
childBucketIndex = lookup[i];
|
|
748
|
+
} else {
|
|
749
|
+
const c = ${ref_getChildBucketAndIndex}(
|
|
750
|
+
childOutputPlan,
|
|
751
|
+
this,
|
|
752
|
+
bucket,
|
|
753
|
+
bucketIndex,
|
|
754
|
+
i,
|
|
755
|
+
);
|
|
756
|
+
if (c !== null) {
|
|
757
|
+
([childBucket, childBucketIndex] = c);
|
|
758
|
+
} else {
|
|
759
|
+
childBucket = childBucketIndex = null;
|
|
760
|
+
}
|
|
761
|
+
}
|
|
762
|
+
|
|
763
|
+
mutablePath[mutablePathIndex] = i;
|
|
764
|
+
${asString ? te_ifIGt0StrPlusEqualComma : tamedevil_1.default.blank}
|
|
765
|
+
${makeExecuteChildPlanCode(asString ? te_stringPlusEquals : te_dataIEquals, te_thisDotLocationDetails, te_childOutputPlan, childIsNonNull, asString)}
|
|
766
|
+
}
|
|
767
|
+
|
|
768
|
+
mutablePath.length = mutablePathIndex;
|
|
769
|
+
${asString ? te_stringPlusEqualsRbracket : tamedevil_1.default.blank}
|
|
770
|
+
}
|
|
771
|
+
${canStream
|
|
772
|
+
? (0, tamedevil_1.default) `\
|
|
773
|
+
const stream = bucketRootValue[${ref_$$streamMore}] /* as | AsyncIterableIterator<any> | undefined*/;
|
|
774
|
+
if (stream !== undefined) {
|
|
775
|
+
root.streams.push({
|
|
776
|
+
root,
|
|
777
|
+
path: mutablePath.slice(1),
|
|
778
|
+
bucket,
|
|
779
|
+
bucketIndex,
|
|
780
|
+
outputPlan: childOutputPlan,
|
|
781
|
+
label: childOutputPlan.layerPlan.reason.stream?.label,
|
|
782
|
+
stream,
|
|
783
|
+
startIndex: bucketRootValue.length,
|
|
784
|
+
});
|
|
785
|
+
}`
|
|
786
|
+
: tamedevil_1.default.blank}
|
|
787
|
+
|
|
788
|
+
return ${asString ? te_string : te_data};
|
|
789
|
+
`,
|
|
790
|
+
nameExtra: (0, tamedevil_1.default) `array${childIsNonNull ? te_underscoreNonNull : tamedevil_1.default.blank}${canStream ? te_underscoreStream : tamedevil_1.default.blank}`,
|
|
791
|
+
asString,
|
|
792
|
+
});
|
|
793
|
+
}
|
|
794
|
+
const arrayExecutor_nullable = makeArrayExecutor(false, false, false);
|
|
795
|
+
const arrayExecutor_nullable_streaming = makeArrayExecutor(false, true, false);
|
|
796
|
+
const arrayExecutor_nonNullable = makeArrayExecutor(true, false, false);
|
|
797
|
+
const arrayExecutor_nonNullable_streaming = makeArrayExecutor(true, true, false);
|
|
798
|
+
const arrayExecutorString_nullable = makeArrayExecutor(false, false, true);
|
|
799
|
+
const arrayExecutorString_nullable_streaming = makeArrayExecutor(false, true, true);
|
|
800
|
+
const arrayExecutorString_nonNullable = makeArrayExecutor(true, false, true);
|
|
801
|
+
const arrayExecutorString_nonNullable_streaming = makeArrayExecutor(true, true, true);
|
|
802
|
+
/**
|
|
803
|
+
* This piggy-backs off of GraphQL.js by rewriting the request, executing it in
|
|
804
|
+
* GraphQL.js, and then patching it into our response. It's a temporary
|
|
805
|
+
* workaround until we can afford the time to write our own introspection
|
|
806
|
+
* execution.
|
|
807
|
+
*
|
|
808
|
+
* ENHANCE: write our own introspection execution!
|
|
809
|
+
*/
|
|
810
|
+
const introspect = (root, outputPlan, mutablePath, asString) => {
|
|
811
|
+
const { locationDetails } = outputPlan;
|
|
812
|
+
const { field: rawField, introspectionCacheByVariableValues, variableNames, } = outputPlan.type;
|
|
813
|
+
const field = {
|
|
814
|
+
...rawField,
|
|
815
|
+
alias: { kind: Kind.NAME, value: "a" },
|
|
816
|
+
};
|
|
817
|
+
const document = {
|
|
818
|
+
definitions: [
|
|
819
|
+
{
|
|
820
|
+
kind: Kind.OPERATION_DEFINITION,
|
|
821
|
+
operation: OperationTypeNode.QUERY,
|
|
822
|
+
selectionSet: {
|
|
823
|
+
kind: Kind.SELECTION_SET,
|
|
824
|
+
selections: [field],
|
|
825
|
+
},
|
|
826
|
+
variableDefinitions: outputPlan.layerPlan.operationPlan.operation.variableDefinitions?.filter((d) => variableNames.includes(d.variable.name.value)),
|
|
827
|
+
},
|
|
828
|
+
...Object.values(outputPlan.layerPlan.operationPlan.fragments),
|
|
829
|
+
],
|
|
830
|
+
kind: Kind.DOCUMENT,
|
|
831
|
+
};
|
|
832
|
+
const variableValues = Object.create(null);
|
|
833
|
+
const sortedVariableNames = [...variableNames].sort();
|
|
834
|
+
for (const variableName of sortedVariableNames) {
|
|
835
|
+
variableValues[variableName] = root.variables[variableName];
|
|
836
|
+
}
|
|
837
|
+
// "canonical" only to one level, but given introspection doesn't really
|
|
838
|
+
// accept objects this should be mostly sufficient for decent optimization
|
|
839
|
+
// level.
|
|
840
|
+
const canonical = JSON.stringify(variableValues);
|
|
841
|
+
const cached = introspectionCacheByVariableValues.get(canonical);
|
|
842
|
+
if (cached !== undefined) {
|
|
843
|
+
return asString ? JSON.stringify(cached) : cached;
|
|
844
|
+
}
|
|
845
|
+
const graphqlResult = executeSync({
|
|
846
|
+
schema: outputPlan.layerPlan.operationPlan.schema,
|
|
847
|
+
document,
|
|
848
|
+
variableValues,
|
|
849
|
+
});
|
|
850
|
+
if (graphqlResult.errors !== undefined) {
|
|
851
|
+
// NOTE: we should map the introspection path, however that might require
|
|
852
|
+
// us to be able to raise multiple errors. Theoretically if the query
|
|
853
|
+
// validates we shouldn't be able to get errors out of the introspection
|
|
854
|
+
// system, so we'll skip over this for now. When we get around to
|
|
855
|
+
// implementing introspection natively in Grafast rather than piggy-backing
|
|
856
|
+
// off of GraphQL.js then this problem will go away on its own.
|
|
857
|
+
console.error("INTROSPECTION FAILED!");
|
|
858
|
+
console.error(graphqlResult);
|
|
859
|
+
const { node } = locationDetails;
|
|
860
|
+
throw new GraphQLError("INTROSPECTION FAILED!", node, null, null, mutablePath.slice(1), null, null);
|
|
861
|
+
}
|
|
862
|
+
const result = graphqlResult.data.a;
|
|
863
|
+
introspectionCacheByVariableValues.set(canonical, result);
|
|
864
|
+
return asString ? JSON.stringify(result) : result;
|
|
865
|
+
};
|
|
866
|
+
const ref_introspect = tamedevil_1.default.ref(introspect, "introspect");
|
|
867
|
+
const introspectionExecutor = makeExecutor({
|
|
868
|
+
inner: (0, tamedevil_1.default) ` return ${ref_introspect}(root, this, mutablePath, false)`,
|
|
869
|
+
nameExtra: tamedevil_1.default.cache `introspection`,
|
|
870
|
+
asString: false,
|
|
871
|
+
skipNullHandling: true,
|
|
872
|
+
});
|
|
873
|
+
const introspectionExecutorString = makeExecutor({
|
|
874
|
+
inner: (0, tamedevil_1.default) ` return ${ref_introspect}(root, this, mutablePath, true)`,
|
|
875
|
+
nameExtra: tamedevil_1.default.cache `introspection`,
|
|
876
|
+
asString: true,
|
|
877
|
+
skipNullHandling: true,
|
|
878
|
+
});
|
|
879
|
+
const SAFE_NAME = /^[A-Za-z_][A-Za-z0-9_]*$/;
|
|
880
|
+
function makeObjectExecutor(typeName, fieldTypes, hasDeferredOutputPlans,
|
|
881
|
+
// this.type.mode === "root",
|
|
882
|
+
isRoot, asString, callback) {
|
|
883
|
+
if (!SAFE_NAME.test(typeName)) {
|
|
884
|
+
throw new Error(`Unsafe type name: ${typeName}; doesn't conform to 'Name' in the GraphQL spec`);
|
|
885
|
+
}
|
|
886
|
+
const keys = [];
|
|
887
|
+
const fieldSpecs = [];
|
|
888
|
+
let signature = (asString ? "s" : "o") +
|
|
889
|
+
(isRoot ? "r" : "") +
|
|
890
|
+
(hasDeferredOutputPlans ? "d" : "");
|
|
891
|
+
let hasChildBucketReference = false;
|
|
892
|
+
for (const [key, fieldSpec] of Object.entries(fieldTypes)) {
|
|
893
|
+
if (!SAFE_NAME.test(key)) {
|
|
894
|
+
// This should not be able to happen if the GraphQL operation is valid
|
|
895
|
+
throw new Error(`Unsafe key: ${key}; doesn't conform to 'Name' in the GraphQL spec`);
|
|
896
|
+
}
|
|
897
|
+
keys.push(key);
|
|
898
|
+
fieldSpecs.push(fieldSpec);
|
|
899
|
+
const { fieldType, sameBucket } = fieldSpec;
|
|
900
|
+
switch (fieldType) {
|
|
901
|
+
case "__typename": {
|
|
902
|
+
signature += "_";
|
|
903
|
+
break;
|
|
904
|
+
}
|
|
905
|
+
case "outputPlan?": {
|
|
906
|
+
signature += "?";
|
|
907
|
+
break;
|
|
908
|
+
}
|
|
909
|
+
case "outputPlan!": {
|
|
910
|
+
signature += "!";
|
|
911
|
+
break;
|
|
912
|
+
}
|
|
913
|
+
default: {
|
|
914
|
+
const never = fieldType;
|
|
915
|
+
throw new Error(`Unsupported field type '${never}'`);
|
|
916
|
+
}
|
|
917
|
+
}
|
|
918
|
+
if (!sameBucket) {
|
|
919
|
+
hasChildBucketReference = true;
|
|
920
|
+
signature += "~";
|
|
921
|
+
}
|
|
922
|
+
}
|
|
923
|
+
withObjectExecutorFactory(signature, fieldSpecs, hasDeferredOutputPlans, isRoot, asString, hasChildBucketReference, (factory) => {
|
|
924
|
+
const fn = factory(typeName, ...keys);
|
|
925
|
+
callback(fn);
|
|
926
|
+
});
|
|
927
|
+
}
|
|
928
|
+
const makeObjectExecutorCache = new lru_1.default({
|
|
929
|
+
maxLength: 1000,
|
|
930
|
+
});
|
|
931
|
+
const makingObjectExecutorCallbacks = new Map();
|
|
932
|
+
function withObjectExecutorFactory(signature, fieldSpecs, hasDeferredOutputPlans, isRoot, asString, hasChildBucketReference, callback) {
|
|
933
|
+
const fn = makeObjectExecutorCache.get(signature);
|
|
934
|
+
if (fn !== undefined) {
|
|
935
|
+
return callback(fn);
|
|
936
|
+
}
|
|
937
|
+
const building = makingObjectExecutorCallbacks.get(signature);
|
|
938
|
+
if (building !== undefined) {
|
|
939
|
+
building.push(callback);
|
|
940
|
+
return;
|
|
941
|
+
}
|
|
942
|
+
const callbacks = [callback];
|
|
943
|
+
makingObjectExecutorCallbacks.set(signature, callbacks);
|
|
944
|
+
const inner = (0, tamedevil_1.default) `\
|
|
945
|
+
${asString ? te_letStringLbrace : te_constObjEqualsObjectCreateNull}
|
|
946
|
+
const { keys } = this;
|
|
947
|
+
const mutablePathIndex = mutablePath.push("!") - 1;
|
|
948
|
+
let spec${hasChildBucketReference ? te_childBucketCBIDC : tamedevil_1.default.blank}, fieldResult;
|
|
949
|
+
|
|
950
|
+
${tamedevil_1.default.join(fieldSpecs.map(({ fieldType, sameBucket }, i) => {
|
|
951
|
+
const te_fieldNameI = tamedevil_1.default.identifier(`fieldName_${i}`);
|
|
952
|
+
switch (fieldType) {
|
|
953
|
+
case "__typename": {
|
|
954
|
+
if (asString) {
|
|
955
|
+
// NOTE: this code relies on the fact that fieldName and typeName do
|
|
956
|
+
// not require any quoting in JSON/JS - they must conform to GraphQL
|
|
957
|
+
// `Name`.
|
|
958
|
+
return (0, tamedevil_1.default) ` string += \`${i === 0 ? tamedevil_1.default.blank : te_comma}"\${${te_fieldNameI}}":"\${typeName}"\`;\n`;
|
|
959
|
+
}
|
|
960
|
+
else {
|
|
961
|
+
return (0, tamedevil_1.default) ` obj[${te_fieldNameI}] = typeName;\n`;
|
|
962
|
+
}
|
|
963
|
+
}
|
|
964
|
+
case "outputPlan!":
|
|
965
|
+
case "outputPlan?": {
|
|
966
|
+
return (0, tamedevil_1.default) `\
|
|
967
|
+
mutablePath[mutablePathIndex] = ${te_fieldNameI};
|
|
968
|
+
spec = keys[${te_fieldNameI}];
|
|
969
|
+
${asString
|
|
970
|
+
? (0, tamedevil_1.default) ` string += \`${i === 0 ? tamedevil_1.default.blank : te_comma}"\${${te_fieldNameI}}":\`;
|
|
971
|
+
`
|
|
972
|
+
: tamedevil_1.default.blank}\
|
|
973
|
+
${sameBucket
|
|
974
|
+
? (0, tamedevil_1.default) `\
|
|
975
|
+
${makeExecuteChildPlanCode(asString ? te_stringPlusEquals : (0, tamedevil_1.default) `obj[${te_fieldNameI}] =`, te_specDotLocationDetails, te_specDotOutputPlan, fieldType === "outputPlan!", asString, te_bucket, te_bucketIndex)}`
|
|
976
|
+
: (0, tamedevil_1.default) `\
|
|
977
|
+
directChild = bucket.children[spec.outputPlan.layerPlanId];
|
|
978
|
+
if (directChild !== undefined) {
|
|
979
|
+
childBucket = directChild.bucket;
|
|
980
|
+
childBucketIndex = directChild.map.get(bucketIndex);
|
|
981
|
+
} else {
|
|
982
|
+
const c = ${ref_getChildBucketAndIndex}(
|
|
983
|
+
spec.outputPlan,
|
|
984
|
+
this,
|
|
985
|
+
bucket,
|
|
986
|
+
bucketIndex,
|
|
987
|
+
);
|
|
988
|
+
if (c !== null) {
|
|
989
|
+
([childBucket, childBucketIndex] = c);
|
|
990
|
+
} else {
|
|
991
|
+
childBucket = childBucketIndex = null;
|
|
992
|
+
}
|
|
993
|
+
}
|
|
994
|
+
${makeExecuteChildPlanCode(asString ? te_stringPlusEquals : (0, tamedevil_1.default) `obj[${te_fieldNameI}] =`, te_specDotLocationDetails, te_specDotOutputPlan, fieldType === "outputPlan!", asString)}`}
|
|
995
|
+
`;
|
|
996
|
+
}
|
|
997
|
+
default: {
|
|
998
|
+
const never = fieldType;
|
|
999
|
+
throw new Error(`GrafastInternalError<879082f4-fe6f-4112-814f-852b9932ca83>: unsupported key type ${never}`);
|
|
1000
|
+
}
|
|
1001
|
+
}
|
|
1002
|
+
}), "\n")}
|
|
1003
|
+
|
|
1004
|
+
mutablePath.length = mutablePathIndex;
|
|
1005
|
+
${asString ? te_stringPlusEqualsRbrace : tamedevil_1.default.blank}\
|
|
1006
|
+
${hasDeferredOutputPlans ? te_handleDeferred : tamedevil_1.default.blank}
|
|
1007
|
+
return ${asString ? te_string : te_obj};`;
|
|
1008
|
+
const executorExpression = makeExecutorExpression({
|
|
1009
|
+
inner: inner,
|
|
1010
|
+
nameExtra: te_object,
|
|
1011
|
+
asString,
|
|
1012
|
+
skipNullHandling: isRoot,
|
|
1013
|
+
preamble: tamedevil_1.default.blank,
|
|
1014
|
+
});
|
|
1015
|
+
const factoryExpression = (0, tamedevil_1.default) `\
|
|
1016
|
+
function objectExecutorFactory(typeName${tamedevil_1.default.join(fieldSpecs.map((_, i) => (0, tamedevil_1.default) `, ${tamedevil_1.default.identifier(`fieldName_${i}`)}`), "")}) {
|
|
1017
|
+
return ${executorExpression};
|
|
1018
|
+
}`;
|
|
1019
|
+
tamedevil_1.default.runInBatch(factoryExpression, (factory) => {
|
|
1020
|
+
makeObjectExecutorCache.set(signature, factory);
|
|
1021
|
+
makingObjectExecutorCallbacks.delete(signature);
|
|
1022
|
+
for (const callback of callbacks) {
|
|
1023
|
+
callback(factory);
|
|
1024
|
+
}
|
|
1025
|
+
});
|
|
1026
|
+
}
|
|
1027
|
+
const makeCache = new lru_1.default({
|
|
1028
|
+
maxLength: 1000,
|
|
1029
|
+
});
|
|
1030
|
+
const makingCache = new Map();
|
|
1031
|
+
function withFastExpression(path, fallback, callback) {
|
|
1032
|
+
const signature = (fallback === undefined ? "d" : "f") + "_" + path.join("|");
|
|
1033
|
+
const existing = makeCache.get(signature);
|
|
1034
|
+
if (existing !== undefined) {
|
|
1035
|
+
callback(existing);
|
|
1036
|
+
return;
|
|
1037
|
+
}
|
|
1038
|
+
const existingCallbacks = makingCache.get(signature);
|
|
1039
|
+
if (existingCallbacks !== undefined) {
|
|
1040
|
+
existingCallbacks.push(callback);
|
|
1041
|
+
return;
|
|
1042
|
+
}
|
|
1043
|
+
const callbacks = [callback];
|
|
1044
|
+
makingCache.set(signature, callbacks);
|
|
1045
|
+
const jitParts = [];
|
|
1046
|
+
for (let i = 0, l = path.length; i < l; i++) {
|
|
1047
|
+
const part = path[i];
|
|
1048
|
+
jitParts.push(tamedevil_1.default.optionalGet(part));
|
|
1049
|
+
}
|
|
1050
|
+
const expression = tamedevil_1.default.join(jitParts, "");
|
|
1051
|
+
tamedevil_1.default.runInBatch((0, tamedevil_1.default) `(value => (value${expression})${fallback !== undefined ? (0, tamedevil_1.default) ` ?? ${tamedevil_1.default.lit(fallback)}` : tamedevil_1.default.blank})`, (fn) => {
|
|
1052
|
+
makeCache.set(signature, fn);
|
|
1053
|
+
makingCache.delete(signature);
|
|
1054
|
+
for (const callback of callbacks) {
|
|
1055
|
+
callback(fn);
|
|
1056
|
+
}
|
|
1057
|
+
});
|
|
1058
|
+
}
|
|
1059
|
+
//# sourceMappingURL=OutputPlan.js.map
|