Skip to content

Commit 1e90861

Browse files
committed
incremental delivery without branching
1 parent 2b69fa2 commit 1e90861

File tree

10 files changed

+1269
-530
lines changed

10 files changed

+1269
-530
lines changed

src/execution/__tests__/defer-test.ts

+40-64
Original file line numberDiff line numberDiff line change
@@ -358,17 +358,17 @@ describe('Execute: defer directive', () => {
358358
incremental: [
359359
{
360360
data: {
361-
friends: [{ name: 'Han' }, { name: 'Leia' }, { name: 'C-3PO' }],
361+
id: '1',
362362
},
363363
path: ['hero'],
364-
label: 'DeferNested',
364+
label: 'DeferTop',
365365
},
366366
{
367367
data: {
368-
id: '1',
368+
friends: [{ name: 'Han' }, { name: 'Leia' }, { name: 'C-3PO' }],
369369
},
370370
path: ['hero'],
371-
label: 'DeferTop',
371+
label: 'DeferNested',
372372
},
373373
],
374374
hasNext: false,
@@ -623,13 +623,6 @@ describe('Execute: defer directive', () => {
623623
},
624624
{
625625
incremental: [
626-
{
627-
data: {
628-
id: '1',
629-
},
630-
path: ['hero'],
631-
label: 'DeferID',
632-
},
633626
{
634627
data: {
635628
hero: {
@@ -639,6 +632,13 @@ describe('Execute: defer directive', () => {
639632
path: [],
640633
label: 'DeferName',
641634
},
635+
{
636+
data: {
637+
id: '1',
638+
},
639+
path: ['hero'],
640+
label: 'DeferID',
641+
},
642642
],
643643
hasNext: false,
644644
},
@@ -693,7 +693,7 @@ describe('Execute: defer directive', () => {
693693
]);
694694
});
695695

696-
it('Does not deduplicate multiple defers on the same object', async () => {
696+
it('Can deduplicate multiple defers on the same object', async () => {
697697
const document = parse(`
698698
query {
699699
hero {
@@ -728,17 +728,8 @@ describe('Execute: defer directive', () => {
728728
},
729729
{
730730
incremental: [
731-
{ data: {}, path: ['hero', 'friends', 0] },
732-
{ data: {}, path: ['hero', 'friends', 0] },
733-
{ data: {}, path: ['hero', 'friends', 0] },
734731
{ data: { id: '2', name: 'Han' }, path: ['hero', 'friends', 0] },
735-
{ data: {}, path: ['hero', 'friends', 1] },
736-
{ data: {}, path: ['hero', 'friends', 1] },
737-
{ data: {}, path: ['hero', 'friends', 1] },
738732
{ data: { id: '3', name: 'Leia' }, path: ['hero', 'friends', 1] },
739-
{ data: {}, path: ['hero', 'friends', 2] },
740-
{ data: {}, path: ['hero', 'friends', 2] },
741-
{ data: {}, path: ['hero', 'friends', 2] },
742733
{ data: { id: '4', name: 'C-3PO' }, path: ['hero', 'friends', 2] },
743734
],
744735
hasNext: false,
@@ -933,11 +924,6 @@ describe('Execute: defer directive', () => {
933924
},
934925
path: ['hero'],
935926
},
936-
],
937-
hasNext: true,
938-
},
939-
{
940-
incremental: [
941927
{
942928
data: {
943929
deeperObject: {
@@ -948,11 +934,6 @@ describe('Execute: defer directive', () => {
948934
},
949935
path: ['hero', 'nestedObject'],
950936
},
951-
],
952-
hasNext: true,
953-
},
954-
{
955-
incremental: [
956937
{
957938
data: {
958939
foo: 'foo',
@@ -968,7 +949,7 @@ describe('Execute: defer directive', () => {
968949
]);
969950
});
970951

971-
it('Does not combine multiple fields from deferred fragments from different branches occurring at the same level', async () => {
952+
it('Can combine multiple fields from deferred fragments from different branches occurring at the same level', async () => {
972953
const document = parse(`
973954
query {
974955
hero {
@@ -1006,12 +987,6 @@ describe('Execute: defer directive', () => {
1006987
},
1007988
{
1008989
incremental: [
1009-
{
1010-
data: {
1011-
foo: 'foo',
1012-
},
1013-
path: ['hero', 'nestedObject', 'deeperObject'],
1014-
},
1015990
{
1016991
data: {
1017992
nestedObject: {
@@ -1020,11 +995,6 @@ describe('Execute: defer directive', () => {
1020995
},
1021996
path: ['hero'],
1022997
},
1023-
],
1024-
hasNext: true,
1025-
},
1026-
{
1027-
incremental: [
1028998
{
1029999
data: {
10301000
foo: 'foo',
@@ -1083,14 +1053,6 @@ describe('Execute: defer directive', () => {
10831053
},
10841054
{
10851055
incremental: [
1086-
{
1087-
data: {
1088-
e: {
1089-
f: 'f',
1090-
},
1091-
},
1092-
path: ['a', 'b'],
1093-
},
10941056
{
10951057
data: {
10961058
a: {
@@ -1106,6 +1068,14 @@ describe('Execute: defer directive', () => {
11061068
},
11071069
path: [],
11081070
},
1071+
{
1072+
data: {
1073+
e: {
1074+
f: 'f',
1075+
},
1076+
},
1077+
path: ['a', 'b'],
1078+
},
11091079
],
11101080
hasNext: false,
11111081
},
@@ -1146,16 +1116,6 @@ describe('Execute: defer directive', () => {
11461116
},
11471117
{
11481118
incremental: [
1149-
{
1150-
data: {
1151-
b: {
1152-
c: {
1153-
d: 'd',
1154-
},
1155-
},
1156-
},
1157-
path: ['a'],
1158-
},
11591119
{
11601120
data: {
11611121
a: {
@@ -1175,6 +1135,16 @@ describe('Execute: defer directive', () => {
11751135
],
11761136
path: [],
11771137
},
1138+
{
1139+
data: {
1140+
b: {
1141+
c: {
1142+
d: 'd',
1143+
},
1144+
},
1145+
},
1146+
path: ['a'],
1147+
},
11781148
],
11791149
hasNext: false,
11801150
},
@@ -1219,10 +1189,16 @@ describe('Execute: defer directive', () => {
12191189
incremental: [
12201190
{
12211191
data: {
1222-
hero: {
1223-
name: 'Luke',
1224-
},
1192+
hero: null,
12251193
},
1194+
errors: [
1195+
{
1196+
message:
1197+
'Cannot return null for non-nullable field Hero.nonNullName.',
1198+
locations: [{ line: 4, column: 11 }],
1199+
path: ['hero', 'nonNullName'],
1200+
},
1201+
],
12261202
path: [],
12271203
},
12281204
],

src/execution/__tests__/executor-test.ts

+38-14
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,12 @@ import { expectJSON } from '../../__testUtils__/expectJSON.js';
55
import { resolveOnNextTick } from '../../__testUtils__/resolveOnNextTick.js';
66

77
import { inspect } from '../../jsutils/inspect.js';
8+
import type { Path } from '../../jsutils/Path.js';
89

910
import { Kind } from '../../language/kinds.js';
1011
import { parse } from '../../language/parser.js';
1112

13+
import type { GraphQLResolveInfo } from '../../type/definition.js';
1214
import {
1315
GraphQLInterfaceType,
1416
GraphQLList,
@@ -191,7 +193,7 @@ describe('Execute: Handles basic execution tasks', () => {
191193
});
192194

193195
it('provides info about current execution state', () => {
194-
let resolvedInfo;
196+
let resolvedInfo: GraphQLResolveInfo | undefined;
195197
const testType = new GraphQLObjectType({
196198
name: 'Test',
197199
fields: {
@@ -239,13 +241,22 @@ describe('Execute: Handles basic execution tasks', () => {
239241
const field = operation.selectionSet.selections[0];
240242
expect(resolvedInfo).to.deep.include({
241243
fieldNodes: [field],
242-
path: { prev: undefined, key: 'result', typename: 'Test' },
243244
variableValues: { var: 'abc' },
244245
});
246+
247+
expect(resolvedInfo?.path).to.deep.include({
248+
prev: undefined,
249+
key: 'result',
250+
});
251+
252+
expect(resolvedInfo?.path.info).to.deep.include({
253+
parentType: testType,
254+
fieldName: 'test',
255+
});
245256
});
246257

247258
it('populates path correctly with complex types', () => {
248-
let path;
259+
let path: Path<unknown> | undefined;
249260
const someObject = new GraphQLObjectType({
250261
name: 'SomeObject',
251262
fields: {
@@ -288,18 +299,31 @@ describe('Execute: Handles basic execution tasks', () => {
288299

289300
executeSync({ schema, document, rootValue });
290301

291-
expect(path).to.deep.equal({
302+
expect(path).to.deep.include({
292303
key: 'l2',
293-
typename: 'SomeObject',
294-
prev: {
295-
key: 0,
296-
typename: undefined,
297-
prev: {
298-
key: 'l1',
299-
typename: 'SomeQuery',
300-
prev: undefined,
301-
},
302-
},
304+
});
305+
306+
expect(path?.info).to.deep.include({
307+
parentType: someObject,
308+
fieldName: 'test',
309+
});
310+
311+
expect(path?.prev).to.deep.include({
312+
key: 0,
313+
});
314+
315+
expect(path?.prev?.info).to.deep.include({
316+
parentType: testType,
317+
fieldName: 'test',
318+
});
319+
320+
expect(path?.prev?.prev).to.deep.include({
321+
key: 'l1',
322+
});
323+
324+
expect(path?.prev?.prev?.info).to.deep.include({
325+
parentType: testType,
326+
fieldName: 'test',
303327
});
304328
});
305329

0 commit comments

Comments
 (0)