Rindle

API index and search · Build metadata

Source snapshot

packages/client/src/ast.ts

Source revision 05d0bf2c2e56 · build details
Source revision: 05d0bf2c2e56.
TypeScript input SHA-256: aabe6cfcc4172b870d5e272142958e9ea8d8784c2aa23133156e5a7ee633318e
Generated 2026-09-04T23:58:25.590Z with TypeScript 6.0.3. Public TypeScript checks and declaration emit passed. Package runtime tests are separate.
1// The Zero-wire query AST — the exact JSON shape the Rust `Ast` deserializes2// (src/ast.rs). The builder emits these; the wasm `Db.query` (and a remote server) parse3// them. camelCase keys, `type`-tagged unions, ops as SQL-ish strings, untagged literals.45export type Dir = "asc" | "desc";67/** One `(field, direction)` ordering — serializes as the 2-tuple `["id", "asc"]`. */8export type OrderPart = [field: string, dir: Dir];910/** An untagged literal (`null | bool | number | string | array`). Numbers are one f64. */11export type LitValue = null | boolean | number | string | LitValue[];1213/** A column reference or a literal — `type`-tagged. */14export type ValuePosition =15  | { type: "column"; name: string }16  | { type: "literal"; value: LitValue };1718/** The wire comparison operators (exact strings, `src/ast.rs` `Op`). */19export type SimpleOp =20  | "="21  | "!="22  | "<"23  | "<="24  | ">"25  | ">="26  | "IS"27  | "IS NOT"28  | "LIKE"29  | "NOT LIKE"30  | "ILIKE"31  | "NOT ILIKE"32  | "IN"33  | "NOT IN";3435export type ExistsOp = "EXISTS" | "NOT EXISTS";3637/** The filter tree — `type`-tagged; recursive. There is no generic NOT node (negation is38 *  via the negated operators and `NOT EXISTS`, matching `src/ast.rs` `Condition`). */39export type Condition =40  | { type: "simple"; op: SimpleOp; left: ValuePosition; right: ValuePosition }41  | { type: "and"; conditions: Condition[] }42  | { type: "or"; conditions: Condition[] }43  | { type: "correlatedSubquery"; related: CorrelatedSubquery; op: ExistsOp; flip?: boolean; scalar?: boolean };4445export interface Correlation {46  parentField: string[];47  childField: string[];48}4950/** A paging lower bound (`Bound`, `src/ast.rs`). `row` is a *partial* wire row — the bound51 *  columns by name (only the sort columns are read by the engine's `Skip` comparator).52 *  `exclusive` ⇒ start *after* the bound row (`Basis::After`); else *at* it (`Basis::At`). */53export interface Bound {54  row: Record<string, LitValue>;55  exclusive: boolean;56}5758export interface CorrelatedSubquery {59  correlation: Correlation;60  subquery: Ast;61  system?: "client" | "permissions" | "test";62}6364/** An aggregate over a (correlated) subquery's rows (`REDUCE-DESIGN.md`). v1: `count(*)`.65 *  Set on a `related` subquery (`Ast.aggregate`), it marks that relationship a count66 *  aggregate the builder lowers to a scalar-projected singular relationship (§9). */67export type Aggregate = "count";6869/** The query AST. `table` is the only required field; the builder omits empty/false fields70 *  (matching the Rust `skip_serializing_if`), which the deserializer treats as absent. */71export interface Ast {72  table: string;73  alias?: string;74  /** Projection (PROJECTION-SUPPORT-DESIGN.md §6). Absent ⇒ select all columns; present ⇒75   *  project to just these (drives what syncs + what the view reports). Serializes only when76   *  set, matching the Rust `Ast.select`'s `skip_serializing_if`. */77  select?: string[];78  where?: Condition;79  related?: CorrelatedSubquery[];80  start?: Bound;81  limit?: number;82  one?: boolean;83  /** Aggregate this (sub)query's rows instead of materializing them (`REDUCE-DESIGN.md`84   *  §9). `count` on a `related` subquery surfaces a scalar `commentCount` field; the85   *  builder lowers it to a scalar-projected singular relationship. Absent ⇒ ordinary rows. */86  aggregate?: Aggregate;87  /** The {@link Ast.aggregate} value is **precomputed** — supplied as rows of a (synthetic)88   *  source table rather than reduced from child rows. Set by the normalized client's AST89   *  rewrite (`AGGREGATE-SYNC-DESIGN.md` §3.3) so the local engine reads the server's count90   *  with a plain singular join + the same projection instead of a `reduce`. Only meaningful91   *  with `aggregate`; absent ⇒ `false`. */92  aggregatePrecomputed?: boolean;93  /** Top-level `GROUP BY` columns (names), meaningful only alongside a root {@link Ast.aggregate}94   *  (`REDUCE-DESIGN.md` §8). Empty + `aggregate` set ⇒ a **global** aggregate (one `[count]` row);95   *  non-empty ⇒ one `[group…, count]` row per distinct value-tuple. Distinct from a relationship96   *  aggregate's implicit grouping (the correlation child key). Absent on the wire ⇒ empty. */97  groupBy?: string[];98  /** `HAVING` — a filter over the **post-aggregation** rows of a root {@link Ast.aggregate}99   *  (`REDUCE-DESIGN.md` §4: a filter directly above the `reduce`). Its condition addresses the100   *  aggregate's *output* columns — the {@link Ast.groupBy} columns and the synthetic `count`101   *  column — not base-table columns (those go in {@link Ast.where}, which filters rows *below* the102   *  reduce). Absent ⇒ no post-aggregation filter. */103  having?: Condition;104  orderBy?: OrderPart[];105}106