@@ -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