@@ -153,33 +153,94 @@ export interface ExecutionArgs {
153
153
contextValue ?: unknown ;
154
154
variableValues ?: Maybe < { readonly [ variable : string ] : unknown } > ;
155
155
operationName ?: Maybe < string > ;
156
+ disableSubscription ?: Maybe < boolean > ;
156
157
fieldResolver ?: Maybe < GraphQLFieldResolver < any , any > > ;
157
158
typeResolver ?: Maybe < GraphQLTypeResolver < any , any > > ;
159
+ subscribeFieldResolver ?: Maybe < GraphQLFieldResolver < unknown , unknown > > ;
158
160
}
159
161
162
+ // Exported for backwards compatibility, see below.
163
+ // eslint-disable-next-line @typescript-eslint/no-empty-interface
164
+ export interface SubscriptionArgs extends ExecutionArgs { }
165
+
160
166
/**
161
167
* Implements the "Executing requests" section of the GraphQL specification.
162
168
*
169
+ * For queries and mutations:
163
170
* Returns either a synchronous ExecutionResult (if all encountered resolvers
164
171
* are synchronous), or a Promise of an ExecutionResult that will eventually be
165
172
* resolved and never rejected.
166
173
*
167
- * If the arguments to this function do not result in a legal execution context,
168
- * a GraphQLError will be thrown immediately explaining the invalid input.
174
+ * For subscriptions:
175
+ * Returns a Promise which resolves to either an AsyncIterator (if successful)
176
+ * or an ExecutionResult (error). The promise will be rejected if the resolved
177
+ * event stream is not an async iterable.
178
+ *
179
+ * If the source stream could not be created due to faulty subscription
180
+ * resolver logic or underlying systems, the promise will resolve to a single
181
+ * ExecutionResult containing `errors` and no `data`.
182
+ *
183
+ * If the operation succeeded, the promise resolves to an AsyncIterator, which
184
+ * yields a stream of ExecutionResults representing the response stream.
185
+ *
186
+ * For queries, mutations and subscriptions:
187
+ * If a valid execution context cannot be created due to incorrect arguments
188
+ * an ExecutionResult containing descriptive errors will be returned.
189
+ *
190
+ * NOTE: the below always async `subscribe` function will return a Promise
191
+ * that resolves to the ExecutionResult containing the errors, rather than the
192
+ * ExecutionResult itself.
193
+ *
194
+ * The `executeRequest` function, in contrast, aligns the return type in the
195
+ * case of incorrect arguments between all operation types. `executeRequest`
196
+ * always returns an ExecutionResult with the errors, even for subscriptions,
197
+ * rather than a promise that resolves to the ExecutionResult with the errors.
198
+ *
169
199
*/
170
- export function execute ( args : ExecutionArgs ) : PromiseOrValue < ExecutionResult > {
171
- // If a valid execution context cannot be created due to incorrect arguments,
172
- // a "Response" with only errors is returned.
200
+ export function executeRequest (
201
+ args : ExecutionArgs ,
202
+ ) :
203
+ | ExecutionResult
204
+ | Promise < ExecutionResult | AsyncGenerator < ExecutionResult , void , void > > {
173
205
const exeContext = buildExecutionContext ( args ) ;
174
206
175
207
// Return early errors if execution context failed.
176
208
if ( ! ( 'schema' in exeContext ) ) {
177
209
return { errors : exeContext } ;
178
210
}
179
211
212
+ if (
213
+ ! args . disableSubscription &&
214
+ exeContext . operation . operation === 'subscription'
215
+ ) {
216
+ return executeSubscription ( exeContext ) ;
217
+ }
218
+
180
219
return executeQueryOrMutation ( exeContext ) ;
181
220
}
182
221
222
+ /**
223
+ * Also implements the "Executing requests" section of the GraphQL specification.
224
+ * The `execute` function presumes the request contains a query or mutation
225
+ * and has a narrower return type than `executeRequest`.
226
+ *
227
+ * The below use of the new `disableSubscription` argument preserves the
228
+ * previous default behavior of executing documents containing subscription
229
+ * operations as queries.
230
+ *
231
+ * Note: In a future version the `execute` function may be entirely replaced
232
+ * with the `executeRequest` function, and the `executeRequest` function may
233
+ * be renamed to `execute`. The `disableSubscription` option may be replaced
234
+ * by an `operationType` option that changes that overrides the operation
235
+ * type stored within the document.
236
+ */
237
+ export function execute ( args : ExecutionArgs ) : PromiseOrValue < ExecutionResult > {
238
+ return executeRequest ( {
239
+ ...args ,
240
+ disableSubscription : true ,
241
+ } ) as PromiseOrValue < ExecutionResult > ;
242
+ }
243
+
183
244
/**
184
245
* Also implements the "Executing requests" section of the GraphQL specification.
185
246
* However, it guarantees to complete synchronously (or throw an error) assuming
@@ -196,6 +257,22 @@ export function executeSync(args: ExecutionArgs): ExecutionResult {
196
257
return result ;
197
258
}
198
259
260
+ /**
261
+ * Also implements the "Executing requests" section of the GraphQL specification.
262
+ * The `subscribe` function presumes the request contains a subscription
263
+ * and has a narrower return type than `executeRequest`.
264
+ *
265
+ * Note: In a future version the `subscribe` function may be entirely replaced
266
+ * with the `executeRequest` function as above.
267
+ */
268
+ export async function subscribe (
269
+ args : SubscriptionArgs ,
270
+ ) : Promise < AsyncGenerator < ExecutionResult , void , void > | ExecutionResult > {
271
+ return executeRequest ( args ) as Promise <
272
+ AsyncGenerator < ExecutionResult , void , void > | ExecutionResult
273
+ > ;
274
+ }
275
+
199
276
/**
200
277
* Implements the "Executing operations" section of the spec for queries and
201
278
* mutations.
@@ -250,23 +327,15 @@ export function assertValidExecutionArguments(
250
327
251
328
/**
252
329
* Constructs a ExecutionContext object from the arguments passed to
253
- * execute , which we will pass throughout the other execution methods.
330
+ * executeRequest , which we will pass throughout the other execution methods.
254
331
*
255
332
* Throws a GraphQLError if a valid execution context cannot be created.
256
333
*
257
334
* @internal
258
335
*/
259
- export function buildExecutionContext ( args : {
260
- schema : GraphQLSchema ;
261
- document : DocumentNode ;
262
- rootValue ?: Maybe < unknown > ;
263
- contextValue ?: Maybe < unknown > ;
264
- variableValues ?: Maybe < { readonly [ variable : string ] : unknown } > ;
265
- operationName ?: Maybe < string > ;
266
- fieldResolver ?: Maybe < GraphQLFieldResolver < unknown , unknown > > ;
267
- typeResolver ?: Maybe < GraphQLTypeResolver < unknown , unknown > > ;
268
- subscribeFieldResolver ?: Maybe < GraphQLFieldResolver < unknown , unknown > > ;
269
- } ) : ReadonlyArray < GraphQLError > | ExecutionContext {
336
+ export function buildExecutionContext (
337
+ args : ExecutionArgs ,
338
+ ) : ReadonlyArray < GraphQLError > | ExecutionContext {
270
339
const {
271
340
schema,
272
341
document,
0 commit comments