@@ -31,8 +31,8 @@ public final class GraphQLSchema {
3131 public let subscriptionType : GraphQLObjectType ?
3232 public let directives : [ GraphQLDirective ]
3333 public let typeMap : TypeMap
34- public let implementations : [ String : [ GraphQLObjectType ] ]
35- private var possibleTypeMap : [ String : [ String : Bool ] ] = [ : ]
34+ public let implementations : [ String : InterfaceImplementations ]
35+ private var subTypeMap : [ String : [ String : Bool ] ] = [ : ]
3636
3737 public init (
3838 query: GraphQLObjectType ,
@@ -77,22 +77,7 @@ public final class GraphQLSchema {
7777 try replaceTypeReferences ( typeMap: typeMap)
7878
7979 // Keep track of all implementations by interface name.
80- var implementations : [ String : [ GraphQLObjectType ] ] = [ : ]
81-
82- for (_, type) in typeMap {
83- if let object = type as? GraphQLObjectType {
84- for interface in object. interfaces {
85- if var i = implementations [ interface. name] {
86- i. append ( object)
87- implementations [ interface. name] = i
88- } else {
89- implementations [ interface. name] = [ object]
90- }
91- }
92- }
93- }
94-
95- self . implementations = implementations. mapValues { $0. sorted { $0. fields. count > $1. fields. count } }
80+ self . implementations = collectImplementations ( types: Array ( typeMap. values) )
9681
9782 // Enforce correct interface implementations.
9883 for (_, type) in typeMap {
@@ -109,48 +94,70 @@ public final class GraphQLSchema {
10994 }
11095
11196 public func getPossibleTypes( abstractType: GraphQLAbstractType ) -> [ GraphQLObjectType ] {
112- if let union = abstractType as? GraphQLUnionType {
113- return union . types
97+ if let unionType = abstractType as? GraphQLUnionType {
98+ return unionType . types
11499 }
115-
116- if let interface = abstractType as? GraphQLInterfaceType {
117- return implementations [ interface . name ] ?? [ ]
100+
101+ if let interfaceType = abstractType as? GraphQLInterfaceType {
102+ return getImplementations ( interfaceType : interfaceType ) . objects
118103 }
119-
104+
120105 fatalError ( " Should be impossible. Only UnionType and InterfaceType should conform to AbstractType " )
121106 }
107+
108+ public func getImplementations(
109+ interfaceType: GraphQLInterfaceType
110+ ) -> InterfaceImplementations {
111+ implementations [ interfaceType. name] !
112+ }
122113
123- public func isPossibleType( abstractType: GraphQLAbstractType , possibleType: GraphQLObjectType ) throws -> Bool {
124- if possibleTypeMap [ abstractType. name] == nil {
125- let possibleTypes = getPossibleTypes ( abstractType: abstractType)
126-
127- guard !possibleTypes. isEmpty else {
128- throw GraphQLError (
129- message:
130- " Could not find possible implementing types for \( abstractType. name) " +
131- " in schema. Check that schema.types is defined and is an array of " +
132- " all possible types in the schema. "
133- )
134-
114+ // @deprecated: use isSubType instead - will be removed in the future.
115+ public func isPossibleType(
116+ abstractType: GraphQLAbstractType ,
117+ possibleType: GraphQLObjectType
118+ ) throws -> Bool {
119+ isSubType ( abstractType: abstractType, maybeSubType: possibleType)
120+ }
121+
122+ public func isSubType(
123+ abstractType: GraphQLAbstractType ,
124+ maybeSubType: GraphQLNamedType
125+ ) -> Bool {
126+ var map = subTypeMap [ abstractType. name]
127+
128+ if map == nil {
129+ map = [ : ]
130+
131+ if let unionType = abstractType as? GraphQLUnionType {
132+ for type in unionType. types {
133+ map ? [ type. name] = true
134+ }
135135 }
136-
137- var map : [ String : Bool ] = [ : ]
138-
139- for type in possibleTypes {
140- map [ type. name] = true
136+
137+ if let interfaceType = abstractType as? GraphQLInterfaceType {
138+ let implementations = getImplementations ( interfaceType: interfaceType)
139+
140+ for type in implementations. objects {
141+ map ? [ type. name] = true
142+ }
143+
144+ for type in implementations. interfaces {
145+ map ? [ type. name] = true
146+ }
141147 }
142-
143- possibleTypeMap [ abstractType. name] = map
148+
149+ subTypeMap [ abstractType. name] = map
144150 }
145151
146- return possibleTypeMap [ abstractType. name] ? [ possibleType. name] != nil
152+ let isSubType = map ? [ maybeSubType. name] != nil
153+ return isSubType
147154 }
148155
149-
150156 public func getDirective( name: String ) -> GraphQLDirective ? {
151157 for directive in directives where directive. name == name {
152158 return directive
153159 }
160+
154161 return nil
155162 }
156163}
@@ -166,6 +173,51 @@ extension GraphQLSchema : Encodable {
166173
167174public typealias TypeMap = [ String : GraphQLNamedType ]
168175
176+ public struct InterfaceImplementations {
177+ public let objects : [ GraphQLObjectType ]
178+ public let interfaces : [ GraphQLInterfaceType ]
179+
180+ public init (
181+ objects: [ GraphQLObjectType ] = [ ] ,
182+ interfaces: [ GraphQLInterfaceType ] = [ ]
183+ ) {
184+ self . objects = objects
185+ self . interfaces = interfaces
186+ }
187+ }
188+
189+ func collectImplementations(
190+ types: [ GraphQLNamedType ]
191+ ) -> [ String : InterfaceImplementations ] {
192+ var implementations : [ String : InterfaceImplementations ] = [ : ]
193+
194+ for type in types {
195+ if let type = type as? GraphQLInterfaceType {
196+ if implementations [ type. name] == nil {
197+ implementations [ type. name] = InterfaceImplementations ( )
198+ }
199+
200+ // Store implementations by interface.
201+ for iface in type. interfaces {
202+ implementations [ iface. name] = InterfaceImplementations (
203+ interfaces: ( implementations [ iface. name] ? . interfaces ?? [ ] ) + [ type]
204+ )
205+ }
206+ }
207+
208+ if let type = type as? GraphQLObjectType {
209+ // Store implementations by objects.
210+ for iface in type. interfaces {
211+ implementations [ iface. name] = InterfaceImplementations (
212+ objects: ( implementations [ iface. name] ? . objects ?? [ ] ) + [ type]
213+ )
214+ }
215+ }
216+ }
217+
218+ return implementations
219+ }
220+
169221func typeMapReducer( typeMap: TypeMap , type: GraphQLType ) throws -> TypeMap {
170222 var typeMap = typeMap
171223
@@ -197,9 +249,7 @@ func typeMapReducer(typeMap: TypeMap, type: GraphQLType) throws -> TypeMap {
197249
198250 if let type = type as? GraphQLObjectType {
199251 typeMap = try type. interfaces. reduce ( typeMap, typeMapReducer)
200- }
201252
202- if let type = type as? GraphQLObjectType {
203253 for (_, field) in type. fields {
204254
205255 if !field. args. isEmpty {
@@ -212,6 +262,8 @@ func typeMapReducer(typeMap: TypeMap, type: GraphQLType) throws -> TypeMap {
212262 }
213263
214264 if let type = type as? GraphQLInterfaceType {
265+ typeMap = try type. interfaces. reduce ( typeMap, typeMapReducer)
266+
215267 for (_, field) in type. fields {
216268
217269 if !field. args. isEmpty {
0 commit comments