@graphql-tools/executor 2.0.0-alpha-20240709212042-9a70c086fa543c594055305622a600bb95343b42 → 2.0.0-alpha-20240804112853-812acba5ea59541106a53f872874fd7aebcffcfc
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 +42 -43
- package/cjs/execution/IncrementalPublisher.js +17 -17
- package/cjs/execution/{buildFieldPlan.js → buildExecutionPlan.js} +29 -42
- package/cjs/execution/execute.js +148 -114
- package/cjs/execution/types.js +17 -17
- package/esm/execution/IncrementalGraph.js +43 -44
- package/esm/execution/IncrementalPublisher.js +18 -18
- package/esm/execution/{buildFieldPlan.js → buildExecutionPlan.js} +26 -39
- package/esm/execution/execute.js +147 -113
- package/esm/execution/types.js +13 -13
- package/package.json +2 -2
- package/typings/execution/IncrementalGraph.d.cts +6 -7
- package/typings/execution/IncrementalGraph.d.ts +6 -7
- package/typings/execution/buildExecutionPlan.d.cts +8 -0
- package/typings/execution/buildExecutionPlan.d.ts +8 -0
- package/typings/execution/execute.d.cts +3 -1
- package/typings/execution/execute.d.ts +3 -1
- package/typings/execution/types.d.cts +22 -22
- package/typings/execution/types.d.ts +22 -22
- package/typings/execution/buildFieldPlan.d.cts +0 -8
- package/typings/execution/buildFieldPlan.d.ts +0 -8
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { createDeferred, isPromise } from '@graphql-tools/utils';
|
|
2
2
|
import { BoxedPromiseOrValue } from './BoxedPromiseOrValue.js';
|
|
3
3
|
import { invariant } from './invariant.js';
|
|
4
|
-
import { isDeferredFragmentRecord,
|
|
4
|
+
import { isDeferredFragmentRecord, isPendingExecutionGroup } from './types.js';
|
|
5
5
|
/**
|
|
6
6
|
* @internal
|
|
7
7
|
*/
|
|
@@ -19,15 +19,16 @@ export class IncrementalGraph {
|
|
|
19
19
|
this._addIncrementalDataRecords(incrementalDataRecords, undefined, initialResultChildren);
|
|
20
20
|
return this._promoteNonEmptyToRoot(initialResultChildren);
|
|
21
21
|
}
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
deferredFragmentRecord
|
|
22
|
+
addCompletedSuccessfulExecutionGroup(successfulExecutionGroup) {
|
|
23
|
+
const { pendingExecutionGroup, incrementalDataRecords } = successfulExecutionGroup;
|
|
24
|
+
const deferredFragmentRecords = pendingExecutionGroup.deferredFragmentRecords;
|
|
25
|
+
for (const deferredFragmentRecord of deferredFragmentRecords) {
|
|
26
|
+
const { pendingExecutionGroups, successfulExecutionGroups } = deferredFragmentRecord;
|
|
27
|
+
pendingExecutionGroups.delete(successfulExecutionGroup.pendingExecutionGroup);
|
|
28
|
+
successfulExecutionGroups.add(successfulExecutionGroup);
|
|
27
29
|
}
|
|
28
|
-
const incrementalDataRecords = reconcilableResult.incrementalDataRecords;
|
|
29
30
|
if (incrementalDataRecords !== undefined) {
|
|
30
|
-
this._addIncrementalDataRecords(incrementalDataRecords,
|
|
31
|
+
this._addIncrementalDataRecords(incrementalDataRecords, deferredFragmentRecords);
|
|
31
32
|
}
|
|
32
33
|
}
|
|
33
34
|
*currentCompletedBatch() {
|
|
@@ -56,42 +57,39 @@ export class IncrementalGraph {
|
|
|
56
57
|
}
|
|
57
58
|
completeDeferredFragment(deferredFragmentRecord) {
|
|
58
59
|
if (!this._rootNodes.has(deferredFragmentRecord) ||
|
|
59
|
-
deferredFragmentRecord.
|
|
60
|
+
deferredFragmentRecord.pendingExecutionGroups.size > 0) {
|
|
60
61
|
return;
|
|
61
62
|
}
|
|
62
|
-
const
|
|
63
|
-
this.
|
|
64
|
-
for (const
|
|
65
|
-
for (const otherDeferredFragmentRecord of
|
|
63
|
+
const successfulExecutionGroups = Array.from(deferredFragmentRecord.successfulExecutionGroups);
|
|
64
|
+
this._rootNodes.delete(deferredFragmentRecord);
|
|
65
|
+
for (const successfulExecutionGroup of successfulExecutionGroups) {
|
|
66
|
+
for (const otherDeferredFragmentRecord of successfulExecutionGroup.pendingExecutionGroup
|
|
66
67
|
.deferredFragmentRecords) {
|
|
67
|
-
otherDeferredFragmentRecord.
|
|
68
|
+
otherDeferredFragmentRecord.successfulExecutionGroups.delete(successfulExecutionGroup);
|
|
68
69
|
}
|
|
69
70
|
}
|
|
70
71
|
const newPending = this._promoteNonEmptyToRoot(deferredFragmentRecord.children);
|
|
71
|
-
return { newPending,
|
|
72
|
+
return { newPending, successfulExecutionGroups };
|
|
72
73
|
}
|
|
73
74
|
removeDeferredFragment(deferredFragmentRecord) {
|
|
74
75
|
if (!this._rootNodes.has(deferredFragmentRecord)) {
|
|
75
76
|
return false;
|
|
76
77
|
}
|
|
77
|
-
this.
|
|
78
|
+
this._rootNodes.delete(deferredFragmentRecord);
|
|
78
79
|
return true;
|
|
79
80
|
}
|
|
80
81
|
removeStream(streamRecord) {
|
|
81
|
-
this.
|
|
82
|
-
}
|
|
83
|
-
_removePending(subsequentResultRecord) {
|
|
84
|
-
this._rootNodes.delete(subsequentResultRecord);
|
|
82
|
+
this._rootNodes.delete(streamRecord);
|
|
85
83
|
}
|
|
86
84
|
_addIncrementalDataRecords(incrementalDataRecords, parents, initialResultChildren) {
|
|
87
85
|
for (const incrementalDataRecord of incrementalDataRecords) {
|
|
88
|
-
if (
|
|
86
|
+
if (isPendingExecutionGroup(incrementalDataRecord)) {
|
|
89
87
|
for (const deferredFragmentRecord of incrementalDataRecord.deferredFragmentRecords) {
|
|
90
88
|
this._addDeferredFragment(deferredFragmentRecord, initialResultChildren);
|
|
91
|
-
deferredFragmentRecord.
|
|
89
|
+
deferredFragmentRecord.pendingExecutionGroups.add(incrementalDataRecord);
|
|
92
90
|
}
|
|
93
91
|
if (this._hasPendingFragment(incrementalDataRecord)) {
|
|
94
|
-
this.
|
|
92
|
+
this._onExecutionGroup(incrementalDataRecord);
|
|
95
93
|
}
|
|
96
94
|
}
|
|
97
95
|
else if (parents === undefined) {
|
|
@@ -108,49 +106,50 @@ export class IncrementalGraph {
|
|
|
108
106
|
}
|
|
109
107
|
_promoteNonEmptyToRoot(maybeEmptyNewPending) {
|
|
110
108
|
const newPending = [];
|
|
111
|
-
for (const
|
|
112
|
-
if (isDeferredFragmentRecord(
|
|
113
|
-
if (
|
|
114
|
-
|
|
115
|
-
for (const
|
|
116
|
-
if (!this._hasPendingFragment(
|
|
117
|
-
this.
|
|
109
|
+
for (const deliveryGroup of maybeEmptyNewPending) {
|
|
110
|
+
if (isDeferredFragmentRecord(deliveryGroup)) {
|
|
111
|
+
if (deliveryGroup.pendingExecutionGroups.size > 0) {
|
|
112
|
+
deliveryGroup.setAsPending();
|
|
113
|
+
for (const pendingExecutionGroup of deliveryGroup.pendingExecutionGroups) {
|
|
114
|
+
if (!this._hasPendingFragment(pendingExecutionGroup)) {
|
|
115
|
+
this._onExecutionGroup(pendingExecutionGroup);
|
|
118
116
|
}
|
|
119
117
|
}
|
|
120
|
-
this._rootNodes.add(
|
|
121
|
-
newPending.push(
|
|
118
|
+
this._rootNodes.add(deliveryGroup);
|
|
119
|
+
newPending.push(deliveryGroup);
|
|
122
120
|
continue;
|
|
123
121
|
}
|
|
124
|
-
for (const child of
|
|
122
|
+
for (const child of deliveryGroup.children) {
|
|
125
123
|
maybeEmptyNewPending.add(child);
|
|
126
124
|
}
|
|
127
125
|
}
|
|
128
126
|
else {
|
|
129
|
-
this._rootNodes.add(
|
|
130
|
-
newPending.push(
|
|
131
|
-
this._onStreamItems(
|
|
127
|
+
this._rootNodes.add(deliveryGroup);
|
|
128
|
+
newPending.push(deliveryGroup);
|
|
129
|
+
this._onStreamItems(deliveryGroup);
|
|
132
130
|
}
|
|
133
131
|
}
|
|
134
132
|
return newPending;
|
|
135
133
|
}
|
|
136
|
-
_hasPendingFragment(
|
|
137
|
-
return
|
|
134
|
+
_hasPendingFragment(pendingExecutionGroup) {
|
|
135
|
+
return pendingExecutionGroup.deferredFragmentRecords.some(deferredFragmentRecord => this._rootNodes.has(deferredFragmentRecord));
|
|
138
136
|
}
|
|
139
|
-
_addDeferredFragment(deferredFragmentRecord,
|
|
137
|
+
_addDeferredFragment(deferredFragmentRecord, deliveryGroups) {
|
|
140
138
|
if (this._rootNodes.has(deferredFragmentRecord)) {
|
|
141
139
|
return;
|
|
142
140
|
}
|
|
143
141
|
const parent = deferredFragmentRecord.parent;
|
|
144
142
|
if (parent === undefined) {
|
|
145
|
-
invariant(
|
|
146
|
-
|
|
143
|
+
invariant(deliveryGroups !== undefined);
|
|
144
|
+
deliveryGroups.add(deferredFragmentRecord);
|
|
147
145
|
return;
|
|
148
146
|
}
|
|
149
147
|
parent.children.add(deferredFragmentRecord);
|
|
150
|
-
this._addDeferredFragment(parent,
|
|
148
|
+
this._addDeferredFragment(parent, deliveryGroups);
|
|
151
149
|
}
|
|
152
|
-
|
|
153
|
-
const result =
|
|
150
|
+
_onExecutionGroup(pendingExecutionGroup) {
|
|
151
|
+
const result = pendingExecutionGroup.result
|
|
152
|
+
.value;
|
|
154
153
|
if (isPromise(result)) {
|
|
155
154
|
result.then(resolved => this._enqueue(resolved));
|
|
156
155
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { addPath, pathToArray } from '@graphql-tools/utils';
|
|
2
2
|
import { IncrementalGraph } from './IncrementalGraph.js';
|
|
3
3
|
import { invariant } from './invariant.js';
|
|
4
|
-
import { isCancellableStreamRecord,
|
|
4
|
+
import { isCancellableStreamRecord, isCompletedExecutionGroup, isFailedExecutionGroup, } from './types.js';
|
|
5
5
|
export function buildIncrementalResponse(context, result, errors, incrementalDataRecords) {
|
|
6
6
|
const incrementalPublisher = new IncrementalPublisher(context);
|
|
7
7
|
return incrementalPublisher.buildResponse(result, errors, incrementalDataRecords);
|
|
@@ -143,17 +143,17 @@ class IncrementalPublisher {
|
|
|
143
143
|
};
|
|
144
144
|
}
|
|
145
145
|
_handleCompletedIncrementalData(completedIncrementalData, context) {
|
|
146
|
-
if (
|
|
147
|
-
this.
|
|
146
|
+
if (isCompletedExecutionGroup(completedIncrementalData)) {
|
|
147
|
+
this._handleCompletedExecutionGroup(completedIncrementalData, context);
|
|
148
148
|
}
|
|
149
149
|
else {
|
|
150
150
|
this._handleCompletedStreamItems(completedIncrementalData, context);
|
|
151
151
|
}
|
|
152
152
|
}
|
|
153
|
-
|
|
154
|
-
if (
|
|
155
|
-
for (const deferredFragmentRecord of
|
|
156
|
-
.
|
|
153
|
+
_handleCompletedExecutionGroup(completedExecutionGroup, context) {
|
|
154
|
+
if (isFailedExecutionGroup(completedExecutionGroup)) {
|
|
155
|
+
for (const deferredFragmentRecord of completedExecutionGroup.pendingExecutionGroup
|
|
156
|
+
.deferredFragmentRecords) {
|
|
157
157
|
const id = deferredFragmentRecord.id;
|
|
158
158
|
if (!this._incrementalGraph.removeDeferredFragment(deferredFragmentRecord)) {
|
|
159
159
|
// This can occur if multiple deferred grouped field sets error for a fragment.
|
|
@@ -164,7 +164,7 @@ class IncrementalPublisher {
|
|
|
164
164
|
const incrementalEntry = {
|
|
165
165
|
id,
|
|
166
166
|
data: null,
|
|
167
|
-
errors:
|
|
167
|
+
errors: completedExecutionGroup.errors,
|
|
168
168
|
};
|
|
169
169
|
if (this._context.sendPathAndLabelOnIncremental) {
|
|
170
170
|
const { path, label } = deferredFragmentRecord;
|
|
@@ -179,14 +179,14 @@ class IncrementalPublisher {
|
|
|
179
179
|
else {
|
|
180
180
|
context.completed.push({
|
|
181
181
|
id,
|
|
182
|
-
errors:
|
|
182
|
+
errors: completedExecutionGroup.errors,
|
|
183
183
|
});
|
|
184
184
|
}
|
|
185
185
|
}
|
|
186
186
|
return;
|
|
187
187
|
}
|
|
188
|
-
this._incrementalGraph.
|
|
189
|
-
for (const deferredFragmentRecord of
|
|
188
|
+
this._incrementalGraph.addCompletedSuccessfulExecutionGroup(completedExecutionGroup);
|
|
189
|
+
for (const deferredFragmentRecord of completedExecutionGroup.pendingExecutionGroup
|
|
190
190
|
.deferredFragmentRecords) {
|
|
191
191
|
const completion = this._incrementalGraph.completeDeferredFragment(deferredFragmentRecord);
|
|
192
192
|
if (completion === undefined) {
|
|
@@ -195,12 +195,12 @@ class IncrementalPublisher {
|
|
|
195
195
|
const id = deferredFragmentRecord.id;
|
|
196
196
|
invariant(id !== undefined);
|
|
197
197
|
const incremental = context.incremental;
|
|
198
|
-
const { newPending,
|
|
198
|
+
const { newPending, successfulExecutionGroups } = completion;
|
|
199
199
|
context.pending.push(...this._pendingSourcesToResults(newPending));
|
|
200
|
-
for (const
|
|
201
|
-
const { bestId, subPath } = this._getBestIdAndSubPath(id, deferredFragmentRecord,
|
|
200
|
+
for (const successfulExecutionGroup of successfulExecutionGroups) {
|
|
201
|
+
const { bestId, subPath } = this._getBestIdAndSubPath(id, deferredFragmentRecord, successfulExecutionGroup);
|
|
202
202
|
const incrementalEntry = {
|
|
203
|
-
...
|
|
203
|
+
...successfulExecutionGroup.result,
|
|
204
204
|
id: bestId,
|
|
205
205
|
};
|
|
206
206
|
if (this._context.sendPathAndLabelOnIncremental) {
|
|
@@ -285,10 +285,10 @@ class IncrementalPublisher {
|
|
|
285
285
|
}
|
|
286
286
|
}
|
|
287
287
|
}
|
|
288
|
-
_getBestIdAndSubPath(initialId, initialDeferredFragmentRecord,
|
|
288
|
+
_getBestIdAndSubPath(initialId, initialDeferredFragmentRecord, completedExecutionGroup) {
|
|
289
289
|
let maxLength = pathToArray(initialDeferredFragmentRecord.path).length;
|
|
290
290
|
let bestId = initialId;
|
|
291
|
-
for (const deferredFragmentRecord of
|
|
291
|
+
for (const deferredFragmentRecord of completedExecutionGroup.pendingExecutionGroup
|
|
292
292
|
.deferredFragmentRecords) {
|
|
293
293
|
if (deferredFragmentRecord === initialDeferredFragmentRecord) {
|
|
294
294
|
continue;
|
|
@@ -306,7 +306,7 @@ class IncrementalPublisher {
|
|
|
306
306
|
bestId = id;
|
|
307
307
|
}
|
|
308
308
|
}
|
|
309
|
-
const subPath =
|
|
309
|
+
const subPath = completedExecutionGroup.path.slice(maxLength);
|
|
310
310
|
return {
|
|
311
311
|
bestId,
|
|
312
312
|
subPath: subPath.length > 0 ? subPath : undefined,
|
|
@@ -1,45 +1,19 @@
|
|
|
1
1
|
import { AccumulatorMap } from './AccumulatorMap.js';
|
|
2
2
|
import { getBySet } from './getBySet.js';
|
|
3
3
|
import { isSameSet } from './isSameSet.js';
|
|
4
|
-
export function
|
|
4
|
+
export function buildExecutionPlan(originalGroupedFieldSet, parentDeferUsages = new Set()) {
|
|
5
5
|
const groupedFieldSet = new Map();
|
|
6
6
|
const newGroupedFieldSets = new Map();
|
|
7
|
-
const map = new Map();
|
|
8
7
|
for (const [responseKey, fieldGroup] of originalGroupedFieldSet) {
|
|
9
|
-
const
|
|
10
|
-
|
|
11
|
-
for (const fieldDetails of fieldGroup) {
|
|
12
|
-
const deferUsage = fieldDetails.deferUsage;
|
|
13
|
-
if (deferUsage === undefined) {
|
|
14
|
-
inOriginalResult = true;
|
|
15
|
-
continue;
|
|
16
|
-
}
|
|
17
|
-
deferUsageSet.add(deferUsage);
|
|
18
|
-
}
|
|
19
|
-
if (inOriginalResult) {
|
|
20
|
-
deferUsageSet.clear();
|
|
21
|
-
}
|
|
22
|
-
else {
|
|
23
|
-
deferUsageSet.forEach(deferUsage => {
|
|
24
|
-
const ancestors = getAncestors(deferUsage);
|
|
25
|
-
for (const ancestor of ancestors) {
|
|
26
|
-
if (deferUsageSet.has(ancestor)) {
|
|
27
|
-
deferUsageSet.delete(deferUsage);
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
});
|
|
31
|
-
}
|
|
32
|
-
map.set(responseKey, { deferUsageSet, fieldGroup });
|
|
33
|
-
}
|
|
34
|
-
for (const [responseKey, { deferUsageSet, fieldGroup }] of map) {
|
|
35
|
-
if (isSameSet(deferUsageSet, parentDeferUsages)) {
|
|
8
|
+
const filteredDeferUsageSet = getFilteredDeferUsageSet(fieldGroup);
|
|
9
|
+
if (isSameSet(filteredDeferUsageSet, parentDeferUsages)) {
|
|
36
10
|
groupedFieldSet.set(responseKey, fieldGroup);
|
|
37
11
|
continue;
|
|
38
12
|
}
|
|
39
|
-
let newGroupedFieldSet = getBySet(newGroupedFieldSets,
|
|
13
|
+
let newGroupedFieldSet = getBySet(newGroupedFieldSets, filteredDeferUsageSet);
|
|
40
14
|
if (newGroupedFieldSet === undefined) {
|
|
41
15
|
newGroupedFieldSet = new Map();
|
|
42
|
-
newGroupedFieldSets.set(
|
|
16
|
+
newGroupedFieldSets.set(filteredDeferUsageSet, newGroupedFieldSet);
|
|
43
17
|
}
|
|
44
18
|
newGroupedFieldSet.set(responseKey, fieldGroup);
|
|
45
19
|
}
|
|
@@ -48,16 +22,29 @@ export function buildFieldPlan(originalGroupedFieldSet, parentDeferUsages = new
|
|
|
48
22
|
newGroupedFieldSets,
|
|
49
23
|
};
|
|
50
24
|
}
|
|
51
|
-
function
|
|
52
|
-
const
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
25
|
+
function getFilteredDeferUsageSet(fieldGroup) {
|
|
26
|
+
const filteredDeferUsageSet = new Set();
|
|
27
|
+
for (const fieldDetails of fieldGroup) {
|
|
28
|
+
const deferUsage = fieldDetails.deferUsage;
|
|
29
|
+
if (deferUsage === undefined) {
|
|
30
|
+
filteredDeferUsageSet.clear();
|
|
31
|
+
return filteredDeferUsageSet;
|
|
32
|
+
}
|
|
33
|
+
filteredDeferUsageSet.add(deferUsage);
|
|
34
|
+
}
|
|
35
|
+
for (const deferUsage of filteredDeferUsageSet) {
|
|
36
|
+
let parentDeferUsage = deferUsage.parentDeferUsage;
|
|
37
|
+
while (parentDeferUsage !== undefined) {
|
|
38
|
+
if (filteredDeferUsageSet.has(parentDeferUsage)) {
|
|
39
|
+
filteredDeferUsageSet.delete(deferUsage);
|
|
40
|
+
break;
|
|
41
|
+
}
|
|
42
|
+
parentDeferUsage = parentDeferUsage.parentDeferUsage;
|
|
43
|
+
}
|
|
57
44
|
}
|
|
58
|
-
return
|
|
45
|
+
return filteredDeferUsageSet;
|
|
59
46
|
}
|
|
60
|
-
export function
|
|
47
|
+
export function buildBranchingExecutionPlan(originalGroupedFieldSet, parentDeferUsages = new Set()) {
|
|
61
48
|
const groupedFieldSet = new AccumulatorMap();
|
|
62
49
|
const newGroupedFieldSets = new Map();
|
|
63
50
|
for (const [responseKey, fieldGroup] of originalGroupedFieldSet) {
|