1+ import Dispatch
12import OrderedCollections
23
34/**
@@ -34,15 +35,53 @@ public final class GraphQLSchema: @unchecked Sendable {
3435 let extensionASTNodes : [ SchemaExtensionDefinition ]
3536
3637 // Used as a cache for validateSchema().
37- var validationErrors : [ GraphQLError ] ?
38+ private var _validationErrors : [ GraphQLError ] ?
39+ private let validationErrorQueue = DispatchQueue (
40+ label: " graphql.schema.validationerrors " ,
41+ attributes: . concurrent
42+ )
43+ var validationErrors : [ GraphQLError ] ? {
44+ get {
45+ // Reads can occur concurrently.
46+ return validationErrorQueue. sync {
47+ _validationErrors
48+ }
49+ }
50+ set {
51+ // Writes occur sequentially.
52+ return validationErrorQueue. async ( flags: . barrier) {
53+ self . _validationErrors = newValue
54+ }
55+ }
56+ }
3857
3958 public let queryType : GraphQLObjectType ?
4059 public let mutationType : GraphQLObjectType ?
4160 public let subscriptionType : GraphQLObjectType ?
4261 public let directives : [ GraphQLDirective ]
4362 public let typeMap : TypeMap
44- public internal( set) var implementations : [ String : InterfaceImplementations ]
45- private var subTypeMap : [ String : [ String : Bool ] ] = [ : ]
63+ public let implementations : [ String : InterfaceImplementations ]
64+
65+ // Used as a cache for validateSchema().
66+ private var _subTypeMap : [ String : [ String : Bool ] ] = [ : ]
67+ private let subTypeMapQueue = DispatchQueue (
68+ label: " graphql.schema.subtypeMap " ,
69+ attributes: . concurrent
70+ )
71+ var subTypeMap : [ String : [ String : Bool ] ] {
72+ get {
73+ // Reads can occur concurrently.
74+ return subTypeMapQueue. sync {
75+ _subTypeMap
76+ }
77+ }
78+ set {
79+ // Writes occur sequentially.
80+ return subTypeMapQueue. async ( flags: . barrier) {
81+ self . _subTypeMap = newValue
82+ }
83+ }
84+ }
4685
4786 public init (
4887 description: String ? = nil ,
@@ -56,7 +95,7 @@ public final class GraphQLSchema: @unchecked Sendable {
5695 extensionASTNodes: [ SchemaExtensionDefinition ] = [ ] ,
5796 assumeValid: Bool = false
5897 ) throws {
59- validationErrors = assumeValid ? [ ] : nil
98+ _validationErrors = assumeValid ? [ ] : nil
6099
61100 self . description = description
62101 self . extensions = extensions
@@ -109,7 +148,38 @@ public final class GraphQLSchema: @unchecked Sendable {
109148 var typeMap = TypeMap ( )
110149
111150 // Keep track of all implementations by interface name.
112- implementations = try collectImplementations ( types: Array ( typeMap. values) )
151+ func collectImplementations(
152+ types: [ GraphQLNamedType ]
153+ ) throws -> [ String : InterfaceImplementations ] {
154+ var implementations : [ String : InterfaceImplementations ] = [ : ]
155+
156+ for type in types {
157+ if let type = type as? GraphQLInterfaceType {
158+ if implementations [ type. name] == nil {
159+ implementations [ type. name] = InterfaceImplementations ( )
160+ }
161+
162+ // Store implementations by interface.
163+ for iface in try type. getInterfaces ( ) {
164+ implementations [ iface. name] = InterfaceImplementations (
165+ interfaces: ( implementations [ iface. name] ? . interfaces ?? [ ] ) + [ type]
166+ )
167+ }
168+ }
169+
170+ if let type = type as? GraphQLObjectType {
171+ // Store implementations by objects.
172+ for iface in try type. getInterfaces ( ) {
173+ implementations [ iface. name] = InterfaceImplementations (
174+ objects: ( implementations [ iface. name] ? . objects ?? [ ] ) + [ type]
175+ )
176+ }
177+ }
178+ }
179+
180+ return implementations
181+ }
182+ var implementations = try collectImplementations ( types: Array ( typeMap. values) )
113183
114184 for namedType in allReferencedTypes. values {
115185 let typeName = namedType. name
@@ -124,37 +194,38 @@ public final class GraphQLSchema: @unchecked Sendable {
124194 if let namedType = namedType as? GraphQLInterfaceType {
125195 // Store implementations by interface.
126196 for iface in try namedType. getInterfaces ( ) {
127- let implementations = self . implementations [ iface. name] ?? . init(
197+ let implementation = implementations [ iface. name] ?? . init(
128198 objects: [ ] ,
129199 interfaces: [ ]
130200 )
131201
132- var interfaces = implementations . interfaces
202+ var interfaces = implementation . interfaces
133203 interfaces. append ( namedType)
134- self . implementations [ iface. name] = . init(
135- objects: implementations . objects,
204+ implementations [ iface. name] = . init(
205+ objects: implementation . objects,
136206 interfaces: interfaces
137207 )
138208 }
139209 } else if let namedType = namedType as? GraphQLObjectType {
140210 // Store implementations by objects.
141211 for iface in try namedType. getInterfaces ( ) {
142- let implementations = self . implementations [ iface. name] ?? . init(
212+ let implementation = implementations [ iface. name] ?? . init(
143213 objects: [ ] ,
144214 interfaces: [ ]
145215 )
146216
147- var objects = implementations . objects
217+ var objects = implementation . objects
148218 objects. append ( namedType)
149- self . implementations [ iface. name] = . init(
219+ implementations [ iface. name] = . init(
150220 objects: objects,
151- interfaces: implementations . interfaces
221+ interfaces: implementation . interfaces
152222 )
153223 }
154224 }
155225 }
156226
157227 self . typeMap = typeMap
228+ self . implementations = implementations
158229 }
159230
160231 convenience init ( config: GraphQLSchemaNormalizedConfig ) throws {
@@ -268,7 +339,7 @@ public final class GraphQLSchema: @unchecked Sendable {
268339
269340public typealias TypeMap = OrderedDictionary < String , GraphQLNamedType >
270341
271- public struct InterfaceImplementations {
342+ public struct InterfaceImplementations : Sendable {
272343 public let objects : [ GraphQLObjectType ]
273344 public let interfaces : [ GraphQLInterfaceType ]
274345
@@ -281,38 +352,6 @@ public struct InterfaceImplementations {
281352 }
282353}
283354
284- func collectImplementations(
285- types: [ GraphQLNamedType ]
286- ) throws -> [ String : InterfaceImplementations ] {
287- var implementations : [ String : InterfaceImplementations ] = [ : ]
288-
289- for type in types {
290- if let type = type as? GraphQLInterfaceType {
291- if implementations [ type. name] == nil {
292- implementations [ type. name] = InterfaceImplementations ( )
293- }
294-
295- // Store implementations by interface.
296- for iface in try type. getInterfaces ( ) {
297- implementations [ iface. name] = InterfaceImplementations (
298- interfaces: ( implementations [ iface. name] ? . interfaces ?? [ ] ) + [ type]
299- )
300- }
301- }
302-
303- if let type = type as? GraphQLObjectType {
304- // Store implementations by objects.
305- for iface in try type. getInterfaces ( ) {
306- implementations [ iface. name] = InterfaceImplementations (
307- objects: ( implementations [ iface. name] ? . objects ?? [ ] ) + [ type]
308- )
309- }
310- }
311- }
312-
313- return implementations
314- }
315-
316355func typeMapReducer( typeMap: TypeMap , type: GraphQLType ) throws -> TypeMap {
317356 var typeMap = typeMap
318357
0 commit comments