Skip to content

Commit ab7788b

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 graphql#3638
1 parent e414279 commit ab7788b

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
@@ -175,6 +175,12 @@ export function execute(args: ExecutionArgs): PromiseOrValue<ExecutionResult> {
175175
return { errors: exeContext };
176176
}
177177

178+
return executeImpl(exeContext);
179+
}
180+
181+
function executeImpl(
182+
exeContext: ExecutionContext,
183+
): PromiseOrValue<ExecutionResult> {
178184
// Return a Promise that will eventually resolve to the data described by
179185
// The "Response" section of the GraphQL specification.
180186
//
@@ -345,6 +351,17 @@ export function buildExecutionContext(
345351
};
346352
}
347353

354+
function buildPerEventExecutionContext(
355+
exeContext: ExecutionContext,
356+
payload: unknown,
357+
): ExecutionContext {
358+
return {
359+
...exeContext,
360+
rootValue: payload,
361+
errors: [],
362+
};
363+
}
364+
348365
/**
349366
* Implements the "Executing operations" section of the spec.
350367
*/
@@ -1044,20 +1061,29 @@ export function subscribe(
10441061
): PromiseOrValue<
10451062
AsyncGenerator<ExecutionResult, void, void> | ExecutionResult
10461063
> {
1047-
const resultOrStream = createSourceEventStream(args);
1064+
// If a valid execution context cannot be created due to incorrect arguments,
1065+
// a "Response" with only errors is returned.
1066+
const exeContext = buildExecutionContext(args);
1067+
1068+
// Return early errors if execution context failed.
1069+
if (!('schema' in exeContext)) {
1070+
return { errors: exeContext };
1071+
}
1072+
1073+
const resultOrStream = createSourceEventStreamImpl(exeContext);
10481074

10491075
if (isPromise(resultOrStream)) {
10501076
return resultOrStream.then((resolvedResultOrStream) =>
1051-
mapSourceToResponse(resolvedResultOrStream, args),
1077+
mapSourceToResponse(exeContext, resolvedResultOrStream),
10521078
);
10531079
}
10541080

1055-
return mapSourceToResponse(resultOrStream, args);
1081+
return mapSourceToResponse(exeContext, resultOrStream);
10561082
}
10571083

10581084
function mapSourceToResponse(
1085+
exeContext: ExecutionContext,
10591086
resultOrStream: ExecutionResult | AsyncIterable<unknown>,
1060-
args: ExecutionArgs,
10611087
): PromiseOrValue<
10621088
AsyncGenerator<ExecutionResult, void, void> | ExecutionResult
10631089
> {
@@ -1072,10 +1098,7 @@ function mapSourceToResponse(
10721098
// "ExecuteSubscriptionEvent" algorithm, as it is nearly identical to the
10731099
// "ExecuteQuery" algorithm, for which `execute` is also used.
10741100
return mapAsyncIterator(resultOrStream, (payload: unknown) =>
1075-
execute({
1076-
...args,
1077-
rootValue: payload,
1078-
}),
1101+
executeImpl(buildPerEventExecutionContext(exeContext, payload)),
10791102
);
10801103
}
10811104

@@ -1119,6 +1142,12 @@ export function createSourceEventStream(
11191142
return { errors: exeContext };
11201143
}
11211144

1145+
return createSourceEventStreamImpl(exeContext);
1146+
}
1147+
1148+
function createSourceEventStreamImpl(
1149+
exeContext: ExecutionContext,
1150+
): PromiseOrValue<AsyncIterable<unknown> | ExecutionResult> {
11221151
try {
11231152
const eventStream = executeSubscription(exeContext);
11241153
if (isPromise(eventStream)) {

0 commit comments

Comments
 (0)