Skip to content

Commit 3b670d8

Browse files
committed
Be stricter about types and usage of getDep/getDepOptions
1 parent d06e474 commit 3b670d8

File tree

14 files changed

+111
-50
lines changed

14 files changed

+111
-50
lines changed

grafast/dataplan-pg/src/steps/pgPolymorphic.ts

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -82,12 +82,13 @@ export class PgPolymorphicStep<
8282
}) as any;
8383
}
8484

85-
itemPlan(): TItemStep {
86-
return this.getDep<any>(this.itemStepId);
85+
private itemPlan(): TItemStep {
86+
return this.getDepOptions<TItemStep>(this.itemStepId).step;
8787
}
8888

89-
typeSpecifierPlan(): TTypeSpecifierStep {
90-
return this.getDep<TTypeSpecifierStep>(this.typeSpecifierStepId);
89+
private typeSpecifierPlan(): TTypeSpecifierStep {
90+
return this.getDepOptions<TTypeSpecifierStep>(this.typeSpecifierStepId)
91+
.step;
9192
}
9293

9394
planForType(type: GraphQLObjectType): ExecutableStep {
@@ -101,7 +102,9 @@ export class PgPolymorphicStep<
101102
).join("', '")}'`,
102103
);
103104
}
104-
return spec.plan(this.typeSpecifierPlan(), this.itemPlan());
105+
const $typeSpecifier = this.typeSpecifierPlan();
106+
const $item = this.itemPlan();
107+
return spec.plan($typeSpecifier, $item);
105108
}
106109

107110
private getTypeNameFromSpecifier(specifier: TTypeSpecifier) {

grafast/dataplan-pg/src/steps/pgSelect.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1644,7 +1644,7 @@ export class PgSelectRowsStep<
16441644
}
16451645

16461646
public getClassStep(): PgSelectStep<TResource> {
1647-
return this.getDep<PgSelectStep<TResource>>(0);
1647+
return this.getDepOptions<PgSelectStep<TResource>>(0).step;
16481648
}
16491649

16501650
listItem(itemPlan: Step) {

grafast/dataplan-pg/src/steps/pgUnionAll.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1096,7 +1096,7 @@ export class PgUnionAllRowsStep<
10961096
this.addDependency($pgUnionAll);
10971097
}
10981098
public getClassStep(): PgUnionAllStep<TAttributes, TTypeNames> {
1099-
return this.getDep<PgUnionAllStep<TAttributes, TTypeNames>>(0);
1099+
return this.getDepOptions<PgUnionAllStep<TAttributes, TTypeNames>>(0).step;
11001100
}
11011101

11021102
listItem(itemPlan: Step) {

grafast/grafast/src/engine/OutputPlan.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -466,7 +466,7 @@ export class OutputPlan<TType extends OutputPlanType = OutputPlanType> {
466466
| undefined = ($root.unbatchedExecute! as any)[expressionSymbol];
467467
if (expressionDetails !== undefined) {
468468
// @ts-ignore
469-
const $parent: Step = $root.getDep(0);
469+
const { step: $parent } = $root.getDepOptions(0);
470470
this.layerPlan.operationPlan.stepTracker.setOutputPlanRootStep(
471471
this,
472472
$parent,

grafast/grafast/src/interfaces.ts

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -788,7 +788,7 @@ export interface LocationDetails {
788788
}
789789

790790
export type UnwrapPlanTuple</* const */ TIn extends readonly Step[]> = {
791-
[Index in keyof TIn]: TIn[Index] extends Step<infer U> ? U : never;
791+
[Index in keyof TIn]: DataFromStep<TIn[Index]>;
792792
};
793793

794794
export type NotVariableValueNode = Exclude<ValueNode, VariableNode>;
@@ -809,14 +809,21 @@ export type Maybe<T> = T | null | undefined;
809809

810810
export * from "./planJSONInterfaces.js";
811811

812-
export interface AddDependencyOptions {
813-
step: Step;
812+
export interface AddDependencyOptions<TStep extends Step = Step> {
813+
step: TStep;
814814
skipDeduplication?: boolean;
815815
/** @defaultValue `FLAG_NULL` */
816816
acceptFlags?: ExecutionEntryFlags;
817-
onReject?: null | Error | undefined;
817+
onReject?: Maybe<Error>;
818818
nonUnaryMessage?: ($dependent: Step, $dependency: Step) => string;
819819
}
820+
821+
export interface DependencyOptions<TStep extends Step = Step> {
822+
step: TStep;
823+
acceptFlags: ExecutionEntryFlags;
824+
onReject: Maybe<Error>;
825+
}
826+
820827
/**
821828
* @internal
822829
*/

grafast/grafast/src/step.ts

Lines changed: 35 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import { getDebug } from "./global.js";
2020
import { inspect } from "./inspect.js";
2121
import type {
2222
AddDependencyOptions,
23+
DependencyOptions,
2324
ExecutionDetails,
2425
ExecutionEntryFlags,
2526
ExecutionResults,
@@ -36,7 +37,7 @@ import {
3637
ALL_FLAGS,
3738
DEFAULT_FORBIDDEN_FLAGS,
3839
} from "./interfaces.js";
39-
import type { __ItemStep } from "./steps/index.js";
40+
import type { __FlagStep, __ItemStep } from "./steps/index.js";
4041
import { stepADependsOnStepB, stepAMayDependOnStepB } from "./utils.js";
4142

4243
/**
@@ -167,8 +168,11 @@ export /* abstract */ class Step<TData = any> {
167168
/**
168169
* What execution entry flags we can't handle for the given indexed dependency
169170
* (default = this.defaultForbiddenFlags)
171+
*
172+
* @internal
170173
*/
171174
protected readonly dependencyForbiddenFlags: ReadonlyArray<ExecutionEntryFlags>;
175+
/** @internal */
172176
protected readonly dependencyOnReject: ReadonlyArray<
173177
Error | null | undefined
174178
>;
@@ -347,25 +351,49 @@ export /* abstract */ class Step<TData = any> {
347351
return this.layerPlan.getStep(id, this);
348352
}
349353

350-
protected getDepOptions(depId: number): AddDependencyOptions {
351-
const step = this.dependencies[depId];
354+
protected getDepOptions<TStep extends Step = Step>(
355+
depId: number,
356+
): DependencyOptions<TStep> {
357+
const step = this.dependencies[depId] as TStep;
352358
const forbiddenFlags = this.dependencyForbiddenFlags[depId];
353359
const onReject = this.dependencyOnReject[depId];
354360
const acceptFlags = ALL_FLAGS & ~forbiddenFlags;
355361
return { step, acceptFlags, onReject };
356362
}
357363

358-
protected getDep<T extends Step = Step>(_depId: number): T {
364+
protected getDep<TStep extends Step = Step>(
365+
_depId: number,
366+
): TStep | __FlagStep<TStep>;
367+
protected getDep<TStep extends Step = Step>(
368+
_depId: number,
369+
throwOnFlagged: true,
370+
): TStep;
371+
protected getDep<TStep extends Step = Step>(
372+
_depId: number,
373+
_throwOnFlagged = false,
374+
): TStep | __FlagStep<TStep> {
359375
// This gets replaced when `__FlagStep` is loaded. Were we on ESM we could
360376
// just put the code here, but since we're not we have to avoid the
361377
// circular dependency.
362378
throw new Error(`Grafast failed to load correctly`);
363379
}
364380

365-
protected maybeGetDep<T extends Step = Step>(
381+
protected maybeGetDep<TStep extends Step = Step>(
382+
depId: number | null | undefined,
383+
): TStep | __FlagStep<TStep> | null;
384+
protected maybeGetDep<TStep extends Step = Step>(
385+
depId: number | null | undefined,
386+
throwOnFlagged: true,
387+
): TStep | null;
388+
protected maybeGetDep<TStep extends Step = Step>(
366389
depId: number | null | undefined,
367-
): T | null {
368-
return depId == null ? null : this.getDep<T>(depId);
390+
throwOnFlagged = false,
391+
): TStep | __FlagStep<TStep> | null {
392+
return depId == null
393+
? null
394+
: throwOnFlagged
395+
? this.getDep<TStep>(depId, true)
396+
: this.getDep<TStep>(depId);
369397
}
370398

371399
protected getDepOrConstant<TData = any>(

grafast/grafast/src/steps/__flag.ts

Lines changed: 30 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { $$inhibit, flagError, SafeError } from "../error.js";
33
import { inspect } from "../inspect.js";
44
import type {
55
AddDependencyOptions,
6+
DataFromStep,
67
ExecutionDetails,
78
ExecutionEntryFlags,
89
GrafastResultsList,
@@ -89,7 +90,7 @@ function resolveTrapValue(tv: TrapValue): ResolvedTrapValue {
8990
}
9091
}
9192

92-
export class __FlagStep<TData> extends Step<TData> {
93+
export class __FlagStep<TStep extends Step> extends Step<DataFromStep<TStep>> {
9394
static $$export = {
9495
moduleName: "grafast",
9596
exportName: "__FlagStep",
@@ -102,7 +103,7 @@ export class __FlagStep<TData> extends Step<TData> {
102103
private valueForInhibited: ResolvedTrapValue;
103104
private valueForError: ResolvedTrapValue;
104105
private canBeInlined: boolean;
105-
constructor(step: Step, options: FlagStepOptions) {
106+
constructor(step: TStep, options: FlagStepOptions) {
106107
super();
107108
const {
108109
acceptFlags = DEFAULT_ACCEPT_FLAGS,
@@ -207,8 +208,8 @@ export class __FlagStep<TData> extends Step<TData> {
207208
}
208209

209210
public execute(
210-
_details: ExecutionDetails<[data: TData, cond?: boolean]>,
211-
): GrafastResultsList<TData> {
211+
_details: ExecutionDetails<[data: DataFromStep<TStep>, cond?: boolean]>,
212+
): GrafastResultsList<DataFromStep<TStep>> {
212213
throw new Error(`${this} not finalized?`);
213214
}
214215

@@ -222,7 +223,7 @@ export class __FlagStep<TData> extends Step<TData> {
222223
}
223224

224225
private fancyExecute(
225-
details: ExecutionDetails<[data: TData, cond?: boolean]>,
226+
details: ExecutionDetails<[data: DataFromStep<TStep>, cond?: boolean]>,
226227
): any {
227228
const dataEv = details.values[0]!;
228229
const condEv =
@@ -268,7 +269,7 @@ export class __FlagStep<TData> extends Step<TData> {
268269

269270
// Checks already performed via addDependency, just pass everything through. Should have been inlined!
270271
private passThroughExecute(
271-
details: ExecutionDetails<[data: TData, cond?: boolean]>,
272+
details: ExecutionDetails<[data: DataFromStep<TStep>, cond?: boolean]>,
272273
): any {
273274
const ev = details.values[0];
274275
if (ev.isBatch) {
@@ -284,11 +285,11 @@ export class __FlagStep<TData> extends Step<TData> {
284285
* Example use case: get user by id, but id is null: no need to fetch the user
285286
* since we know they won't exist.
286287
*/
287-
export function inhibitOnNull<T>(
288-
$step: Step<T>,
288+
export function inhibitOnNull<TStep extends Step>(
289+
$step: TStep,
289290
options?: { if?: FlagStepOptions["if"] },
290291
) {
291-
return new __FlagStep<T>($step, {
292+
return new __FlagStep<TStep>($step, {
292293
...options,
293294
acceptFlags: DEFAULT_ACCEPT_FLAGS & ~FLAG_NULL,
294295
});
@@ -299,39 +300,52 @@ export function inhibitOnNull<T>(
299300
* that represents a Post instead: throw error to tell user they've sent invalid
300301
* data.
301302
*/
302-
export function assertNotNull<T>(
303-
$step: Step<T>,
303+
export function assertNotNull<TStep extends Step>(
304+
$step: TStep,
304305
message: string,
305306
options?: { if?: FlagStepOptions["if"] },
306307
) {
307-
return new __FlagStep<T>($step, {
308+
return new __FlagStep<TStep>($step, {
308309
...options,
309310
acceptFlags: DEFAULT_ACCEPT_FLAGS & ~FLAG_NULL,
310311
onReject: new SafeError(message),
311312
});
312313
}
313314

314-
export function trap<T>(
315-
$step: Step<T>,
315+
export function trap<TStep extends Step>(
316+
$step: TStep,
316317
acceptFlags: ExecutionEntryFlags,
317318
options?: {
318319
valueForInhibited?: FlagStepOptions["valueForInhibited"];
319320
valueForError?: FlagStepOptions["valueForError"];
320321
if?: FlagStepOptions["if"];
321322
},
322323
) {
323-
return new __FlagStep<T>($step, {
324+
return new __FlagStep<TStep>($step, {
324325
...options,
325326
acceptFlags: (acceptFlags & TRAPPABLE_FLAGS) | FLAG_NULL,
326327
});
327328
}
328329

329330
// Have to overwrite the getDep method due to circular dependency
330-
(Step.prototype as any).getDep = function (this: Step, depId: number) {
331+
(Step.prototype as any).getDep = function (
332+
this: Step,
333+
depId: number,
334+
throwOnFlagged = false,
335+
) {
331336
const { step, acceptFlags, onReject } = this.getDepOptions(depId);
332337
if (acceptFlags === DEFAULT_ACCEPT_FLAGS && onReject == null) {
333338
return step;
334339
} else {
340+
if (throwOnFlagged) {
341+
throw new Error(
342+
`When retrieving dependency ${step} of ${this}, the dependency is flagged as ${digestAcceptFlags(
343+
acceptFlags,
344+
)}/onReject=${String(
345+
onReject,
346+
)}. Please use \`this.getDepOptions(depId)\` instead, and handle the flags`,
347+
);
348+
}
335349
// Return a __FlagStep around options.step so that all the options are preserved.
336350
return new __FlagStep(step, { acceptFlags, onReject });
337351
}

grafast/grafast/src/steps/__inputDynamicScalar.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ export class __InputDynamicScalarStep<
132132
/** @internal */
133133
eval(): TLeaf {
134134
const variableValues = this.variableNames.map((variableName, i) =>
135-
this.getDep<__TrackedValueStep>(i).eval(),
135+
this.getDep<__TrackedValueStep>(i, true).eval(),
136136
);
137137
return this.valueFromValues(variableValues);
138138
}

grafast/grafast/src/steps/__trackedValue.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,7 @@ export class __TrackedValueStep<
166166
}
167167

168168
private getValuePlan() {
169-
return this.getDep<__ValueStep<TData> | AccessStep<TData>>(0);
169+
return this.getDep<__ValueStep<TData> | AccessStep<TData>>(0, true);
170170
}
171171

172172
/**

grafast/grafast/src/steps/access.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -160,12 +160,12 @@ export class AccessStep<TData> extends UnbatchedStep<TData> {
160160
}
161161

162162
toStringMeta(): string {
163-
return `${chalk.bold.yellow(String(this.getDep(0).id))}.${this.path
164-
.map((p) => String(p))
165-
.join(".")}`;
163+
return `${chalk.bold.yellow(
164+
String(this.getDepOptions(0).step.id),
165+
)}.${this.path.map((p) => String(p)).join(".")}`;
166166
}
167167

168-
getParentStep(): Step {
168+
getParentStep() {
169169
return this.getDep(0);
170170
}
171171

0 commit comments

Comments
 (0)