-
-
Notifications
You must be signed in to change notification settings - Fork 76
/
SchemaComposer.js
158 lines (135 loc) · 4.78 KB
/
SchemaComposer.js
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
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
/* @flow strict */
/* eslint-disable class-methods-use-this */
import { GraphQLObjectType, GraphQLSchema } from './graphql';
import { TypeStorage } from './TypeStorage';
import { TypeMapper } from './TypeMapper';
import { TypeComposer as _TypeComposer } from './TypeComposer';
import { InputTypeComposer as _InputTypeComposer } from './InputTypeComposer';
import { EnumTypeComposer as _EnumTypeComposer } from './EnumTypeComposer';
import { Resolver as _Resolver } from './Resolver';
import { isFunction } from './utils/is';
export class SchemaComposer<TContext> extends TypeStorage<TContext> {
typeMapper: TypeMapper<TContext>;
TypeComposer: Class<_TypeComposer<TContext>>;
InputTypeComposer: typeof _InputTypeComposer;
EnumTypeComposer: typeof _EnumTypeComposer;
Resolver: Class<_Resolver<any, TContext>>;
constructor(): SchemaComposer<TContext> {
super();
const schema = this;
class TypeComposer extends _TypeComposer<TContext> {
static schemaComposer = schema;
}
this.TypeComposer = TypeComposer;
class InputTypeComposer extends _InputTypeComposer {
static schemaComposer = schema;
}
this.InputTypeComposer = InputTypeComposer;
class Resolver extends _Resolver<any, TContext> {
static schemaComposer = schema;
}
this.Resolver = Resolver;
class EnumTypeComposer extends _EnumTypeComposer {
static schemaComposer = schema;
}
this.EnumTypeComposer = EnumTypeComposer;
this.typeMapper = new TypeMapper(schema);
// alive proper Flow type casting in autosuggestions
/* :: return this; */
}
rootQuery(): _TypeComposer<TContext> {
return this.getOrCreateTC('Query');
}
rootMutation(): _TypeComposer<TContext> {
return this.getOrCreateTC('Mutation');
}
rootSubscription(): _TypeComposer<TContext> {
return this.getOrCreateTC('Subscription');
}
buildSchema(): GraphQLSchema {
const roots = {};
if (this.has('Query')) {
const tc = this.getTC('Query');
this.removeEmptyTypes(tc, new Set());
roots.query = tc.getType();
}
if (this.has('Mutation')) {
const tc = this.getTC('Mutation');
this.removeEmptyTypes(tc, new Set());
roots.mutation = tc.getType();
}
if (this.has('Subscription')) {
const tc = this.getTC('Subscription');
this.removeEmptyTypes(tc, new Set());
roots.subscription = tc.getType();
}
if (Object.keys(roots).length === 0) {
throw new Error(
'Can not build schema. Must be initialized at least one ' +
'of the following types: Query, Mutation, Subscription.'
);
}
return new GraphQLSchema(roots);
}
removeEmptyTypes(typeComposer: _TypeComposer<TContext>, passedTypes: Set<string> = new Set()) {
const fields = typeComposer.getFields();
Object.keys(fields).forEach(fieldName => {
const fieldType = fields[fieldName].type;
if (fieldType instanceof GraphQLObjectType) {
const typeName = fieldType.name;
if (!passedTypes.has(typeName)) {
passedTypes.add(typeName);
const tc = new this.TypeComposer(fieldType);
if (Object.keys(tc.getFields()).length > 0) {
this.removeEmptyTypes(tc, passedTypes);
} else {
// eslint-disable-next-line
console.log(
`GQC: Delete field '${typeComposer.getTypeName()}.${fieldName}' ` +
`with type '${tc.getTypeName()}', cause it does not have fields.`
);
delete fields[fieldName];
}
}
}
});
typeComposer.setFields(fields);
}
getOrCreateTC(
typeName: string,
onCreate?: (_TypeComposer<TContext>) => any
): _TypeComposer<TContext> {
if (!this.hasInstance(typeName, _TypeComposer)) {
const tc = this.TypeComposer.create(typeName);
this.set(typeName, tc);
if (onCreate && isFunction(onCreate)) onCreate(tc);
}
return (this.get(typeName): any);
}
getOrCreateITC(typeName: string, onCreate?: _InputTypeComposer => any): _InputTypeComposer {
if (!this.hasInstance(typeName, _InputTypeComposer)) {
const itc = this.InputTypeComposer.create(typeName);
this.set(typeName, itc);
if (onCreate && isFunction(onCreate)) onCreate(itc);
}
return (this.get(typeName): any);
}
getOrCreateETC(typeName: string, onCreate?: _EnumTypeComposer => any): _EnumTypeComposer {
if (!this.hasInstance(typeName, _EnumTypeComposer)) {
const etc = this.EnumTypeComposer.create(typeName);
this.set(typeName, etc);
if (onCreate && isFunction(onCreate)) onCreate(etc);
}
return (this.get(typeName): any);
}
// disable redundant noise in console.logs
toString(): string {
return 'SchemaComposer';
}
toJSON() {
return 'SchemaComposer';
}
inspect() {
return 'SchemaComposer';
}
}