Skip to content

Commit 2ce309d

Browse files
committed
do not emit pending for empty non-published subsequent results
The publish method checks to see if a subsequent result is empty; this same logic should be employed to suppress pending notices for empty records. This has already been achieved for subsequent results that are children of the initial result, as we generated the pending notices from the list of initially published records. For subsequent results that are children of other subsequent results, we previously generated the pending notice prior to actually publishing. This change integrates the logic: the publishing method itself returns a pending notice as required. This results in a bug-fix for subsequent records of other subsequent records as well as a reduction of code for subsequent results to the initial result.
1 parent 2aedf25 commit 2ce309d

File tree

2 files changed

+78
-20
lines changed

2 files changed

+78
-20
lines changed

src/execution/IncrementalPublisher.ts

Lines changed: 24 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -301,25 +301,20 @@ export class IncrementalPublisher {
301301
initialResultRecord: InitialResultRecord,
302302
data: ObjMap<unknown> | null,
303303
): ExecutionResult | ExperimentalIncrementalExecutionResults {
304+
const pendingSources = new Set<DeferredFragmentRecord | StreamRecord>();
304305
for (const child of initialResultRecord.children) {
305306
if (child.filtered) {
306307
continue;
307308
}
308-
this._publish(child);
309+
const maybePendingSource = this._publish(child);
310+
if (maybePendingSource) {
311+
pendingSources.add(maybePendingSource);
312+
}
309313
}
310314

311315
const errors = initialResultRecord.errors;
312316
const initialResult = errors.length === 0 ? { data } : { errors, data };
313-
const pending = this._pending;
314-
if (pending.size > 0) {
315-
const pendingSources = new Set<DeferredFragmentRecord | StreamRecord>();
316-
for (const subsequentResultRecord of pending) {
317-
const pendingSource = isStreamItemsRecord(subsequentResultRecord)
318-
? subsequentResultRecord.streamRecord
319-
: subsequentResultRecord;
320-
pendingSources.add(pendingSource);
321-
}
322-
317+
if (pendingSources.size > 0) {
323318
return {
324319
initialResult: {
325320
...initialResult,
@@ -542,13 +537,10 @@ export class IncrementalPublisher {
542537
if (child.filtered) {
543538
continue;
544539
}
545-
const pendingSource = isStreamItemsRecord(child)
546-
? child.streamRecord
547-
: child;
548-
if (!pendingSource.pendingSent) {
549-
newPendingSources.add(pendingSource);
540+
const maybePendingSource = this._publish(child);
541+
if (maybePendingSource) {
542+
newPendingSources.add(maybePendingSource);
550543
}
551-
this._publish(child);
552544
}
553545
if (isStreamItemsRecord(subsequentResultRecord)) {
554546
if (subsequentResultRecord.isFinalRecord) {
@@ -655,14 +647,20 @@ export class IncrementalPublisher {
655647
return result;
656648
}
657649

658-
private _publish(subsequentResultRecord: SubsequentResultRecord): void {
650+
private _publish(
651+
subsequentResultRecord: SubsequentResultRecord,
652+
): DeferredFragmentRecord | StreamRecord | undefined {
659653
if (isStreamItemsRecord(subsequentResultRecord)) {
660654
if (subsequentResultRecord.isCompleted) {
661655
this._push(subsequentResultRecord);
662-
return;
656+
} else {
657+
this._introduce(subsequentResultRecord);
663658
}
664659

665-
this._introduce(subsequentResultRecord);
660+
const stream = subsequentResultRecord.streamRecord;
661+
if (!stream.pendingSent) {
662+
return stream;
663+
}
666664
return;
667665
}
668666

@@ -673,6 +671,12 @@ export class IncrementalPublisher {
673671
subsequentResultRecord.children.size > 0
674672
) {
675673
this._push(subsequentResultRecord);
674+
} else {
675+
return;
676+
}
677+
678+
if (!subsequentResultRecord.pendingSent) {
679+
return subsequentResultRecord;
676680
}
677681
}
678682

src/execution/__tests__/defer-test.ts

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ const anotherNestedObject = new GraphQLObjectType({
6464

6565
const hero = {
6666
name: 'Luke',
67+
lastName: 'SkyWalker',
6768
id: 1,
6869
friends,
6970
nestedObject,
@@ -112,6 +113,7 @@ const heroType = new GraphQLObjectType({
112113
fields: {
113114
id: { type: GraphQLID },
114115
name: { type: GraphQLString },
116+
lastName: { type: GraphQLString },
115117
nonNullName: { type: new GraphQLNonNull(GraphQLString) },
116118
friends: {
117119
type: new GraphQLList(friendType),
@@ -566,6 +568,58 @@ describe('Execute: defer directive', () => {
566568
]);
567569
});
568570

571+
it('Separately emits defer fragments with different labels with varying subfields with superimposed masked defer', async () => {
572+
const document = parse(`
573+
query HeroNameQuery {
574+
... @defer(label: "DeferID") {
575+
hero {
576+
id
577+
}
578+
}
579+
... @defer(label: "DeferName") {
580+
hero {
581+
name
582+
lastName
583+
... @defer {
584+
lastName
585+
}
586+
}
587+
}
588+
}
589+
`);
590+
const result = await complete(document);
591+
expectJSON(result).toDeepEqual([
592+
{
593+
data: {},
594+
pending: [
595+
{ id: '0', path: [], label: 'DeferID' },
596+
{ id: '1', path: [], label: 'DeferName' },
597+
],
598+
hasNext: true,
599+
},
600+
{
601+
incremental: [
602+
{
603+
data: { hero: {} },
604+
id: '0',
605+
},
606+
{
607+
data: { id: '1' },
608+
id: '0',
609+
subPath: ['hero'],
610+
},
611+
{
612+
data: { name: 'Luke', lastName: 'SkyWalker' },
613+
id: '1',
614+
subPath: ['hero'],
615+
},
616+
],
617+
completed: [{ id: '0' }, { id: '1' }],
618+
hasNext: false,
619+
},
620+
]);
621+
});
622+
569623
it('Separately emits defer fragments with different labels with varying subfields that return promises', async () => {
570624
const document = parse(`
571625
query HeroNameQuery {

0 commit comments

Comments
 (0)