@@ -26,10 +26,6 @@ import OrderedCollections
2626/// Namely, schema of the type system that is currently executing,
2727/// and the fragments defined in the query document
2828public final class ExecutionContext : @unchecked Sendable {
29- let queryStrategy : QueryFieldExecutionStrategy = ConcurrentFieldExecutionStrategy ( )
30- let mutationStrategy : MutationFieldExecutionStrategy = SerialFieldExecutionStrategy ( )
31- let subscriptionStrategy : SubscriptionFieldExecutionStrategy =
32- ConcurrentFieldExecutionStrategy ( )
3329 public let schema : GraphQLSchema
3430 public let fragments : [ String : FragmentDefinition ]
3531 public let rootValue : any Sendable
@@ -84,6 +80,7 @@ public final class ExecutionContext: @unchecked Sendable {
8480 }
8581}
8682
83+ @ available ( * , deprecated , message : " FieldExecutionStrategy type no longer supported " )
8784public protocol FieldExecutionStrategy : Sendable {
8885 func executeFields (
8986 exeContext : ExecutionContext ,
@@ -94,78 +91,63 @@ public protocol FieldExecutionStrategy: Sendable {
9491 ) async throws -> OrderedDictionary < String , any Sendable >
9592}
9693
94+ @ available ( * , deprecated , message : " FieldExecutionStrategy type no longer supported " )
9795public protocol MutationFieldExecutionStrategy : FieldExecutionStrategy { }
96+
97+ @ available ( * , deprecated , message : " FieldExecutionStrategy type no longer supported " )
9898public protocol QueryFieldExecutionStrategy : FieldExecutionStrategy { }
99+
100+ @ available ( * , deprecated , message : " FieldExecutionStrategy type no longer supported " )
99101public protocol SubscriptionFieldExecutionStrategy : FieldExecutionStrategy { }
100102
101103/// Serial field execution strategy that's suitable for the "Evaluating selection sets" section of the spec for "write" mode.
104+ @ available ( * , deprecated , message : " FieldExecutionStrategy type no longer supported " )
102105public struct SerialFieldExecutionStrategy : QueryFieldExecutionStrategy ,
103106 MutationFieldExecutionStrategy , SubscriptionFieldExecutionStrategy
104107{
108+ @ available ( * , deprecated , message : " FieldExecutionStrategy type no longer supported " )
105109 public init ( ) { }
106110
111+ @ available ( * , deprecated , message : " FieldExecutionStrategy type no longer supported " )
107112 public func executeFields (
108113 exeContext : ExecutionContext ,
109114 parentType : GraphQLObjectType ,
110115 sourceValue : any Sendable ,
111116 path : IndexPath ,
112117 fields : OrderedDictionary < String , [ Field ] >
113118 ) async throws -> OrderedDictionary < String , any Sendable > {
114- var results = OrderedDictionary < String , any Sendable > ( )
115- for field in fields {
116- let fieldASTs = field . value
117- let fieldPath = path . appending ( field . key )
118- results [ field . key ] =
119- try await resolveField (
120- exeContext : exeContext ,
121- parentType : parentType ,
122- source : sourceValue ,
123- fieldASTs : fieldASTs ,
124- path : fieldPath
125- ) ?? Map . null
126- }
127- return results
119+ return try await GraphQL . executeFieldsSerially (
120+ exeContext : exeContext ,
121+ parentType : parentType ,
122+ sourceValue : sourceValue ,
123+ path : path ,
124+ fields : fields
125+ )
128126 }
129127}
130128
131129/// Serial field execution strategy that's suitable for the "Evaluating selection sets" section of the spec for "read" mode.
132130///
133131/// Each field is resolved as an individual task on a concurrent dispatch queue.
132+ @ available ( * , deprecated , message : " FieldExecutionStrategy type no longer supported " )
134133public struct ConcurrentFieldExecutionStrategy : QueryFieldExecutionStrategy ,
135134 SubscriptionFieldExecutionStrategy
136135{
136+ @ available ( * , deprecated , message : " FieldExecutionStrategy type no longer supported " )
137137 public func executeFields (
138138 exeContext : ExecutionContext ,
139139 parentType : GraphQLObjectType ,
140140 sourceValue : any Sendable ,
141141 path : IndexPath ,
142142 fields : OrderedDictionary < String , [ Field ] >
143143 ) async throws -> OrderedDictionary < String , any Sendable > {
144- return try await withThrowingTaskGroup ( of : ( String , ( any Sendable ) ? ) . self ) { group in
145- // preserve field order by assigning to null and filtering later
146- var results : OrderedDictionary < String , ( any Sendable ) ? > =
147- fields
148- . mapValues { _ -> Any ? in nil }
149- for field in fields {
150- group . addTask {
151- let fieldASTs = field . value
152- let fieldPath = path . appending ( field . key )
153- let result =
154- try await resolveField (
155- exeContext : exeContext ,
156- parentType : parentType ,
157- source : sourceValue ,
158- fieldASTs : fieldASTs ,
159- path : fieldPath
160- ) ?? Map . null
161- return ( field . key , result )
162- }
163- }
164- for try await result in group {
165- results [ result . 0 ] = result . 1
166- }
167- return results . compactMapValues { $0 }
168- }
144+ return try await GraphQL . executeFields (
145+ exeContext : exeContext ,
146+ parentType : parentType ,
147+ sourceValue : sourceValue ,
148+ path : path ,
149+ fields : fields
150+ )
169151 }
170152}
171153
@@ -311,24 +293,91 @@ func executeOperation(
311293 visitedFragmentNames : & visitedFragmentNames
312294 )
313295
314- let fieldExecutionStrategy : FieldExecutionStrategy
315-
316296 switch operation . operation {
317297 case . query :
318- fieldExecutionStrategy = exeContext . queryStrategy
298+ return try await executeFields (
299+ exeContext : exeContext ,
300+ parentType : type ,
301+ sourceValue : rootValue ,
302+ path : [ ] ,
303+ fields : fields
304+ )
319305 case . mutation :
320- fieldExecutionStrategy = exeContext . mutationStrategy
306+ return try await executeFieldsSerially (
307+ exeContext : exeContext ,
308+ parentType : type ,
309+ sourceValue : rootValue ,
310+ path : [ ] ,
311+ fields : fields
312+ )
321313 case . subscription :
322- fieldExecutionStrategy = exeContext . subscriptionStrategy
314+ return try await executeFields (
315+ exeContext : exeContext ,
316+ parentType : type ,
317+ sourceValue : rootValue ,
318+ path : [ ] ,
319+ fields : fields
320+ )
321+ }
322+ }
323+
324+ /// Implements the "Executing selection sets" section of the spec for fields that must be executed serially.
325+ func executeFieldsSerially (
326+ exeContext : ExecutionContext ,
327+ parentType : GraphQLObjectType ,
328+ sourceValue : any Sendable ,
329+ path : IndexPath ,
330+ fields : OrderedDictionary < String , [ Field ] >
331+ ) async throws -> OrderedDictionary < String , any Sendable > {
332+ var results = OrderedDictionary < String , any Sendable > ( )
333+ for field in fields {
334+ let fieldASTs = field . value
335+ let fieldPath = path . appending ( field . key )
336+ results [ field . key ] =
337+ try await resolveField (
338+ exeContext : exeContext ,
339+ parentType : parentType ,
340+ source : sourceValue ,
341+ fieldASTs : fieldASTs ,
342+ path : fieldPath
343+ ) ?? Map . null
323344 }
345+ return results
346+ }
324347
325- return try await fieldExecutionStrategy . executeFields (
326- exeContext : exeContext ,
327- parentType : type ,
328- sourceValue : rootValue ,
329- path : [ ] ,
330- fields : fields
331- )
348+ /// Implements the "Executing selection sets" section of the spec for fields that may be executed in parallel.
349+ func executeFields (
350+ exeContext : ExecutionContext ,
351+ parentType : GraphQLObjectType ,
352+ sourceValue : any Sendable ,
353+ path : IndexPath ,
354+ fields : OrderedDictionary < String , [ Field ] >
355+ ) async throws -> OrderedDictionary < String , any Sendable > {
356+ return try await withThrowingTaskGroup ( of : ( String , ( any Sendable ) ? ) . self ) { group in
357+ // preserve field order by assigning to null and filtering later
358+ var results : OrderedDictionary < String , ( any Sendable ) ? > =
359+ fields
360+ . mapValues { _ -> Any ? in nil }
361+ for field in fields {
362+ group . addTask {
363+ let fieldASTs = field . value
364+ let fieldPath = path . appending ( field . key )
365+ let result =
366+ try await resolveField (
367+ exeContext : exeContext ,
368+ parentType : parentType ,
369+ source : sourceValue ,
370+ fieldASTs : fieldASTs ,
371+ path : fieldPath
372+ ) ?? Map . null
373+ return ( field . key , result )
374+ }
375+ }
376+ for try await result in group {
377+ results [ result . 0 ] = result . 1
378+ }
379+ return results . compactMapValues { $0 }
380+ }
332381}
333382
334383/// Extracts the root type of the operation from the schema.
@@ -969,7 +1018,7 @@ func completeObjectValue(
9691018 }
9701019 }
9711020
972- return try await exeContext . queryStrategy . executeFields (
1021+ return try await executeFields (
9731022 exeContext : exeContext ,
9741023 parentType : returnType ,
9751024 sourceValue : result ,
0 commit comments