Skip to content

Commit 693db20

Browse files
committed
Make 'ASTDefinitionBuilder' responsible only for build types from AST
1 parent 98751e4 commit 693db20

File tree

2 files changed

+62
-76
lines changed

2 files changed

+62
-76
lines changed

src/utilities/buildASTSchema.js

Lines changed: 16 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -176,22 +176,20 @@ export function buildASTSchema(
176176
const operationTypes = schemaDef
177177
? getOperationTypes(schemaDef)
178178
: {
179-
query: nodeMap.Query ? 'Query' : null,
180-
mutation: nodeMap.Mutation ? 'Mutation' : null,
181-
subscription: nodeMap.Subscription ? 'Subscription' : null,
179+
query: nodeMap.Query,
180+
mutation: nodeMap.Mutation,
181+
subscription: nodeMap.Subscription,
182182
};
183183

184184
const definitionBuilder = new ASTDefinitionBuilder(
185185
nodeMap,
186186
options,
187-
typeName => {
188-
throw new Error(`Type "${typeName}" not found in document.`);
187+
typeRef => {
188+
throw new Error(`Type "${typeRef.name.value}" not found in document.`);
189189
},
190190
);
191191

192-
const types = typeDefs.map(def =>
193-
definitionBuilder.buildType(def.name.value),
194-
);
192+
const types = typeDefs.map(def => definitionBuilder.buildType(def));
195193

196194
const directives = directiveDefs.map(def =>
197195
definitionBuilder.buildDirective(def),
@@ -242,17 +240,14 @@ export function buildASTSchema(
242240
`Specified ${operation} type "${typeName}" not found in document.`,
243241
);
244242
}
245-
opTypes[operation] = typeName;
243+
opTypes[operation] = operationType.type;
246244
});
247245
return opTypes;
248246
}
249247
}
250248

251249
type TypeDefinitionsMap = ObjMap<TypeDefinitionNode>;
252-
type TypeResolver = (
253-
typeName: string,
254-
node?: ?NamedTypeNode,
255-
) => GraphQLNamedType;
250+
type TypeResolver = (typeRef: NamedTypeNode) => GraphQLNamedType;
256251

257252
export class ASTDefinitionBuilder {
258253
_typeDefinitionsMap: TypeDefinitionsMap;
@@ -275,25 +270,21 @@ export class ASTDefinitionBuilder {
275270
);
276271
}
277272

278-
_buildType(typeName: string, typeNode?: ?NamedTypeNode): GraphQLNamedType {
273+
buildType(node: NamedTypeNode | TypeDefinitionNode): GraphQLNamedType {
274+
const typeName = node.name.value;
279275
if (!this._cache[typeName]) {
280-
const defNode = this._typeDefinitionsMap[typeName];
281-
if (defNode) {
282-
this._cache[typeName] = this._makeSchemaDef(defNode);
276+
if (node.kind === Kind.NAMED_TYPE) {
277+
const defNode = this._typeDefinitionsMap[typeName];
278+
this._cache[typeName] = defNode
279+
? this._makeSchemaDef(defNode)
280+
: this._resolveType(node);
283281
} else {
284-
this._cache[typeName] = this._resolveType(typeName, typeNode);
282+
this._cache[typeName] = this._makeSchemaDef(node);
285283
}
286284
}
287285
return this._cache[typeName];
288286
}
289287

290-
buildType(ref: string | NamedTypeNode): GraphQLNamedType {
291-
if (typeof ref === 'string') {
292-
return this._buildType(ref);
293-
}
294-
return this._buildType(ref.name.value, ref);
295-
}
296-
297288
_buildWrappedType(typeNode: TypeNode): GraphQLType {
298289
const typeDef = this.buildType(getNamedTypeNode(typeNode));
299290
return buildWrappedType(typeDef, typeNode);

src/utilities/extendSchema.js

Lines changed: 46 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,11 @@
99

1010
import invariant from '../jsutils/invariant';
1111
import keyMap from '../jsutils/keyMap';
12+
import objectValues from '../jsutils/objectValues';
1213
import { ASTDefinitionBuilder } from './buildASTSchema';
1314
import { GraphQLError } from '../error/GraphQLError';
1415
import { isSchema, GraphQLSchema } from '../type/schema';
16+
import { isIntrospectionType } from '../type/introspection';
1517

1618
import {
1719
isObjectType,
@@ -194,56 +196,50 @@ export function extendSchema(
194196
return schema;
195197
}
196198

197-
const definitionBuilder = new ASTDefinitionBuilder(
199+
const astBuilder = new ASTDefinitionBuilder(
198200
typeDefinitionMap,
199201
options,
200-
(typeName, node) => {
202+
typeRef => {
203+
const typeName = typeRef.name.value;
201204
const existingType = schema.getType(typeName);
202205
if (existingType) {
203206
return extendType(existingType);
204207
}
205208

206-
if (node) {
207-
throw new GraphQLError(
208-
`Unknown type: "${typeName}". Ensure that this type exists ` +
209-
'either in the original schema, or is added in a type definition.',
210-
[node],
211-
);
212-
}
213-
throw GraphQLError('Missing type from schema');
209+
throw new GraphQLError(
210+
`Unknown type: "${typeName}". Ensure that this type exists ` +
211+
'either in the original schema, or is added in a type definition.',
212+
[typeRef],
213+
);
214214
},
215215
);
216216

217+
const extendTypeCache = Object.create(null);
218+
217219
// Get the root Query, Mutation, and Subscription object types.
218220
// Note: While this could make early assertions to get the correctly
219221
// typed values below, that would throw immediately while type system
220222
// validation with validateSchema() will produce more actionable results.
221223
const existingQueryType = schema.getQueryType();
222-
const queryType = existingQueryType
223-
? (definitionBuilder.buildType(existingQueryType.name): any)
224-
: null;
224+
const queryType = existingQueryType ? extendType(existingQueryType) : null;
225225

226226
const existingMutationType = schema.getMutationType();
227227
const mutationType = existingMutationType
228-
? (definitionBuilder.buildType(existingMutationType.name): any)
228+
? extendType(existingMutationType)
229229
: null;
230230

231231
const existingSubscriptionType = schema.getSubscriptionType();
232232
const subscriptionType = existingSubscriptionType
233-
? (definitionBuilder.buildType(existingSubscriptionType.name): any)
233+
? extendType(existingSubscriptionType)
234234
: null;
235235

236-
// Iterate through all types, getting the type definition for each, ensuring
237-
// that any type not directly referenced by a field will get created.
238-
const typeMap = schema.getTypeMap();
239-
const types = Object.keys(typeMap).map(typeName =>
240-
definitionBuilder.buildType(typeName),
241-
);
242-
243-
// Do the same with new types, appending to the list of defined types.
244-
Object.keys(typeDefinitionMap).forEach(typeName => {
245-
types.push(definitionBuilder.buildType(typeName));
246-
});
236+
const types = [
237+
// Iterate through all types, getting the type definition for each, ensuring
238+
// that any type not directly referenced by a field will get created.
239+
...objectValues(schema.getTypeMap()).map(type => extendType(type)),
240+
// Do the same with new types.
241+
...objectValues(typeDefinitionMap).map(type => astBuilder.buildType(type)),
242+
];
247243

248244
// Then produce and return a Schema with these types.
249245
return new GraphQLSchema({
@@ -275,30 +271,29 @@ export function extendSchema(
275271
const existingDirectives = schema.getDirectives();
276272
invariant(existingDirectives, 'schema must have default directives');
277273

278-
const newDirectives = directiveDefinitions.map(directiveNode =>
279-
definitionBuilder.buildDirective(directiveNode),
274+
return existingDirectives.concat(
275+
directiveDefinitions.map(node => astBuilder.buildDirective(node)),
280276
);
281-
return existingDirectives.concat(newDirectives);
282-
}
283-
284-
function getTypeFromDef<T: GraphQLNamedType>(typeDef: T): T {
285-
const type = definitionBuilder.buildType(typeDef.name);
286-
return (type: any);
287277
}
288278

289-
// Given a type's introspection result, construct the correct
290-
// GraphQLType instance.
291-
function extendType(type: GraphQLNamedType): GraphQLNamedType {
292-
if (isObjectType(type)) {
293-
return extendObjectType(type);
294-
}
295-
if (isInterfaceType(type)) {
296-
return extendInterfaceType(type);
297-
}
298-
if (isUnionType(type)) {
299-
return extendUnionType(type);
279+
function extendType<T: GraphQLNamedType>(type: T): T {
280+
let extendedType = extendTypeCache[type.name];
281+
282+
if (!extendedType) {
283+
if (isIntrospectionType(type)) {
284+
extendedType = type;
285+
} else if (isObjectType(type)) {
286+
extendedType = extendObjectType(type);
287+
} else if (isInterfaceType(type)) {
288+
extendedType = extendInterfaceType(type);
289+
} else if (isUnionType(type)) {
290+
extendedType = extendUnionType(type);
291+
} else {
292+
extendedType = type;
293+
}
294+
extendTypeCache[type.name] = extendedType;
300295
}
301-
return type;
296+
return (extendedType: any);
302297
}
303298

304299
function extendObjectType(type: GraphQLObjectType): GraphQLObjectType {
@@ -342,7 +337,7 @@ export function extendSchema(
342337
return new GraphQLUnionType({
343338
name: type.name,
344339
description: type.description,
345-
types: type.getTypes().map(getTypeFromDef),
340+
types: type.getTypes().map(extendType),
346341
astNode: type.astNode,
347342
resolveType: type.resolveType,
348343
});
@@ -351,7 +346,7 @@ export function extendSchema(
351346
function extendImplementedInterfaces(
352347
type: GraphQLObjectType,
353348
): Array<GraphQLInterfaceType> {
354-
const interfaces = type.getInterfaces().map(getTypeFromDef);
349+
const interfaces = type.getInterfaces().map(extendType);
355350

356351
// If there are any extensions to the interfaces, apply those here.
357352
const extensions = typeExtensionsMap[type.name];
@@ -361,7 +356,7 @@ export function extendSchema(
361356
// Note: While this could make early assertions to get the correctly
362357
// typed values, that would throw immediately while type system
363358
// validation with validateSchema() will produce more actionable results.
364-
interfaces.push((definitionBuilder.buildType(namedType): any));
359+
interfaces.push((astBuilder.buildType(namedType): any));
365360
});
366361
});
367362
}
@@ -397,7 +392,7 @@ export function extendSchema(
397392
[field],
398393
);
399394
}
400-
newFieldMap[fieldName] = definitionBuilder.buildField(field);
395+
newFieldMap[fieldName] = astBuilder.buildField(field);
401396
});
402397
});
403398
}
@@ -412,6 +407,6 @@ export function extendSchema(
412407
if (isNonNullType(typeDef)) {
413408
return (GraphQLNonNull(extendFieldType(typeDef.ofType)): any);
414409
}
415-
return getTypeFromDef(typeDef);
410+
return extendType(typeDef);
416411
}
417412
}

0 commit comments

Comments
 (0)