@@ -276,8 +276,8 @@ public final class GraphQLObjectType: @unchecked Sendable {
276276 public let name : String
277277 public let description : String ?
278278
279- // While technically not sendable, fields and interfaces should not be mutated after schema
280- // creation .
279+ /// The fields that the object defines. These may be mutated during setup, but should not be
280+ /// modified once the schema is being used for execution .
281281 public var fields : ( ) throws -> GraphQLFieldMap {
282282 get {
283283 fieldFunc
@@ -294,6 +294,8 @@ public final class GraphQLObjectType: @unchecked Sendable {
294294 private var fieldFunc : ( ) throws -> GraphQLFieldMap
295295 private var fieldCache : GraphQLFieldDefinitionMap ?
296296
297+ /// The interfaces that the object conforms to. These may be mutated during setup, but should
298+ /// not be modified once the schema is being used for execution.
297299 public var interfaces : ( ) throws -> [ GraphQLInterfaceType ] {
298300 get {
299301 interfaceFunc
@@ -505,13 +507,34 @@ public struct GraphQLResolveInfo: Sendable {
505507
506508public typealias GraphQLFieldMap = OrderedDictionary < String , GraphQLField >
507509
508- public struct GraphQLField : Sendable {
510+ public final class GraphQLField : @ unchecked Sendable {
509511 public let type : GraphQLOutputType
510512 public let args : GraphQLArgumentConfigMap
511513 public let deprecationReason : String ?
512514 public let description : String ?
513- public let resolve : GraphQLFieldResolve ?
514- public let subscribe : GraphQLFieldResolve ?
515+
516+ public var resolve : GraphQLFieldResolve ? {
517+ get {
518+ fieldPropertyQueue. sync { _resolve }
519+ }
520+ set {
521+ fieldPropertyQueue. sync ( flags: . barrier) { _resolve = newValue }
522+ }
523+ }
524+
525+ private var _resolve : GraphQLFieldResolve ?
526+
527+ public var subscribe : GraphQLFieldResolve ? {
528+ get {
529+ fieldPropertyQueue. sync { _subscribe }
530+ }
531+ set {
532+ fieldPropertyQueue. sync ( flags: . barrier) { _subscribe = newValue }
533+ }
534+ }
535+
536+ private var _subscribe : GraphQLFieldResolve ?
537+
515538 public let astNode : FieldDefinition ?
516539
517540 public init (
@@ -526,8 +549,8 @@ public struct GraphQLField: Sendable {
526549 self . deprecationReason = deprecationReason
527550 self . description = description
528551 self . astNode = astNode
529- resolve = nil
530- subscribe = nil
552+ _resolve = nil
553+ _subscribe = nil
531554 }
532555
533556 public init (
@@ -544,8 +567,8 @@ public struct GraphQLField: Sendable {
544567 self . deprecationReason = deprecationReason
545568 self . description = description
546569 self . astNode = astNode
547- self . resolve = resolve
548- self . subscribe = subscribe
570+ _resolve = resolve
571+ _subscribe = subscribe
549572 }
550573
551574 public init (
@@ -562,11 +585,11 @@ public struct GraphQLField: Sendable {
562585 self . description = description
563586 self . astNode = astNode
564587
565- self . resolve = { source, args, context, info in
588+ _resolve = { source, args, context, info in
566589 let result = try resolve ( source, args, context, info)
567590 return result
568591 }
569- subscribe = nil
592+ _subscribe = nil
570593 }
571594}
572595
@@ -711,8 +734,8 @@ public final class GraphQLInterfaceType: @unchecked Sendable {
711734 public let description : String ?
712735 public let resolveType : GraphQLTypeResolve ?
713736
714- // While technically not sendable, fields and interfaces should not be mutated after schema
715- // creation .
737+ /// The fields that the interface defines. These may be mutated during setup, but should not be
738+ /// modified once the schema is being used for execution .
716739 public var fields : ( ) throws -> GraphQLFieldMap {
717740 get {
718741 fieldFunc
@@ -729,6 +752,8 @@ public final class GraphQLInterfaceType: @unchecked Sendable {
729752 private var fieldFunc : ( ) throws -> GraphQLFieldMap
730753 private var fieldCache : GraphQLFieldDefinitionMap ?
731754
755+ /// The interfaces that the interface conforms to. This may be mutated during setup, but should
756+ /// not be modified once the schema is being used for execution.
732757 public var interfaces : ( ) throws -> [ GraphQLInterfaceType ] {
733758 get {
734759 interfaceFunc
@@ -869,7 +894,9 @@ public final class GraphQLUnionType: @unchecked Sendable {
869894 public let name : String
870895 public let description : String ?
871896 public let resolveType : GraphQLTypeResolve ?
872- // While technically not sendable, types should not be mutated after schema creation.
897+
898+ /// The types that belong to the union. This may be mutated during setup, but must not be
899+ /// modified once the schema is being used for execution.
873900 public internal( set) var types : ( ) throws -> [ GraphQLObjectType ]
874901 public let possibleTypeNames : [ String : Bool ]
875902 let extensions : [ GraphQLUnionTypeExtensions ]
@@ -1164,7 +1191,9 @@ public struct GraphQLEnumValueDefinition: Sendable {
11641191public final class GraphQLInputObjectType : @unchecked Sendable {
11651192 public let name : String
11661193 public let description : String ?
1167- // While technically not sendable, this should not be mutated after schema creation.
1194+
1195+ /// The fields that the input has. This may be mutated during setup, but must not be modified
1196+ /// once the schema is being used for execution.
11681197 public var fields : ( ) throws -> InputObjectFieldMap
11691198 public let astNode : InputObjectTypeDefinition ?
11701199 public let extensionASTNodes : [ InputObjectExtensionDefinition ]
@@ -1422,3 +1451,10 @@ private let cacheQueue = DispatchQueue(
14221451 label: " graphql.objecttype.cache " ,
14231452 attributes: . concurrent
14241453)
1454+
1455+ /// Shared queue for field property access
1456+ /// Uses reader/writer pattern for read-heavy workload
1457+ private let fieldPropertyQueue = DispatchQueue (
1458+ label: " graphql.field.properties " ,
1459+ attributes: . concurrent
1460+ )
0 commit comments