schema.go

  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}