@@ -53,6 +53,7 @@ import type {
53
53
DocumentNode ,
54
54
DirectiveDefinitionNode ,
55
55
SchemaExtensionNode ,
56
+ SchemaDefinitionNode ,
56
57
} from '../language/ast' ;
57
58
58
59
type Options = { |
@@ -106,18 +107,28 @@ export function extendSchema(
106
107
// have the same name. For example, a type named "skip".
107
108
const directiveDefinitions : Array < DirectiveDefinitionNode > = [ ] ;
108
109
110
+ let schemaDef : ?SchemaDefinitionNode ;
109
111
// Schema extensions are collected which may add additional operation types.
110
112
const schemaExtensions : Array < SchemaExtensionNode > = [ ] ;
111
113
112
114
for ( let i = 0 ; i < documentAST . definitions . length ; i ++ ) {
113
115
const def = documentAST . definitions [ i ] ;
114
116
switch ( def . kind ) {
115
117
case Kind . SCHEMA_DEFINITION :
116
- // Sanity check that a schema extension is not defining a new schema
117
- throw new GraphQLError (
118
- 'Cannot define a new schema within a schema extension.' ,
119
- [ def ] ,
120
- ) ;
118
+ // Sanity check that a schema extension is not overriding the schema
119
+ if (
120
+ schema . astNode ||
121
+ schema . getQueryType ( ) ||
122
+ schema . getMutationType ( ) ||
123
+ schema . getSubscriptionType ( )
124
+ ) {
125
+ throw new GraphQLError (
126
+ 'Cannot define a new schema within a schema extension.' ,
127
+ [ def ] ,
128
+ ) ;
129
+ }
130
+ schemaDef = def ;
131
+ break ;
121
132
case Kind . SCHEMA_EXTENSION :
122
133
schemaExtensions . push ( def ) ;
123
134
break ;
@@ -184,7 +195,8 @@ export function extendSchema(
184
195
Object . keys ( typeExtensionsMap ) . length === 0 &&
185
196
Object . keys ( typeDefinitionMap ) . length === 0 &&
186
197
directiveDefinitions . length === 0 &&
187
- schemaExtensions . length === 0
198
+ schemaExtensions . length === 0 &&
199
+ ! schemaDef
188
200
) {
189
201
return schema ;
190
202
}
@@ -216,19 +228,28 @@ export function extendSchema(
216
228
subscription : extendMaybeNamedType ( schema . getSubscriptionType ( ) ) ,
217
229
} ;
218
230
219
- // Then, incorporate all schema extensions.
231
+ if ( schemaDef ) {
232
+ for ( const { operation, type } of schemaDef . operationTypes ) {
233
+ if ( operationTypes [ operation ] ) {
234
+ throw new Error ( `Must provide only one ${ operation } type in schema.` ) ;
235
+ }
236
+ // Note: While this could make early assertions to get the correctly
237
+ // typed values, that would throw immediately while type system
238
+ // validation with validateSchema() will produce more actionable results.
239
+ operationTypes [ operation ] = ( astBuilder . buildType ( type ) : any ) ;
240
+ }
241
+ }
242
+ // Then, incorporate schema definition and all schema extensions.
220
243
for ( const schemaExtension of schemaExtensions ) {
221
244
if ( schemaExtension . operationTypes ) {
222
- for ( const operationType of schemaExtension . operationTypes ) {
223
- const operation = operationType . operation ;
245
+ for ( const { operation, type } of schemaExtension . operationTypes ) {
224
246
if ( operationTypes [ operation ] ) {
225
247
throw new Error ( `Must provide only one ${ operation } type in schema.` ) ;
226
248
}
227
- const typeRef = operationType . type ;
228
249
// Note: While this could make early assertions to get the correctly
229
250
// typed values, that would throw immediately while type system
230
251
// validation with validateSchema() will produce more actionable results.
231
- operationTypes [ operation ] = ( astBuilder . buildType ( typeRef ) : any ) ;
252
+ operationTypes [ operation ] = ( astBuilder . buildType ( type ) : any ) ;
232
253
}
233
254
}
234
255
}
@@ -254,9 +275,7 @@ export function extendSchema(
254
275
255
276
// Then produce and return a Schema with these types.
256
277
return new GraphQLSchema ( {
257
- query : operationTypes . query ,
258
- mutation : operationTypes . mutation ,
259
- subscription : operationTypes . subscription ,
278
+ ...operationTypes ,
260
279
types,
261
280
directives : getMergedDirectives ( ) ,
262
281
astNode : schema . astNode ,
0 commit comments