@graphql-tools/executor 2.0.0-alpha-20240606224953-6d3be8381f7a6b24f2793457d1f05f89f1ae953a → 2.0.0-alpha-20240620034109-2a2878866aed08fedf5baaa5878414b9de79fdb2

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.
@@ -3,86 +3,33 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.IncrementalGraph = void 0;
4
4
  const utils_1 = require("@graphql-tools/utils");
5
5
  const BoxedPromiseOrValue_js_1 = require("./BoxedPromiseOrValue.js");
6
+ const invariant_js_1 = require("./invariant.js");
6
7
  const promiseWithResolvers_js_1 = require("./promiseWithResolvers.js");
7
8
  const types_js_1 = require("./types.js");
8
- function isDeferredFragmentNode(node) {
9
- return node !== undefined;
10
- }
11
- function isStreamNode(record) {
12
- return 'streamItemQueue' in record;
13
- }
14
9
  /**
15
10
  * @internal
16
11
  */
17
12
  class IncrementalGraph {
18
13
  constructor() {
19
- this._pending = new Set();
20
- this._deferredFragmentNodes = new Map();
21
- this._newIncrementalDataRecords = new Set();
22
- this._newPending = new Set();
14
+ this._rootNodes = new Set();
23
15
  this._completedQueue = [];
24
16
  this._nextQueue = [];
25
17
  }
26
- addIncrementalDataRecords(incrementalDataRecords) {
27
- for (const incrementalDataRecord of incrementalDataRecords) {
28
- if ((0, types_js_1.isDeferredGroupedFieldSetRecord)(incrementalDataRecord)) {
29
- this._addDeferredGroupedFieldSetRecord(incrementalDataRecord);
30
- }
31
- else {
32
- this._addStreamRecord(incrementalDataRecord);
33
- }
34
- }
18
+ getNewPending(incrementalDataRecords) {
19
+ const initialResultChildren = new Set();
20
+ this._addIncrementalDataRecords(incrementalDataRecords, undefined, initialResultChildren);
21
+ return this._promoteNonEmptyToRoot(initialResultChildren);
35
22
  }
36
23
  addCompletedReconcilableDeferredGroupedFieldSet(reconcilableResult) {
37
- const deferredFragmentNodes = reconcilableResult.deferredGroupedFieldSetRecord.deferredFragmentRecords
38
- .map(deferredFragmentRecord => this._deferredFragmentNodes.get(deferredFragmentRecord))
39
- .filter(isDeferredFragmentNode);
40
- for (const deferredFragmentNode of deferredFragmentNodes) {
41
- deferredFragmentNode.deferredGroupedFieldSetRecords.delete(reconcilableResult.deferredGroupedFieldSetRecord);
42
- deferredFragmentNode.reconcilableResults.add(reconcilableResult);
43
- }
44
- }
45
- getNewPending() {
46
- const newPending = [];
47
- for (const node of this._newPending) {
48
- if (isStreamNode(node)) {
49
- this._pending.add(node);
50
- newPending.push(node);
51
- this._newIncrementalDataRecords.add(node);
52
- }
53
- else if (node.deferredGroupedFieldSetRecords.size > 0) {
54
- for (const deferredGroupedFieldSetNode of node.deferredGroupedFieldSetRecords) {
55
- this._newIncrementalDataRecords.add(deferredGroupedFieldSetNode);
56
- }
57
- this._pending.add(node);
58
- newPending.push(node.deferredFragmentRecord);
59
- }
60
- else {
61
- for (const child of node.children) {
62
- this._newPending.add(child);
63
- }
64
- }
24
+ for (const deferredFragmentRecord of reconcilableResult.deferredGroupedFieldSetRecord
25
+ .deferredFragmentRecords) {
26
+ deferredFragmentRecord.deferredGroupedFieldSetRecords.delete(reconcilableResult.deferredGroupedFieldSetRecord);
27
+ deferredFragmentRecord.reconcilableResults.add(reconcilableResult);
65
28
  }
66
- this._newPending.clear();
67
- for (const incrementalDataRecord of this._newIncrementalDataRecords) {
68
- if (isStreamNode(incrementalDataRecord)) {
69
- this._onStreamItems(incrementalDataRecord, incrementalDataRecord.streamItemQueue);
70
- }
71
- else {
72
- const deferredGroupedFieldSetResult = incrementalDataRecord.result;
73
- const result = deferredGroupedFieldSetResult instanceof BoxedPromiseOrValue_js_1.BoxedPromiseOrValue
74
- ? deferredGroupedFieldSetResult.value
75
- : deferredGroupedFieldSetResult().value;
76
- if ((0, utils_1.isPromise)(result)) {
77
- result.then(resolved => this._enqueue(resolved));
78
- }
79
- else {
80
- this._enqueue(result);
81
- }
82
- }
29
+ const incrementalDataRecords = reconcilableResult.incrementalDataRecords;
30
+ if (incrementalDataRecords !== undefined) {
31
+ this._addIncrementalDataRecords(incrementalDataRecords, reconcilableResult.deferredGroupedFieldSetRecord.deferredFragmentRecords);
83
32
  }
84
- this._newIncrementalDataRecords.clear();
85
- return newPending;
86
33
  }
87
34
  completedIncrementalData() {
88
35
  return {
@@ -110,100 +57,127 @@ class IncrementalGraph {
110
57
  };
111
58
  }
112
59
  hasNext() {
113
- return this._pending.size > 0;
60
+ return this._rootNodes.size > 0;
114
61
  }
115
62
  completeDeferredFragment(deferredFragmentRecord) {
116
- const deferredFragmentNode = this._deferredFragmentNodes.get(deferredFragmentRecord);
117
- // TODO: add test case?
118
- /* c8 ignore next 3 */
119
- if (deferredFragmentNode === undefined) {
120
- return undefined;
121
- }
122
- if (deferredFragmentNode.deferredGroupedFieldSetRecords.size > 0) {
63
+ if (!this._rootNodes.has(deferredFragmentRecord) ||
64
+ deferredFragmentRecord.deferredGroupedFieldSetRecords.size > 0) {
123
65
  return;
124
66
  }
125
- const reconcilableResults = Array.from(deferredFragmentNode.reconcilableResults);
67
+ const reconcilableResults = Array.from(deferredFragmentRecord.reconcilableResults);
68
+ this._removePending(deferredFragmentRecord);
126
69
  for (const reconcilableResult of reconcilableResults) {
127
70
  for (const otherDeferredFragmentRecord of reconcilableResult.deferredGroupedFieldSetRecord
128
71
  .deferredFragmentRecords) {
129
- const otherDeferredFragmentNode = this._deferredFragmentNodes.get(otherDeferredFragmentRecord);
130
- if (otherDeferredFragmentNode === undefined) {
131
- continue;
132
- }
133
- otherDeferredFragmentNode.reconcilableResults.delete(reconcilableResult);
72
+ otherDeferredFragmentRecord.reconcilableResults.delete(reconcilableResult);
134
73
  }
135
74
  }
136
- this._removePending(deferredFragmentNode);
137
- for (const child of deferredFragmentNode.children) {
138
- this._newPending.add(child);
139
- }
140
- return reconcilableResults;
75
+ const newPending = this._promoteNonEmptyToRoot(deferredFragmentRecord.children);
76
+ return { newPending, reconcilableResults };
141
77
  }
142
78
  removeDeferredFragment(deferredFragmentRecord) {
143
- const deferredFragmentNode = this._deferredFragmentNodes.get(deferredFragmentRecord);
144
- if (deferredFragmentNode === undefined) {
79
+ if (!this._rootNodes.has(deferredFragmentRecord)) {
145
80
  return false;
146
81
  }
147
- this._removePending(deferredFragmentNode);
148
- this._deferredFragmentNodes.delete(deferredFragmentRecord);
149
- // TODO: add test case for an erroring deferred fragment with child defers
150
- /* c8 ignore next 3 */
151
- for (const child of deferredFragmentNode.children) {
152
- this.removeDeferredFragment(child.deferredFragmentRecord);
153
- }
82
+ this._removePending(deferredFragmentRecord);
154
83
  return true;
155
84
  }
156
85
  removeStream(streamRecord) {
157
86
  this._removePending(streamRecord);
158
87
  }
159
- _removePending(subsequentResultNode) {
160
- this._pending.delete(subsequentResultNode);
161
- if (this._pending.size === 0) {
88
+ _removePending(subsequentResultRecord) {
89
+ this._rootNodes.delete(subsequentResultRecord);
90
+ if (this._rootNodes.size === 0) {
162
91
  for (const resolve of this._nextQueue) {
163
92
  resolve({ value: undefined, done: true });
164
93
  }
165
94
  }
166
95
  }
167
- _addDeferredGroupedFieldSetRecord(deferredGroupedFieldSetRecord) {
168
- for (const deferredFragmentRecord of deferredGroupedFieldSetRecord.deferredFragmentRecords) {
169
- const deferredFragmentNode = this._addDeferredFragmentNode(deferredFragmentRecord);
170
- if (this._pending.has(deferredFragmentNode)) {
171
- this._newIncrementalDataRecords.add(deferredGroupedFieldSetRecord);
96
+ _addIncrementalDataRecords(incrementalDataRecords, parents, initialResultChildren) {
97
+ for (const incrementalDataRecord of incrementalDataRecords) {
98
+ if ((0, types_js_1.isDeferredGroupedFieldSetRecord)(incrementalDataRecord)) {
99
+ for (const deferredFragmentRecord of incrementalDataRecord.deferredFragmentRecords) {
100
+ this._addDeferredFragment(deferredFragmentRecord, initialResultChildren);
101
+ deferredFragmentRecord.deferredGroupedFieldSetRecords.add(incrementalDataRecord);
102
+ }
103
+ if (this._hasPendingFragment(incrementalDataRecord)) {
104
+ this._onDeferredGroupedFieldSet(incrementalDataRecord);
105
+ }
106
+ }
107
+ else if (parents === undefined) {
108
+ (0, invariant_js_1.invariant)(initialResultChildren !== undefined);
109
+ initialResultChildren.add(incrementalDataRecord);
110
+ }
111
+ else {
112
+ for (const parent of parents) {
113
+ this._addDeferredFragment(parent, initialResultChildren);
114
+ parent.children.add(incrementalDataRecord);
115
+ }
116
+ }
117
+ }
118
+ }
119
+ _promoteNonEmptyToRoot(maybeEmptyNewPending) {
120
+ const newPending = [];
121
+ for (const subsequentResultRecord of maybeEmptyNewPending) {
122
+ if ((0, types_js_1.isDeferredFragmentRecord)(subsequentResultRecord)) {
123
+ if (subsequentResultRecord.deferredGroupedFieldSetRecords.size > 0) {
124
+ subsequentResultRecord.setAsPending();
125
+ for (const deferredGroupedFieldSetRecord of subsequentResultRecord.deferredGroupedFieldSetRecords) {
126
+ if (!this._hasPendingFragment(deferredGroupedFieldSetRecord)) {
127
+ this._onDeferredGroupedFieldSet(deferredGroupedFieldSetRecord);
128
+ }
129
+ }
130
+ this._rootNodes.add(subsequentResultRecord);
131
+ newPending.push(subsequentResultRecord);
132
+ continue;
133
+ }
134
+ for (const child of subsequentResultRecord.children) {
135
+ maybeEmptyNewPending.add(child);
136
+ }
137
+ }
138
+ else {
139
+ this._rootNodes.add(subsequentResultRecord);
140
+ newPending.push(subsequentResultRecord);
141
+ this._onStreamItems(subsequentResultRecord);
172
142
  }
173
- deferredFragmentNode.deferredGroupedFieldSetRecords.add(deferredGroupedFieldSetRecord);
174
143
  }
144
+ return newPending;
175
145
  }
176
- _addStreamRecord(streamRecord) {
177
- this._newPending.add(streamRecord);
146
+ _hasPendingFragment(deferredGroupedFieldSetRecord) {
147
+ return deferredGroupedFieldSetRecord.deferredFragmentRecords.some(deferredFragmentRecord => this._rootNodes.has(deferredFragmentRecord));
178
148
  }
179
- _addDeferredFragmentNode(deferredFragmentRecord) {
180
- let deferredFragmentNode = this._deferredFragmentNodes.get(deferredFragmentRecord);
181
- if (deferredFragmentNode !== undefined) {
182
- return deferredFragmentNode;
149
+ _addDeferredFragment(deferredFragmentRecord, subsequentResultRecords) {
150
+ if (this._rootNodes.has(deferredFragmentRecord)) {
151
+ return;
183
152
  }
184
- deferredFragmentNode = {
185
- deferredFragmentRecord,
186
- deferredGroupedFieldSetRecords: new Set(),
187
- reconcilableResults: new Set(),
188
- children: [],
189
- };
190
- this._deferredFragmentNodes.set(deferredFragmentRecord, deferredFragmentNode);
191
153
  const parent = deferredFragmentRecord.parent;
192
154
  if (parent === undefined) {
193
- this._newPending.add(deferredFragmentNode);
194
- return deferredFragmentNode;
155
+ (0, invariant_js_1.invariant)(subsequentResultRecords !== undefined);
156
+ subsequentResultRecords.add(deferredFragmentRecord);
157
+ return;
158
+ }
159
+ parent.children.add(deferredFragmentRecord);
160
+ this._addDeferredFragment(parent, subsequentResultRecords);
161
+ }
162
+ _onDeferredGroupedFieldSet(deferredGroupedFieldSetRecord) {
163
+ const result = deferredGroupedFieldSetRecord.result.value;
164
+ if ((0, utils_1.isPromise)(result)) {
165
+ result.then(resolved => this._enqueue(resolved));
166
+ }
167
+ else {
168
+ this._enqueue(result);
195
169
  }
196
- const parentNode = this._addDeferredFragmentNode(parent);
197
- parentNode.children.push(deferredFragmentNode);
198
- return deferredFragmentNode;
199
170
  }
200
- async _onStreamItems(streamRecord, streamItemQueue) {
171
+ async _onStreamItems(streamRecord) {
201
172
  let items = [];
202
173
  let errors = [];
203
174
  let incrementalDataRecords = [];
175
+ const streamItemQueue = streamRecord.streamItemQueue;
204
176
  let streamItemRecord;
205
177
  while ((streamItemRecord = streamItemQueue.shift()) !== undefined) {
206
- let result = typeof streamItemRecord === 'function' ? streamItemRecord().value : streamItemRecord.value;
178
+ let result = streamItemRecord instanceof BoxedPromiseOrValue_js_1.BoxedPromiseOrValue
179
+ ? streamItemRecord.value
180
+ : streamItemRecord().value;
207
181
  if ((0, utils_1.isPromise)(result)) {
208
182
  if (items.length > 0) {
209
183
  this._enqueue({
@@ -23,8 +23,7 @@ class IncrementalPublisher {
23
23
  this._incrementalGraph = new IncrementalGraph_js_1.IncrementalGraph();
24
24
  }
25
25
  buildResponse(data, errors, incrementalDataRecords) {
26
- this._incrementalGraph.addIncrementalDataRecords(incrementalDataRecords);
27
- const newPending = this._incrementalGraph.getNewPending();
26
+ const newPending = this._incrementalGraph.getNewPending(incrementalDataRecords);
28
27
  const pending = this._pendingSourcesToResults(newPending);
29
28
  const initialResult = errors === undefined
30
29
  ? { data, pending, hasNext: true }
@@ -132,8 +131,6 @@ class IncrementalPublisher {
132
131
  else {
133
132
  this._handleCompletedStreamItems(completedIncrementalData, context);
134
133
  }
135
- const newPending = this._incrementalGraph.getNewPending();
136
- context.pending.push(...this._pendingSourcesToResults(newPending));
137
134
  }
138
135
  _handleCompletedDeferredGroupedFieldSet(deferredGroupedFieldSetResult, context) {
139
136
  if ((0, types_js_1.isNonReconcilableDeferredGroupedFieldSetResult)(deferredGroupedFieldSetResult)) {
@@ -149,30 +146,21 @@ class IncrementalPublisher {
149
146
  id,
150
147
  errors: deferredGroupedFieldSetResult.errors,
151
148
  });
152
- this._incrementalGraph.removeDeferredFragment(deferredFragmentRecord);
153
149
  }
154
150
  return;
155
151
  }
156
152
  this._incrementalGraph.addCompletedReconcilableDeferredGroupedFieldSet(deferredGroupedFieldSetResult);
157
- const incrementalDataRecords = deferredGroupedFieldSetResult.incrementalDataRecords;
158
- if (incrementalDataRecords !== undefined) {
159
- this._incrementalGraph.addIncrementalDataRecords(incrementalDataRecords);
160
- }
161
153
  for (const deferredFragmentRecord of deferredGroupedFieldSetResult.deferredGroupedFieldSetRecord
162
154
  .deferredFragmentRecords) {
163
- const id = deferredFragmentRecord.id;
164
- // TODO: add test case for this.
165
- // Presumably, this can occur if an error causes a fragment to be completed early,
166
- // while an asynchronous deferred grouped field set result is enqueued.
167
- /* c8 ignore next 3 */
168
- if (id === undefined) {
169
- continue;
170
- }
171
- const reconcilableResults = this._incrementalGraph.completeDeferredFragment(deferredFragmentRecord);
172
- if (reconcilableResults === undefined) {
155
+ const completion = this._incrementalGraph.completeDeferredFragment(deferredFragmentRecord);
156
+ if (completion === undefined) {
173
157
  continue;
174
158
  }
159
+ const id = deferredFragmentRecord.id;
160
+ (0, invariant_js_1.invariant)(id !== undefined);
175
161
  const incremental = context.incremental;
162
+ const { newPending, reconcilableResults } = completion;
163
+ context.pending.push(...this._pendingSourcesToResults(newPending));
176
164
  for (const reconcilableResult of reconcilableResults) {
177
165
  const { bestId, subPath } = this._getBestIdAndSubPath(id, deferredFragmentRecord, reconcilableResult);
178
166
  const incrementalEntry = {
@@ -220,8 +208,10 @@ class IncrementalPublisher {
220
208
  ...streamItemsResult.result,
221
209
  };
222
210
  context.incremental.push(incrementalEntry);
223
- if (streamItemsResult.incrementalDataRecords !== undefined) {
224
- this._incrementalGraph.addIncrementalDataRecords(streamItemsResult.incrementalDataRecords);
211
+ const incrementalDataRecords = streamItemsResult.incrementalDataRecords;
212
+ if (incrementalDataRecords !== undefined) {
213
+ const newPending = this._incrementalGraph.getNewPending(incrementalDataRecords);
214
+ context.pending.push(...this._pendingSourcesToResults(newPending));
225
215
  }
226
216
  }
227
217
  }
@@ -10,6 +10,7 @@ const collectFields_js_1 = require("./collectFields.js");
10
10
  const IncrementalPublisher_js_1 = require("./IncrementalPublisher.js");
11
11
  const invariant_js_1 = require("./invariant.js");
12
12
  const promiseForObject_js_1 = require("./promiseForObject.js");
13
+ const types_js_1 = require("./types.js");
13
14
  const values_js_1 = require("./values.js");
14
15
  /**
15
16
  * A memoized collection of relevant subfields with regard to the return
@@ -811,11 +812,7 @@ function addNewDeferredFragments(newDeferUsages, newDeferMap, path) {
811
812
  ? undefined
812
813
  : deferredFragmentRecordFromDeferUsage(parentDeferUsage, newDeferMap);
813
814
  // Instantiate the new record.
814
- const deferredFragmentRecord = {
815
- path,
816
- label: newDeferUsage.label,
817
- parent,
818
- };
815
+ const deferredFragmentRecord = new types_js_1.DeferredFragmentRecord(path, newDeferUsage.label, parent);
819
816
  // Update the map.
820
817
  newDeferMap.set(newDeferUsage, deferredFragmentRecord);
821
818
  }
@@ -1114,12 +1111,26 @@ function executeDeferredGroupedFieldSets(exeContext, parentType, sourceValue, pa
1114
1111
  deferUsageSet,
1115
1112
  incrementalDataRecords: undefined,
1116
1113
  }, deferMap);
1117
- const shouldDeferThisDeferUsageSet = shouldDefer(parentDeferUsages, deferUsageSet);
1118
- deferredGroupedFieldSetRecord.result = shouldDeferThisDeferUsageSet
1119
- ? exeContext.enableEarlyExecution
1120
- ? new BoxedPromiseOrValue_js_1.BoxedPromiseOrValue(Promise.resolve().then(executor))
1121
- : () => new BoxedPromiseOrValue_js_1.BoxedPromiseOrValue(executor())
1122
- : new BoxedPromiseOrValue_js_1.BoxedPromiseOrValue(executor());
1114
+ if (exeContext.enableEarlyExecution) {
1115
+ deferredGroupedFieldSetRecord.result = new BoxedPromiseOrValue_js_1.BoxedPromiseOrValue(shouldDefer(parentDeferUsages, deferUsageSet)
1116
+ ? Promise.resolve().then(executor)
1117
+ : executor());
1118
+ }
1119
+ else if (deferredFragmentRecords.some(deferredFragmentRecord => deferredFragmentRecord.pending)) {
1120
+ deferredGroupedFieldSetRecord.result = new BoxedPromiseOrValue_js_1.BoxedPromiseOrValue(executor());
1121
+ }
1122
+ else {
1123
+ deferredGroupedFieldSetRecord.result = () => new BoxedPromiseOrValue_js_1.BoxedPromiseOrValue(executor());
1124
+ const resolveThunk = () => {
1125
+ const maybeThunk = deferredGroupedFieldSetRecord.result;
1126
+ if (!(maybeThunk instanceof BoxedPromiseOrValue_js_1.BoxedPromiseOrValue)) {
1127
+ deferredGroupedFieldSetRecord.result = maybeThunk();
1128
+ }
1129
+ };
1130
+ for (const deferredFragmentRecord of deferredFragmentRecords) {
1131
+ deferredFragmentRecord.onPending(resolveThunk);
1132
+ }
1133
+ }
1123
1134
  newDeferredGroupedFieldSetRecords.push(deferredGroupedFieldSetRecord);
1124
1135
  }
1125
1136
  return newDeferredGroupedFieldSetRecords;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.isCancellableStreamRecord = exports.isNonReconcilableDeferredGroupedFieldSetResult = exports.isDeferredGroupedFieldSetResult = exports.isDeferredGroupedFieldSetRecord = void 0;
3
+ exports.isCancellableStreamRecord = exports.isDeferredFragmentRecord = exports.DeferredFragmentRecord = exports.isNonReconcilableDeferredGroupedFieldSetResult = exports.isDeferredGroupedFieldSetResult = exports.isDeferredGroupedFieldSetRecord = void 0;
4
4
  function isDeferredGroupedFieldSetRecord(incrementalDataRecord) {
5
5
  return 'deferredFragmentRecords' in incrementalDataRecord;
6
6
  }
@@ -13,6 +13,33 @@ function isNonReconcilableDeferredGroupedFieldSetResult(deferredGroupedFieldSetR
13
13
  return deferredGroupedFieldSetResult.errors !== undefined;
14
14
  }
15
15
  exports.isNonReconcilableDeferredGroupedFieldSetResult = isNonReconcilableDeferredGroupedFieldSetResult;
16
+ /** @internal */
17
+ class DeferredFragmentRecord {
18
+ constructor(path, label, parent) {
19
+ this.path = path;
20
+ this.label = label;
21
+ this.parent = parent;
22
+ this.deferredGroupedFieldSetRecords = new Set();
23
+ this.reconcilableResults = new Set();
24
+ this.children = new Set();
25
+ this.pending = false;
26
+ this.fns = [];
27
+ }
28
+ onPending(fn) {
29
+ this.fns.push(fn);
30
+ }
31
+ setAsPending() {
32
+ this.pending = true;
33
+ for (const fn of this.fns) {
34
+ fn();
35
+ }
36
+ }
37
+ }
38
+ exports.DeferredFragmentRecord = DeferredFragmentRecord;
39
+ function isDeferredFragmentRecord(subsequentResultRecord) {
40
+ return subsequentResultRecord instanceof DeferredFragmentRecord;
41
+ }
42
+ exports.isDeferredFragmentRecord = isDeferredFragmentRecord;
16
43
  function isCancellableStreamRecord(subsequentResultRecord) {
17
44
  return 'earlyReturn' in subsequentResultRecord;
18
45
  }
@@ -1,85 +1,32 @@
1
1
  import { isPromise } from '@graphql-tools/utils';
2
2
  import { BoxedPromiseOrValue } from './BoxedPromiseOrValue.js';
3
+ import { invariant } from './invariant.js';
3
4
  import { promiseWithResolvers } from './promiseWithResolvers.js';
4
- import { isDeferredGroupedFieldSetRecord } from './types.js';
5
- function isDeferredFragmentNode(node) {
6
- return node !== undefined;
7
- }
8
- function isStreamNode(record) {
9
- return 'streamItemQueue' in record;
10
- }
5
+ import { isDeferredFragmentRecord, isDeferredGroupedFieldSetRecord } from './types.js';
11
6
  /**
12
7
  * @internal
13
8
  */
14
9
  export class IncrementalGraph {
15
10
  constructor() {
16
- this._pending = new Set();
17
- this._deferredFragmentNodes = new Map();
18
- this._newIncrementalDataRecords = new Set();
19
- this._newPending = new Set();
11
+ this._rootNodes = new Set();
20
12
  this._completedQueue = [];
21
13
  this._nextQueue = [];
22
14
  }
23
- addIncrementalDataRecords(incrementalDataRecords) {
24
- for (const incrementalDataRecord of incrementalDataRecords) {
25
- if (isDeferredGroupedFieldSetRecord(incrementalDataRecord)) {
26
- this._addDeferredGroupedFieldSetRecord(incrementalDataRecord);
27
- }
28
- else {
29
- this._addStreamRecord(incrementalDataRecord);
30
- }
31
- }
15
+ getNewPending(incrementalDataRecords) {
16
+ const initialResultChildren = new Set();
17
+ this._addIncrementalDataRecords(incrementalDataRecords, undefined, initialResultChildren);
18
+ return this._promoteNonEmptyToRoot(initialResultChildren);
32
19
  }
33
20
  addCompletedReconcilableDeferredGroupedFieldSet(reconcilableResult) {
34
- const deferredFragmentNodes = reconcilableResult.deferredGroupedFieldSetRecord.deferredFragmentRecords
35
- .map(deferredFragmentRecord => this._deferredFragmentNodes.get(deferredFragmentRecord))
36
- .filter(isDeferredFragmentNode);
37
- for (const deferredFragmentNode of deferredFragmentNodes) {
38
- deferredFragmentNode.deferredGroupedFieldSetRecords.delete(reconcilableResult.deferredGroupedFieldSetRecord);
39
- deferredFragmentNode.reconcilableResults.add(reconcilableResult);
40
- }
41
- }
42
- getNewPending() {
43
- const newPending = [];
44
- for (const node of this._newPending) {
45
- if (isStreamNode(node)) {
46
- this._pending.add(node);
47
- newPending.push(node);
48
- this._newIncrementalDataRecords.add(node);
49
- }
50
- else if (node.deferredGroupedFieldSetRecords.size > 0) {
51
- for (const deferredGroupedFieldSetNode of node.deferredGroupedFieldSetRecords) {
52
- this._newIncrementalDataRecords.add(deferredGroupedFieldSetNode);
53
- }
54
- this._pending.add(node);
55
- newPending.push(node.deferredFragmentRecord);
56
- }
57
- else {
58
- for (const child of node.children) {
59
- this._newPending.add(child);
60
- }
61
- }
21
+ for (const deferredFragmentRecord of reconcilableResult.deferredGroupedFieldSetRecord
22
+ .deferredFragmentRecords) {
23
+ deferredFragmentRecord.deferredGroupedFieldSetRecords.delete(reconcilableResult.deferredGroupedFieldSetRecord);
24
+ deferredFragmentRecord.reconcilableResults.add(reconcilableResult);
62
25
  }
63
- this._newPending.clear();
64
- for (const incrementalDataRecord of this._newIncrementalDataRecords) {
65
- if (isStreamNode(incrementalDataRecord)) {
66
- this._onStreamItems(incrementalDataRecord, incrementalDataRecord.streamItemQueue);
67
- }
68
- else {
69
- const deferredGroupedFieldSetResult = incrementalDataRecord.result;
70
- const result = deferredGroupedFieldSetResult instanceof BoxedPromiseOrValue
71
- ? deferredGroupedFieldSetResult.value
72
- : deferredGroupedFieldSetResult().value;
73
- if (isPromise(result)) {
74
- result.then(resolved => this._enqueue(resolved));
75
- }
76
- else {
77
- this._enqueue(result);
78
- }
79
- }
26
+ const incrementalDataRecords = reconcilableResult.incrementalDataRecords;
27
+ if (incrementalDataRecords !== undefined) {
28
+ this._addIncrementalDataRecords(incrementalDataRecords, reconcilableResult.deferredGroupedFieldSetRecord.deferredFragmentRecords);
80
29
  }
81
- this._newIncrementalDataRecords.clear();
82
- return newPending;
83
30
  }
84
31
  completedIncrementalData() {
85
32
  return {
@@ -107,100 +54,127 @@ export class IncrementalGraph {
107
54
  };
108
55
  }
109
56
  hasNext() {
110
- return this._pending.size > 0;
57
+ return this._rootNodes.size > 0;
111
58
  }
112
59
  completeDeferredFragment(deferredFragmentRecord) {
113
- const deferredFragmentNode = this._deferredFragmentNodes.get(deferredFragmentRecord);
114
- // TODO: add test case?
115
- /* c8 ignore next 3 */
116
- if (deferredFragmentNode === undefined) {
117
- return undefined;
118
- }
119
- if (deferredFragmentNode.deferredGroupedFieldSetRecords.size > 0) {
60
+ if (!this._rootNodes.has(deferredFragmentRecord) ||
61
+ deferredFragmentRecord.deferredGroupedFieldSetRecords.size > 0) {
120
62
  return;
121
63
  }
122
- const reconcilableResults = Array.from(deferredFragmentNode.reconcilableResults);
64
+ const reconcilableResults = Array.from(deferredFragmentRecord.reconcilableResults);
65
+ this._removePending(deferredFragmentRecord);
123
66
  for (const reconcilableResult of reconcilableResults) {
124
67
  for (const otherDeferredFragmentRecord of reconcilableResult.deferredGroupedFieldSetRecord
125
68
  .deferredFragmentRecords) {
126
- const otherDeferredFragmentNode = this._deferredFragmentNodes.get(otherDeferredFragmentRecord);
127
- if (otherDeferredFragmentNode === undefined) {
128
- continue;
129
- }
130
- otherDeferredFragmentNode.reconcilableResults.delete(reconcilableResult);
69
+ otherDeferredFragmentRecord.reconcilableResults.delete(reconcilableResult);
131
70
  }
132
71
  }
133
- this._removePending(deferredFragmentNode);
134
- for (const child of deferredFragmentNode.children) {
135
- this._newPending.add(child);
136
- }
137
- return reconcilableResults;
72
+ const newPending = this._promoteNonEmptyToRoot(deferredFragmentRecord.children);
73
+ return { newPending, reconcilableResults };
138
74
  }
139
75
  removeDeferredFragment(deferredFragmentRecord) {
140
- const deferredFragmentNode = this._deferredFragmentNodes.get(deferredFragmentRecord);
141
- if (deferredFragmentNode === undefined) {
76
+ if (!this._rootNodes.has(deferredFragmentRecord)) {
142
77
  return false;
143
78
  }
144
- this._removePending(deferredFragmentNode);
145
- this._deferredFragmentNodes.delete(deferredFragmentRecord);
146
- // TODO: add test case for an erroring deferred fragment with child defers
147
- /* c8 ignore next 3 */
148
- for (const child of deferredFragmentNode.children) {
149
- this.removeDeferredFragment(child.deferredFragmentRecord);
150
- }
79
+ this._removePending(deferredFragmentRecord);
151
80
  return true;
152
81
  }
153
82
  removeStream(streamRecord) {
154
83
  this._removePending(streamRecord);
155
84
  }
156
- _removePending(subsequentResultNode) {
157
- this._pending.delete(subsequentResultNode);
158
- if (this._pending.size === 0) {
85
+ _removePending(subsequentResultRecord) {
86
+ this._rootNodes.delete(subsequentResultRecord);
87
+ if (this._rootNodes.size === 0) {
159
88
  for (const resolve of this._nextQueue) {
160
89
  resolve({ value: undefined, done: true });
161
90
  }
162
91
  }
163
92
  }
164
- _addDeferredGroupedFieldSetRecord(deferredGroupedFieldSetRecord) {
165
- for (const deferredFragmentRecord of deferredGroupedFieldSetRecord.deferredFragmentRecords) {
166
- const deferredFragmentNode = this._addDeferredFragmentNode(deferredFragmentRecord);
167
- if (this._pending.has(deferredFragmentNode)) {
168
- this._newIncrementalDataRecords.add(deferredGroupedFieldSetRecord);
93
+ _addIncrementalDataRecords(incrementalDataRecords, parents, initialResultChildren) {
94
+ for (const incrementalDataRecord of incrementalDataRecords) {
95
+ if (isDeferredGroupedFieldSetRecord(incrementalDataRecord)) {
96
+ for (const deferredFragmentRecord of incrementalDataRecord.deferredFragmentRecords) {
97
+ this._addDeferredFragment(deferredFragmentRecord, initialResultChildren);
98
+ deferredFragmentRecord.deferredGroupedFieldSetRecords.add(incrementalDataRecord);
99
+ }
100
+ if (this._hasPendingFragment(incrementalDataRecord)) {
101
+ this._onDeferredGroupedFieldSet(incrementalDataRecord);
102
+ }
103
+ }
104
+ else if (parents === undefined) {
105
+ invariant(initialResultChildren !== undefined);
106
+ initialResultChildren.add(incrementalDataRecord);
107
+ }
108
+ else {
109
+ for (const parent of parents) {
110
+ this._addDeferredFragment(parent, initialResultChildren);
111
+ parent.children.add(incrementalDataRecord);
112
+ }
113
+ }
114
+ }
115
+ }
116
+ _promoteNonEmptyToRoot(maybeEmptyNewPending) {
117
+ const newPending = [];
118
+ for (const subsequentResultRecord of maybeEmptyNewPending) {
119
+ if (isDeferredFragmentRecord(subsequentResultRecord)) {
120
+ if (subsequentResultRecord.deferredGroupedFieldSetRecords.size > 0) {
121
+ subsequentResultRecord.setAsPending();
122
+ for (const deferredGroupedFieldSetRecord of subsequentResultRecord.deferredGroupedFieldSetRecords) {
123
+ if (!this._hasPendingFragment(deferredGroupedFieldSetRecord)) {
124
+ this._onDeferredGroupedFieldSet(deferredGroupedFieldSetRecord);
125
+ }
126
+ }
127
+ this._rootNodes.add(subsequentResultRecord);
128
+ newPending.push(subsequentResultRecord);
129
+ continue;
130
+ }
131
+ for (const child of subsequentResultRecord.children) {
132
+ maybeEmptyNewPending.add(child);
133
+ }
134
+ }
135
+ else {
136
+ this._rootNodes.add(subsequentResultRecord);
137
+ newPending.push(subsequentResultRecord);
138
+ this._onStreamItems(subsequentResultRecord);
169
139
  }
170
- deferredFragmentNode.deferredGroupedFieldSetRecords.add(deferredGroupedFieldSetRecord);
171
140
  }
141
+ return newPending;
172
142
  }
173
- _addStreamRecord(streamRecord) {
174
- this._newPending.add(streamRecord);
143
+ _hasPendingFragment(deferredGroupedFieldSetRecord) {
144
+ return deferredGroupedFieldSetRecord.deferredFragmentRecords.some(deferredFragmentRecord => this._rootNodes.has(deferredFragmentRecord));
175
145
  }
176
- _addDeferredFragmentNode(deferredFragmentRecord) {
177
- let deferredFragmentNode = this._deferredFragmentNodes.get(deferredFragmentRecord);
178
- if (deferredFragmentNode !== undefined) {
179
- return deferredFragmentNode;
146
+ _addDeferredFragment(deferredFragmentRecord, subsequentResultRecords) {
147
+ if (this._rootNodes.has(deferredFragmentRecord)) {
148
+ return;
180
149
  }
181
- deferredFragmentNode = {
182
- deferredFragmentRecord,
183
- deferredGroupedFieldSetRecords: new Set(),
184
- reconcilableResults: new Set(),
185
- children: [],
186
- };
187
- this._deferredFragmentNodes.set(deferredFragmentRecord, deferredFragmentNode);
188
150
  const parent = deferredFragmentRecord.parent;
189
151
  if (parent === undefined) {
190
- this._newPending.add(deferredFragmentNode);
191
- return deferredFragmentNode;
152
+ invariant(subsequentResultRecords !== undefined);
153
+ subsequentResultRecords.add(deferredFragmentRecord);
154
+ return;
155
+ }
156
+ parent.children.add(deferredFragmentRecord);
157
+ this._addDeferredFragment(parent, subsequentResultRecords);
158
+ }
159
+ _onDeferredGroupedFieldSet(deferredGroupedFieldSetRecord) {
160
+ const result = deferredGroupedFieldSetRecord.result.value;
161
+ if (isPromise(result)) {
162
+ result.then(resolved => this._enqueue(resolved));
163
+ }
164
+ else {
165
+ this._enqueue(result);
192
166
  }
193
- const parentNode = this._addDeferredFragmentNode(parent);
194
- parentNode.children.push(deferredFragmentNode);
195
- return deferredFragmentNode;
196
167
  }
197
- async _onStreamItems(streamRecord, streamItemQueue) {
168
+ async _onStreamItems(streamRecord) {
198
169
  let items = [];
199
170
  let errors = [];
200
171
  let incrementalDataRecords = [];
172
+ const streamItemQueue = streamRecord.streamItemQueue;
201
173
  let streamItemRecord;
202
174
  while ((streamItemRecord = streamItemQueue.shift()) !== undefined) {
203
- let result = typeof streamItemRecord === 'function' ? streamItemRecord().value : streamItemRecord.value;
175
+ let result = streamItemRecord instanceof BoxedPromiseOrValue
176
+ ? streamItemRecord.value
177
+ : streamItemRecord().value;
204
178
  if (isPromise(result)) {
205
179
  if (items.length > 0) {
206
180
  this._enqueue({
@@ -19,8 +19,7 @@ class IncrementalPublisher {
19
19
  this._incrementalGraph = new IncrementalGraph();
20
20
  }
21
21
  buildResponse(data, errors, incrementalDataRecords) {
22
- this._incrementalGraph.addIncrementalDataRecords(incrementalDataRecords);
23
- const newPending = this._incrementalGraph.getNewPending();
22
+ const newPending = this._incrementalGraph.getNewPending(incrementalDataRecords);
24
23
  const pending = this._pendingSourcesToResults(newPending);
25
24
  const initialResult = errors === undefined
26
25
  ? { data, pending, hasNext: true }
@@ -128,8 +127,6 @@ class IncrementalPublisher {
128
127
  else {
129
128
  this._handleCompletedStreamItems(completedIncrementalData, context);
130
129
  }
131
- const newPending = this._incrementalGraph.getNewPending();
132
- context.pending.push(...this._pendingSourcesToResults(newPending));
133
130
  }
134
131
  _handleCompletedDeferredGroupedFieldSet(deferredGroupedFieldSetResult, context) {
135
132
  if (isNonReconcilableDeferredGroupedFieldSetResult(deferredGroupedFieldSetResult)) {
@@ -145,30 +142,21 @@ class IncrementalPublisher {
145
142
  id,
146
143
  errors: deferredGroupedFieldSetResult.errors,
147
144
  });
148
- this._incrementalGraph.removeDeferredFragment(deferredFragmentRecord);
149
145
  }
150
146
  return;
151
147
  }
152
148
  this._incrementalGraph.addCompletedReconcilableDeferredGroupedFieldSet(deferredGroupedFieldSetResult);
153
- const incrementalDataRecords = deferredGroupedFieldSetResult.incrementalDataRecords;
154
- if (incrementalDataRecords !== undefined) {
155
- this._incrementalGraph.addIncrementalDataRecords(incrementalDataRecords);
156
- }
157
149
  for (const deferredFragmentRecord of deferredGroupedFieldSetResult.deferredGroupedFieldSetRecord
158
150
  .deferredFragmentRecords) {
159
- const id = deferredFragmentRecord.id;
160
- // TODO: add test case for this.
161
- // Presumably, this can occur if an error causes a fragment to be completed early,
162
- // while an asynchronous deferred grouped field set result is enqueued.
163
- /* c8 ignore next 3 */
164
- if (id === undefined) {
165
- continue;
166
- }
167
- const reconcilableResults = this._incrementalGraph.completeDeferredFragment(deferredFragmentRecord);
168
- if (reconcilableResults === undefined) {
151
+ const completion = this._incrementalGraph.completeDeferredFragment(deferredFragmentRecord);
152
+ if (completion === undefined) {
169
153
  continue;
170
154
  }
155
+ const id = deferredFragmentRecord.id;
156
+ invariant(id !== undefined);
171
157
  const incremental = context.incremental;
158
+ const { newPending, reconcilableResults } = completion;
159
+ context.pending.push(...this._pendingSourcesToResults(newPending));
172
160
  for (const reconcilableResult of reconcilableResults) {
173
161
  const { bestId, subPath } = this._getBestIdAndSubPath(id, deferredFragmentRecord, reconcilableResult);
174
162
  const incrementalEntry = {
@@ -216,8 +204,10 @@ class IncrementalPublisher {
216
204
  ...streamItemsResult.result,
217
205
  };
218
206
  context.incremental.push(incrementalEntry);
219
- if (streamItemsResult.incrementalDataRecords !== undefined) {
220
- this._incrementalGraph.addIncrementalDataRecords(streamItemsResult.incrementalDataRecords);
207
+ const incrementalDataRecords = streamItemsResult.incrementalDataRecords;
208
+ if (incrementalDataRecords !== undefined) {
209
+ const newPending = this._incrementalGraph.getNewPending(incrementalDataRecords);
210
+ context.pending.push(...this._pendingSourcesToResults(newPending));
221
211
  }
222
212
  }
223
213
  }
@@ -7,6 +7,7 @@ import { collectSubfields as _collectSubfields, collectFields, } from './collect
7
7
  import { buildIncrementalResponse } from './IncrementalPublisher.js';
8
8
  import { invariant } from './invariant.js';
9
9
  import { promiseForObject } from './promiseForObject.js';
10
+ import { DeferredFragmentRecord, } from './types.js';
10
11
  import { getVariableValues } from './values.js';
11
12
  /**
12
13
  * A memoized collection of relevant subfields with regard to the return
@@ -803,11 +804,7 @@ function addNewDeferredFragments(newDeferUsages, newDeferMap, path) {
803
804
  ? undefined
804
805
  : deferredFragmentRecordFromDeferUsage(parentDeferUsage, newDeferMap);
805
806
  // Instantiate the new record.
806
- const deferredFragmentRecord = {
807
- path,
808
- label: newDeferUsage.label,
809
- parent,
810
- };
807
+ const deferredFragmentRecord = new DeferredFragmentRecord(path, newDeferUsage.label, parent);
811
808
  // Update the map.
812
809
  newDeferMap.set(newDeferUsage, deferredFragmentRecord);
813
810
  }
@@ -1102,12 +1099,26 @@ function executeDeferredGroupedFieldSets(exeContext, parentType, sourceValue, pa
1102
1099
  deferUsageSet,
1103
1100
  incrementalDataRecords: undefined,
1104
1101
  }, deferMap);
1105
- const shouldDeferThisDeferUsageSet = shouldDefer(parentDeferUsages, deferUsageSet);
1106
- deferredGroupedFieldSetRecord.result = shouldDeferThisDeferUsageSet
1107
- ? exeContext.enableEarlyExecution
1108
- ? new BoxedPromiseOrValue(Promise.resolve().then(executor))
1109
- : () => new BoxedPromiseOrValue(executor())
1110
- : new BoxedPromiseOrValue(executor());
1102
+ if (exeContext.enableEarlyExecution) {
1103
+ deferredGroupedFieldSetRecord.result = new BoxedPromiseOrValue(shouldDefer(parentDeferUsages, deferUsageSet)
1104
+ ? Promise.resolve().then(executor)
1105
+ : executor());
1106
+ }
1107
+ else if (deferredFragmentRecords.some(deferredFragmentRecord => deferredFragmentRecord.pending)) {
1108
+ deferredGroupedFieldSetRecord.result = new BoxedPromiseOrValue(executor());
1109
+ }
1110
+ else {
1111
+ deferredGroupedFieldSetRecord.result = () => new BoxedPromiseOrValue(executor());
1112
+ const resolveThunk = () => {
1113
+ const maybeThunk = deferredGroupedFieldSetRecord.result;
1114
+ if (!(maybeThunk instanceof BoxedPromiseOrValue)) {
1115
+ deferredGroupedFieldSetRecord.result = maybeThunk();
1116
+ }
1117
+ };
1118
+ for (const deferredFragmentRecord of deferredFragmentRecords) {
1119
+ deferredFragmentRecord.onPending(resolveThunk);
1120
+ }
1121
+ }
1111
1122
  newDeferredGroupedFieldSetRecords.push(deferredGroupedFieldSetRecord);
1112
1123
  }
1113
1124
  return newDeferredGroupedFieldSetRecords;
@@ -7,6 +7,31 @@ export function isDeferredGroupedFieldSetResult(subsequentResult) {
7
7
  export function isNonReconcilableDeferredGroupedFieldSetResult(deferredGroupedFieldSetResult) {
8
8
  return deferredGroupedFieldSetResult.errors !== undefined;
9
9
  }
10
+ /** @internal */
11
+ export class DeferredFragmentRecord {
12
+ constructor(path, label, parent) {
13
+ this.path = path;
14
+ this.label = label;
15
+ this.parent = parent;
16
+ this.deferredGroupedFieldSetRecords = new Set();
17
+ this.reconcilableResults = new Set();
18
+ this.children = new Set();
19
+ this.pending = false;
20
+ this.fns = [];
21
+ }
22
+ onPending(fn) {
23
+ this.fns.push(fn);
24
+ }
25
+ setAsPending() {
26
+ this.pending = true;
27
+ for (const fn of this.fns) {
28
+ fn();
29
+ }
30
+ }
31
+ }
32
+ export function isDeferredFragmentRecord(subsequentResultRecord) {
33
+ return subsequentResultRecord instanceof DeferredFragmentRecord;
34
+ }
10
35
  export function isCancellableStreamRecord(subsequentResultRecord) {
11
36
  return 'earlyReturn' in subsequentResultRecord;
12
37
  }
package/package.json CHANGED
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@graphql-tools/executor",
3
- "version": "2.0.0-alpha-20240606224953-6d3be8381f7a6b24f2793457d1f05f89f1ae953a",
3
+ "version": "2.0.0-alpha-20240620034109-2a2878866aed08fedf5baaa5878414b9de79fdb2",
4
4
  "sideEffects": false,
5
5
  "peerDependencies": {
6
6
  "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0"
7
7
  },
8
8
  "dependencies": {
9
- "@graphql-tools/utils": "10.3.0-alpha-20240606224953-6d3be8381f7a6b24f2793457d1f05f89f1ae953a",
9
+ "@graphql-tools/utils": "10.3.0-alpha-20240620034109-2a2878866aed08fedf5baaa5878414b9de79fdb2",
10
10
  "@graphql-typed-document-node/core": "3.2.0",
11
11
  "@repeaterjs/repeater": "^3.0.4",
12
12
  "tslib": "^2.4.0",
@@ -3,29 +3,30 @@ import type { DeferredFragmentRecord, IncrementalDataRecord, IncrementalDataReco
3
3
  * @internal
4
4
  */
5
5
  export declare class IncrementalGraph {
6
- private _pending;
7
- private _deferredFragmentNodes;
8
- private _newPending;
9
- private _newIncrementalDataRecords;
6
+ private _rootNodes;
10
7
  private _completedQueue;
11
8
  private _nextQueue;
12
9
  constructor();
13
- addIncrementalDataRecords(incrementalDataRecords: ReadonlyArray<IncrementalDataRecord>): void;
10
+ getNewPending(incrementalDataRecords: ReadonlyArray<IncrementalDataRecord>): ReadonlyArray<SubsequentResultRecord>;
14
11
  addCompletedReconcilableDeferredGroupedFieldSet(reconcilableResult: ReconcilableDeferredGroupedFieldSetResult): void;
15
- getNewPending(): ReadonlyArray<SubsequentResultRecord>;
16
12
  completedIncrementalData(): {
17
13
  [Symbol.asyncIterator](): any;
18
14
  next: () => Promise<IteratorResult<Iterable<IncrementalDataRecordResult>>>;
19
15
  return: () => Promise<IteratorResult<Iterable<IncrementalDataRecordResult>>>;
20
16
  };
21
17
  hasNext(): boolean;
22
- completeDeferredFragment(deferredFragmentRecord: DeferredFragmentRecord): Array<ReconcilableDeferredGroupedFieldSetResult> | undefined;
18
+ completeDeferredFragment(deferredFragmentRecord: DeferredFragmentRecord): {
19
+ newPending: ReadonlyArray<SubsequentResultRecord>;
20
+ reconcilableResults: ReadonlyArray<ReconcilableDeferredGroupedFieldSetResult>;
21
+ } | undefined;
23
22
  removeDeferredFragment(deferredFragmentRecord: DeferredFragmentRecord): boolean;
24
23
  removeStream(streamRecord: StreamRecord): void;
25
24
  private _removePending;
26
- private _addDeferredGroupedFieldSetRecord;
27
- private _addStreamRecord;
28
- private _addDeferredFragmentNode;
25
+ private _addIncrementalDataRecords;
26
+ private _promoteNonEmptyToRoot;
27
+ private _hasPendingFragment;
28
+ private _addDeferredFragment;
29
+ private _onDeferredGroupedFieldSet;
29
30
  private _onStreamItems;
30
31
  private _yieldCurrentCompletedIncrementalData;
31
32
  private _enqueue;
@@ -3,29 +3,30 @@ import type { DeferredFragmentRecord, IncrementalDataRecord, IncrementalDataReco
3
3
  * @internal
4
4
  */
5
5
  export declare class IncrementalGraph {
6
- private _pending;
7
- private _deferredFragmentNodes;
8
- private _newPending;
9
- private _newIncrementalDataRecords;
6
+ private _rootNodes;
10
7
  private _completedQueue;
11
8
  private _nextQueue;
12
9
  constructor();
13
- addIncrementalDataRecords(incrementalDataRecords: ReadonlyArray<IncrementalDataRecord>): void;
10
+ getNewPending(incrementalDataRecords: ReadonlyArray<IncrementalDataRecord>): ReadonlyArray<SubsequentResultRecord>;
14
11
  addCompletedReconcilableDeferredGroupedFieldSet(reconcilableResult: ReconcilableDeferredGroupedFieldSetResult): void;
15
- getNewPending(): ReadonlyArray<SubsequentResultRecord>;
16
12
  completedIncrementalData(): {
17
13
  [Symbol.asyncIterator](): any;
18
14
  next: () => Promise<IteratorResult<Iterable<IncrementalDataRecordResult>>>;
19
15
  return: () => Promise<IteratorResult<Iterable<IncrementalDataRecordResult>>>;
20
16
  };
21
17
  hasNext(): boolean;
22
- completeDeferredFragment(deferredFragmentRecord: DeferredFragmentRecord): Array<ReconcilableDeferredGroupedFieldSetResult> | undefined;
18
+ completeDeferredFragment(deferredFragmentRecord: DeferredFragmentRecord): {
19
+ newPending: ReadonlyArray<SubsequentResultRecord>;
20
+ reconcilableResults: ReadonlyArray<ReconcilableDeferredGroupedFieldSetResult>;
21
+ } | undefined;
23
22
  removeDeferredFragment(deferredFragmentRecord: DeferredFragmentRecord): boolean;
24
23
  removeStream(streamRecord: StreamRecord): void;
25
24
  private _removePending;
26
- private _addDeferredGroupedFieldSetRecord;
27
- private _addStreamRecord;
28
- private _addDeferredFragmentNode;
25
+ private _addIncrementalDataRecords;
26
+ private _promoteNonEmptyToRoot;
27
+ private _hasPendingFragment;
28
+ private _addDeferredFragment;
29
+ private _onDeferredGroupedFieldSet;
29
30
  private _onStreamItems;
30
31
  private _yieldCurrentCompletedIncrementalData;
31
32
  private _enqueue;
@@ -121,12 +121,22 @@ export interface DeferredGroupedFieldSetRecord {
121
121
  result: BoxedPromiseOrValue<DeferredGroupedFieldSetResult> | (() => BoxedPromiseOrValue<DeferredGroupedFieldSetResult>);
122
122
  }
123
123
  export type SubsequentResultRecord = DeferredFragmentRecord | StreamRecord;
124
- export interface DeferredFragmentRecord {
124
+ /** @internal */
125
+ export declare class DeferredFragmentRecord {
125
126
  path: Path | undefined;
126
127
  label: string | undefined;
127
128
  id?: string | undefined;
128
129
  parent: DeferredFragmentRecord | undefined;
129
- }
130
+ deferredGroupedFieldSetRecords: Set<DeferredGroupedFieldSetRecord>;
131
+ reconcilableResults: Set<ReconcilableDeferredGroupedFieldSetResult>;
132
+ children: Set<SubsequentResultRecord>;
133
+ pending: boolean;
134
+ fns: Array<() => void>;
135
+ constructor(path: Path | undefined, label: string | undefined, parent: DeferredFragmentRecord | undefined);
136
+ onPending(fn: () => void): void;
137
+ setAsPending(): void;
138
+ }
139
+ export declare function isDeferredFragmentRecord(subsequentResultRecord: SubsequentResultRecord): subsequentResultRecord is DeferredFragmentRecord;
130
140
  export interface StreamItemResult {
131
141
  path: Path;
132
142
  item?: unknown;
@@ -121,12 +121,22 @@ export interface DeferredGroupedFieldSetRecord {
121
121
  result: BoxedPromiseOrValue<DeferredGroupedFieldSetResult> | (() => BoxedPromiseOrValue<DeferredGroupedFieldSetResult>);
122
122
  }
123
123
  export type SubsequentResultRecord = DeferredFragmentRecord | StreamRecord;
124
- export interface DeferredFragmentRecord {
124
+ /** @internal */
125
+ export declare class DeferredFragmentRecord {
125
126
  path: Path | undefined;
126
127
  label: string | undefined;
127
128
  id?: string | undefined;
128
129
  parent: DeferredFragmentRecord | undefined;
129
- }
130
+ deferredGroupedFieldSetRecords: Set<DeferredGroupedFieldSetRecord>;
131
+ reconcilableResults: Set<ReconcilableDeferredGroupedFieldSetResult>;
132
+ children: Set<SubsequentResultRecord>;
133
+ pending: boolean;
134
+ fns: Array<() => void>;
135
+ constructor(path: Path | undefined, label: string | undefined, parent: DeferredFragmentRecord | undefined);
136
+ onPending(fn: () => void): void;
137
+ setAsPending(): void;
138
+ }
139
+ export declare function isDeferredFragmentRecord(subsequentResultRecord: SubsequentResultRecord): subsequentResultRecord is DeferredFragmentRecord;
130
140
  export interface StreamItemResult {
131
141
  path: Path;
132
142
  item?: unknown;