TypeDrop

2026-04-17 Challenge

2026-04-17 Hard

Typed Query Plan Builder

You're building the query planning layer for an in-memory analytics engine. Raw query descriptors arrive as unknown JSON from a REST API; your planner must validate them, compile them into a strongly-typed execution plan through a composable operator pipeline, execute each operator with typed intermediate results, and surface a discriminated-union outcome per stage — with zero `any`.

Goals

  • Define `OperatorExecutor<O>` as a generic function type constrained to `PlanOperator` variants, and `ExecutorRegistry` as a mapped type using `Extract` to pair each `OperatorKind` key with its correctly-typed executor.
  • Implement `validateQuery` to safely narrow `unknown` input into a `ValidatedQuery`, branding all field and table name strings, and returning typed `QueryError` discriminants on every violation.
  • Implement `buildPlan` to compile a `ValidatedQuery` into an ordered `ExecutionPlan`, enforcing the groupBy-select compatibility rule and emitting only the operators that apply.
  • Implement `executePlan` to fold over the plan's operator array, dispatch each operator through the `ExecutorRegistry`, collect per-stage metrics, and short-circuit on the first execution error.
challenge.ts
// Key types and main orchestrator signature

type OperatorExecutor<O extends PlanOperator> =
  (operator: O, rows: ReadonlyArray<Row>, registry: TableRegistry)
    => Result<ReadonlyArray<Row>, QueryError>;

type ExecutorRegistry = {
  [K in OperatorKind]: OperatorExecutor<Extract<PlanOperator, { kind: K }>>;
};

// Discriminated operator union (one variant shown):
interface FilterOperatorNode { readonly kind: "filter"; readonly clause: FilterClause; }
interface ScanOperator       { readonly kind: "scan";   readonly table: TableName; }
// … + project | groupBy | sort | limit

// Top-level orchestrator — compose all four stages:
function runQuery(
  raw: unknown,
  registry: TableRegistry
): Result<QueryReport, QueryError>;
Hints (click to reveal)

Hints

  • For `ExecutorRegistry`, the mapped type key `K` extends `OperatorKind` — use `Extract<PlanOperator, { kind: K }>` as the type argument to `OperatorExecutor<…>` so each executor is narrowed to its exact operator variant.
  • Inside `executePlan`, a `switch (operator.kind)` over the discriminant lets TypeScript narrow `operator` to the specific variant, allowing you to index `executors[operator.kind]` with the correctly-typed argument without any cast.
  • Brand `FieldName` and `TableName` by writing a runtime-validated helper (e.g. `toFieldName(s: string): FieldName`) that asserts the non-empty invariant before returning `s as FieldName` — keep the cast inside the helper so the rest of the code stays assertion-free.

Or clone locally

git clone -b challenge/2026-04-17 https://github.com/niltonheck/typedrop.git