Skip to content

Commit

Permalink
introduce experimental parallel streaming
Browse files Browse the repository at this point in the history
extracted from #154

relies on bundlers that can be used for batched streaming as well
  • Loading branch information
yaacovCR committed Mar 18, 2022
1 parent 3083c1d commit ed5420a
Show file tree
Hide file tree
Showing 10 changed files with 1,339 additions and 227 deletions.
7 changes: 7 additions & 0 deletions .changeset/giant-llamas-peel.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
'graphql-executor': patch
---

introduce experimental parallel streaming

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.
106 changes: 103 additions & 3 deletions src/execution/__tests__/stream-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -100,8 +100,8 @@ const query = new GraphQLObjectType({
type: new GraphQLList(new GraphQLNonNull(friendType)),
async *resolve() {
yield await Promise.resolve(friends[0]);
yield await Promise.resolve(null); /* c8 ignore start */
// Not reachable, error from resolving null
yield await Promise.resolve(null);
yield await Promise.resolve(friends[1]);
},
/* c8 ignore stop */
},
Expand Down Expand Up @@ -149,7 +149,7 @@ const query = new GraphQLObjectType({
for (const friend of friends) {
yield friend;
}
await new Promise((r) => setTimeout(r, 1));
await new Promise((r) => setTimeout(r, 10));
},
},
nestedObject: {
Expand Down Expand Up @@ -442,6 +442,49 @@ describe('Execute: stream directive', () => {
},
]);
});
it('Can stream in parallel', async () => {
const document = parse(`
query {
asyncSlowList @stream(initialCount: 0, inParallel: true) {
name
id
}
}
`);
const result = await complete(document);
expect(result).to.deep.equal([
{
data: {
asyncSlowList: [],
},
hasNext: true,
},
{
data: {
name: 'Han',
id: '2',
},
path: ['asyncSlowList', 1],
hasNext: true,
},
{
data: {
name: 'Leia',
id: '3',
},
path: ['asyncSlowList', 2],
hasNext: true,
},
{
data: {
name: 'Luke',
id: '1',
},
path: ['asyncSlowList', 0],
hasNext: false,
},
]);
});
it('Handles rejections in a field that returns a list of promises before initialCount is reached', async () => {
const document = parse(`
query {
Expand Down Expand Up @@ -876,6 +919,63 @@ describe('Execute: stream directive', () => {
path: ['asyncIterableNonNullError', 1],
},
],
hasNext: true,
},
{
data: {
name: 'Han',
},
path: ['asyncIterableNonNullError', 2],
hasNext: false,
},
]);
});
it('Handles null returned in non-null async iterable list items after initialCount is reached with parallel streaming', async () => {
const document = parse(`
query {
asyncIterableNonNullError @stream(initialCount: 0, inParallel: true) {
name
}
}
`);
const result = await complete(document);
expectJSON(result).toDeepEqual([
{
data: {
asyncIterableNonNullError: [],
},
hasNext: true,
},
{
data: {
name: 'Luke',
},
path: ['asyncIterableNonNullError', 0],
hasNext: true,
},
{
data: null,
path: ['asyncIterableNonNullError', 1],
errors: [
{
message:
'Cannot return null for non-nullable field Query.asyncIterableNonNullError.',
locations: [
{
line: 3,
column: 9,
},
],
path: ['asyncIterableNonNullError', 1],
},
],
hasNext: true,
},
{
data: {
name: 'Han',
},
path: ['asyncIterableNonNullError', 2],
hasNext: false,
},
]);
Expand Down
Loading

0 comments on commit ed5420a

Please sign in to comment.