Skip to content

Commit 0a5d362

Browse files
committed
enable defer stream across schema creation
1 parent 3a4084f commit 0a5d362

File tree

11 files changed

+115
-9
lines changed

11 files changed

+115
-9
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,6 @@
8383
"./website"
8484
],
8585
"resolutions": {
86-
"graphql": "15.3.0"
86+
"graphql": "npm:graphql-experimental"
8787
}
8888
}

packages/delegate/src/defaultMergedResolver.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,16 @@ export function defaultMergedResolver(
3333

3434
const data = parent[responseKey];
3535
const unpathedErrors = getUnpathedErrors(parent);
36+
37+
// To Do: extract this section to separate function.
38+
// If proxied result with defer or stream, result may be initially undefined
39+
// so must call out to a to-be-created Receiver abstraction
40+
// (as opposed to Dispatcher within graphql-js) that will notify of data arrival
41+
42+
if (data === undefined) {
43+
return 'test';
44+
}
45+
3646
const subschema = getSubschema(parent, responseKey);
3747

3848
return resolveExternalValue(data, unpathedErrors, subschema, context, info);
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
import { graphql } from 'graphql/experimental';
2+
3+
import { makeExecutableSchema } from '@graphql-tools/schema';
4+
5+
describe('defer support', () => {
6+
test('should work', async () => {
7+
const schema = makeExecutableSchema({
8+
typeDefs: `
9+
type Query {
10+
test(input: String): String
11+
}
12+
`,
13+
resolvers: {
14+
Query: {
15+
test: (_root, args) => args.input,
16+
}
17+
},
18+
});
19+
20+
const result = await graphql(
21+
schema,
22+
`
23+
query {
24+
... on Query @defer {
25+
test(input: "test")
26+
}
27+
}
28+
`,
29+
);
30+
31+
const results = [];
32+
if (result[Symbol.asyncIterator]) {
33+
for await (let patch of result) {
34+
results.push(patch);
35+
}
36+
}
37+
38+
expect(results[0]).toEqual({
39+
data: {},
40+
hasNext: true,
41+
});
42+
expect(results[1]).toEqual({
43+
data: {
44+
test: 'test'
45+
},
46+
hasNext: false,
47+
path: [],
48+
});
49+
50+
});
51+
});

packages/load/tests/loaders/schema/integration.spec.ts

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,31 @@ describe('loadSchema', () => {
5353
const schemaStr = printSchema(schema);
5454

5555
expect(schemaStr).toBeSimilarGqlDoc(/* GraphQL */`
56+
"""
57+
Directs the executor to defer this fragment when the \`if\` argument is true or undefined.
58+
"""
59+
directive @defer(
60+
"""Deferred when true or undefined."""
61+
if: Boolean
62+
63+
"""Unique name"""
64+
label: String
65+
) on FRAGMENT_SPREAD | INLINE_FRAGMENT
66+
67+
"""
68+
Directs the executor to stream plural fields when the \`if\` argument is true or undefined.
69+
"""
70+
directive @stream(
71+
"""Stream when true or undefined."""
72+
if: Boolean
73+
74+
"""Unique name"""
75+
label: String
76+
77+
"""Number of items to return immediately"""
78+
initialCount: Int!
79+
) on FIELD
80+
5681
type Query {
5782
a: A
5883
b: B

packages/schema/src/buildSchemaFromTypeDefinitions.ts

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { extendSchema, buildASTSchema, GraphQLSchema, DocumentNode, ASTNode } from 'graphql';
1+
import { extendSchema, buildASTSchema, GraphQLSchema, DocumentNode, ASTNode, BuildSchemaOptions } from 'graphql';
22

33
import { ITypeDefinitions, GraphQLParseOptions, parseGraphQLSDL } from '@graphql-tools/utils';
44

@@ -12,12 +12,16 @@ export function buildSchemaFromTypeDefinitions(
1212
const document = buildDocumentFromTypeDefinitions(typeDefinitions, parseOptions);
1313
const typesAst = filterExtensionDefinitions(document);
1414

15-
const backcompatOptions = { commentDescriptions: true };
16-
let schema: GraphQLSchema = buildASTSchema(typesAst, backcompatOptions);
15+
const options: BuildSchemaOptions = {
16+
commentDescriptions: true,
17+
experimentalDefer: true,
18+
experimentalStream: true,
19+
};
20+
let schema: GraphQLSchema = buildASTSchema(typesAst, options);
1721

1822
const extensionsAst = extractExtensionDefinitions(document);
1923
if (extensionsAst.definitions.length > 0) {
20-
schema = extendSchema(schema, extensionsAst, backcompatOptions);
24+
schema = extendSchema(schema, extensionsAst, options);
2125
}
2226

2327
return schema;

packages/schema/src/types.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,4 +67,12 @@ export interface IExecutableSchemaDefinition<TContext = any> {
6767
* Additional options for removing unused types from the schema
6868
*/
6969
pruningOptions?: PruneSchemaOptions;
70+
/**
71+
* Set to `true` to enable support within queries for the experimental `defer` directive
72+
*/
73+
experimentalDefer?: boolean;
74+
/**
75+
* Set to `true` to enable support within queries for the experimental `stream` directive
76+
*/
77+
experimentalStream?: boolean;
7078
}

packages/stitch/src/stitchSchemas.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,8 @@ export function stitchSchemas({
141141
astNode: schemaDefs.schemaDef,
142142
extensionASTNodes: schemaDefs.schemaExtensions,
143143
extensions: null,
144+
experimentalDefer: true,
145+
experimentalStream: true,
144146
});
145147

146148
extensions.forEach(extension => {

packages/stitch/src/stitchingInfo.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -348,6 +348,8 @@ export function addStitchingInfo(stitchedSchema: GraphQLSchema, stitchingInfo: S
348348
...stitchedSchema.extensions,
349349
stitchingInfo,
350350
},
351+
experimentalDefer: true,
352+
experimentalStream: true,
351353
});
352354
}
353355

packages/utils/src/addTypes.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,5 +80,7 @@ export function addTypes(
8080
subscription: subscriptionTypeName != null ? (typeMap[subscriptionTypeName] as GraphQLObjectType) : undefined,
8181
types: Object.keys(typeMap).map(typeName => typeMap[typeName]),
8282
directives,
83+
experimentalDefer: true,
84+
experimentalStream: true,
8385
});
8486
}

packages/utils/src/mapSchema.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,8 @@ export function mapSchema(schema: GraphQLSchema, schemaMapper: SchemaMapper = {}
8888
subscription: newSubscriptionTypeName != null ? (typeMap[newSubscriptionTypeName] as GraphQLObjectType) : undefined,
8989
types: Object.keys(typeMap).map(typeName => typeMap[typeName]),
9090
directives,
91+
experimentalDefer: true,
92+
experimentalStream: true,
9193
});
9294
}
9395

yarn.lock

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6782,10 +6782,10 @@ graphql-upload@^8.0.2:
67826782
http-errors "^1.7.3"
67836783
object-path "^0.11.4"
67846784

6785-
[email protected], graphql@^14.5.3:
6786-
version "15.3.0"
6787-
resolved "https://registry.yarnpkg.com/graphql/-/graphql-15.3.0.tgz#3ad2b0caab0d110e3be4a5a9b2aa281e362b5278"
6788-
integrity sha512-GTCJtzJmkFLWRfFJuoo9RWWa/FfamUHgiFosxi/X1Ani4AVWbeyBenZTNX6dM+7WSbbFfTo/25eh0LLkwHMw2w==
6785+
[email protected], graphql@^14.5.3, "graphql@npm:graphql-experimental":
6786+
version "4.0.1"
6787+
resolved "https://registry.yarnpkg.com/graphql-experimental/-/graphql-experimental-4.0.1.tgz#65a2bb1573d20685be62493287c31273419b99ce"
6788+
integrity sha512-Z9GHafFdxDMq7sGq+iUdfPCMeTphc/LOOjt2EB9RNDB0j1ShsIg8Bp7PV42oKw3C1ccLvguQaw1DeuldsQuuxw==
67896789

67906790
gray-matter@^4.0.2:
67916791
version "4.0.2"

0 commit comments

Comments
 (0)