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