@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.
- package/cjs/execution/IncrementalGraph.js +97 -123
- package/cjs/execution/IncrementalPublisher.js +11 -21
- package/cjs/execution/execute.js +22 -11
- package/cjs/execution/types.js +28 -1
- package/esm/execution/IncrementalGraph.js +98 -124
- package/esm/execution/IncrementalPublisher.js +11 -21
- package/esm/execution/execute.js +22 -11
- package/esm/execution/types.js +25 -0
- package/package.json +2 -2
- package/typings/execution/IncrementalGraph.d.cts +11 -10
- package/typings/execution/IncrementalGraph.d.ts +11 -10
- package/typings/execution/types.d.cts +12 -2
- package/typings/execution/types.d.ts +12 -2
|
@@ -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.
|
|
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
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
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
|
|
38
|
-
.
|
|
39
|
-
.
|
|
40
|
-
|
|
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
|
-
|
|
67
|
-
|
|
68
|
-
|
|
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.
|
|
60
|
+
return this._rootNodes.size > 0;
|
|
114
61
|
}
|
|
115
62
|
completeDeferredFragment(deferredFragmentRecord) {
|
|
116
|
-
|
|
117
|
-
|
|
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(
|
|
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
|
-
|
|
130
|
-
if (otherDeferredFragmentNode === undefined) {
|
|
131
|
-
continue;
|
|
132
|
-
}
|
|
133
|
-
otherDeferredFragmentNode.reconcilableResults.delete(reconcilableResult);
|
|
72
|
+
otherDeferredFragmentRecord.reconcilableResults.delete(reconcilableResult);
|
|
134
73
|
}
|
|
135
74
|
}
|
|
136
|
-
this.
|
|
137
|
-
|
|
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
|
-
|
|
144
|
-
if (deferredFragmentNode === undefined) {
|
|
79
|
+
if (!this._rootNodes.has(deferredFragmentRecord)) {
|
|
145
80
|
return false;
|
|
146
81
|
}
|
|
147
|
-
this._removePending(
|
|
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(
|
|
160
|
-
this.
|
|
161
|
-
if (this.
|
|
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
|
-
|
|
168
|
-
for (const
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
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
|
-
|
|
177
|
-
this.
|
|
146
|
+
_hasPendingFragment(deferredGroupedFieldSetRecord) {
|
|
147
|
+
return deferredGroupedFieldSetRecord.deferredFragmentRecords.some(deferredFragmentRecord => this._rootNodes.has(deferredFragmentRecord));
|
|
178
148
|
}
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
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
|
-
|
|
194
|
-
|
|
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
|
|
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 =
|
|
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.
|
|
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
|
|
164
|
-
|
|
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
|
-
|
|
224
|
-
|
|
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
|
}
|
package/cjs/execution/execute.js
CHANGED
|
@@ -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
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
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;
|
package/cjs/execution/types.js
CHANGED
|
@@ -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.
|
|
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
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
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
|
|
35
|
-
.
|
|
36
|
-
.
|
|
37
|
-
|
|
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
|
-
|
|
64
|
-
|
|
65
|
-
|
|
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.
|
|
57
|
+
return this._rootNodes.size > 0;
|
|
111
58
|
}
|
|
112
59
|
completeDeferredFragment(deferredFragmentRecord) {
|
|
113
|
-
|
|
114
|
-
|
|
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(
|
|
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
|
-
|
|
127
|
-
if (otherDeferredFragmentNode === undefined) {
|
|
128
|
-
continue;
|
|
129
|
-
}
|
|
130
|
-
otherDeferredFragmentNode.reconcilableResults.delete(reconcilableResult);
|
|
69
|
+
otherDeferredFragmentRecord.reconcilableResults.delete(reconcilableResult);
|
|
131
70
|
}
|
|
132
71
|
}
|
|
133
|
-
this.
|
|
134
|
-
|
|
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
|
-
|
|
141
|
-
if (deferredFragmentNode === undefined) {
|
|
76
|
+
if (!this._rootNodes.has(deferredFragmentRecord)) {
|
|
142
77
|
return false;
|
|
143
78
|
}
|
|
144
|
-
this._removePending(
|
|
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(
|
|
157
|
-
this.
|
|
158
|
-
if (this.
|
|
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
|
-
|
|
165
|
-
for (const
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
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
|
-
|
|
174
|
-
this.
|
|
143
|
+
_hasPendingFragment(deferredGroupedFieldSetRecord) {
|
|
144
|
+
return deferredGroupedFieldSetRecord.deferredFragmentRecords.some(deferredFragmentRecord => this._rootNodes.has(deferredFragmentRecord));
|
|
175
145
|
}
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
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
|
-
|
|
191
|
-
|
|
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
|
|
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 =
|
|
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.
|
|
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
|
|
160
|
-
|
|
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
|
-
|
|
220
|
-
|
|
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
|
}
|
package/esm/execution/execute.js
CHANGED
|
@@ -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
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
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;
|
package/esm/execution/types.js
CHANGED
|
@@ -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-
|
|
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-
|
|
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
|
|
7
|
-
private _deferredFragmentNodes;
|
|
8
|
-
private _newPending;
|
|
9
|
-
private _newIncrementalDataRecords;
|
|
6
|
+
private _rootNodes;
|
|
10
7
|
private _completedQueue;
|
|
11
8
|
private _nextQueue;
|
|
12
9
|
constructor();
|
|
13
|
-
|
|
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):
|
|
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
|
|
27
|
-
private
|
|
28
|
-
private
|
|
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
|
|
7
|
-
private _deferredFragmentNodes;
|
|
8
|
-
private _newPending;
|
|
9
|
-
private _newIncrementalDataRecords;
|
|
6
|
+
private _rootNodes;
|
|
10
7
|
private _completedQueue;
|
|
11
8
|
private _nextQueue;
|
|
12
9
|
constructor();
|
|
13
|
-
|
|
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):
|
|
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
|
|
27
|
-
private
|
|
28
|
-
private
|
|
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
|
-
|
|
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
|
-
|
|
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;
|