Skip to content

Commit 35f9c1d

Browse files
committed
Make 'ASTDefinitionBuilder' responsible only for build types from AST
1 parent 5f50543 commit 35f9c1d

File tree

2 files changed

+62
-76
lines changed

2 files changed

+62
-76
lines changed

src/utilities/buildASTSchema.js

+16-25
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

+46-51
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,
@@ -171,56 +173,50 @@ export function extendSchema(
171173
return schema;
172174
}
173175

174-
const definitionBuilder = new ASTDefinitionBuilder(
176+
const astBuilder = new ASTDefinitionBuilder(
175177
typeDefinitionMap,
176178
options,
177-
(typeName, node) => {
179+
typeRef => {
180+
const typeName = typeRef.name.value;
178181
const existingType = schema.getType(typeName);
179182
if (existingType) {
180183
return extendType(existingType);
181184
}
182185

183-
if (node) {
184-
throw new GraphQLError(
185-
`Unknown type: "${typeName}". Ensure that this type exists ` +
186-
'either in the original schema, or is added in a type definition.',
187-
[node],
188-
);
189-
}
190-
throw GraphQLError('Missing type from schema');
186+
throw new GraphQLError(
187+
`Unknown type: "${typeName}". Ensure that this type exists ` +
188+
'either in the original schema, or is added in a type definition.',
189+
[typeRef],
190+
);
191191
},
192192
);
193193

194+
const extendTypeCache = Object.create(null);
195+
194196
// Get the root Query, Mutation, and Subscription object types.
195197
// Note: While this could make early assertions to get the correctly
196198
// typed values below, that would throw immediately while type system
197199
// validation with validateSchema() will produce more actionable results.
198200
const existingQueryType = schema.getQueryType();
199-
const queryType = existingQueryType
200-
? (definitionBuilder.buildType(existingQueryType.name): any)
201-
: null;
201+
const queryType = existingQueryType ? extendType(existingQueryType) : null;
202202

203203
const existingMutationType = schema.getMutationType();
204204
const mutationType = existingMutationType
205-
? (definitionBuilder.buildType(existingMutationType.name): any)
205+
? extendType(existingMutationType)
206206
: null;
207207

208208
const existingSubscriptionType = schema.getSubscriptionType();
209209
const subscriptionType = existingSubscriptionType
210-
? (definitionBuilder.buildType(existingSubscriptionType.name): any)
210+
? extendType(existingSubscriptionType)
211211
: null;
212212

213-
// Iterate through all types, getting the type definition for each, ensuring
214-
// that any type not directly referenced by a field will get created.
215-
const typeMap = schema.getTypeMap();
216-
const types = Object.keys(typeMap).map(typeName =>
217-
definitionBuilder.buildType(typeName),
218-
);
219-
220-
// Do the same with new types, appending to the list of defined types.
221-
Object.keys(typeDefinitionMap).forEach(typeName => {
222-
types.push(definitionBuilder.buildType(typeName));
223-
});
213+
const types = [
214+
// Iterate through all types, getting the type definition for each, ensuring
215+
// that any type not directly referenced by a field will get created.
216+
...objectValues(schema.getTypeMap()).map(type => extendType(type)),
217+
// Do the same with new types.
218+
...objectValues(typeDefinitionMap).map(type => astBuilder.buildType(type)),
219+
];
224220

225221
// Then produce and return a Schema with these types.
226222
return new GraphQLSchema({
@@ -241,30 +237,29 @@ export function extendSchema(
241237
const existingDirectives = schema.getDirectives();
242238
invariant(existingDirectives, 'schema must have default directives');
243239

244-
const newDirectives = directiveDefinitions.map(directiveNode =>
245-
definitionBuilder.buildDirective(directiveNode),
240+
return existingDirectives.concat(
241+
directiveDefinitions.map(node => astBuilder.buildDirective(node)),
246242
);
247-
return existingDirectives.concat(newDirectives);
248-
}
249-
250-
function getTypeFromDef<T: GraphQLNamedType>(typeDef: T): T {
251-
const type = definitionBuilder.buildType(typeDef.name);
252-
return (type: any);
253243
}
254244

255-
// Given a type's introspection result, construct the correct
256-
// GraphQLType instance.
257-
function extendType(type: GraphQLNamedType): GraphQLNamedType {
258-
if (isObjectType(type)) {
259-
return extendObjectType(type);
260-
}
261-
if (isInterfaceType(type)) {
262-
return extendInterfaceType(type);
263-
}
264-
if (isUnionType(type)) {
265-
return extendUnionType(type);
245+
function extendType<T: GraphQLNamedType>(type: T): T {
246+
let extendedType = extendTypeCache[type.name];
247+
248+
if (!extendedType) {
249+
if (isIntrospectionType(type)) {
250+
extendedType = type;
251+
} else if (isObjectType(type)) {
252+
extendedType = extendObjectType(type);
253+
} else if (isInterfaceType(type)) {
254+
extendedType = extendInterfaceType(type);
255+
} else if (isUnionType(type)) {
256+
extendedType = extendUnionType(type);
257+
} else {
258+
extendedType = type;
259+
}
260+
extendTypeCache[type.name] = extendedType;
266261
}
267-
return type;
262+
return (extendedType: any);
268263
}
269264

270265
function extendObjectType(type: GraphQLObjectType): GraphQLObjectType {
@@ -301,7 +296,7 @@ export function extendSchema(
301296
return new GraphQLUnionType({
302297
name: type.name,
303298
description: type.description,
304-
types: type.getTypes().map(getTypeFromDef),
299+
types: type.getTypes().map(extendType),
305300
astNode: type.astNode,
306301
resolveType: type.resolveType,
307302
});
@@ -310,7 +305,7 @@ export function extendSchema(
310305
function extendImplementedInterfaces(
311306
type: GraphQLObjectType,
312307
): Array<GraphQLInterfaceType> {
313-
const interfaces = type.getInterfaces().map(getTypeFromDef);
308+
const interfaces = type.getInterfaces().map(extendType);
314309

315310
// If there are any extensions to the interfaces, apply those here.
316311
const extensions = typeExtensionsMap[type.name];
@@ -320,7 +315,7 @@ export function extendSchema(
320315
// Note: While this could make early assertions to get the correctly
321316
// typed values, that would throw immediately while type system
322317
// validation with validateSchema() will produce more actionable results.
323-
interfaces.push((definitionBuilder.buildType(namedType): any));
318+
interfaces.push((astBuilder.buildType(namedType): any));
324319
});
325320
});
326321
}
@@ -356,7 +351,7 @@ export function extendSchema(
356351
[field],
357352
);
358353
}
359-
newFieldMap[fieldName] = definitionBuilder.buildField(field);
354+
newFieldMap[fieldName] = astBuilder.buildField(field);
360355
});
361356
});
362357
}
@@ -371,6 +366,6 @@ export function extendSchema(
371366
if (isNonNullType(typeDef)) {
372367
return (GraphQLNonNull(extendFieldType(typeDef.ofType)): any);
373368
}
374-
return getTypeFromDef(typeDef);
369+
return extendType(typeDef);
375370
}
376371
}

0 commit comments

Comments
 (0)