Skip to content

Commit bb094f4

Browse files
committed
refactor: subscribe: introduce new buildPerEventExecutionContext
= introduces `buildPerEventExecutionContext` that creates an `ExecutionContext` for each subscribe event from the original `ExecutionContext` used to create the event stream = `subscribe` now directly builds the `ExecutionContext` instead of relying on `createSourceEventStream` = introduces `createSourceEventStreamImpl` and `executeImpl` functions that operate on the built `ExecutionContext` rather the `ExecutionArgs` = `subscribe` calls the `createSourceEventStreamImpl` function on the original context and eventuallys calls `executeImpl` on the per event context created by `buildEventExecutionContext`. Motivation: 1. remove unnecessary `buildExecutionContext` call, reducing duplicate work 2. paves the way for easily enhancing the `buildPerEventExecutionContext` to add a new `perEventContextFactory` argument to augment the context argument passed to resolvers as need per event. depends on #3638
1 parent 3a17407 commit bb094f4

File tree

1 file changed

+37
-8
lines changed

1 file changed

+37
-8
lines changed

src/execution/execute.ts

Lines changed: 37 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,12 @@ export function execute(args: ExecutionArgs): PromiseOrValue<ExecutionResult> {
171171
return { errors: exeContext };
172172
}
173173

174+
return executeImpl(exeContext);
175+
}
176+
177+
function executeImpl(
178+
exeContext: ExecutionContext,
179+
): PromiseOrValue<ExecutionResult> {
174180
// Return a Promise that will eventually resolve to the data described by
175181
// The "Response" section of the GraphQL specification.
176182
//
@@ -341,6 +347,17 @@ export function buildExecutionContext(
341347
};
342348
}
343349

350+
function buildPerEventExecutionContext(
351+
exeContext: ExecutionContext,
352+
payload: unknown,
353+
): ExecutionContext {
354+
return {
355+
...exeContext,
356+
rootValue: payload,
357+
errors: [],
358+
};
359+
}
360+
344361
/**
345362
* Implements the "Executing operations" section of the spec.
346363
*/
@@ -1040,20 +1057,29 @@ export function subscribe(
10401057
): PromiseOrValue<
10411058
AsyncGenerator<ExecutionResult, void, void> | ExecutionResult
10421059
> {
1043-
const resultOrStream = createSourceEventStream(args);
1060+
// If a valid execution context cannot be created due to incorrect arguments,
1061+
// a "Response" with only errors is returned.
1062+
const exeContext = buildExecutionContext(args);
1063+
1064+
// Return early errors if execution context failed.
1065+
if (!('schema' in exeContext)) {
1066+
return { errors: exeContext };
1067+
}
1068+
1069+
const resultOrStream = createSourceEventStreamImpl(exeContext);
10441070

10451071
if (isPromise(resultOrStream)) {
10461072
return resultOrStream.then((resolvedResultOrStream) =>
1047-
mapSourceToResponse(resolvedResultOrStream, args),
1073+
mapSourceToResponse(exeContext, resolvedResultOrStream),
10481074
);
10491075
}
10501076

1051-
return mapSourceToResponse(resultOrStream, args);
1077+
return mapSourceToResponse(exeContext, resultOrStream);
10521078
}
10531079

10541080
function mapSourceToResponse(
1081+
exeContext: ExecutionContext,
10551082
resultOrStream: ExecutionResult | AsyncIterable<unknown>,
1056-
args: ExecutionArgs,
10571083
): PromiseOrValue<
10581084
AsyncGenerator<ExecutionResult, void, void> | ExecutionResult
10591085
> {
@@ -1068,10 +1094,7 @@ function mapSourceToResponse(
10681094
// "ExecuteSubscriptionEvent" algorithm, as it is nearly identical to the
10691095
// "ExecuteQuery" algorithm, for which `execute` is also used.
10701096
return mapAsyncIterator(resultOrStream, (payload: unknown) =>
1071-
execute({
1072-
...args,
1073-
rootValue: payload,
1074-
}),
1097+
executeImpl(buildPerEventExecutionContext(exeContext, payload)),
10751098
);
10761099
}
10771100

@@ -1115,6 +1138,12 @@ export function createSourceEventStream(
11151138
return { errors: exeContext };
11161139
}
11171140

1141+
return createSourceEventStreamImpl(exeContext);
1142+
}
1143+
1144+
function createSourceEventStreamImpl(
1145+
exeContext: ExecutionContext,
1146+
): PromiseOrValue<AsyncIterable<unknown> | ExecutionResult> {
11181147
try {
11191148
const eventStream = executeSubscription(exeContext);
11201149
if (isPromise(eventStream)) {

0 commit comments

Comments
 (0)