Skip to content

Commit 2c079a2

Browse files
fix: Field resolvers are mutable
This allows us to modify resolvers after creation, making conversions between AST schemas (that have no resolvers) and executable schemas easier.
1 parent de08923 commit 2c079a2

1 file changed

Lines changed: 35 additions & 9 deletions

File tree

Sources/GraphQL/Type/Definition.swift

Lines changed: 35 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -505,13 +505,32 @@ public struct GraphQLResolveInfo: Sendable {
505505

506506
public typealias GraphQLFieldMap = OrderedDictionary<String, GraphQLField>
507507

508-
public struct GraphQLField: Sendable {
508+
public final class GraphQLField: @unchecked Sendable {
509509
public let type: GraphQLOutputType
510510
public let args: GraphQLArgumentConfigMap
511511
public let deprecationReason: String?
512512
public let description: String?
513-
public let resolve: GraphQLFieldResolve?
514-
public let subscribe: GraphQLFieldResolve?
513+
514+
private var _resolve: GraphQLFieldResolve?
515+
public var resolve: GraphQLFieldResolve? {
516+
get {
517+
fieldPropertyQueue.sync { _resolve }
518+
}
519+
set {
520+
fieldPropertyQueue.sync(flags: .barrier) { _resolve = newValue }
521+
}
522+
}
523+
524+
private var _subscribe: GraphQLFieldResolve?
525+
public var subscribe: GraphQLFieldResolve? {
526+
get {
527+
fieldPropertyQueue.sync { _subscribe }
528+
}
529+
set {
530+
fieldPropertyQueue.sync(flags: .barrier) { _subscribe = newValue }
531+
}
532+
}
533+
515534
public let astNode: FieldDefinition?
516535

517536
public init(
@@ -526,8 +545,8 @@ public struct GraphQLField: Sendable {
526545
self.deprecationReason = deprecationReason
527546
self.description = description
528547
self.astNode = astNode
529-
resolve = nil
530-
subscribe = nil
548+
_resolve = nil
549+
_subscribe = nil
531550
}
532551

533552
public init(
@@ -544,8 +563,8 @@ public struct GraphQLField: Sendable {
544563
self.deprecationReason = deprecationReason
545564
self.description = description
546565
self.astNode = astNode
547-
self.resolve = resolve
548-
self.subscribe = subscribe
566+
self._resolve = resolve
567+
self._subscribe = subscribe
549568
}
550569

551570
public init(
@@ -562,11 +581,11 @@ public struct GraphQLField: Sendable {
562581
self.description = description
563582
self.astNode = astNode
564583

565-
self.resolve = { source, args, context, info in
584+
self._resolve = { source, args, context, info in
566585
let result = try resolve(source, args, context, info)
567586
return result
568587
}
569-
subscribe = nil
588+
_subscribe = nil
570589
}
571590
}
572591

@@ -1422,3 +1441,10 @@ private let cacheQueue = DispatchQueue(
14221441
label: "graphql.objecttype.cache",
14231442
attributes: .concurrent
14241443
)
1444+
1445+
/// Shared queue for field property access
1446+
/// Uses reader/writer pattern for read-heavy workload
1447+
private let fieldPropertyQueue = DispatchQueue(
1448+
label: "graphql.field.properties",
1449+
attributes: .concurrent
1450+
)

0 commit comments

Comments
 (0)