Skip to content

Commit 020b9e4

Browse files
committed
enhance: AbortSignal in GraphQLResolveInfo, and AbortSignal in ExecutionRequest
1 parent aeee7db commit 020b9e4

File tree

8 files changed

+62
-17
lines changed

8 files changed

+62
-17
lines changed

.changeset/selfish-mugs-promise.md

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
---
2+
'@graphql-tools/executor': patch
3+
'@graphql-tools/schema': patch
4+
'@graphql-tools/utils': patch
5+
'@graphql-tools/mock': patch
6+
---
7+
8+
\`AbortSignal\` in \`GraphQLResolveInfo\`, and \`AbortSignal\` in \`ExecutionRequest\`

packages/executor/src/execution/__tests__/executor-test.ts

+1
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,7 @@ describe('Execute: Handles basic execution tasks', () => {
206206
'rootValue',
207207
'operation',
208208
'variableValues',
209+
'signal',
209210
]);
210211

211212
const operation = document.definitions[0];

packages/executor/src/execution/execute.ts

+18-9
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ import {
1313
GraphQLList,
1414
GraphQLObjectType,
1515
GraphQLOutputType,
16-
GraphQLResolveInfo,
1716
GraphQLSchema,
1817
GraphQLTypeResolver,
1918
isAbstractType,
@@ -38,6 +37,7 @@ import {
3837
fakePromise,
3938
getArgumentValues,
4039
getDefinedRootType,
40+
GraphQLResolveInfo,
4141
GraphQLStreamDirective,
4242
inspect,
4343
isAsyncIterable,
@@ -758,6 +758,7 @@ export function buildResolveInfo(
758758
rootValue: exeContext.rootValue,
759759
operation: exeContext.operation,
760760
variableValues: exeContext.variableValues,
761+
signal: exeContext.signal,
761762
};
762763
}
763764

@@ -957,9 +958,13 @@ async function completeAsyncIteratorValue(
957958
iterator: AsyncIterator<unknown>,
958959
asyncPayloadRecord?: AsyncPayloadRecord,
959960
): Promise<ReadonlyArray<unknown>> {
960-
exeContext.signal?.addEventListener('abort', () => {
961-
iterator.return?.();
962-
});
961+
exeContext.signal?.addEventListener(
962+
'abort',
963+
() => {
964+
iterator.return?.();
965+
},
966+
{ once: true },
967+
);
963968
const errors = asyncPayloadRecord?.errors ?? exeContext.errors;
964969
const stream = getStreamValues(exeContext, fieldNodes, path);
965970
let containsPromise = false;
@@ -2080,10 +2085,14 @@ function yieldSubsequentPayloads(
20802085
let isDone = false;
20812086

20822087
const abortPromise = new Promise<void>((_, reject) => {
2083-
exeContext.signal?.addEventListener('abort', () => {
2084-
isDone = true;
2085-
reject(exeContext.signal?.reason);
2086-
});
2088+
exeContext.signal?.addEventListener(
2089+
'abort',
2090+
() => {
2091+
isDone = true;
2092+
reject(exeContext.signal?.reason);
2093+
},
2094+
{ once: true },
2095+
);
20872096
});
20882097

20892098
async function next(): Promise<IteratorResult<SubsequentIncrementalExecutionResult, void>> {
@@ -2141,7 +2150,7 @@ function yieldSubsequentPayloads(
21412150
async throw(error?: unknown): Promise<IteratorResult<never, void>> {
21422151
await returnStreamIterators();
21432152
isDone = true;
2144-
return Promise.reject(error);
2153+
throw error;
21452154
},
21462155
async [DisposableSymbols.asyncDispose]() {
21472156
await returnStreamIterators();

packages/executor/src/execution/normalizedExecutor.ts

+25-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,13 @@
1-
import { getOperationAST } from 'graphql';
1+
import { getOperationAST, GraphQLSchema } from 'graphql';
22
import { ValueOrPromise } from 'value-or-promise';
3-
import { ExecutionResult, MaybeAsyncIterable, MaybePromise } from '@graphql-tools/utils';
3+
import {
4+
ExecutionRequest,
5+
ExecutionResult,
6+
Executor,
7+
MaybeAsyncIterable,
8+
MaybePromise,
9+
memoize1,
10+
} from '@graphql-tools/utils';
411
import { execute, ExecutionArgs, flattenIncrementalResults, subscribe } from './execute.js';
512

613
export function normalizedExecutor<TData = any, TVariables = any, TContext = any>(
@@ -22,3 +29,19 @@ export function normalizedExecutor<TData = any, TVariables = any, TContext = any
2229
})
2330
.resolve()!;
2431
}
32+
33+
export const executorFromSchema = memoize1(function executorFromSchema(
34+
schema: GraphQLSchema,
35+
): Executor {
36+
return function schemaExecutor(request: ExecutionRequest) {
37+
return normalizedExecutor({
38+
schema,
39+
document: request.document,
40+
variableValues: request.variables,
41+
operationName: request.operationName,
42+
rootValue: request.rootValue,
43+
contextValue: request.context,
44+
signal: request.signal || request.info?.signal,
45+
});
46+
};
47+
});

packages/mock/src/pagination.ts

+1-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
import { GraphQLResolveInfo } from 'graphql';
2-
import { IFieldResolver } from '@graphql-tools/utils';
1+
import { GraphQLResolveInfo, IFieldResolver } from '@graphql-tools/utils';
32
import { IMockStore, Ref } from './types.js';
43
import { isRootType, makeRef } from './utils.js';
54

packages/schema/src/chainResolvers.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
import { defaultFieldResolver, GraphQLFieldResolver, GraphQLResolveInfo } from 'graphql';
2-
import { Maybe } from '@graphql-tools/utils';
1+
import { defaultFieldResolver, GraphQLFieldResolver } from 'graphql';
2+
import { GraphQLResolveInfo, Maybe } from '@graphql-tools/utils';
33

44
export function chainResolvers<TArgs extends { [argName: string]: any }>(
55
resolvers: Array<Maybe<GraphQLFieldResolver<any, any, TArgs>>>,

packages/utils/src/Interfaces.ts

+6-1
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@ import {
2424
GraphQLNamedType,
2525
GraphQLObjectType,
2626
GraphQLOutputType,
27-
GraphQLResolveInfo,
2827
GraphQLScalarLiteralParser,
2928
GraphQLScalarSerializer,
3029
GraphQLScalarType,
@@ -40,6 +39,7 @@ import {
4039
ObjectTypeDefinitionNode,
4140
ObjectTypeExtensionNode,
4241
OperationTypeNode,
42+
GraphQLResolveInfo as OrigGraphQLResolveInfo,
4343
ScalarTypeDefinitionNode,
4444
ScalarTypeExtensionNode,
4545
SelectionNode,
@@ -68,6 +68,10 @@ export interface ExecutionResult<TData = any, TExtensions = any> {
6868
items?: TData | null;
6969
}
7070

71+
export interface GraphQLResolveInfo extends OrigGraphQLResolveInfo {
72+
signal?: AbortSignal;
73+
}
74+
7175
export interface ExecutionRequest<
7276
TVariables extends Record<string, any> = any,
7377
TContext = any,
@@ -86,6 +90,7 @@ export interface ExecutionRequest<
8690
// If the request originates within execution of a parent request, it may contain the parent context and info
8791
context?: TContext;
8892
info?: GraphQLResolveInfo;
93+
signal?: AbortSignal;
8994
}
9095

9196
// graphql-js non-exported typings

packages/utils/src/getResponseKeyFromInfo.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { GraphQLResolveInfo } from 'graphql';
1+
import { GraphQLResolveInfo } from './Interfaces.js';
22

33
/**
44
* Get the key under which the result of this resolver will be placed in the response JSON. Basically, just

0 commit comments

Comments
 (0)