1package graphql
2
3import (
4 "fmt"
5)
6
7type SchemaConfig struct {
8 Query *Object
9 Mutation *Object
10 Subscription *Object
11 Types []Type
12 Directives []*Directive
13}
14
15type TypeMap map[string]Type
16
17// Schema Definition
18// A Schema is created by supplying the root types of each type of operation,
19// query, mutation (optional) and subscription (optional). A schema definition is then supplied to the
20// validator and executor.
21// Example:
22// myAppSchema, err := NewSchema(SchemaConfig({
23// Query: MyAppQueryRootType,
24// Mutation: MyAppMutationRootType,
25// Subscription: MyAppSubscriptionRootType,
26// });
27// Note: If an array of `directives` are provided to GraphQLSchema, that will be
28// the exact list of directives represented and allowed. If `directives` is not
29// provided then a default set of the specified directives (e.g. @include and
30// @skip) will be used. If you wish to provide *additional* directives to these
31// specified directives, you must explicitly declare them. Example:
32//
33// const MyAppSchema = new GraphQLSchema({
34// ...
35// directives: specifiedDirectives.concat([ myCustomDirective ]),
36// })
37type Schema struct {
38 typeMap TypeMap
39 directives []*Directive
40
41 queryType *Object
42 mutationType *Object
43 subscriptionType *Object
44 implementations map[string][]*Object
45 possibleTypeMap map[string]map[string]bool
46}
47
48func NewSchema(config SchemaConfig) (Schema, error) {
49 var err error
50
51 schema := Schema{}
52
53 err = invariant(config.Query != nil, "Schema query must be Object Type but got: nil.")
54 if err != nil {
55 return schema, err
56 }
57
58 // if schema config contains error at creation time, return those errors
59 if config.Query != nil && config.Query.err != nil {
60 return schema, config.Query.err
61 }
62 if config.Mutation != nil && config.Mutation.err != nil {
63 return schema, config.Mutation.err
64 }
65
66 schema.queryType = config.Query
67 schema.mutationType = config.Mutation
68 schema.subscriptionType = config.Subscription
69
70 // Provide specified directives (e.g. @include and @skip) by default.
71 schema.directives = config.Directives
72 if len(schema.directives) == 0 {
73 schema.directives = SpecifiedDirectives
74 }
75 // Ensure directive definitions are error-free
76 for _, dir := range schema.directives {
77 if dir.err != nil {
78 return schema, dir.err
79 }
80 }
81
82 // Build type map now to detect any errors within this schema.
83 typeMap := TypeMap{}
84 initialTypes := []Type{}
85 if schema.QueryType() != nil {
86 initialTypes = append(initialTypes, schema.QueryType())
87 }
88 if schema.MutationType() != nil {
89 initialTypes = append(initialTypes, schema.MutationType())
90 }
91 if schema.SubscriptionType() != nil {
92 initialTypes = append(initialTypes, schema.SubscriptionType())
93 }
94 if SchemaType != nil {
95 initialTypes = append(initialTypes, SchemaType)
96 }
97
98 for _, ttype := range config.Types {
99 // assume that user will never add a nil object to config
100 initialTypes = append(initialTypes, ttype)
101 }
102
103 for _, ttype := range initialTypes {
104 if ttype.Error() != nil {
105 return schema, ttype.Error()
106 }
107 typeMap, err = typeMapReducer(&schema, typeMap, ttype)
108 if err != nil {
109 return schema, err
110 }
111 }
112
113 schema.typeMap = typeMap
114
115 // Keep track of all implementations by interface name.
116 if schema.implementations == nil {
117 schema.implementations = map[string][]*Object{}
118 }
119 for _, ttype := range schema.typeMap {
120 if ttype, ok := ttype.(*Object); ok {
121 for _, iface := range ttype.Interfaces() {
122 impls, ok := schema.implementations[iface.Name()]
123 if impls == nil || !ok {
124 impls = []*Object{}
125 }
126 impls = append(impls, ttype)
127 schema.implementations[iface.Name()] = impls
128 }
129 }
130 }
131
132 // Enforce correct interface implementations
133 for _, ttype := range schema.typeMap {
134 if ttype, ok := ttype.(*Object); ok {
135 for _, iface := range ttype.Interfaces() {
136 err := assertObjectImplementsInterface(&schema, ttype, iface)
137 if err != nil {
138 return schema, err
139 }
140 }
141 }
142 }
143
144 return schema, nil
145}
146
147
148
149//Added Check implementation of interfaces at runtime..
150//Add Implementations at Runtime..
151func (gq *Schema) AddImplementation() error{
152
153 // Keep track of all implementations by interface name.
154 if gq.implementations == nil {
155 gq.implementations = map[string][]*Object{}
156 }
157 for _, ttype := range gq.typeMap {
158 if ttype, ok := ttype.(*Object); ok {
159 for _, iface := range ttype.Interfaces() {
160 impls, ok := gq.implementations[iface.Name()]
161 if impls == nil || !ok {
162 impls = []*Object{}
163 }
164 impls = append(impls, ttype)
165 gq.implementations[iface.Name()] = impls
166 }
167 }
168 }
169
170 // Enforce correct interface implementations
171 for _, ttype := range gq.typeMap {
172 if ttype, ok := ttype.(*Object); ok {
173 for _, iface := range ttype.Interfaces() {
174 err := assertObjectImplementsInterface(gq, ttype, iface)
175 if err != nil {
176 return err
177 }
178 }
179 }
180 }
181
182 return nil
183}
184
185
186//Edited. To check add Types at RunTime..
187//Append Runtime schema to typeMap
188func (gq *Schema)AppendType(objectType Type) error {
189 if objectType.Error() != nil {
190 return objectType.Error()
191 }
192 var err error
193 gq.typeMap, err = typeMapReducer(gq, gq.typeMap, objectType)
194 if err != nil {
195 return err
196 }
197 //Now Add interface implementation..
198 return gq.AddImplementation()
199}
200
201
202
203
204func (gq *Schema) QueryType() *Object {
205 return gq.queryType
206}
207
208func (gq *Schema) MutationType() *Object {
209 return gq.mutationType
210}
211
212func (gq *Schema) SubscriptionType() *Object {
213 return gq.subscriptionType
214}
215
216func (gq *Schema) Directives() []*Directive {
217 return gq.directives
218}
219
220func (gq *Schema) Directive(name string) *Directive {
221 for _, directive := range gq.Directives() {
222 if directive.Name == name {
223 return directive
224 }
225 }
226 return nil
227}
228
229func (gq *Schema) TypeMap() TypeMap {
230 return gq.typeMap
231}
232
233func (gq *Schema) Type(name string) Type {
234 return gq.TypeMap()[name]
235}
236
237func (gq *Schema) PossibleTypes(abstractType Abstract) []*Object {
238 if abstractType, ok := abstractType.(*Union); ok {
239 return abstractType.Types()
240 }
241 if abstractType, ok := abstractType.(*Interface); ok {
242 if impls, ok := gq.implementations[abstractType.Name()]; ok {
243 return impls
244 }
245 }
246 return []*Object{}
247}
248func (gq *Schema) IsPossibleType(abstractType Abstract, possibleType *Object) bool {
249 possibleTypeMap := gq.possibleTypeMap
250 if possibleTypeMap == nil {
251 possibleTypeMap = map[string]map[string]bool{}
252 }
253
254 if typeMap, ok := possibleTypeMap[abstractType.Name()]; !ok {
255 typeMap = map[string]bool{}
256 for _, possibleType := range gq.PossibleTypes(abstractType) {
257 typeMap[possibleType.Name()] = true
258 }
259 possibleTypeMap[abstractType.Name()] = typeMap
260 }
261
262 gq.possibleTypeMap = possibleTypeMap
263 if typeMap, ok := possibleTypeMap[abstractType.Name()]; ok {
264 isPossible, _ := typeMap[possibleType.Name()]
265 return isPossible
266 }
267 return false
268}
269func typeMapReducer(schema *Schema, typeMap TypeMap, objectType Type) (TypeMap, error) {
270 var err error
271 if objectType == nil || objectType.Name() == "" {
272 return typeMap, nil
273 }
274
275 switch objectType := objectType.(type) {
276 case *List:
277 if objectType.OfType != nil {
278 return typeMapReducer(schema, typeMap, objectType.OfType)
279 }
280 case *NonNull:
281 if objectType.OfType != nil {
282 return typeMapReducer(schema, typeMap, objectType.OfType)
283 }
284 case *Object:
285 if objectType.err != nil {
286 return typeMap, objectType.err
287 }
288 }
289
290 if mappedObjectType, ok := typeMap[objectType.Name()]; ok {
291 err = invariantf(
292 mappedObjectType == objectType,
293 `Schema must contain unique named types but contains multiple types named "%v".`, objectType.Name())
294
295 if err != nil {
296 return typeMap, err
297 }
298 return typeMap, err
299 }
300 if objectType.Name() == "" {
301 return typeMap, nil
302 }
303
304 typeMap[objectType.Name()] = objectType
305
306 switch objectType := objectType.(type) {
307 case *Union:
308 types := schema.PossibleTypes(objectType)
309 if objectType.err != nil {
310 return typeMap, objectType.err
311 }
312 for _, innerObjectType := range types {
313 if innerObjectType.err != nil {
314 return typeMap, innerObjectType.err
315 }
316 typeMap, err = typeMapReducer(schema, typeMap, innerObjectType)
317 if err != nil {
318 return typeMap, err
319 }
320 }
321 case *Interface:
322 types := schema.PossibleTypes(objectType)
323 if objectType.err != nil {
324 return typeMap, objectType.err
325 }
326 for _, innerObjectType := range types {
327 if innerObjectType.err != nil {
328 return typeMap, innerObjectType.err
329 }
330 typeMap, err = typeMapReducer(schema, typeMap, innerObjectType)
331 if err != nil {
332 return typeMap, err
333 }
334 }
335 case *Object:
336 interfaces := objectType.Interfaces()
337 if objectType.err != nil {
338 return typeMap, objectType.err
339 }
340 for _, innerObjectType := range interfaces {
341 if innerObjectType.err != nil {
342 return typeMap, innerObjectType.err
343 }
344 typeMap, err = typeMapReducer(schema, typeMap, innerObjectType)
345 if err != nil {
346 return typeMap, err
347 }
348 }
349 }
350
351 switch objectType := objectType.(type) {
352 case *Object:
353 fieldMap := objectType.Fields()
354 if objectType.err != nil {
355 return typeMap, objectType.err
356 }
357 for _, field := range fieldMap {
358 for _, arg := range field.Args {
359 typeMap, err = typeMapReducer(schema, typeMap, arg.Type)
360 if err != nil {
361 return typeMap, err
362 }
363 }
364 typeMap, err = typeMapReducer(schema, typeMap, field.Type)
365 if err != nil {
366 return typeMap, err
367 }
368 }
369 case *Interface:
370 fieldMap := objectType.Fields()
371 if objectType.err != nil {
372 return typeMap, objectType.err
373 }
374 for _, field := range fieldMap {
375 for _, arg := range field.Args {
376 typeMap, err = typeMapReducer(schema, typeMap, arg.Type)
377 if err != nil {
378 return typeMap, err
379 }
380 }
381 typeMap, err = typeMapReducer(schema, typeMap, field.Type)
382 if err != nil {
383 return typeMap, err
384 }
385 }
386 case *InputObject:
387 fieldMap := objectType.Fields()
388 if objectType.err != nil {
389 return typeMap, objectType.err
390 }
391 for _, field := range fieldMap {
392 typeMap, err = typeMapReducer(schema, typeMap, field.Type)
393 if err != nil {
394 return typeMap, err
395 }
396 }
397 }
398 return typeMap, nil
399}
400
401func assertObjectImplementsInterface(schema *Schema, object *Object, iface *Interface) error {
402 objectFieldMap := object.Fields()
403 ifaceFieldMap := iface.Fields()
404
405 // Assert each interface field is implemented.
406 for fieldName := range ifaceFieldMap {
407 objectField := objectFieldMap[fieldName]
408 ifaceField := ifaceFieldMap[fieldName]
409
410 // Assert interface field exists on object.
411 err := invariantf(
412 objectField != nil,
413 `"%v" expects field "%v" but "%v" does not `+
414 `provide it.`, iface, fieldName, object)
415
416 if err != nil {
417 return err
418 }
419
420 // Assert interface field type is satisfied by object field type, by being
421 // a valid subtype. (covariant)
422 err = invariant(
423 isTypeSubTypeOf(schema, objectField.Type, ifaceField.Type),
424 fmt.Sprintf(`%v.%v expects type "%v" but `+
425 `%v.%v provides type "%v".`,
426 iface, fieldName, ifaceField.Type,
427 object, fieldName, objectField.Type),
428 )
429 if err != nil {
430 return err
431 }
432
433 // Assert each interface field arg is implemented.
434 for _, ifaceArg := range ifaceField.Args {
435 argName := ifaceArg.PrivateName
436 var objectArg *Argument
437 for _, arg := range objectField.Args {
438 if arg.PrivateName == argName {
439 objectArg = arg
440 break
441 }
442 }
443 // Assert interface field arg exists on object field.
444 err = invariant(
445 objectArg != nil,
446 fmt.Sprintf(`%v.%v expects argument "%v" but `+
447 `%v.%v does not provide it.`,
448 iface, fieldName, argName,
449 object, fieldName),
450 )
451 if err != nil {
452 return err
453 }
454
455 // Assert interface field arg type matches object field arg type.
456 // (invariant)
457 err = invariant(
458 isEqualType(ifaceArg.Type, objectArg.Type),
459 fmt.Sprintf(
460 `%v.%v(%v:) expects type "%v" `+
461 `but %v.%v(%v:) provides `+
462 `type "%v".`,
463 iface, fieldName, argName, ifaceArg.Type,
464 object, fieldName, argName, objectArg.Type),
465 )
466 if err != nil {
467 return err
468 }
469 }
470 // Assert additional arguments must not be required.
471 for _, objectArg := range objectField.Args {
472 argName := objectArg.PrivateName
473 var ifaceArg *Argument
474 for _, arg := range ifaceField.Args {
475 if arg.PrivateName == argName {
476 ifaceArg = arg
477 break
478 }
479 }
480
481 if ifaceArg == nil {
482 _, ok := objectArg.Type.(*NonNull)
483 err = invariant(
484 !ok,
485 fmt.Sprintf(`%v.%v(%v:) is of required type `+
486 `"%v" but is not also provided by the interface %v.%v.`,
487 object, fieldName, argName,
488 objectArg.Type, iface, fieldName),
489 )
490 if err != nil {
491 return err
492 }
493 }
494 }
495 }
496 return nil
497}
498
499func isEqualType(typeA Type, typeB Type) bool {
500 // Equivalent type is a valid subtype
501 if typeA == typeB {
502 return true
503 }
504 // If either type is non-null, the other must also be non-null.
505 if typeA, ok := typeA.(*NonNull); ok {
506 if typeB, ok := typeB.(*NonNull); ok {
507 return isEqualType(typeA.OfType, typeB.OfType)
508 }
509 }
510 // If either type is a list, the other must also be a list.
511 if typeA, ok := typeA.(*List); ok {
512 if typeB, ok := typeB.(*List); ok {
513 return isEqualType(typeA.OfType, typeB.OfType)
514 }
515 }
516 // Otherwise the types are not equal.
517 return false
518}
519
520// isTypeSubTypeOf Provided a type and a super type, return true if the first type is either
521// equal or a subset of the second super type (covariant).
522func isTypeSubTypeOf(schema *Schema, maybeSubType Type, superType Type) bool {
523 // Equivalent type is a valid subtype
524 if maybeSubType == superType {
525 return true
526 }
527
528 // If superType is non-null, maybeSubType must also be nullable.
529 if superType, ok := superType.(*NonNull); ok {
530 if maybeSubType, ok := maybeSubType.(*NonNull); ok {
531 return isTypeSubTypeOf(schema, maybeSubType.OfType, superType.OfType)
532 }
533 return false
534 }
535 if maybeSubType, ok := maybeSubType.(*NonNull); ok {
536 // If superType is nullable, maybeSubType may be non-null.
537 return isTypeSubTypeOf(schema, maybeSubType.OfType, superType)
538 }
539
540 // If superType type is a list, maybeSubType type must also be a list.
541 if superType, ok := superType.(*List); ok {
542 if maybeSubType, ok := maybeSubType.(*List); ok {
543 return isTypeSubTypeOf(schema, maybeSubType.OfType, superType.OfType)
544 }
545 return false
546 } else if _, ok := maybeSubType.(*List); ok {
547 // If superType is not a list, maybeSubType must also be not a list.
548 return false
549 }
550
551 // If superType type is an abstract type, maybeSubType type may be a currently
552 // possible object type.
553 if superType, ok := superType.(*Interface); ok {
554 if maybeSubType, ok := maybeSubType.(*Object); ok && schema.IsPossibleType(superType, maybeSubType) {
555 return true
556 }
557 }
558 if superType, ok := superType.(*Union); ok {
559 if maybeSubType, ok := maybeSubType.(*Object); ok && schema.IsPossibleType(superType, maybeSubType) {
560 return true
561 }
562 }
563
564 // Otherwise, the child type is not a valid subtype of the parent type.
565 return false
566}