Skip to content

Commit

Permalink
enhance: AbortSignal in GraphQLResolveInfo, and AbortSignal in …
Browse files Browse the repository at this point in the history
…`ExecutionRequest`
  • Loading branch information
ardatan committed Dec 13, 2024
1 parent aeee7db commit 020b9e4
Show file tree
Hide file tree
Showing 8 changed files with 62 additions and 17 deletions.
8 changes: 8 additions & 0 deletions .changeset/selfish-mugs-promise.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
'@graphql-tools/executor': patch
'@graphql-tools/schema': patch
'@graphql-tools/utils': patch
'@graphql-tools/mock': patch
---

\`AbortSignal\` in \`GraphQLResolveInfo\`, and \`AbortSignal\` in \`ExecutionRequest\`
1 change: 1 addition & 0 deletions packages/executor/src/execution/__tests__/executor-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,7 @@ describe('Execute: Handles basic execution tasks', () => {
'rootValue',
'operation',
'variableValues',
'signal',
]);

const operation = document.definitions[0];
Expand Down
27 changes: 18 additions & 9 deletions packages/executor/src/execution/execute.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ import {
GraphQLList,
GraphQLObjectType,
GraphQLOutputType,
GraphQLResolveInfo,
GraphQLSchema,
GraphQLTypeResolver,
isAbstractType,
Expand All @@ -38,6 +37,7 @@ import {
fakePromise,
getArgumentValues,
getDefinedRootType,
GraphQLResolveInfo,
GraphQLStreamDirective,
inspect,
isAsyncIterable,
Expand Down Expand Up @@ -758,6 +758,7 @@ export function buildResolveInfo(
rootValue: exeContext.rootValue,
operation: exeContext.operation,
variableValues: exeContext.variableValues,
signal: exeContext.signal,
};
}

Expand Down Expand Up @@ -957,9 +958,13 @@ async function completeAsyncIteratorValue(
iterator: AsyncIterator<unknown>,
asyncPayloadRecord?: AsyncPayloadRecord,
): Promise<ReadonlyArray<unknown>> {
exeContext.signal?.addEventListener('abort', () => {
iterator.return?.();
});
exeContext.signal?.addEventListener(
'abort',
() => {
iterator.return?.();
},
{ once: true },
);
const errors = asyncPayloadRecord?.errors ?? exeContext.errors;
const stream = getStreamValues(exeContext, fieldNodes, path);
let containsPromise = false;
Expand Down Expand Up @@ -2080,10 +2085,14 @@ function yieldSubsequentPayloads(
let isDone = false;

const abortPromise = new Promise<void>((_, reject) => {
exeContext.signal?.addEventListener('abort', () => {
isDone = true;
reject(exeContext.signal?.reason);
});
exeContext.signal?.addEventListener(
'abort',
() => {
isDone = true;
reject(exeContext.signal?.reason);
},
{ once: true },
);
});

async function next(): Promise<IteratorResult<SubsequentIncrementalExecutionResult, void>> {
Expand Down Expand Up @@ -2141,7 +2150,7 @@ function yieldSubsequentPayloads(
async throw(error?: unknown): Promise<IteratorResult<never, void>> {
await returnStreamIterators();
isDone = true;
return Promise.reject(error);
throw error;
},
async [DisposableSymbols.asyncDispose]() {
await returnStreamIterators();
Expand Down
27 changes: 25 additions & 2 deletions packages/executor/src/execution/normalizedExecutor.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
import { getOperationAST } from 'graphql';
import { getOperationAST, GraphQLSchema } from 'graphql';
import { ValueOrPromise } from 'value-or-promise';
import { ExecutionResult, MaybeAsyncIterable, MaybePromise } from '@graphql-tools/utils';
import {
ExecutionRequest,
ExecutionResult,
Executor,
MaybeAsyncIterable,
MaybePromise,
memoize1,
} from '@graphql-tools/utils';
import { execute, ExecutionArgs, flattenIncrementalResults, subscribe } from './execute.js';

export function normalizedExecutor<TData = any, TVariables = any, TContext = any>(
Expand All @@ -22,3 +29,19 @@ export function normalizedExecutor<TData = any, TVariables = any, TContext = any
})
.resolve()!;
}

export const executorFromSchema = memoize1(function executorFromSchema(
schema: GraphQLSchema,
): Executor {
return function schemaExecutor(request: ExecutionRequest) {
return normalizedExecutor({
schema,
document: request.document,
variableValues: request.variables,
operationName: request.operationName,
rootValue: request.rootValue,
contextValue: request.context,
signal: request.signal || request.info?.signal,
});
};
});
3 changes: 1 addition & 2 deletions packages/mock/src/pagination.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { GraphQLResolveInfo } from 'graphql';
import { IFieldResolver } from '@graphql-tools/utils';
import { GraphQLResolveInfo, IFieldResolver } from '@graphql-tools/utils';
import { IMockStore, Ref } from './types.js';
import { isRootType, makeRef } from './utils.js';

Expand Down
4 changes: 2 additions & 2 deletions packages/schema/src/chainResolvers.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { defaultFieldResolver, GraphQLFieldResolver, GraphQLResolveInfo } from 'graphql';
import { Maybe } from '@graphql-tools/utils';
import { defaultFieldResolver, GraphQLFieldResolver } from 'graphql';
import { GraphQLResolveInfo, Maybe } from '@graphql-tools/utils';

export function chainResolvers<TArgs extends { [argName: string]: any }>(
resolvers: Array<Maybe<GraphQLFieldResolver<any, any, TArgs>>>,
Expand Down
7 changes: 6 additions & 1 deletion packages/utils/src/Interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ import {
GraphQLNamedType,
GraphQLObjectType,
GraphQLOutputType,
GraphQLResolveInfo,
GraphQLScalarLiteralParser,
GraphQLScalarSerializer,
GraphQLScalarType,
Expand All @@ -40,6 +39,7 @@ import {
ObjectTypeDefinitionNode,
ObjectTypeExtensionNode,
OperationTypeNode,
GraphQLResolveInfo as OrigGraphQLResolveInfo,
ScalarTypeDefinitionNode,
ScalarTypeExtensionNode,
SelectionNode,
Expand Down Expand Up @@ -68,6 +68,10 @@ export interface ExecutionResult<TData = any, TExtensions = any> {
items?: TData | null;
}

export interface GraphQLResolveInfo extends OrigGraphQLResolveInfo {
signal?: AbortSignal;
}

export interface ExecutionRequest<
TVariables extends Record<string, any> = any,
TContext = any,
Expand All @@ -86,6 +90,7 @@ export interface ExecutionRequest<
// If the request originates within execution of a parent request, it may contain the parent context and info
context?: TContext;
info?: GraphQLResolveInfo;
signal?: AbortSignal;
}

// graphql-js non-exported typings
Expand Down
2 changes: 1 addition & 1 deletion packages/utils/src/getResponseKeyFromInfo.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { GraphQLResolveInfo } from 'graphql';
import { GraphQLResolveInfo } from './Interfaces.js';

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

0 comments on commit 020b9e4

Please sign in to comment.