Skip to content

Commit 7a5ca0f

Browse files
committed
consolidate payloads
1 parent e1c8c16 commit 7a5ca0f

File tree

3 files changed

+91
-167
lines changed

3 files changed

+91
-167
lines changed

src/execution/IncrementalPublisher.ts

+59-43
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,12 @@ export interface FormattedCompletedResult {
109109
errors?: ReadonlyArray<GraphQLError>;
110110
}
111111

112+
interface IncrementalAggregate {
113+
newPendingSources: Set<DeferredFragmentRecord | StreamRecord>;
114+
incrementalResults: Array<IncrementalResult>;
115+
completedResults: Array<CompletedResult>;
116+
}
117+
112118
/**
113119
* This class is used to publish incremental results to the client, enabling semi-concurrent
114120
* execution while preserving result order.
@@ -179,20 +185,28 @@ export class IncrementalPublisher {
179185
return { value: undefined, done: true };
180186
}
181187

182-
for (const item of this._released) {
183-
this._pending.delete(item);
184-
}
185-
const released = this._released;
186-
this._released = new Set();
188+
if (this._released.size > 0) {
189+
let aggregate = this._incrementalInitializer();
190+
do {
191+
for (const item of this._released) {
192+
this._pending.delete(item);
193+
}
194+
const released = this._released;
195+
this._released = new Set();
187196

188-
const result = this._getIncrementalResult(released);
197+
aggregate = this._incrementalReducer(aggregate, released);
198+
} while (this._released.size > 0);
189199

190-
if (!this.hasNext()) {
191-
isDone = true;
192-
}
200+
const hasNext = this.hasNext();
201+
202+
if (!hasNext) {
203+
isDone = true;
204+
}
193205

194-
if (result !== undefined) {
195-
return { value: result, done: false };
206+
return {
207+
value: this._incrementalFinalizer(aggregate),
208+
done: false,
209+
};
196210
}
197211

198212
// eslint-disable-next-line no-await-in-loop
@@ -532,37 +546,20 @@ export class IncrementalPublisher {
532546
this._trigger();
533547
}
534548

535-
private _getIncrementalResult(
536-
completedRecords: ReadonlySet<SubsequentResultRecord>,
537-
): SubsequentIncrementalExecutionResult | undefined {
538-
const { pending, incremental, completed } =
539-
this._processPending(completedRecords);
540-
541-
const hasNext = this.hasNext();
542-
if (incremental.length === 0 && completed.length === 0 && hasNext) {
543-
return undefined;
544-
}
545-
546-
const result: SubsequentIncrementalExecutionResult = { hasNext };
547-
if (pending.length) {
548-
result.pending = pending;
549-
}
550-
if (incremental.length) {
551-
result.incremental = incremental;
552-
}
553-
if (completed.length) {
554-
result.completed = completed;
555-
}
556-
557-
return result;
549+
private _incrementalInitializer(): IncrementalAggregate {
550+
return {
551+
newPendingSources: new Set<DeferredFragmentRecord | StreamRecord>(),
552+
incrementalResults: [],
553+
completedResults: [],
554+
};
558555
}
559556

560-
private _processPending(
557+
private _incrementalReducer(
558+
aggregate: IncrementalAggregate,
561559
completedRecords: ReadonlySet<SubsequentResultRecord>,
562-
): IncrementalUpdate {
563-
const newPendingSources = new Set<DeferredFragmentRecord | StreamRecord>();
564-
const incrementalResults: Array<IncrementalResult> = [];
565-
const completedResults: Array<CompletedResult> = [];
560+
): IncrementalAggregate {
561+
const { newPendingSources, incrementalResults, completedResults } =
562+
aggregate;
566563
for (const subsequentResultRecord of completedRecords) {
567564
for (const child of subsequentResultRecord.children) {
568565
const pendingSource = isStreamItemsRecord(child)
@@ -625,11 +622,30 @@ export class IncrementalPublisher {
625622
}
626623
}
627624

628-
return {
629-
pending: this.pendingSourcesToResults(newPendingSources),
630-
incremental: incrementalResults,
631-
completed: completedResults,
625+
return aggregate;
626+
}
627+
628+
private _incrementalFinalizer(
629+
aggregate: IncrementalAggregate,
630+
): SubsequentIncrementalExecutionResult {
631+
const { newPendingSources, incrementalResults, completedResults } =
632+
aggregate;
633+
const pendingResults = this.pendingSourcesToResults(newPendingSources);
634+
635+
const result: SubsequentIncrementalExecutionResult = {
636+
hasNext: this.hasNext(),
632637
};
638+
if (pendingResults.length) {
639+
result.pending = pendingResults;
640+
}
641+
if (incrementalResults.length) {
642+
result.incremental = incrementalResults;
643+
}
644+
if (completedResults.length) {
645+
result.completed = completedResults;
646+
}
647+
648+
return result;
633649
}
634650

635651
private _completedRecordToResult(

src/execution/__tests__/defer-test.ts

+11-37
Original file line numberDiff line numberDiff line change
@@ -1000,35 +1000,25 @@ describe('Execute: defer directive', () => {
10001000
hasNext: true,
10011001
},
10021002
{
1003-
pending: [{ path: ['hero', 'nestedObject'] }],
10041003
incremental: [
10051004
{
10061005
data: { bar: 'bar' },
10071006
path: ['hero', 'nestedObject', 'deeperObject'],
10081007
},
1009-
],
1010-
completed: [{ path: ['hero'] }],
1011-
hasNext: true,
1012-
},
1013-
{
1014-
pending: [{ path: ['hero', 'nestedObject', 'deeperObject'] }],
1015-
incremental: [
10161008
{
10171009
data: { baz: 'baz' },
10181010
path: ['hero', 'nestedObject', 'deeperObject'],
10191011
},
1020-
],
1021-
hasNext: true,
1022-
completed: [{ path: ['hero', 'nestedObject'] }],
1023-
},
1024-
{
1025-
incremental: [
10261012
{
10271013
data: { bak: 'bak' },
10281014
path: ['hero', 'nestedObject', 'deeperObject'],
10291015
},
10301016
],
1031-
completed: [{ path: ['hero', 'nestedObject', 'deeperObject'] }],
1017+
completed: [
1018+
{ path: ['hero'] },
1019+
{ path: ['hero', 'nestedObject'] },
1020+
{ path: ['hero', 'nestedObject', 'deeperObject'] },
1021+
],
10321022
hasNext: false,
10331023
},
10341024
]);
@@ -1075,31 +1065,25 @@ describe('Execute: defer directive', () => {
10751065
hasNext: true,
10761066
},
10771067
{
1078-
pending: [{ path: ['hero', 'nestedObject', 'deeperObject'] }],
10791068
incremental: [
10801069
{
10811070
data: {
10821071
foo: 'foo',
10831072
},
10841073
path: ['hero', 'nestedObject', 'deeperObject'],
10851074
},
1086-
],
1087-
completed: [
1088-
{ path: ['hero'] },
1089-
{ path: ['hero', 'nestedObject', 'deeperObject'] },
1090-
],
1091-
hasNext: true,
1092-
},
1093-
{
1094-
incremental: [
10951075
{
10961076
data: {
10971077
bar: 'bar',
10981078
},
10991079
path: ['hero', 'nestedObject', 'deeperObject'],
11001080
},
11011081
],
1102-
completed: [{ path: ['hero', 'nestedObject', 'deeperObject'] }],
1082+
completed: [
1083+
{ path: ['hero'] },
1084+
{ path: ['hero', 'nestedObject', 'deeperObject'] },
1085+
{ path: ['hero', 'nestedObject', 'deeperObject'] },
1086+
],
11031087
hasNext: false,
11041088
},
11051089
]);
@@ -1895,27 +1879,17 @@ describe('Execute: defer directive', () => {
18951879
hasNext: true,
18961880
},
18971881
{
1898-
pending: [
1899-
{ path: ['hero', 'friends', 0] },
1900-
{ path: ['hero', 'friends', 1] },
1901-
{ path: ['hero', 'friends', 2] },
1902-
],
19031882
incremental: [
19041883
{
19051884
data: { name: 'slow', friends: [{}, {}, {}] },
19061885
path: ['hero'],
19071886
},
1908-
],
1909-
completed: [{ path: ['hero'] }],
1910-
hasNext: true,
1911-
},
1912-
{
1913-
incremental: [
19141887
{ data: { name: 'Han' }, path: ['hero', 'friends', 0] },
19151888
{ data: { name: 'Leia' }, path: ['hero', 'friends', 1] },
19161889
{ data: { name: 'C-3PO' }, path: ['hero', 'friends', 2] },
19171890
],
19181891
completed: [
1892+
{ path: ['hero'] },
19191893
{ path: ['hero', 'friends', 0] },
19201894
{ path: ['hero', 'friends', 1] },
19211895
{ path: ['hero', 'friends', 2] },

0 commit comments

Comments
 (0)