Skip to content

Commit d0a66d1

Browse files
committed
limit when data property is an array
when using `@stream`, the `data` property will be an array only when batching. when/if graphql-js changes to always send data as an array for streamed results, graphql-executor will do so as well. until then, data will be an array only when necessary, i.e. when batch streaming
1 parent 99a85d4 commit d0a66d1

7 files changed

Lines changed: 363 additions & 270 deletions

File tree

.changeset/giant-llamas-peel.md

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,3 @@
55
introduce experimental parallel streaming
66

77
Experimental `inParallel` boolean argument to the stream directive may now be used to stream list items as they are ready instead of in sequential list order.
8-
9-
When parallel streaming is enabled, the `data` property of execution patch results will consist of an array of items and a new `atIndices` property will contain the corresponding indices of the items.

.changeset/thin-maps-boil.md

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,4 @@ introduce experimental batched streaming
66

77
Experimental `maxChunkSize` and `maxInterval` arguments allows for increasing the number of items in each streamed payload up to the specified maximum size. A maximum interval (specified in milliseconds) can be used to send any ready items prior to the maximum chunk size.
88

9-
When using a `maxChunkSize` greater than 1, the `data` property of execution patch results will consist of an array of items and a new `atIndex` property will contain the initial index for the items included within the chunk.
10-
11-
These options can be combined with parallel streaming. When streaming in parallel, the `data` property will always consist on an array of items and the `atIndices` property will always consist of an array of the matching indices, even when `maxChunkSize` is equal to 1. If these new arguments prove popular, `data` should probably be an array even when `maxChunkSize` is equal to one, even without parallel streaming.
9+
When using a `maxChunkSize` greater than 1, the `data` property of execution patch results will consist of an array of items and a new `atIndex` property will contain the initial index for the items included within the chunk. When streaming in parallel, new `atIndices` property will be used instead of `atIndex` and withh contain an array of the corresponding indices for each of the items included within the `data` property.

src/execution/__tests__/stream-test.ts

Lines changed: 80 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ const query = new GraphQLObjectType({
101101
async *resolve() {
102102
yield await Promise.resolve(friends[0]);
103103
yield await Promise.resolve(null);
104-
yield await Promise.resolve(friends[1]);
104+
yield await Promise.resolve(null);
105105
},
106106
/* c8 ignore stop */
107107
},
@@ -522,6 +522,50 @@ describe('Execute: stream directive', () => {
522522
}
523523
`);
524524
const result = await complete(document);
525+
expect(result).to.deep.equal([
526+
{
527+
data: {
528+
asyncSlowList: [],
529+
},
530+
hasNext: true,
531+
},
532+
{
533+
data: {
534+
name: 'Han',
535+
id: '2',
536+
},
537+
path: ['asyncSlowList', 1],
538+
hasNext: true,
539+
},
540+
{
541+
data: {
542+
name: 'Leia',
543+
id: '3',
544+
},
545+
path: ['asyncSlowList', 2],
546+
hasNext: true,
547+
},
548+
{
549+
data: {
550+
name: 'Luke',
551+
id: '1',
552+
},
553+
554+
path: ['asyncSlowList', 0],
555+
hasNext: false,
556+
},
557+
]);
558+
});
559+
it('Can batch stream in parallel', async () => {
560+
const document = parse(`
561+
query {
562+
asyncSlowList @stream(initialCount: 0, inParallel: true, maxChunkSize: 2) {
563+
name
564+
id
565+
}
566+
}
567+
`);
568+
const result = await complete(document);
525569
expect(result).to.deep.equal([
526570
{
527571
data: {
@@ -535,20 +579,13 @@ describe('Execute: stream directive', () => {
535579
name: 'Han',
536580
id: '2',
537581
},
538-
],
539-
path: ['asyncSlowList'],
540-
atIndices: [1],
541-
hasNext: true,
542-
},
543-
{
544-
data: [
545582
{
546583
name: 'Leia',
547584
id: '3',
548585
},
549586
],
550587
path: ['asyncSlowList'],
551-
atIndices: [2],
588+
atIndices: [1, 2],
552589
hasNext: true,
553590
},
554591
{
@@ -1047,10 +1084,21 @@ describe('Execute: stream directive', () => {
10471084
hasNext: true,
10481085
},
10491086
{
1050-
data: {
1051-
name: 'Han',
1052-
},
1087+
data: null,
10531088
path: ['asyncIterableNonNullError', 2],
1089+
errors: [
1090+
{
1091+
message:
1092+
'Cannot return null for non-nullable field Query.asyncIterableNonNullError.',
1093+
locations: [
1094+
{
1095+
line: 3,
1096+
column: 9,
1097+
},
1098+
],
1099+
path: ['asyncIterableNonNullError', 2],
1100+
},
1101+
],
10541102
hasNext: false,
10551103
},
10561104
]);
@@ -1097,25 +1145,26 @@ describe('Execute: stream directive', () => {
10971145
],
10981146
path: ['asyncIterableNonNullError', 1],
10991147
},
1100-
],
1101-
hasNext: true,
1102-
},
1103-
{
1104-
data: [
11051148
{
1106-
name: 'Han',
1149+
message:
1150+
'Cannot return null for non-nullable field Query.asyncIterableNonNullError.',
1151+
locations: [
1152+
{
1153+
line: 3,
1154+
column: 9,
1155+
},
1156+
],
1157+
path: ['asyncIterableNonNullError', 2],
11071158
},
11081159
],
1109-
path: ['asyncIterableNonNullError'],
1110-
atIndex: 2,
11111160
hasNext: false,
11121161
},
11131162
]);
11141163
});
11151164
it('Handles null returned in non-null async iterable list items after initialCount is reached with parallel streaming', async () => {
11161165
const document = parse(`
11171166
query {
1118-
asyncIterableNonNullError @stream(initialCount: 0, inParallel: true) {
1167+
asyncIterableNonNullError @stream(initialCount: 0, inParallel: true, maxChunkSize: 2) {
11191168
name
11201169
}
11211170
}
@@ -1141,7 +1190,7 @@ describe('Execute: stream directive', () => {
11411190
{
11421191
data: null,
11431192
path: ['asyncIterableNonNullError'],
1144-
atIndices: [1],
1193+
atIndices: [1, 2],
11451194
errors: [
11461195
{
11471196
message:
@@ -1154,17 +1203,18 @@ describe('Execute: stream directive', () => {
11541203
],
11551204
path: ['asyncIterableNonNullError', 1],
11561205
},
1157-
],
1158-
hasNext: true,
1159-
},
1160-
{
1161-
data: [
11621206
{
1163-
name: 'Han',
1207+
message:
1208+
'Cannot return null for non-nullable field Query.asyncIterableNonNullError.',
1209+
locations: [
1210+
{
1211+
line: 3,
1212+
column: 9,
1213+
},
1214+
],
1215+
path: ['asyncIterableNonNullError', 2],
11641216
},
11651217
],
1166-
path: ['asyncIterableNonNullError'],
1167-
atIndices: [2],
11681218
hasNext: false,
11691219
},
11701220
]);

0 commit comments

Comments
 (0)