@@ -147,6 +147,9 @@ export interface ValidatedExecutionArgs {
147
147
fieldResolver : GraphQLFieldResolver < any , any > ;
148
148
typeResolver : GraphQLTypeResolver < any , any > ;
149
149
subscribeFieldResolver : GraphQLFieldResolver < any , any > ;
150
+ perEventExecutor : (
151
+ validatedExecutionArgs : ValidatedExecutionArgs ,
152
+ ) => PromiseOrValue < ExecutionResult > ;
150
153
enableEarlyExecution : boolean ;
151
154
}
152
155
@@ -171,6 +174,11 @@ export interface ExecutionArgs {
171
174
fieldResolver ?: Maybe < GraphQLFieldResolver < any , any > > ;
172
175
typeResolver ?: Maybe < GraphQLTypeResolver < any , any > > ;
173
176
subscribeFieldResolver ?: Maybe < GraphQLFieldResolver < any , any > > ;
177
+ perEventExecutor ?: Maybe <
178
+ (
179
+ validatedExecutionArgs : ValidatedExecutionArgs ,
180
+ ) => PromiseOrValue < ExecutionResult >
181
+ > ;
174
182
enableEarlyExecution ?: Maybe < boolean > ;
175
183
}
176
184
@@ -210,23 +218,28 @@ export function execute(args: ExecutionArgs): PromiseOrValue<ExecutionResult> {
210
218
}
211
219
212
220
const result = experimentalExecuteIncrementally ( args ) ;
213
- if ( ! isPromise ( result ) ) {
214
- if ( 'initialResult' in result ) {
215
- // This can happen if the operation contains @defer or @stream directives
216
- // and is not validated prior to execution
217
- throw new Error ( UNEXPECTED_MULTIPLE_PAYLOADS ) ;
218
- }
219
- return result ;
220
- }
221
+ // Multiple payloads could be encountered if the operation contains @defer or
222
+ // @stream directives and is not validated prior to execution
223
+ return ensureSinglePayload ( result ) ;
224
+ }
221
225
222
- return result . then ( ( incrementalResult ) => {
223
- if ( 'initialResult' in incrementalResult ) {
224
- // This can happen if the operation contains @defer or @stream directives
225
- // and is not validated prior to execution
226
- throw new Error ( UNEXPECTED_MULTIPLE_PAYLOADS ) ;
227
- }
228
- return incrementalResult ;
229
- } ) ;
226
+ function ensureSinglePayload (
227
+ result : PromiseOrValue <
228
+ ExecutionResult | ExperimentalIncrementalExecutionResults
229
+ > ,
230
+ ) : PromiseOrValue < ExecutionResult > {
231
+ if ( isPromise ( result ) ) {
232
+ return result . then ( ( resolved ) => {
233
+ if ( 'initialResult' in resolved ) {
234
+ throw new Error ( UNEXPECTED_MULTIPLE_PAYLOADS ) ;
235
+ }
236
+ return resolved ;
237
+ } ) ;
238
+ }
239
+ if ( 'initialResult' in result ) {
240
+ throw new Error ( UNEXPECTED_MULTIPLE_PAYLOADS ) ;
241
+ }
242
+ return result ;
230
243
}
231
244
232
245
/**
@@ -253,7 +266,7 @@ export function experimentalExecuteIncrementally(
253
266
return { errors : validatedExecutionArgs } ;
254
267
}
255
268
256
- return executeOperation ( validatedExecutionArgs ) ;
269
+ return executeQueryOrMutationOrSubscriptionEvent ( validatedExecutionArgs ) ;
257
270
}
258
271
259
272
/**
@@ -271,7 +284,7 @@ export function experimentalExecuteIncrementally(
271
284
* at which point we still log the error and null the parent field, which
272
285
* in this case is the entire response.
273
286
*/
274
- function executeOperation (
287
+ function executeQueryOrMutationOrSubscriptionEvent (
275
288
validatedExecutionArgs : ValidatedExecutionArgs ,
276
289
) : PromiseOrValue < ExecutionResult | ExperimentalIncrementalExecutionResults > {
277
290
const exeContext : ExecutionContext = {
@@ -471,6 +484,7 @@ export function validateExecutionArgs(
471
484
fieldResolver,
472
485
typeResolver,
473
486
subscribeFieldResolver,
487
+ perEventExecutor,
474
488
enableEarlyExecution,
475
489
} = args ;
476
490
@@ -544,6 +558,7 @@ export function validateExecutionArgs(
544
558
fieldResolver : fieldResolver ?? defaultFieldResolver ,
545
559
typeResolver : typeResolver ?? defaultTypeResolver ,
546
560
subscribeFieldResolver : subscribeFieldResolver ?? defaultFieldResolver ,
561
+ perEventExecutor : perEventExecutor ?? executeSubscriptionEvent ,
547
562
enableEarlyExecution : enableEarlyExecution === true ,
548
563
} ;
549
564
}
@@ -1938,21 +1953,25 @@ function mapSourceToResponse(
1938
1953
// For each payload yielded from a subscription, map it over the normal
1939
1954
// GraphQL `execute` function, with `payload` as the rootValue.
1940
1955
// This implements the "MapSourceToResponseEvent" algorithm described in
1941
- // the GraphQL specification. The `execute` function provides the
1942
- // "ExecuteSubscriptionEvent" algorithm, as it is nearly identical to the
1943
- // "ExecuteQuery" algorithm, for which `execute` is also used.
1956
+ // the GraphQL specification..
1944
1957
return mapAsyncIterable ( resultOrStream , ( payload : unknown ) => {
1945
1958
const perEventExecutionArgs : ValidatedExecutionArgs = {
1946
1959
...validatedExecutionArgs ,
1947
1960
rootValue : payload ,
1948
1961
} ;
1949
- // typecast to ExecutionResult, not possible to return
1950
- // ExperimentalIncrementalExecutionResults when
1951
- // exeContext.operation is 'subscription'.
1952
- return executeOperation ( perEventExecutionArgs ) as ExecutionResult ;
1962
+ return validatedExecutionArgs . perEventExecutor ( perEventExecutionArgs ) ;
1953
1963
} ) ;
1954
1964
}
1955
1965
1966
+ export function executeSubscriptionEvent (
1967
+ validatedExecutionArgs : ValidatedExecutionArgs ,
1968
+ ) : PromiseOrValue < ExecutionResult > {
1969
+ const result = executeQueryOrMutationOrSubscriptionEvent (
1970
+ validatedExecutionArgs ,
1971
+ ) ;
1972
+ return ensureSinglePayload ( result ) ;
1973
+ }
1974
+
1956
1975
/**
1957
1976
* Implements the "CreateSourceEventStream" algorithm described in the
1958
1977
* GraphQL specification, resolving the subscription source event stream.
0 commit comments