Skip to content

Commit 76f9a8d

Browse files
committed
add CollectedErrors utility class
1 parent 8893d15 commit 76f9a8d

File tree

1 file changed

+43
-36
lines changed

1 file changed

+43
-36
lines changed

src/execution/execute.ts

Lines changed: 43 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -114,8 +114,41 @@ export interface ExecutionContext {
114114
fieldResolver: GraphQLFieldResolver<any, any>;
115115
typeResolver: GraphQLTypeResolver<any, any>;
116116
subscribeFieldResolver: GraphQLFieldResolver<any, any>;
117-
errorPositions: Set<Path | undefined>;
118-
errors: Array<GraphQLError>;
117+
collectedErrors: CollectedErrors;
118+
}
119+
120+
/**
121+
* @internal
122+
*/
123+
class CollectedErrors {
124+
private _errorPositions: Set<Path | undefined>;
125+
private _errors: Array<GraphQLError>;
126+
constructor() {
127+
this._errorPositions = new Set<Path | undefined>();
128+
this._errors = [];
129+
}
130+
get errors(): ReadonlyArray<GraphQLError> {
131+
return this._errors;
132+
}
133+
add(error: GraphQLError, path: Path | undefined) {
134+
// Do not modify errors list if a response position for this error has already been nulled.
135+
// This check is unnecessary for implementations able to implement proper cancellation.
136+
if (this._hasNulledPosition(path)) {
137+
return;
138+
}
139+
this._errorPositions.add(path);
140+
this._errors.push(error);
141+
}
142+
private _hasNulledPosition(startPath: Path | undefined): boolean {
143+
let path = startPath;
144+
while (path !== undefined) {
145+
if (this._errorPositions.has(path)) {
146+
return true;
147+
}
148+
path = path.prev;
149+
}
150+
return this._errorPositions.has(undefined);
151+
}
119152
}
120153

121154
/**
@@ -207,21 +240,17 @@ export function execute(args: ExecutionArgs): PromiseOrValue<ExecutionResult> {
207240
const result = executeOperation(exeContext, operation, rootValue);
208241
if (isPromise(result)) {
209242
return result.then(
210-
(data) => buildResponse(data, exeContext.errors),
243+
(data) => buildResponse(data, exeContext.collectedErrors.errors),
211244
(error) => {
212-
const { errorPositions, errors } = exeContext;
213-
errorPositions.add(undefined);
214-
errors.push(error);
215-
return buildResponse(null, errors);
245+
exeContext.collectedErrors.add(error, undefined);
246+
return buildResponse(null, exeContext.collectedErrors.errors);
216247
},
217248
);
218249
}
219-
return buildResponse(result, exeContext.errors);
250+
return buildResponse(result, exeContext.collectedErrors.errors);
220251
} catch (error) {
221-
const { errorPositions, errors } = exeContext;
222-
errorPositions.add(undefined);
223-
errors.push(error);
224-
return buildResponse(null, errors);
252+
exeContext.collectedErrors.add(error, undefined);
253+
return buildResponse(null, exeContext.collectedErrors.errors);
225254
}
226255
}
227256

@@ -357,8 +386,7 @@ export function buildExecutionContext(
357386
fieldResolver: fieldResolver ?? defaultFieldResolver,
358387
typeResolver: typeResolver ?? defaultTypeResolver,
359388
subscribeFieldResolver: subscribeFieldResolver ?? defaultFieldResolver,
360-
errorPositions: new Set(),
361-
errors: [],
389+
collectedErrors: new CollectedErrors(),
362390
};
363391
}
364392

@@ -612,33 +640,12 @@ function handleFieldError(
612640
throw error;
613641
}
614642

615-
// Do not modify errors list if a response position for this error has already been nulled.
616-
const errorPositions = exeContext.errorPositions;
617-
if (hasNulledPosition(errorPositions, path)) {
618-
return null;
619-
}
620-
errorPositions.add(path);
621-
622643
// Otherwise, error protection is applied, logging the error and resolving
623644
// a null value for this field if one is encountered.
624-
exeContext.errors.push(error);
645+
exeContext.collectedErrors.add(error, path);
625646
return null;
626647
}
627648

628-
function hasNulledPosition(
629-
errorPositions: Set<Path | undefined>,
630-
startPath: Path | undefined,
631-
): boolean {
632-
let path = startPath;
633-
while (path !== undefined) {
634-
if (errorPositions.has(path)) {
635-
return true;
636-
}
637-
path = path.prev;
638-
}
639-
return errorPositions.has(undefined);
640-
}
641-
642649
/**
643650
* Implements the instructions for completeValue as defined in the
644651
* "Value Completion" section of the spec.

0 commit comments

Comments
 (0)