API index and search · Build metadata
Source snapshot
packages/query-compiler/src/dialect.ts
1// The dialect seam (§6.1). The walker is dialect-independent; only these leaves differ2// between SQLite and Postgres: the Postgres leaf carries the §6.2 `::text::<type>` casts and3// explicit NULLS ordering; the SQLite leaf binds natives with NO casts (the canonical store4// needs no reconciliation — DAEMON-INTERACTIVE-TXN-DESIGN.md §5.4).56import type { Dir } from "./ast.ts";7import type { ColumnType } from "./catalog.ts";89/** A scalar value bindable as a parameter (an array filter value is split into scalars). */10export type LitScalar = null | boolean | number | string;1112export interface Dialect {13 readonly name: "postgres" | "sqlite";1415 /** `json_object('k', v, …)` | `jsonb_build_object('k', v, …)`. `parts` are the flat16 * `'key', valueExpr` fragments, in order. */17 objectBuild(parts: string[]): string;1819 /** The array aggregate over `elem` with `orderSql` (e.g. ` ORDER BY __o0 ASC`) inside:20 * `json_group_array(elem ORDER BY …)` | `jsonb_agg(elem ORDER BY …)`. */21 groupArray(elem: string, orderSql: string): string;2223 /** The empty-array default for the `COALESCE` wrapper: `'[]'` | `'[]'::jsonb`. */24 readonly emptyArray: string;2526 /** Re-assert the JSON subtype on a value round-tripped through a subquery's `AS` column27 * (`json(x)` in SQLite; identity in Postgres, where `jsonb` is a real type). */28 reassertJson(x: string): string;2930 /** The truthy/falsy constants for empty `AND`/`OR` folding and boolean keyword positions:31 * `1`/`0` | `TRUE`/`FALSE`. */32 readonly trueLit: string;33 readonly falseLit: string;3435 /** An `ORDER BY` direction with the engine's null-low ordering made explicit where the36 * dialect default differs (§8): SQLite is null-low by default (`ASC`/`DESC`); Postgres's37 * default is the opposite, so it must emit `ASC NULLS FIRST` / `DESC NULLS LAST`. */38 orderDir(dir: Dir): string;3940 /** Project a stored column into the value model's representation for the result JSON.41 * Identity in SQLite; the outbound half of §6.2 in Postgres (e.g. timestamptz → epoch-ms). */42 projectColumn(colRef: string, col: ColumnType | null): string;4344 /** Bind a scalar filter/paging value as a parameter: push onto `params`, return the45 * placeholder SQL. `col` is the compared column's type when known (drives the Postgres46 * `::text::<type>` casts, §6.2); `null` ⇒ infer from the JS type. SQLite ignores `col`47 * and `isComparison` — it binds natives. */48 bindValue(params: unknown[], value: LitScalar, col: ColumnType | null, isComparison: boolean): string;4950 /** Double-quote an identifier, doubling embedded `"`. Identical across dialects (kept on51 * the seam for uniformity). */52 quoteIdent(name: string): string;53}5455function quoteIdent(name: string): string {56 return `"${name.replace(/"/g, '""')}"`;57}5859/**60 * The SQLite dialect — the daemon backend's session-read target (DAEMON-INTERACTIVE-TXN §5.4)61 * and the offline differential oracle (§9). It binds native values as parameters (no62 * `::text::<type>` casts — SQLite is the canonical store, so there is no driver seam to pin63 * and no second representation to reconcile), relies on SQLite's null-low default ordering64 * (which matches the engine's `null < everything`), and re-asserts the `json()` subtype where65 * objects round-trip through a subquery column. Matches `rindle-d2s`'s raw SQL shapes so the66 * two agree modulo parameterization; the executing connection must run67 * `PRAGMA case_sensitive_like = ON` (every daemon cluster connection does — `open_wal2`).68 */69export const sqliteDialect: Dialect = {70 name: "sqlite",71 objectBuild: (parts) => `json_object(${parts.join(", ")})`,72 groupArray: (elem, orderSql) => `json_group_array(${elem}${orderSql})`,73 emptyArray: "'[]'",74 reassertJson: (x) => `json(${x})`,75 trueLit: "1",76 falseLit: "0",77 orderDir: (dir) => (dir === "asc" ? "ASC" : "DESC"),78 projectColumn: (colRef) => colRef,79 bindValue: (params, value) => {80 // SQLite has no boolean type; its driver binds 1/0. Everything else binds natively.81 params.push(typeof value === "boolean" ? (value ? 1 : 0) : value);82 return "?";83 },84 quoteIdent,85};86