@@ -41,7 +41,7 @@ public final class GraphQLSchema {
41
41
public let subscriptionType : GraphQLObjectType ?
42
42
public let directives : [ GraphQLDirective ]
43
43
public let typeMap : TypeMap
44
- public let implementations : [ String : InterfaceImplementations ]
44
+ public internal ( set ) var implementations : [ String : InterfaceImplementations ]
45
45
private var subTypeMap : [ String : [ String : Bool ] ] = [ : ]
46
46
47
47
public init (
@@ -70,58 +70,92 @@ public final class GraphQLSchema {
70
70
// Provide specified directives (e.g. @include and @skip) by default.
71
71
self . directives = directives. isEmpty ? specifiedDirectives : directives
72
72
73
- // Build type map now to detect any errors within this schema.
74
-
75
- var typeMap = TypeMap ( )
76
-
77
73
// To preserve order of user-provided types, we add first to add them to
78
74
// the set of "collected" types, so `collectReferencedTypes` ignore them.
75
+ var allReferencedTypes = TypeMap ( )
79
76
for type in types {
80
- typeMap [ type. name] = type
77
+ allReferencedTypes [ type. name] = type
81
78
}
82
79
if !types. isEmpty {
83
80
for type in types {
84
81
// When we ready to process this type, we remove it from "collected" types
85
82
// and then add it together with all dependent types in the correct position.
86
- typeMap [ type. name] = nil
87
- typeMap = try typeMapReducer ( typeMap: typeMap , type: type)
83
+ allReferencedTypes [ type. name] = nil
84
+ allReferencedTypes = try typeMapReducer ( typeMap: allReferencedTypes , type: type)
88
85
}
89
86
}
90
87
91
88
if let query = queryType {
92
- typeMap = try typeMapReducer ( typeMap: typeMap , type: query)
89
+ allReferencedTypes = try typeMapReducer ( typeMap: allReferencedTypes , type: query)
93
90
}
94
91
95
92
if let mutation = mutationType {
96
- typeMap = try typeMapReducer ( typeMap: typeMap , type: mutation)
93
+ allReferencedTypes = try typeMapReducer ( typeMap: allReferencedTypes , type: mutation)
97
94
}
98
95
99
96
if let subscription = subscriptionType {
100
- typeMap = try typeMapReducer ( typeMap: typeMap , type: subscription)
97
+ allReferencedTypes = try typeMapReducer ( typeMap: allReferencedTypes , type: subscription)
101
98
}
102
99
103
100
for directive in self . directives {
104
101
for arg in directive. args {
105
- typeMap = try typeMapReducer ( typeMap: typeMap , type: arg. type)
102
+ allReferencedTypes = try typeMapReducer ( typeMap: allReferencedTypes , type: arg. type)
106
103
}
107
104
}
108
105
109
- typeMap = try typeMapReducer ( typeMap: typeMap, type: __Schema)
106
+ allReferencedTypes = try typeMapReducer ( typeMap: allReferencedTypes, type: __Schema)
107
+ try replaceTypeReferences ( typeMap: allReferencedTypes)
110
108
111
- self . typeMap = typeMap
112
- try replaceTypeReferences ( typeMap: typeMap )
109
+ // Storing the resulting map for reference by the schema.
110
+ var typeMap = TypeMap ( )
113
111
114
112
// Keep track of all implementations by interface name.
115
113
implementations = try collectImplementations ( types: Array ( typeMap. values) )
116
114
117
- // Enforce correct interface implementations.
118
- for (_, type) in typeMap {
119
- if let object = type as? GraphQLObjectType {
120
- for interface in try object. getInterfaces ( ) {
121
- try assert ( object: object, implementsInterface: interface, schema: self )
115
+ for namedType in allReferencedTypes. values {
116
+ let typeName = namedType. name
117
+ if typeMap [ typeName] != nil {
118
+ throw GraphQLError (
119
+ message:
120
+ " Schema must contain uniquely named types but contains multiple types named \" \( typeName) \" . "
121
+ )
122
+ }
123
+ typeMap [ typeName] = namedType
124
+
125
+ if let namedType = namedType as? GraphQLInterfaceType {
126
+ // Store implementations by interface.
127
+ for iface in try namedType. getInterfaces ( ) {
128
+ let implementations = self . implementations [ iface. name] ?? . init(
129
+ objects: [ ] ,
130
+ interfaces: [ ]
131
+ )
132
+
133
+ var interfaces = implementations. interfaces
134
+ interfaces. append ( namedType)
135
+ self . implementations [ iface. name] = . init(
136
+ objects: implementations. objects,
137
+ interfaces: interfaces
138
+ )
139
+ }
140
+ } else if let namedType = namedType as? GraphQLObjectType {
141
+ // Store implementations by objects.
142
+ for iface in try namedType. getInterfaces ( ) {
143
+ let implementations = self . implementations [ iface. name] ?? . init(
144
+ objects: [ ] ,
145
+ interfaces: [ ]
146
+ )
147
+
148
+ var objects = implementations. objects
149
+ objects. append ( namedType)
150
+ self . implementations [ iface. name] = . init(
151
+ objects: objects,
152
+ interfaces: implementations. interfaces
153
+ )
122
154
}
123
155
}
124
156
}
157
+
158
+ self . typeMap = typeMap
125
159
}
126
160
127
161
convenience init ( config: GraphQLSchemaNormalizedConfig ) throws {
@@ -356,75 +390,6 @@ func typeMapReducer(typeMap: TypeMap, type: GraphQLType) throws -> TypeMap {
356
390
return typeMap
357
391
}
358
392
359
- func assert(
360
- object: GraphQLObjectType ,
361
- implementsInterface interface: GraphQLInterfaceType ,
362
- schema _: GraphQLSchema
363
- ) throws {
364
- let objectFieldMap = try object. getFields ( )
365
- let interfaceFieldMap = try interface. getFields ( )
366
-
367
- for (fieldName, interfaceField) in interfaceFieldMap {
368
- guard let objectField = objectFieldMap [ fieldName] else {
369
- throw GraphQLError (
370
- message:
371
- " \( interface. name) expects field \( fieldName) " +
372
- " but \( object. name) does not provide it. "
373
- )
374
- }
375
-
376
- // // Assert interface field type is satisfied by object field type, by being
377
- // // a valid subtype. (covariant)
378
- // guard try isTypeSubTypeOf(schema, objectField.type, interfaceField.type) else {
379
- // throw GraphQLError(
380
- // message:
381
- // "\(interface.name).\(fieldName) expects type \"\(interfaceField.type)\" " +
382
- // "but " +
383
- // "\(object.name).\(fieldName) provides type \"\(objectField.type)\"."
384
- // )
385
- // }
386
-
387
- // Assert each interface field arg is implemented.
388
- for interfaceArg in interfaceField. args {
389
- let argName = interfaceArg. name
390
- guard let objectArg = objectField. args. find ( { $0. name == argName } ) else {
391
- throw GraphQLError (
392
- message:
393
- " \( interface. name) . \( fieldName) expects argument \" \( argName) \" but " +
394
- " \( object. name) . \( fieldName) does not provide it. "
395
- )
396
- }
397
-
398
- // Assert interface field arg type matches object field arg type.
399
- // (invariant)
400
- guard isEqualType ( interfaceArg. type, objectArg. type) else {
401
- throw GraphQLError (
402
- message:
403
- " \( interface. name) . \( fieldName) ( \( argName) :) expects type " +
404
- " \" \( interfaceArg. type) \" but " +
405
- " \( object. name) . \( fieldName) ( \( argName) :) provides type " +
406
- " \" \( objectArg. type) \" . "
407
- )
408
- }
409
- }
410
-
411
- // Assert additional arguments must not be required.
412
- for objectArg in objectField. args {
413
- let argName = objectArg. name
414
- if
415
- interfaceField. args. find ( { $0. name == argName } ) == nil ,
416
- isRequiredArgument ( objectArg)
417
- {
418
- throw GraphQLError (
419
- message:
420
- " \( object. name) . \( fieldName) includes required argument ( \( argName) :) that is missing " +
421
- " from the Interface field \( interface. name) . \( fieldName) . "
422
- )
423
- }
424
- }
425
- }
426
- }
427
-
428
393
func replaceTypeReferences( typeMap: TypeMap ) throws {
429
394
for type in typeMap {
430
395
if let typeReferenceContainer = type. value as? GraphQLTypeReferenceContainer {
0 commit comments