grafast 1.0.0-rc.6 → 1.0.0-rc.7

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.
@@ -16,12 +16,17 @@ const executeBucket_ts_1 = require("./executeBucket.js");
16
16
  * If any of these flags exist on a value then it isn't the value we want to
17
17
  * include for the combo step.
18
18
  */
19
- const SKIP_FLAGS = constants_ts_1.FLAG_ERROR | constants_ts_1.FLAG_STOPPED | constants_ts_1.FLAG_POLY_SKIPPED | constants_ts_1.FLAG_INHIBITED;
19
+ const SKIP_FLAGS = constants_ts_1.FLAG_ERROR | constants_ts_1.FLAG_STOPPED | constants_ts_1.FLAG_POLY_SKIPPED | constants_ts_1.FLAG_INHIBITED | constants_ts_1.FLAG_NULL;
20
20
  /**
21
21
  * If any of these flags exist on the "$__typename" step, then the value
22
22
  * should resolve to null
23
23
  */
24
24
  const NO_TYPENAME_FLAGS = constants_ts_1.FLAG_ERROR | constants_ts_1.FLAG_STOPPED | constants_ts_1.FLAG_POLY_SKIPPED | constants_ts_1.FLAG_INHIBITED | constants_ts_1.FLAG_NULL;
25
+ /**
26
+ * Used to determine if we should copy the error. Should only be copied if it's
27
+ * NOT polymorphic skipped; so we check the result `=== FLAG_ERROR`
28
+ */
29
+ const ERROR_OR_POLY_SKIPPED_FLAGS = constants_ts_1.FLAG_ERROR | constants_ts_1.FLAG_POLY_SKIPPED;
25
30
  function hasParentLayerPlan(reason) {
26
31
  return reason.type !== "root" && reason.type !== "combined";
27
32
  }
@@ -298,6 +303,7 @@ class LayerPlan {
298
303
  const polymorphicType = this.reason.type === "polymorphic" ? [] : null;
299
304
  const iterators = this.reason.type === "mutationField" ? parentBucket.iterators : [];
300
305
  const map = new Map();
306
+ let flagUnion = parentBucket.flagUnion;
301
307
  const $parentSideEffect = this.parentSideEffectStep;
302
308
  let parentSideEffectValue;
303
309
  if ($parentSideEffect) {
@@ -476,6 +482,7 @@ class LayerPlan {
476
482
  flags = flags | constants_ts_1.FLAG_NULL;
477
483
  }
478
484
  }
485
+ flagUnion |= flags;
479
486
  ev._setResult(newIndex, val, flags);
480
487
  polymorphicPathList[newIndex] =
481
488
  parentBucket.polymorphicPathList[originalIndex];
@@ -640,7 +647,7 @@ class LayerPlan {
640
647
  size,
641
648
  store,
642
649
  // PERF: not necessarily, if we don't copy the errors, we don't have the errors.
643
- flagUnion: parentBucket.flagUnion,
650
+ flagUnion,
644
651
  polymorphicPathList,
645
652
  polymorphicType,
646
653
  iterators,
@@ -669,6 +676,8 @@ class LayerPlan {
669
676
  return null;
670
677
  }
671
678
  }
679
+ // TODO: currently we copy nulls and errors through. Ideally we wouldn't,
680
+ // thereby shrinking the size of the bucket.
672
681
  newCombinedBucket(finalParentBucket) {
673
682
  const t = this.reason.type;
674
683
  if (t !== "combined") {
@@ -753,6 +762,7 @@ class LayerPlan {
753
762
  continue;
754
763
  for (let originalIndex = 0; originalIndex < parentBucket.size; originalIndex++) {
755
764
  const newIndex = originalIndex + offset;
765
+ let fallbackErrorSource = null;
756
766
  if (sourceStepsByLayerPlanId[plp.id]) {
757
767
  for (const stepId of sourceStepsByLayerPlanId[plp.id]) {
758
768
  const sourceStore = parentBucket.store.get(stepId);
@@ -760,12 +770,29 @@ class LayerPlan {
760
770
  const step = this.operationPlan.stepTracker.getStepById(stepId);
761
771
  throw new Error(`GrafastInternalError<a48ca88c-e4b9-4a4f-9a38-846fa067f143>: missing source store for ${step} (${stepId}) in ${this}`);
762
772
  }
763
- if ((sourceStore._flagsAt(originalIndex) & SKIP_FLAGS) == 0) {
773
+ const sourceFlags = sourceStore._flagsAt(originalIndex);
774
+ if ((sourceFlags & SKIP_FLAGS) === 0) {
764
775
  ev._copyResult(newIndex, sourceStore, originalIndex);
776
+ fallbackErrorSource = null;
765
777
  break;
766
778
  }
779
+ else if (fallbackErrorSource === null &&
780
+ (sourceFlags & ERROR_OR_POLY_SKIPPED_FLAGS) === constants_ts_1.FLAG_ERROR) {
781
+ fallbackErrorSource = sourceStore;
782
+ } // If no matches, it retains `FLAG_NULL | FLAG_STOPPED` from above
767
783
  }
768
784
  }
785
+ if (fallbackErrorSource !== null) {
786
+ // No non-skipped source existed for this index; preserve the first
787
+ // available error instead of silently converting to stopped/null.
788
+ //
789
+ // Normally we'd do:
790
+ //
791
+ // ev._copyResult(newIndex, fallbackErrorSource, originalIndex);
792
+ //
793
+ // However, we want to add FLAG_STOPPED, so we do this manually:
794
+ ev._setResult(newIndex, fallbackErrorSource.at(originalIndex), fallbackErrorSource._flagsAt(originalIndex) | constants_ts_1.FLAG_STOPPED);
795
+ }
769
796
  iterators[newIndex] = parentBucket.iterators[originalIndex];
770
797
  }
771
798
  offset += parentBucket.size;
@@ -1220,6 +1220,9 @@ class OperationPlan {
1220
1220
  : (0, step_ts_1.stepHasToRecord)($original)
1221
1221
  ? (0, withGlobalLayerPlan_ts_1.withGlobalLayerPlan)(commonLayerPlan, polymorphicPaths, planningPath, null, $original.toRecord, $original)
1222
1222
  : $original;
1223
+ // Combo layer plan filters nulls for us; since we're skipping that
1224
+ // we need to explicitly inhibit nulls
1225
+ commonStep = (0, withGlobalLayerPlan_ts_1.withGlobalLayerPlan)(commonLayerPlan, polymorphicPaths, planningPath, null, index_ts_1.inhibitOnNull, null, commonStep);
1223
1226
  for (const detailsRecord of detailsRecordList) {
1224
1227
  detailsRecord.layerPlan = commonLayerPlan;
1225
1228
  const polymorphicPaths = detailsRecord.polymorphicPaths;
@@ -147,7 +147,7 @@ function distributor(sourceIterable, dependentSteps, abortSignal, distributorOpt
147
147
  let advanced = false;
148
148
  while (smallest >= lowWaterMark) {
149
149
  advanced = true;
150
- buffer.shift();
150
+ void buffer.shift();
151
151
  lowWaterMark++;
152
152
  }
153
153
  // Announce that the lowWaterMark advanced
@@ -342,14 +342,14 @@ function distributor(sourceIterable, dependentSteps, abortSignal, distributorOpt
342
342
  const stepIndex = getStepIndex(stepId);
343
343
  if (!hasIterator[stepIndex]) {
344
344
  hasIterator[stepIndex] = true;
345
- stop(stepIndex);
345
+ void stop(stepIndex);
346
346
  }
347
347
  },
348
348
  };
349
349
  abortSignal.addEventListener("abort", () => {
350
350
  for (let stepIndex = 0, l = dependentSteps.length; stepIndex < l; stepIndex++) {
351
351
  hasIterator[stepIndex] = true;
352
- stop(stepIndex, undefined, false);
352
+ void stop(stepIndex, undefined, false);
353
353
  }
354
354
  maybeAdvanceLowWaterMark();
355
355
  });
@@ -181,9 +181,7 @@ function executeBucket(bucket, requestContext) {
181
181
  // **DO NOT THROW, DO NOT ALLOW AN ERROR TO BE RAISED!**
182
182
  // **USE DEFENSIVE PROGRAMMING HERE!**
183
183
  /** PROMISES ADDED HERE MUST NOT REJECT */
184
- let promises;
185
- let pendingPromises;
186
- let pendingPromiseIndexes;
184
+ let promises = undefined;
187
185
  // TODO: it seems that if this throws an error it results in a permanent
188
186
  // hang of defers? In the mean time... Don't throw any errors here!
189
187
  const success = (finishedStep, bucket, resultIndex, rawValue, flags) => {
@@ -234,8 +232,9 @@ function executeBucket(bucket, requestContext) {
234
232
  }
235
233
  replacement[i] = null;
236
234
  const index = i;
235
+ // Must not reject
237
236
  const promise = item.then((v) => void (replacement[index] = v), (e) => void (replacement[index] = (0, error_ts_1.flagError)(e)));
238
- if (!promises) {
237
+ if (promises === undefined) {
239
238
  promises = [promise];
240
239
  }
241
240
  else {
@@ -343,7 +342,7 @@ function executeBucket(bucket, requestContext) {
343
342
  bucket.setResult(finishedStep, resultIndex, e, flags | constants_ts_1.FLAG_ERROR);
344
343
  }
345
344
  })();
346
- if (!promises) {
345
+ if (promises === undefined) {
347
346
  promises = [promise];
348
347
  }
349
348
  else {
@@ -365,56 +364,26 @@ function executeBucket(bucket, requestContext) {
365
364
  const count = step._isUnary ? 1 : size;
366
365
  for (let dataIndex = 0; dataIndex < count; dataIndex++) {
367
366
  const val = results[dataIndex];
367
+ const valFlags = flags[dataIndex];
368
+ if (valFlags == null) {
369
+ throw new Error(`GraphileInternalError<75df71bb-0f76-4a98-9664-9167d502296a>: result for ${step} has no flag at index ${dataIndex} (value = ${(0, inspect_ts_1.inspect)(val)})`);
370
+ }
368
371
  if (step.isSyncAndSafe || !(0, utils_ts_1.isPromiseLike)(val)) {
369
- if (flags[dataIndex] == null) {
370
- throw new Error(`GraphileInternalError<75df71bb-0f76-4a98-9664-9167d502296a>: result for ${step} has no flag at index ${dataIndex} (value = ${(0, inspect_ts_1.inspect)(val)})`);
371
- }
372
- success(step, bucket, dataIndex, val, flags[dataIndex]);
372
+ success(step, bucket, dataIndex, val, valFlags);
373
373
  }
374
374
  else {
375
- if (!pendingPromises) {
376
- pendingPromises = [val];
377
- pendingPromiseIndexes = [{ s: allStepsIndex, i: dataIndex }];
375
+ // Must not reject!
376
+ const valSuccess = val.then((val) => success(step, bucket, dataIndex, val, valFlags), (error) => bucket.setResult(step, dataIndex, error, constants_ts_1.FLAG_ERROR));
377
+ if (promises === undefined) {
378
+ promises = [valSuccess];
378
379
  }
379
380
  else {
380
- pendingPromises.push(val);
381
- pendingPromiseIndexes.push({ s: allStepsIndex, i: dataIndex });
381
+ promises.push(valSuccess);
382
382
  }
383
383
  }
384
384
  }
385
385
  }
386
- if (pendingPromises !== undefined) {
387
- return Promise.allSettled(pendingPromises)
388
- .then((resultSettledResult) => {
389
- for (let i = 0, pendingPromisesLength = resultSettledResult.length; i < pendingPromisesLength; i++) {
390
- const settledResult = resultSettledResult[i];
391
- const { s: allStepsIndex, i: dataIndex } = pendingPromiseIndexes[i];
392
- const finishedStep = _allSteps[allStepsIndex];
393
- if (settledResult.status === "fulfilled") {
394
- success(finishedStep, bucket, dataIndex, settledResult.value, constants_ts_1.NO_FLAGS);
395
- }
396
- else {
397
- const error = settledResult.reason;
398
- bucket.setResult(finishedStep, dataIndex, error, constants_ts_1.FLAG_ERROR);
399
- }
400
- }
401
- return promises ? Promise.all(promises) : undefined;
402
- })
403
- .then(null, (e) => {
404
- // THIS SHOULD NEVER HAPPEN!
405
- console.error(`GrafastInternalError<1e9731b4-005e-4b0e-bc61-43baa62e6444>: this error should never occur! Please file an issue against grafast. Details: ${e}`);
406
- bucket.flagUnion |= constants_ts_1.FLAG_ERROR;
407
- for (let i = 0, pendingPromisesLength = pendingPromises.length; i < pendingPromisesLength; i++) {
408
- const { s: allStepsIndex, i: dataIndex } = pendingPromiseIndexes[i];
409
- const finishedStep = _allSteps[allStepsIndex];
410
- const error = new Error(`GrafastInternalError<1e9731b4-005e-4b0e-bc61-43baa62e6444>: error occurred whilst performing completedStep(${finishedStep.id})`);
411
- bucket.setResult(finishedStep, dataIndex, error, constants_ts_1.FLAG_ERROR);
412
- }
413
- });
414
- }
415
- else {
416
- return promises ? Promise.all(promises) : undefined;
417
- }
386
+ return promises === undefined ? undefined : Promise.all(promises);
418
387
  };
419
388
  const runSyncSteps = () => {
420
389
  const executedLength = resultList.length;
@@ -1046,14 +1015,22 @@ function markLayerPlanAsDone(requestContext, sharedState, layerPlan, bucket) {
1046
1015
  if (!allParentLayerPlansAreReady) {
1047
1016
  // The last parent layer plan to complete will handle it.
1048
1017
  // Make sure we're retained so it can use our data!
1049
- // Will be released inside the "combined" branch in childLayerPlan.newBucket
1018
+ // Released below.
1050
1019
  if (bucket != null) {
1051
1020
  bucket.sharedState.retain(bucket);
1052
1021
  }
1053
- // TODO: MAKE SURE CANCELLED BUCKETS ARE HANDLED!
1054
1022
  continue loop;
1055
1023
  }
1056
1024
  const childBucket = childLayerPlan.newCombinedBucket({ sharedState });
1025
+ // Every parent except the final parent was retained while waiting for all
1026
+ // parents to complete; release those temporary retains now.
1027
+ for (const plp of childLayerPlan.reason.parentLayerPlans) {
1028
+ if (plp === layerPlan)
1029
+ continue; // Was never retained
1030
+ const otherBucket = sharedState._retainedBuckets.get(plp.id);
1031
+ if (otherBucket !== undefined)
1032
+ sharedState.release(otherBucket);
1033
+ }
1057
1034
  if (childBucket !== null) {
1058
1035
  // Execute
1059
1036
  const result = executeBucket(childBucket, requestContext);
@@ -1174,9 +1151,7 @@ function newBucket(parent, spec) {
1174
1151
  if (index >= size) {
1175
1152
  throw new Error(`GrafastInternalError<9465db89-cc9d-415c-97e7-57bb19ddebe0>: attempt to write to out of bounds index ${index} for bucket of size ${size} for step ${step}`);
1176
1153
  }
1177
- if (flags !== constants_ts_1.NO_FLAGS) {
1178
- this.flagUnion |= flags;
1179
- }
1154
+ this.flagUnion |= flags;
1180
1155
  if (step._isUnary) {
1181
1156
  if (dev_ts_1.isDev && store.has(stepId)) {
1182
1157
  const ev = store.get(stepId);
@@ -171,7 +171,7 @@ function executeLoad(details, sharedDepId, paramDepIdByKey, baseLoadInfo, load)
171
171
  (0, exports.nextTick)(() => {
172
172
  // Don't allow adding anything else to the batch
173
173
  meta.loadBatchesByLoad.delete(load);
174
- executeBatches(loadBatches, loadInfo, load);
174
+ void executeBatches(loadBatches, loadInfo, load);
175
175
  });
176
176
  }
177
177
  return (async () => {
@@ -66,10 +66,10 @@ class GraphQLResolverStep extends step_ts_1.UnbatchedStep {
66
66
  }
67
67
  else {
68
68
  if (this.isNotRoot) {
69
- return Promise.reject(new Error(`Invalid non-root subscribe`));
69
+ return (0, index_ts_1.flagError)(new Error(`Invalid non-root subscribe`));
70
70
  }
71
71
  if (this.subscriber == null) {
72
- return Promise.reject(new Error(`Cannot subscribe to field`));
72
+ return (0, index_ts_1.flagError)(new Error(`Cannot subscribe to field`));
73
73
  }
74
74
  const resolveInfo = Object.assign(Object.create(this.resolveInfoBase), {
75
75
  // ENHANCE: add support for path
@@ -119,6 +119,8 @@ class GraphQLResolveTypeStep extends step_ts_1.Step {
119
119
  * resolution part.
120
120
  */
121
121
  figureOutTheTypeOf(data, context, resolveInfo) {
122
+ if (data == null)
123
+ return data;
122
124
  const abstractType = this.abstractType;
123
125
  if (abstractType.resolveType != null) {
124
126
  return abstractType.resolveType(data, context, resolveInfo, abstractType);
package/dist/version.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- export declare const version = "1.0.0-rc.6";
1
+ export declare const version = "1.0.0-rc.7";
2
2
  //# sourceMappingURL=version.d.ts.map
package/dist/version.js CHANGED
@@ -2,5 +2,5 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.version = void 0;
4
4
  // This file is autogenerated by /scripts/postversion.mjs
5
- exports.version = "1.0.0-rc.6";
5
+ exports.version = "1.0.0-rc.7";
6
6
  //# sourceMappingURL=version.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "grafast",
3
- "version": "1.0.0-rc.6",
3
+ "version": "1.0.0-rc.7",
4
4
  "description": "Cutting edge GraphQL planning and execution engine",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -59,7 +59,7 @@
59
59
  "chalk": "^4.1.2",
60
60
  "debug": "^4.4.3",
61
61
  "eventemitter3": "^5.0.1",
62
- "graphile-config": "^1.0.0-rc.4",
62
+ "graphile-config": "^1.0.0-rc.5",
63
63
  "graphql": "^16.9.0",
64
64
  "iterall": "^1.3.0",
65
65
  "tslib": "^2.8.1"