@graphitation/supermassive 3.17.2-canary.1 → 3.18.0

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.
@@ -9,6 +9,7 @@ import {
9
9
  collectSubfields as _collectSubfields
10
10
  } from "./collectFields.mjs";
11
11
  import { devAssert } from "./jsutils/devAssert.mjs";
12
+ import { getObjectAtPath } from "./jsutils/getObjectAtPath.mjs";
12
13
  import { inspect } from "./jsutils/inspect.mjs";
13
14
  import { invariant } from "./jsutils/invariant.mjs";
14
15
  import { isIterableObject } from "./jsutils/isIterableObject.mjs";
@@ -69,7 +70,10 @@ function buildExecutionContext(args) {
69
70
  typeResolver,
70
71
  subscribeFieldResolver,
71
72
  fieldExecutionHooks,
72
- enablePerEventContext
73
+ enablePerEventContext,
74
+ enableEarlyExecution,
75
+ enableDeferredMerge,
76
+ incrementalPayloadBatchingTimeoutMs
73
77
  } = args;
74
78
  assertValidExecutionArguments(document, variableValues);
75
79
  let operation;
@@ -127,7 +131,10 @@ function buildExecutionContext(args) {
127
131
  errors: [],
128
132
  fieldExecutionHooks,
129
133
  subsequentPayloads: /* @__PURE__ */ new Set(),
130
- enablePerEventContext: enablePerEventContext != null ? enablePerEventContext : true
134
+ enablePerEventContext: enablePerEventContext != null ? enablePerEventContext : true,
135
+ enableEarlyExecution: enableEarlyExecution != null ? enableEarlyExecution : false,
136
+ enableDeferredMerge: enableDeferredMerge != null ? enableDeferredMerge : false,
137
+ incrementalPayloadBatchingTimeoutMs
131
138
  };
132
139
  }
133
140
  function buildPerEventExecutionContext(exeContext, payload) {
@@ -176,7 +183,8 @@ function executeOperation(exeContext) {
176
183
  rootValue,
177
184
  path,
178
185
  groupedFieldSet,
179
- void 0
186
+ void 0,
187
+ exeContext.enableEarlyExecution ? patches : void 0
180
188
  );
181
189
  result = buildResponse(exeContext, result);
182
190
  break;
@@ -186,7 +194,8 @@ function executeOperation(exeContext) {
186
194
  rootTypeName,
187
195
  rootValue,
188
196
  path,
189
- groupedFieldSet
197
+ groupedFieldSet,
198
+ exeContext.enableEarlyExecution ? patches : void 0
190
199
  );
191
200
  result = buildResponse(exeContext, result);
192
201
  break;
@@ -207,16 +216,18 @@ function executeOperation(exeContext) {
207
216
  `Operation "${operation.operation}" is not a part of GraphQL spec`
208
217
  );
209
218
  }
210
- for (const patch of patches) {
211
- const { label, groupedFieldSet: patchGroupedFieldSet } = patch;
212
- executeDeferredFragment(
213
- exeContext,
214
- rootTypeName,
215
- rootValue,
216
- patchGroupedFieldSet,
217
- label,
218
- path
219
- );
219
+ if (!exeContext.enableEarlyExecution) {
220
+ for (const patch of patches) {
221
+ const { label, groupedFieldSet: patchGroupedFieldSet } = patch;
222
+ executeDeferredFragment(
223
+ exeContext,
224
+ rootTypeName,
225
+ rootValue,
226
+ patchGroupedFieldSet,
227
+ label,
228
+ path
229
+ );
230
+ }
220
231
  }
221
232
  return result;
222
233
  } catch (error) {
@@ -224,7 +235,7 @@ function executeOperation(exeContext) {
224
235
  return buildResponse(exeContext, null);
225
236
  }
226
237
  }
227
- function buildResponse(exeContext, data) {
238
+ function buildResponse(exeContext, data, deferredMergeAwaited = false) {
228
239
  var _a, _b;
229
240
  if (isPromise(data)) {
230
241
  return data.then(
@@ -237,6 +248,16 @@ function buildResponse(exeContext, data) {
237
248
  }
238
249
  const hooks = exeContext.fieldExecutionHooks;
239
250
  try {
251
+ if (exeContext.enableDeferredMerge && data !== null) {
252
+ const pendingDeferredFragments = includeCompletedDeferredFragmentsInResult(exeContext, data);
253
+ const batchTimeout = exeContext.incrementalPayloadBatchingTimeoutMs;
254
+ if (typeof batchTimeout === "number" && !deferredMergeAwaited && pendingDeferredFragments.length > 0) {
255
+ return raceIncrementalPayloadBatch(
256
+ pendingDeferredFragments,
257
+ batchTimeout
258
+ ).then(() => buildResponse(exeContext, data, true));
259
+ }
260
+ }
240
261
  const initialResult = exeContext.errors.length === 0 ? { data } : { errors: exeContext.errors, data };
241
262
  if (exeContext.subsequentPayloads.size > 0) {
242
263
  return {
@@ -266,7 +287,17 @@ function buildResponse(exeContext, data) {
266
287
  return buildResponse(exeContext, null);
267
288
  }
268
289
  }
269
- function executeFieldsSerially(exeContext, parentTypeName, sourceValue, path, groupedFieldSet) {
290
+ function executeFieldsSerially(exeContext, parentTypeName, sourceValue, path, groupedFieldSet, patches) {
291
+ if (exeContext.enableEarlyExecution) {
292
+ startExecutingPatches(
293
+ exeContext,
294
+ parentTypeName,
295
+ sourceValue,
296
+ path,
297
+ patches,
298
+ void 0
299
+ );
300
+ }
270
301
  return promiseReduce(
271
302
  groupedFieldSet,
272
303
  (results, [responseName, fieldGroup]) => {
@@ -297,9 +328,19 @@ function executeFieldsSerially(exeContext, parentTypeName, sourceValue, path, gr
297
328
  /* @__PURE__ */ Object.create(null)
298
329
  );
299
330
  }
300
- function executeFields(exeContext, parentTypeName, sourceValue, path, groupedFieldSet, incrementalDataRecord) {
331
+ function executeFields(exeContext, parentTypeName, sourceValue, path, groupedFieldSet, incrementalDataRecord, patches) {
301
332
  const results = /* @__PURE__ */ Object.create(null);
302
333
  let containsPromise = false;
334
+ if (exeContext.enableEarlyExecution) {
335
+ startExecutingPatches(
336
+ exeContext,
337
+ parentTypeName,
338
+ sourceValue,
339
+ path,
340
+ patches,
341
+ incrementalDataRecord
342
+ );
343
+ }
303
344
  try {
304
345
  for (const [responseName, fieldGroup] of groupedFieldSet) {
305
346
  const fieldPath = addPath(path, responseName, parentTypeName);
@@ -331,6 +372,46 @@ function executeFields(exeContext, parentTypeName, sourceValue, path, groupedFie
331
372
  }
332
373
  return promiseForObject(results);
333
374
  }
375
+ function startExecutingPatches(exeContext, parentTypeName, sourceValue, path, patches, incrementalDataRecord) {
376
+ if (!patches) {
377
+ return;
378
+ }
379
+ for (const { label, groupedFieldSet: patchGroupedFieldSet } of patches) {
380
+ executeDeferredFragment(
381
+ exeContext,
382
+ parentTypeName,
383
+ sourceValue,
384
+ patchGroupedFieldSet,
385
+ label,
386
+ path,
387
+ incrementalDataRecord
388
+ );
389
+ }
390
+ }
391
+ function includeCompletedDeferredFragmentsInResult(exeContext, result) {
392
+ const pendingDeferredFragments = [];
393
+ for (const incrementalDataRecord of exeContext.subsequentPayloads) {
394
+ if (!isDeferredFragmentRecord(incrementalDataRecord)) {
395
+ continue;
396
+ }
397
+ if (!incrementalDataRecord.isCompleted) {
398
+ pendingDeferredFragments.push(incrementalDataRecord.promise);
399
+ continue;
400
+ }
401
+ const target = getObjectAtPath(result, incrementalDataRecord.path);
402
+ if (!target) {
403
+ continue;
404
+ }
405
+ if (incrementalDataRecord.data != null) {
406
+ Object.assign(target, incrementalDataRecord.data);
407
+ }
408
+ if (incrementalDataRecord.errors.length > 0) {
409
+ exeContext.errors.push(...incrementalDataRecord.errors);
410
+ }
411
+ exeContext.subsequentPayloads.delete(incrementalDataRecord);
412
+ }
413
+ return pendingDeferredFragments;
414
+ }
334
415
  function executeField(exeContext, parentTypeName, source, fieldGroup, path, incrementalDataRecord) {
335
416
  const schemaFragment = exeContext.schemaFragment;
336
417
  const fieldName = fieldGroup[0].name.value;
@@ -1308,6 +1389,17 @@ function completeObjectValue(exeContext, returnTypeName, fieldGroup, path, resul
1308
1389
  }
1309
1390
  function collectAndExecuteSubfields(exeContext, returnTypeName, fieldGroup, path, result, incrementalDataRecord) {
1310
1391
  const { groupedFieldSet: subGroupedFieldSet, patches: subPatches } = collectSubfields(exeContext, { name: returnTypeName }, fieldGroup);
1392
+ if (exeContext.enableEarlyExecution) {
1393
+ return executeFields(
1394
+ exeContext,
1395
+ returnTypeName,
1396
+ result,
1397
+ path,
1398
+ subGroupedFieldSet,
1399
+ incrementalDataRecord,
1400
+ subPatches
1401
+ );
1402
+ }
1311
1403
  const subFields = executeFields(
1312
1404
  exeContext,
1313
1405
  returnTypeName,
@@ -1926,6 +2018,34 @@ function getCompletedIncrementalResults(exeContext) {
1926
2018
  }
1927
2019
  return incrementalResults;
1928
2020
  }
2021
+ async function getCompletedIncrementalResultsWithBatching(exeContext, batchTimeout) {
2022
+ const incremental = getCompletedIncrementalResults(exeContext);
2023
+ if (incremental.length && exeContext.subsequentPayloads.size > 0) {
2024
+ await raceIncrementalPayloadBatch(
2025
+ Array.from(exeContext.subsequentPayloads).map((p) => p.promise),
2026
+ batchTimeout
2027
+ );
2028
+ incremental.push(...getCompletedIncrementalResults(exeContext));
2029
+ }
2030
+ return incremental;
2031
+ }
2032
+ function raceIncrementalPayloadBatch(promises, batchTimeout) {
2033
+ if (!Number.isFinite(batchTimeout) || batchTimeout <= 0) {
2034
+ return Promise.resolve();
2035
+ }
2036
+ let timeoutId;
2037
+ const timeoutPromise = new Promise((resolve) => {
2038
+ timeoutId = setTimeout(resolve, batchTimeout);
2039
+ });
2040
+ return Promise.race([
2041
+ Promise.all(promises).then(() => void 0),
2042
+ timeoutPromise
2043
+ ]).finally(() => {
2044
+ if (timeoutId !== void 0) {
2045
+ clearTimeout(timeoutId);
2046
+ }
2047
+ });
2048
+ }
1929
2049
  function yieldSubsequentPayloads(exeContext) {
1930
2050
  let isDone = false;
1931
2051
  async function next() {
@@ -1938,7 +2058,11 @@ function yieldSubsequentPayloads(exeContext) {
1938
2058
  if (isDone) {
1939
2059
  return { value: void 0, done: true };
1940
2060
  }
1941
- const incremental = getCompletedIncrementalResults(exeContext);
2061
+ const batchTimeout = exeContext.incrementalPayloadBatchingTimeoutMs;
2062
+ const incremental = typeof batchTimeout === "number" ? await getCompletedIncrementalResultsWithBatching(
2063
+ exeContext,
2064
+ batchTimeout
2065
+ ) : getCompletedIncrementalResults(exeContext);
1942
2066
  const hasNext = exeContext.subsequentPayloads.size > 0;
1943
2067
  if (!incremental.length && hasNext) {
1944
2068
  return next();
@@ -1981,6 +2105,9 @@ function yieldSubsequentPayloads(exeContext) {
1981
2105
  function isStreamItemsRecord(incrementalDataRecord) {
1982
2106
  return incrementalDataRecord.type === "stream";
1983
2107
  }
2108
+ function isDeferredFragmentRecord(incrementalDataRecord) {
2109
+ return incrementalDataRecord.type === "defer";
2110
+ }
1984
2111
  var DeferredFragmentRecord = class {
1985
2112
  constructor(opts) {
1986
2113
  this.type = "defer";
@@ -1996,10 +2123,11 @@ var DeferredFragmentRecord = class {
1996
2123
  this._resolve = (promiseOrValue) => {
1997
2124
  resolve(promiseOrValue);
1998
2125
  };
1999
- }).then((data) => {
2000
- this.data = data;
2001
- this.isCompleted = true;
2002
- });
2126
+ }).then((data) => this.complete(data));
2127
+ }
2128
+ complete(data) {
2129
+ this.data = data;
2130
+ this.isCompleted = true;
2003
2131
  }
2004
2132
  addData(data) {
2005
2133
  var _a, _b, _c;
@@ -2008,6 +2136,9 @@ var DeferredFragmentRecord = class {
2008
2136
  (_b = this._resolve) == null ? void 0 : _b.call(this, parentData.then(() => data));
2009
2137
  return;
2010
2138
  }
2139
+ if (!isPromise(data)) {
2140
+ this.complete(data);
2141
+ }
2011
2142
  (_c = this._resolve) == null ? void 0 : _c.call(this, data);
2012
2143
  }
2013
2144
  };