-
-
Notifications
You must be signed in to change notification settings - Fork 816
/
addTypes.ts
73 lines (66 loc) · 2.81 KB
/
addTypes.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
// addTypes uses toConfig to create a new schema with a new or replaced
// type or directive. Rewiring is employed so that the replaced type can be
// reconnected with the existing types.
//
// Rewiring is employed even for new types or directives as a convenience, so
// that type references within the new type or directive do not have to be to
// the identical objects within the original schema.
//
// In fact, the type references could even be stub types with entirely different
// fields, as long as the type references share the same name as the desired
// type within the original schema's type map.
//
// This makes it easy to perform simple schema operations (e.g. adding a new
// type with a fiew fields removed from an existing type) that could normally be
// performed by using toConfig directly, but is blocked if any intervening
// more advanced schema operations have caused the types to be recreated via
// rewiring.
//
// Type recreation happens, for example, with every use of mapSchema, as the
// types are always rewired. If fields are selected and removed using
// mapSchema, adding those fields to a new type can no longer be simply done
// by toConfig, as the types are not the identical JavaScript objects, and
// schema creation will fail with errors referencing multiple types with the
// same names.
//
// enhanceSchema can fill this gap by adding an additional round of rewiring.
//
import {
GraphQLDirective,
GraphQLNamedType,
GraphQLSchema,
isDirective,
isNamedType,
} from 'graphql';
import { getObjectTypeFromTypeMap } from './getObjectTypeFromTypeMap.js';
import { rewireTypes } from './rewire.js';
export function addTypes(
schema: GraphQLSchema,
newTypesOrDirectives: Array<GraphQLNamedType | GraphQLDirective>,
): GraphQLSchema {
const config = schema.toConfig();
const originalTypeMap: Record<string, GraphQLNamedType> = {};
for (const type of config.types) {
originalTypeMap[type.name] = type;
}
const originalDirectiveMap: Record<string, GraphQLDirective> = {};
for (const directive of config.directives) {
originalDirectiveMap[directive.name] = directive;
}
for (const newTypeOrDirective of newTypesOrDirectives) {
if (isNamedType(newTypeOrDirective)) {
originalTypeMap[newTypeOrDirective.name] = newTypeOrDirective;
} else if (isDirective(newTypeOrDirective)) {
originalDirectiveMap[newTypeOrDirective.name] = newTypeOrDirective;
}
}
const { typeMap, directives } = rewireTypes(originalTypeMap, Object.values(originalDirectiveMap));
return new GraphQLSchema({
...config,
query: getObjectTypeFromTypeMap(typeMap, schema.getQueryType()),
mutation: getObjectTypeFromTypeMap(typeMap, schema.getMutationType()),
subscription: getObjectTypeFromTypeMap(typeMap, schema.getSubscriptionType()),
types: Object.values(typeMap),
directives,
});
}