Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion grafast/grafast/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,6 @@ requirements:
- for every request:
- `context` must be an object (anything suitable to be used as the key to a
`WeakMap`); if you do not need a context then `{}` is perfectly acceptable
- `rootValue` must be an object or `null`/`undefined`
- resolver limitations:
- only explicit field resolvers (baked into the GraphQL schema) are supported,
i.e. resolvers passed via `rootValue` are not (currently) supported
Expand Down
2 changes: 2 additions & 0 deletions grafast/grafast/src/bucket.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ export interface RequestTools {
/** @internal */
args: GrafastExecutionArgs;
/** @internal */
currentRootValue: any;
/** @internal */
onError: ErrorBehavior;
/** The `timeSource.now()` at which the request started executing */
startTime: number;
Expand Down
1 change: 1 addition & 0 deletions grafast/grafast/src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ export const $$idempotent = Symbol("idempotent");
* The event emitter used for outputting execution events.
*/
export const $$eventEmitter = Symbol("executionEventEmitter");
export const $$originalRootValue = Symbol("originalRootValue");

/**
* Used to indicate that an array has more results available via a stream.
Expand Down
2 changes: 1 addition & 1 deletion grafast/grafast/src/engine/OperationPlan.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1503,7 +1503,7 @@ export class OperationPlan {
deferredLayerPlan,
outputPlan.rootStep,
{
mode: "object",
mode: outputPlan.type.mode === "root" ? "root" : "object",
deferLabel: deferred.label,
typeName: objectType.name,
},
Expand Down
5 changes: 3 additions & 2 deletions grafast/grafast/src/engine/OutputPlan.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ export type OutputPlanTypeRoot = {
*/
mode: "root";
typeName: string;
deferLabel?: string | undefined;
};
export type OutputPlanTypeObject = {
/**
Expand Down Expand Up @@ -214,10 +215,10 @@ export class OutputPlan<TType extends OutputPlanType = OutputPlanType> {
| undefined;

/**
* For object output plan types only.
* For root and object output plan types only.
*/
public deferredOutputPlans: OutputPlan<
OutputPlanTypeObject | OutputPlanTypePolymorphicObject
OutputPlanTypeRoot | OutputPlanTypeObject | OutputPlanTypePolymorphicObject
>[] = [];

public layerPlan: LayerPlan;
Expand Down
37 changes: 11 additions & 26 deletions grafast/grafast/src/execute.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,11 @@ import type {
} from "graphql";
import type { PromiseOrValue } from "graphql/jsutils/PromiseOrValue.js";

import { $$eventEmitter, $$extensions } from "./constants.ts";
import { isDev } from "./dev.ts";
import { inspect } from "./inspect.ts";
import {
$$eventEmitter,
$$extensions,
$$originalRootValue,
} from "./constants.ts";
import type {
ExecuteEvent,
ExecutionEventEmitter,
Expand All @@ -30,40 +32,23 @@ export function withGrafastArgs(
ExecutionResult | AsyncGenerator<AsyncExecutionResult, void, void>
> {
const options = args.resolvedPreset?.grafast;
if (isDev) {
if (
args.rootValue != null &&
(typeof args.rootValue !== "object" ||
Object.keys(args.rootValue).length > 0)
) {
throw new Error(
`Grafast executor doesn't support there being a rootValue (found ${inspect(
args.rootValue,
)})`,
);
}
}
args[$$originalRootValue] = args.rootValue;
if (args.rootValue == null) {
args.rootValue = Object.create(null);
}
if (typeof args.rootValue !== "object" || args.rootValue == null) {
throw new Error("Grafast requires that the 'rootValue' be an object");
}
const explain = options?.explain;
const shouldExplain = !!explain;

let unlisten: (() => void) | null = null;
if (shouldExplain) {
const eventEmitter: ExecutionEventEmitter | undefined = new EventEmitter();
const explainOperations: any[] = [];
args.rootValue = Object.assign(Object.create(null), args.rootValue, {
[$$eventEmitter]: eventEmitter,
[$$extensions]: {
explain: {
operations: explainOperations,
},
args[$$eventEmitter] = eventEmitter;
args[$$extensions] = {
explain: {
operations: explainOperations,
},
});
};
const handleExplainOperation = ({
operation,
}: ExecutionEventMap["explainOperation"]) => {
Expand Down
16 changes: 11 additions & 5 deletions grafast/grafast/src/interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,14 @@ import type {
import type { ObjMap } from "graphql/jsutils/ObjMap.js";

import type { Bucket, RequestTools } from "./bucket.ts";
import type {
$$streamMore,
$$timeout,
$$ts,
ExecutionEntryFlags,
import {
$$eventEmitter,
$$extensions,
$$originalRootValue,
type $$streamMore,
type $$timeout,
type $$ts,
type ExecutionEntryFlags,
} from "./constants.ts";
import type { Constraint } from "./constraints.ts";
import type { LayerPlanReasonListItemStream } from "./engine/LayerPlan.ts";
Expand Down Expand Up @@ -825,6 +828,9 @@ export interface GrafastExecutionArgs extends ExecutionArgs {
middleware?: Middleware<GraphileConfig.GrafastMiddleware> | null;
requestContext?: Partial<Grafast.RequestContext>;
outputDataAsString?: boolean;
[$$eventEmitter]?: ExecutionEventEmitter;
[$$extensions]?: Record<string, unknown>;
[$$originalRootValue]?: any;
}

export interface ValidateSchemaEvent {
Expand Down
27 changes: 18 additions & 9 deletions grafast/grafast/src/prepare.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
$$contextPlanCache,
$$eventEmitter,
$$extensions,
$$originalRootValue,
$$streamMore,
FLAG_ERROR,
NO_FLAGS,
Expand Down Expand Up @@ -359,11 +360,12 @@ function executePreemptive(
executionTimeout !== null ? startTime + executionTimeout : null;
const requestContext: RequestTools = {
args,
currentRootValue: args[$$originalRootValue],
onError,
startTime,
stopTime,
// toSerialize: [],
eventEmitter: rootValue?.[$$eventEmitter],
eventEmitter: args[$$eventEmitter],
abortSignal,
insideGraphQL: false,
};
Expand Down Expand Up @@ -404,14 +406,21 @@ function executePreemptive(
iterators: [new Set()],
size: 1, //store.size
});
const bucketPromise = executeBucket(subscriptionBucket, requestContext);
const subscriptionRequestContext: RequestTools = {
...requestContext,
currentRootValue: payload,
};
const bucketPromise = executeBucket(
subscriptionBucket,
subscriptionRequestContext,
);
function outputStreamBucket() {
// NOTE: this is the root output plan for a subscription operation.
const [ctx, result] = outputBucket(
operationPlan.rootOutputPlan,
subscriptionBucket,
ZERO,
requestContext,
subscriptionRequestContext,
[],
rootBucket.store
.get(operationPlan.variableValuesStep.id)!
Expand All @@ -421,7 +430,7 @@ function executePreemptive(
return finalize(
result,
ctx,
index === 0 ? (rootValue[$$extensions] ?? undefined) : undefined,
index === 0 ? (args[$$extensions] ?? undefined) : undefined,
outputDataAsString,
);
}
Expand Down Expand Up @@ -460,7 +469,7 @@ function executePreemptive(
];
const payload = Object.create(null) as ExecutionResult;
payload.errors = errors;
const extensions = bucketRootValue[$$extensions];
const extensions = args[$$extensions];
if (extensions != null) {
payload.extensions = extensions;
}
Expand Down Expand Up @@ -564,7 +573,7 @@ function executePreemptive(
return finalize(
result,
ctx,
rootValue[$$extensions] ?? undefined,
args[$$extensions] ?? undefined,
outputDataAsString,
);
}
Expand Down Expand Up @@ -601,7 +610,7 @@ export function grafastPrepare(
const {
schema,
contextValue: context,
rootValue = Object.create(null),
rootValue,
// operationName,
// document,
middleware,
Expand All @@ -612,7 +621,7 @@ export function grafastPrepare(
if (Array.isArray(exeContext) || "length" in exeContext) {
return Object.assign(Object.create(bypassGraphQLObj), {
errors: exeContext,
extensions: rootValue[$$extensions],
extensions: args[$$extensions],
});
}

Expand Down Expand Up @@ -674,7 +683,7 @@ export function grafastPrepare(
if (operationPlan[$$contextPlanCache] == null) {
operationPlan[$$contextPlanCache] = operationPlan.generatePlanJSON();
}
rootValue[$$extensions]?.explain?.operations.push({
(args[$$extensions] as any)?.explain?.operations.push({
type: "plan",
title: "Plan",
plan: operationPlan[$$contextPlanCache],
Expand Down
20 changes: 16 additions & 4 deletions grafast/grafast/src/steps/graphqlResolver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,15 +97,17 @@ export class GraphQLResolverStep extends UnbatchedStep {
variableValues: any,
rootValue: any,
): any {
const executionRootValue = extra._requestContext.currentRootValue;
if (!extra.stream) {
if (this.isNotRoot && source == null) {
return source;
}
const resolverSource = this.isNotRoot ? source : executionRootValue;
const resolveInfo: GraphQLResolveInfo = Object.assign(
Object.create(this.resolveInfoBase),
{
variableValues,
rootValue,
rootValue: executionRootValue,
path: {
typename: this.resolveInfoBase.parentType.name,
key: this.resolveInfoBase.fieldName,
Expand All @@ -114,7 +116,12 @@ export class GraphQLResolverStep extends UnbatchedStep {
},
},
);
const data = this.resolver?.(source, args, context, resolveInfo);
const data = this.resolver?.(
resolverSource,
args,
context,
resolveInfo,
);
return flagErrorIfErrorAsync(data);
} else {
if (this.isNotRoot) {
Expand All @@ -128,10 +135,15 @@ export class GraphQLResolverStep extends UnbatchedStep {
{
// ENHANCE: add support for path
variableValues,
rootValue,
rootValue: executionRootValue,
},
);
const data = this.subscriber(source, args, context, resolveInfo);
const data = this.subscriber(
executionRootValue,
args,
context,
resolveInfo,
);
return flagErrorIfErrorAsync(data);
}
}
Expand Down
1 change: 0 additions & 1 deletion grafast/website/grafast/getting-started/existing-schema.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ following hold:
currently populate that in an equivalent fashion
- `context` must be an object (anything suitable to be used as the key to a
`WeakMap`); if you do not need a context then `{}` is perfectly acceptable
- `rootValue`, if specified, must be an object or `null`/`undefined`
- `resolveType` and `isTypeOf`, if specified, must return the
GraphQL type name as a string (rather than returning the object type itself)
and their version of `GraphQLResolveInfo` is even more cut down (but you
Expand Down
Loading