@@ -147,6 +147,9 @@ export interface ValidatedExecutionArgs {
147147 fieldResolver : GraphQLFieldResolver < any , any > ;
148148 typeResolver : GraphQLTypeResolver < any , any > ;
149149 subscribeFieldResolver : GraphQLFieldResolver < any , any > ;
150+ perEventExecutor : (
151+ validatedExecutionArgs : ValidatedExecutionArgs ,
152+ ) => PromiseOrValue < ExecutionResult > ;
150153 enableEarlyExecution : boolean ;
151154}
152155
@@ -171,6 +174,11 @@ export interface ExecutionArgs {
171174 fieldResolver ?: Maybe < GraphQLFieldResolver < any , any > > ;
172175 typeResolver ?: Maybe < GraphQLTypeResolver < any , any > > ;
173176 subscribeFieldResolver ?: Maybe < GraphQLFieldResolver < any , any > > ;
177+ perEventExecutor ?: Maybe <
178+ (
179+ validatedExecutionArgs : ValidatedExecutionArgs ,
180+ ) => PromiseOrValue < ExecutionResult >
181+ > ;
174182 enableEarlyExecution ?: Maybe < boolean > ;
175183}
176184
@@ -210,23 +218,28 @@ export function execute(args: ExecutionArgs): PromiseOrValue<ExecutionResult> {
210218 }
211219
212220 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+ }
221225
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 ;
230243}
231244
232245/**
@@ -253,7 +266,7 @@ export function experimentalExecuteIncrementally(
253266 return { errors : validatedExecutionArgs } ;
254267 }
255268
256- return executeOperation ( validatedExecutionArgs ) ;
269+ return executeQueryOrMutationOrSubscriptionEvent ( validatedExecutionArgs ) ;
257270}
258271
259272/**
@@ -271,7 +284,7 @@ export function experimentalExecuteIncrementally(
271284 * at which point we still log the error and null the parent field, which
272285 * in this case is the entire response.
273286 */
274- function executeOperation (
287+ function executeQueryOrMutationOrSubscriptionEvent (
275288 validatedExecutionArgs : ValidatedExecutionArgs ,
276289) : PromiseOrValue < ExecutionResult | ExperimentalIncrementalExecutionResults > {
277290 const exeContext : ExecutionContext = {
@@ -471,6 +484,7 @@ export function validateExecutionArgs(
471484 fieldResolver,
472485 typeResolver,
473486 subscribeFieldResolver,
487+ perEventExecutor,
474488 enableEarlyExecution,
475489 } = args ;
476490
@@ -544,6 +558,7 @@ export function validateExecutionArgs(
544558 fieldResolver : fieldResolver ?? defaultFieldResolver ,
545559 typeResolver : typeResolver ?? defaultTypeResolver ,
546560 subscribeFieldResolver : subscribeFieldResolver ?? defaultFieldResolver ,
561+ perEventExecutor : perEventExecutor ?? executeSubscriptionEvent ,
547562 enableEarlyExecution : enableEarlyExecution === true ,
548563 } ;
549564}
@@ -1938,21 +1953,25 @@ function mapSourceToResponse(
19381953 // For each payload yielded from a subscription, map it over the normal
19391954 // GraphQL `execute` function, with `payload` as the rootValue.
19401955 // 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..
19441957 return mapAsyncIterable ( resultOrStream , ( payload : unknown ) => {
19451958 const perEventExecutionArgs : ValidatedExecutionArgs = {
19461959 ...validatedExecutionArgs ,
19471960 rootValue : payload ,
19481961 } ;
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 ) ;
19531963 } ) ;
19541964}
19551965
1966+ export function executeSubscriptionEvent (
1967+ validatedExecutionArgs : ValidatedExecutionArgs ,
1968+ ) : PromiseOrValue < ExecutionResult > {
1969+ const result = executeQueryOrMutationOrSubscriptionEvent (
1970+ validatedExecutionArgs ,
1971+ ) ;
1972+ return ensureSinglePayload ( result ) ;
1973+ }
1974+
19561975/**
19571976 * Implements the "CreateSourceEventStream" algorithm described in the
19581977 * GraphQL specification, resolving the subscription source event stream.
0 commit comments