Rindle

API index and search · Build metadata

Source snapshot

packages/client/src/operators.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// Named value-operators (`eq`/`gt`/`like`/…) + boolean combinators (`or`/`and`) for the2// query builder. Operators are VALUE-ONLY — the value type `V` is inferred from the value,3// and the FIELD is bound separately (by `where.<field>(…)` or `table.<field>(…)`), so4// `or`/`exists` need no closure (WASM-CLIENT-DESIGN.md §6).56import type { Condition, LitValue, SimpleOp } from "./ast.ts";78const PRED: unique symbol = Symbol("rindle.pred");910/** A value predicate (an operator applied to a value). `V` is a phantom for type-checking. */11export interface Pred<V> {12  readonly [PRED]: true;13  readonly op: SimpleOp;14  readonly value: LitValue;15  readonly __v?: V;16}1718function mk<V>(op: SimpleOp, value: LitValue): Pred<V> {19  return { [PRED]: true, op, value } as Pred<V>;20}2122export function isPred(x: unknown): x is Pred<unknown> {23  return typeof x === "object" && x !== null && (x as Record<symbol, unknown>)[PRED] === true;24}2526export const eq = <V>(v: V): Pred<V> => mk("=", v as LitValue);27export const ne = <V>(v: V): Pred<V> => mk("!=", v as LitValue);28export const gt = <V extends number | string>(v: V): Pred<V> => mk(">", v as LitValue);29export const ge = <V extends number | string>(v: V): Pred<V> => mk(">=", v as LitValue);30export const lt = <V extends number | string>(v: V): Pred<V> => mk("<", v as LitValue);31export const le = <V extends number | string>(v: V): Pred<V> => mk("<=", v as LitValue);32export const like = (pattern: string): Pred<string> => mk("LIKE", pattern);33export const notLike = (pattern: string): Pred<string> => mk("NOT LIKE", pattern);34export const ilike = (pattern: string): Pred<string> => mk("ILIKE", pattern);35export const notIlike = (pattern: string): Pred<string> => mk("NOT ILIKE", pattern);36export const inList = <V>(values: V[]): Pred<V> => mk("IN", values as LitValue);37export const notInList = <V>(values: V[]): Pred<V> => mk("NOT IN", values as LitValue);38export const is = <V>(v: V): Pred<V> => mk("IS", v as LitValue);39export const isNot = <V>(v: V): Pred<V> => mk("IS NOT", v as LitValue);40/** `IS NULL` — a field-agnostic null check. `V` is inferred from the field's expected `Arg<V>`41 *  (e.g. `where.signedAt(isNull())`), so it fits a column of any type without a cast. */42export const isNull = <V = never>(): Pred<V> => mk("IS", null);43/** `IS NOT NULL` — the negation of {@link isNull}; `V` is inferred from the field, like {@link isNull}. */44export const isNotNull = <V = never>(): Pred<V> => mk("IS NOT", null);4546/** A field argument: its typed predicate, or a bare value (bare = `eq` sugar). */47export type Arg<V> = Pred<V> | V;4849/** A condition over row `R`. The runtime value is the wire {@link Condition}; `R` is a50 *  phantom brand so a condition for one table can't be `.where()`d onto another. */51export type Cond<R> = Condition & { readonly __row?: R };5253/** Build a `simple` condition from a field name + (predicate | bare value). */54export function fieldCondition(field: string, arg: unknown): Condition {55  const op: SimpleOp = isPred(arg) ? arg.op : "=";56  const value: LitValue = isPred(arg) ? arg.value : (arg as LitValue);57  return {58    type: "simple",59    op,60    left: { type: "column", name: field },61    right: { type: "literal", value },62  };63}6465/** All children must hold. */66export function and<R>(...conds: Cond<R>[]): Cond<R> {67  return { type: "and", conditions: conds } as Cond<R>;68}6970/** At least one child must hold. */71export function or<R>(...conds: Cond<R>[]): Cond<R> {72  return { type: "or", conditions: conds } as Cond<R>;73}74