Skip to content

Commit b52b05e

Browse files
authored
Revert "refactor buildResolveInfo into a lazy class (#4530)" (#4553)
Sadly, this would break existing users that resolver functions by spreading the info argument. BREAKING CHANGE: this PR changes `info.abortSignal` to `info.getAbortSignal()` => while `info` as a whole is not lazy, changing to a method allows us to maintain laziness at least with regards to the creation of the abort signal.
1 parent d2b549a commit b52b05e

File tree

9 files changed

+119
-313
lines changed

9 files changed

+119
-313
lines changed

src/execution/Executor.ts

Lines changed: 36 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -53,9 +53,9 @@ import {
5353
collectFields,
5454
collectSubfields as _collectSubfields,
5555
} from './collectFields.js';
56+
import { buildResolveInfo } from './execute.js';
5657
import type { StreamUsage } from './getStreamUsage.js';
5758
import { getStreamUsage as _getStreamUsage } from './getStreamUsage.js';
58-
import { ResolveInfo } from './ResolveInfo.js';
5959
import { returnIteratorCatchingErrors } from './returnIteratorCatchingErrors.js';
6060
import type { VariableValues } from './values.js';
6161
import { getArgumentValues } from './values.js';
@@ -218,13 +218,13 @@ export class Executor<
218218
validatedExecutionArgs: ValidatedExecutionArgs;
219219
finished: boolean;
220220
initialResponseAbortController: AbortController | undefined;
221-
resolverAbortControllers: Set<AbortController>;
221+
resolverAbortControllers: Map<Path, AbortController>;
222222
collectedErrors: CollectedErrors;
223223

224224
constructor(validatedExecutionArgs: ValidatedExecutionArgs) {
225225
this.validatedExecutionArgs = validatedExecutionArgs;
226226
this.finished = false;
227-
this.resolverAbortControllers = new Set();
227+
this.resolverAbortControllers = new Map();
228228
this.collectedErrors = new CollectedErrors();
229229
}
230230

@@ -333,10 +333,24 @@ export class Executor<
333333
const { resolverAbortControllers } = this;
334334
const finishReason =
335335
reason ?? new Error('Execution has already completed.');
336-
for (const abortController of resolverAbortControllers) {
336+
for (const abortController of resolverAbortControllers.values()) {
337337
abortController.abort(finishReason);
338338
}
339339
}
340+
341+
getAbortSignal(path: Path): AbortSignal {
342+
const resolverAbortSignal = this.resolverAbortControllers.get(path)?.signal;
343+
if (resolverAbortSignal !== undefined) {
344+
return resolverAbortSignal;
345+
}
346+
const abortController = new AbortController();
347+
this.resolverAbortControllers.set(path, abortController);
348+
if (this.finished) {
349+
abortController.abort(new Error('Execution has already completed.'));
350+
}
351+
return abortController.signal;
352+
}
353+
340354
/**
341355
* Given a completed execution context and data, build the `{ errors, data }`
342356
* response defined by the "Response" section of the GraphQL specification.
@@ -522,26 +536,13 @@ export class Executor<
522536
const returnType = fieldDef.type;
523537
const resolveFn = fieldDef.resolve ?? validatedExecutionArgs.fieldResolver;
524538

525-
const info = new ResolveInfo(
539+
const info = buildResolveInfo(
526540
validatedExecutionArgs,
527541
fieldDef,
528-
fieldDetailsList,
542+
toNodes(fieldDetailsList),
529543
parentType,
530544
path,
531-
() => {
532-
/* c8 ignore next 3 */
533-
if (this.finished) {
534-
throw new Error('Execution has already completed.');
535-
}
536-
const abortController = new AbortController();
537-
this.resolverAbortControllers.add(abortController);
538-
return {
539-
abortSignal: abortController.signal,
540-
unregister: () => {
541-
this.resolverAbortControllers.delete(abortController);
542-
},
543-
};
544-
},
545+
() => this.getAbortSignal(path),
545546
);
546547

547548
// Get the resolve function, regardless of if its result is normal or abrupt (error).
@@ -588,20 +589,20 @@ export class Executor<
588589
// to take a second callback for the error case.
589590
return completed.then(
590591
(resolved) => {
591-
info.unregisterAbortSignal();
592+
this.resolverAbortControllers.delete(path);
592593
return resolved;
593594
},
594595
(rawError: unknown) => {
595-
info.unregisterAbortSignal();
596+
this.resolverAbortControllers.delete(path);
596597
this.handleFieldError(rawError, returnType, fieldDetailsList, path);
597598
return null;
598599
},
599600
);
600601
}
601-
info.unregisterAbortSignal();
602+
this.resolverAbortControllers.delete(path);
602603
return completed;
603604
} catch (rawError) {
604-
info.unregisterAbortSignal();
605+
this.resolverAbortControllers.delete(path);
605606
this.handleFieldError(rawError, returnType, fieldDetailsList, path);
606607
return null;
607608
}
@@ -661,7 +662,7 @@ export class Executor<
661662
completeValue(
662663
returnType: GraphQLOutputType,
663664
fieldDetailsList: FieldDetailsList,
664-
info: ResolveInfo,
665+
info: GraphQLResolveInfo,
665666
path: Path,
666667
result: unknown,
667668
positionContext: TPositionContext | undefined,
@@ -750,7 +751,7 @@ export class Executor<
750751
async completePromisedValue(
751752
returnType: GraphQLOutputType,
752753
fieldDetailsList: FieldDetailsList,
753-
info: ResolveInfo,
754+
info: GraphQLResolveInfo,
754755
path: Path,
755756
result: Promise<unknown>,
756757
positionContext: TPositionContext | undefined,
@@ -774,12 +775,12 @@ export class Executor<
774775
completed = await completed;
775776
}
776777
if (isFieldValue) {
777-
info.unregisterAbortSignal();
778+
this.resolverAbortControllers.delete(path);
778779
}
779780
return completed;
780781
} catch (rawError) {
781782
if (isFieldValue) {
782-
info.unregisterAbortSignal();
783+
this.resolverAbortControllers.delete(path);
783784
}
784785
this.handleFieldError(rawError, returnType, fieldDetailsList, path);
785786
return null;
@@ -793,7 +794,7 @@ export class Executor<
793794
async completeAsyncIterableValue(
794795
itemType: GraphQLOutputType,
795796
fieldDetailsList: FieldDetailsList,
796-
info: ResolveInfo,
797+
info: GraphQLResolveInfo,
797798
path: Path,
798799
items: AsyncIterable<unknown>,
799800
positionContext: TPositionContext | undefined,
@@ -879,7 +880,7 @@ export class Executor<
879880
| { handle: Iterator<unknown>; isAsync?: never }
880881
| { handle: AsyncIterator<unknown>; isAsync: true },
881882
_streamUsage: StreamUsage,
882-
_info: ResolveInfo,
883+
_info: GraphQLResolveInfo,
883884
_itemType: GraphQLOutputType,
884885
): boolean {
885886
return false;
@@ -892,7 +893,7 @@ export class Executor<
892893
completeListValue(
893894
returnType: GraphQLList<GraphQLOutputType>,
894895
fieldDetailsList: FieldDetailsList,
895-
info: ResolveInfo,
896+
info: GraphQLResolveInfo,
896897
path: Path,
897898
result: unknown,
898899
positionContext: TPositionContext | undefined,
@@ -929,7 +930,7 @@ export class Executor<
929930
completeIterableValue(
930931
itemType: GraphQLOutputType,
931932
fieldDetailsList: FieldDetailsList,
932-
info: ResolveInfo,
933+
info: GraphQLResolveInfo,
933934
path: Path,
934935
items: Iterable<unknown>,
935936
positionContext: TPositionContext | undefined,
@@ -1002,7 +1003,7 @@ export class Executor<
10021003
completedResults: Array<unknown>,
10031004
itemType: GraphQLOutputType,
10041005
fieldDetailsList: FieldDetailsList,
1005-
info: ResolveInfo,
1006+
info: GraphQLResolveInfo,
10061007
itemPath: Path,
10071008
positionContext: TPositionContext | undefined,
10081009
): boolean {
@@ -1044,7 +1045,7 @@ export class Executor<
10441045
completedResults: Array<unknown>,
10451046
itemType: GraphQLOutputType,
10461047
fieldDetailsList: FieldDetailsList,
1047-
info: ResolveInfo,
1048+
info: GraphQLResolveInfo,
10481049
itemPath: Path,
10491050
positionContext: TPositionContext | undefined,
10501051
): boolean {
@@ -1087,7 +1088,7 @@ export class Executor<
10871088
item: Promise<unknown>,
10881089
itemType: GraphQLOutputType,
10891090
fieldDetailsList: FieldDetailsList,
1090-
info: ResolveInfo,
1091+
info: GraphQLResolveInfo,
10911092
itemPath: Path,
10921093
positionContext: TPositionContext | undefined,
10931094
): Promise<unknown> {

src/execution/ExecutorThrowingOnIncremental.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import type {
99
GraphQLList,
1010
GraphQLObjectType,
1111
GraphQLOutputType,
12+
GraphQLResolveInfo,
1213
} from '../type/index.js';
1314

1415
import type {
@@ -17,7 +18,6 @@ import type {
1718
GroupedFieldSet,
1819
} from './collectFields.js';
1920
import { Executor, getStreamUsage } from './Executor.js';
20-
import type { ResolveInfo } from './ResolveInfo.js';
2121

2222
const UNEXPECTED_MULTIPLE_PAYLOADS =
2323
'Executing this GraphQL operation would unexpectedly produce multiple payloads (due to @defer or @stream directive)';
@@ -81,7 +81,7 @@ export class ExecutorThrowingOnIncremental extends Executor {
8181
override completeListValue(
8282
returnType: GraphQLList<GraphQLOutputType>,
8383
fieldDetailsList: FieldDetailsList,
84-
info: ResolveInfo,
84+
info: GraphQLResolveInfo,
8585
path: Path,
8686
result: unknown,
8787
positionContext: undefined,

src/execution/ResolveInfo.ts

Lines changed: 0 additions & 131 deletions
This file was deleted.

0 commit comments

Comments
 (0)