API index and search · Build metadata
Supporting declarations
packages/client/src/query.ts. These declarations explain referenced types. Only package-page symbols are package exports.
FieldFn
type FieldFn<C extends AnyCols, K extends keyof C, Rels, One extends boolean, Sel extends string, LocalRels> = (arg: Arg<ColT<C[K]>>) => Query<C, Rels, One, Sel, LocalRels>;WhereProxy
/** `where.closed(false)`, `where.priority(gt(3))`. */
type WhereProxy<C extends AnyCols, Rels, One extends boolean, Sel extends string, LocalRels> = {
[K in keyof C]: FieldFn<C, K, Rels, One, Sel, LocalRels>;
};WhereSugar
/** `whereClosed(false)`, `wherePriority(gt(3))`. */
type WhereSugar<C extends AnyCols, Rels, One extends boolean, Sel extends string, LocalRels> = {
[K in keyof C as `where${Capitalize<string & K>}`]: FieldFn<C, K, Rels, One, Sel, LocalRels>;
};MaterializedView
/** What `materialize()` returns: singular (`R | null`) for a top-level `.one()`, else plural. */
type MaterializedView<R, One extends boolean> = One extends true ? SingularArrayView<R> : ArrayView<R>;Projected
/**
* The result row type of a projection (masking, FRAGMENT-COMPOSITION-DESIGN.md §6 / §10.6).
* `Sel` is the union of columns named via `select(...)`. With nothing selected (`Sel = never`)
* it stays the full {@link RowOf} — the "no `select` ⇒ all columns" convention, kept and made
* type-honest. Once any column is selected, the row is **masked** to exactly those columns, so a
* component (its fragment) can read only what it declared. `Pick` only ever *removes* fields, so
* narrowing is always sound versus a runtime row that may still carry more.
*/
type Projected<C extends AnyCols, Sel extends string> = [
Sel
] extends [
never
] ? RowOf<C> : Pick<RowOf<C>, Sel & keyof C>;AggAcc
/**
* The accumulating result row of a top-level aggregate (REDUCE-DESIGN.md §8). `Agg` is `false`
* until {@link QueryBase.count}/{@link QueryBase.groupBy} reshapes the query; then it is the
* group-by columns intersected with the synthetic `{ count: number }`. {@link AggAcc} treats the
* `false` state as `{}` so the intersections in `count`/`groupBy` compose either way.
*/
type AggAcc<Agg> = [
Agg
] extends [
false
] ? {} : Agg;HavingProxy
/** `having`'s field binder: one accessor per aggregate-OUTPUT column (the group-by columns plus the
* synthetic numeric `count`), each producing a {@link Cond} over that aggregate row. It is the only
* way to name `count` in a predicate (it lives on no base table); compose several with `and`/`or`. */
type HavingProxy<Row> = {
[K in keyof Row & string]: (arg: Arg<Row[K]>) => Cond<Row>;
};AggregateAlias
/** The `countAs` relationship aliases of a query — the {@link Rels} keys whose value is the scalar
* `number` a count aggregate surfaces. These are the only aliases {@link QueryBase.having}'s
* parent-by-child-aggregate overload accepts (a plain `sub` alias carries a row object, not a
* number, so it is rejected). */
type AggregateAlias<Rels> = {
[K in keyof Rels]: Rels[K] extends number ? K & string : never;
}[keyof Rels];ResultRow
/** What a query materializes: the post-aggregation row once reshaped by {@link QueryBase.count}
* (`Agg`), else the projected base row plus its relationship values. */
type ResultRow<C extends AnyCols, Rels, Sel extends string, Agg> = [
Agg
] extends [
false
] ? Projected<C, Sel> & Rels : Agg;FragmentEdge
type FragmentEdge<C extends AnyCols, Rels, Sel extends string, LocalRels> = (q: Query<C, Rels, false, Sel, LocalRels>) => Query<C, Rels, boolean, Sel, LocalRels>;QueryBase
interface QueryBase<C extends AnyCols, Rels, One extends boolean, Sel extends string, LocalRels, Agg = false> {
/** Present when this local query came from `defineQuery`; used as the remote identity. */
readonly name?: string;
/** Present when this local query came from `defineQuery`; sent with `name` upstream. */
readonly args?: unknown;
/** Present when this local query came from a realtime-labeled `defineQuery`
* (RINDLE-REALTIME-QUERY-ENABLEMENT §2.1). Declaration metadata only — it never joins the
* wire identity and never changes the AST. */
readonly realtime?: RealtimeQueryLabel;
/** Condition form — consumes `or()`/`and()`/`exists()`/field conditions (AND-ed across calls).
* Filters over the FULL column set (`RowOf<C>`), independent of what's `select`ed/masked. */
where(cond: Cond<RowOf<C>>): Query<C, Rels, One, Sel, LocalRels>;
orderBy<K extends keyof C>(col: K, dir: Dir): Query<C, Rels, One, Sel, LocalRels>;
/** Project a subset of columns (PROJECTION-SUPPORT-DESIGN.md §6, masking §6/§10.6). Chainable
* (each call unions into `Sel`); omit to select all. Drives what the server syncs, what the
* view reports, AND — once any column is named — narrows the result row TYPE to exactly the
* selection (masking). `where`/`orderBy`/`start`/`sub` still see the full column set. */
select<K extends keyof C & string>(...cols: K[]): Query<C, Rels, One, Sel | K, LocalRels>;
limit(n: number): Query<C, Rels, One, Sel, LocalRels>;
/** Cursor paging: start at (or, with `exclusive`, after) the partial `cursor` row over the
* sort columns. Lowers to a `Skip` in the engine. */
start(cursor: Partial<RowOf<C>>, opts?: {
exclusive?: boolean;
}): Query<C, Rels, One, Sel, LocalRels>;
/** Return a single row: `materialize()` yields a {@link SingularArrayView} (`data: R | null`)
* and the engine caps the query to `limit = 1`. */
one(): Query<C, Rels, true, Sel, LocalRels>;
/** **Merge** a {@link Fragment} into THIS node — Relay's "spread on the same type" (§5). The
* fragment must be over the same table (enforced in the result type: a fragment over a different
* table yields `never`, plus a runtime throw). Unions the projection (`Sel | FSel`), folds in the
* fragment's nested relationships (`Rels & FRels`), and merges any same-`alias` edge recursively
* — canonically, so `include` order doesn't matter (§10.5). Two fragments that spread the same
* alias with a conflicting row-set (correlation/where/orderBy/…) **throw** (§10.2); an included
* fragment may **not** add a root `where`/`orderBy`/`limit` (§10.3). This is also the single-shot
* way to ROOT a fragment onto a base query (`queries.issue.where.id(x).include(IssueCard)`) — the
* loader's composed root — equivalent to applying the fragment, but canonicalized.
*
* The fragment's columns are a *separate* inferred parameter `FC` (not the class `C`) so that
* `include` keeps `C` out of any contravariant position — preserving `Query<Concrete>`'s
* assignability to `Query<AnyCols>` (needed by `Store<ColsMap>`/`QueryRoot`). Same-table is then
* checked as the mutual-assignability of `C` and `FC` in the return type. */
include<FC extends AnyCols, FRels = {}, FSel extends string = never, FLocalRels = FRels>(fragment: Fragment<FC, FRels, FSel, FLocalRels>): [
C
] extends [
FC
] ? ([
FC
] extends [
C
] ? Query<C, Rels & FRels, One, Sel | FSel, LocalRels & FLocalRels> : never) : never;
/** Nest a child fragment as an opaque local-read ref. The coverage query still composes the
* child's full AST at runtime; the React-facing fragment data exposes only refs at this
* boundary so the child component owns its local subscription. */
sub<A extends string, CC extends AnyCols, CRels = {}, CSel extends string = never, CLocalRels = CRels, F extends Fragment<CC, CRels, CSel, CLocalRels> = Fragment<CC, CRels, CSel, CLocalRels>>(alias: A, child: TableLike<CC>, corr: {
parent: Array<keyof C & string>;
child: Array<keyof CC & string>;
}, build: F, edge: FragmentEdge<CC, CRels, CSel, CLocalRels>): Query<C, Rels & {
[P in A]: Array<Projected<CC, CSel> & CRels>;
}, One, Sel, LocalRels & {
[P in A]: Array<FragmentRef<F>>;
}>;
sub<A extends string, CC extends AnyCols, CRels = {}, CSel extends string = never, CLocalRels = CRels, F extends Fragment<CC, CRels, CSel, CLocalRels> = Fragment<CC, CRels, CSel, CLocalRels>>(alias: A, child: TableLike<CC>, corr: {
parent: Array<keyof C & string>;
child: Array<keyof CC & string>;
}, build: F): Query<C, Rels & {
[P in A]: Array<Projected<CC, CSel> & CRels>;
}, One, Sel, LocalRels & {
[P in A]: Array<FragmentRef<F>>;
}>;
/** Relationship-value form of the fragment-ref overload above. */
sub<A extends string, CC extends AnyCols, CRels = {}, CSel extends string = never, CLocalRels = CRels, F extends Fragment<CC, CRels, CSel, CLocalRels> = Fragment<CC, CRels, CSel, CLocalRels>>(alias: A, relationship: Relationship<C, CC>, build: F, edge: FragmentEdge<CC, CRels, CSel, CLocalRels>): Query<C, Rels & {
[P in A]: Array<Projected<CC, CSel> & CRels>;
}, One, Sel, LocalRels & {
[P in A]: Array<FragmentRef<F>>;
}>;
/** Relationship-value form of the fragment-ref overload above. */
sub<A extends string, CC extends AnyCols, CRels = {}, CSel extends string = never, CLocalRels = CRels, F extends Fragment<CC, CRels, CSel, CLocalRels> = Fragment<CC, CRels, CSel, CLocalRels>>(alias: A, relationship: Relationship<C, CC>, build: F): Query<C, Rels & {
[P in A]: Array<Projected<CC, CSel> & CRels>;
}, One, Sel, LocalRels & {
[P in A]: Array<FragmentRef<F>>;
}>;
/** Nest a child by EXPLICIT correlation (no schema relationship). `alias` is the result key.
* The child's own projection (`CSel`) masks the nested row, so a fragment spread here
* contributes exactly the columns it declared. */
sub<A extends string, CC extends AnyCols, CRels = {}, CSel extends string = never>(alias: A, child: TableLike<CC>, corr: {
parent: Array<keyof C & string>;
child: Array<keyof CC & string>;
}, build?: (q: Query<CC>) => Query<CC, CRels, boolean, CSel>): Query<C, Rels & {
[P in A]: Array<Projected<CC, CSel> & CRels>;
}, One, Sel, LocalRels & {
[P in A]: Array<Projected<CC, CSel> & CRels>;
}>;
/** Nest a child by a named {@link Relationship} (`rel(parent, child, {...})`) — the correlation comes
* from the relationship, so no `{ parent, child }` keys are restated. The relationship must belong to
* THIS table (its parent columns are checked against `C`). `alias` is still the result key. */
sub<A extends string, CC extends AnyCols, CRels = {}, CSel extends string = never>(alias: A, relationship: Relationship<C, CC>, build?: (q: Query<CC>) => Query<CC, CRels, boolean, CSel>): Query<C, Rels & {
[P in A]: Array<Projected<CC, CSel> & CRels>;
}, One, Sel, LocalRels & {
[P in A]: Array<Projected<CC, CSel> & CRels>;
}>;
/** Add a **relationship aggregate** — `issue.countAs("commentCount", comment, …)`
* (`REDUCE-DESIGN.md` §9). Like {@link sub} (explicit correlation, optional child
* `build` for a filtered `count(child WHERE …)`), but the relationship surfaces a single
* scalar `count(*)` of the correlated child rows named `alias` — so the result key is a
* `number`, not an array; an empty (childless) parent reads `0`. */
countAs<A extends string, CC extends AnyCols>(alias: A, child: TableLike<CC>, corr: {
parent: Array<keyof C & string>;
child: Array<keyof CC & string>;
}, build?: (q: Query<CC>) => Query<CC, unknown>): Query<C, Rels & {
[P in A]: number;
}, One, Sel, LocalRels & {
[P in A]: number;
}>;
/** `countAs` by a named {@link Relationship} — like the explicit form, but the correlation comes from
* `rel(...)` instead of being restated. */
countAs<A extends string, CC extends AnyCols>(alias: A, relationship: Relationship<C, CC>, build?: (q: Query<CC>) => Query<CC, unknown>): Query<C, Rels & {
[P in A]: number;
}, One, Sel, LocalRels & {
[P in A]: number;
}>;
/** Reshape this query into a top-level `count(*)` aggregate (`REDUCE-DESIGN.md` §8) — the SQL
* `SELECT count(*) FROM table [GROUP BY …] [HAVING …]`. Without {@link groupBy} it is a GLOBAL
* count (one `{ count }` row, value `0` even on empty input); with it, one `{ …group, count }`
* row per distinct group. The result row becomes the aggregate's OUTPUT — the group-by columns
* plus a numeric `count` — so chain {@link having} to filter it. Distinct from {@link countAs}
* (a child-relationship scalar attached to the parent row); this reshapes the query ITSELF. The
* engine rejects pairing a root aggregate with `select`/`sub`/`countAs`/`orderBy`/`limit`/`one`. */
count(): Query<C, Rels, One, Sel, LocalRels, AggAcc<Agg> & {
count: number;
}>;
/** Add a top-level `GROUP BY` column (chain for a compound key); only meaningful with
* {@link count}. Each grouped column joins the aggregate result row, keyed + sorted by the
* group key. */
groupBy<K extends keyof C & string>(col: K): Query<C, Rels, One, Sel, LocalRels, AggAcc<Agg> & Pick<RowOf<C>, K>>;
/** `HAVING (…)` — filter the **post-aggregation** rows of a {@link count} query (`REDUCE-DESIGN.md`
* §4: a filter directly above the reduce). `build` receives a field binder over the aggregate's
* OUTPUT columns — the {@link groupBy} columns and the synthetic `count` — and returns a
* {@link Cond}; compose several with `and`/`or`. E.g.
* `.groupBy("status").count().having((h) => h.count(gt(3)))`. Distinct from {@link where}, which
* filters base rows BELOW the reduce. */
having(build: (h: HavingProxy<AggAcc<Agg>>) => Cond<AggAcc<Agg>>): Query<C, Rels, One, Sel, LocalRels, Agg>;
/** `HAVING count(child) <op> n` — filter THIS parent by a child relationship aggregate's count
* (`PARENT-AGGREGATE-FILTER-DESIGN.md`). `alias` must name a {@link countAs} relationship already
* on this query; this drops parents whose child count fails `<op> val`, maintained incrementally
* (a child add/remove crossing the threshold adds/removes the parent). The display `countAs` is
* untouched — a survivor still shows its real count. Distinct from the {@link having} overload
* above, which filters a top-level {@link count}'s own output rows.
*
* **v1: high-pass predicates only** — predicates *false* at count 0 (`>`, `>=`/`=`/`!=` for
* `n ≥ 1`). A childless parent forms no group, so the engine rejects (at build) a predicate *true*
* at count 0 (`<=`, `< n` for `n ≥ 1`, `= 0`, `>= 0`); those need row-widening (deferred). */
having<A extends AggregateAlias<Rels>>(alias: A, op: SimpleOp, val: number): Query<C, Rels, One, Sel, LocalRels, Agg>;
/** The compiled Zero-wire AST (what a backend's `query` consumes). */
ast(): Ast;
/** Materialize into a live, typed view. Wired by the Store/backend. A top-level `.one()`
* yields a {@link SingularArrayView}; otherwise an {@link ArrayView}. The row is the aggregate
* output once {@link count} reshaped the query, else masked to the projection ({@link Projected})
* — full {@link RowOf} until a column is `select`ed. */
materialize(): MaterializedView<ResultRow<C, Rels, Sel, Agg>, One>;
}Query
export type Query<C extends AnyCols, Rels = {}, One extends boolean = false, Sel extends string = never, LocalRels = Rels, Agg = false> = Omit<QueryBase<C, Rels, One, Sel, LocalRels, Agg>, "where"> & {
where: QueryBase<C, Rels, One, Sel, LocalRels, Agg>["where"] & WhereProxy<C, Rels, One, Sel, LocalRels>;
} & WhereSugar<C, Rels, One, Sel, LocalRels>;AnyQuery
export type AnyQuery = Query<any, any, any, any, any, any>;QueryLocalData
export type QueryLocalData<Q extends AnyQuery> = Q extends Query<infer C, any, infer One, infer Sel, infer LocalRels, infer Agg> ? [
Agg
] extends [
false
] ? One extends true ? (Projected<C, Sel> & LocalRels) | null : readonly (Projected<C, Sel> & LocalRels)[] : readonly Agg[] : never;QueryValidator
/** Turn raw, UNTRUSTED wire args into the canonical, typed args a query is built from. Its return
* type IS the query's args type — written once, it flows to both the client call signature and the
* `build` step, so there's no second place to restate the shape. */
export type QueryValidator<Args> = (rawArgs: unknown) => Args;QueryBuilder
/**
* Build a `Query` (an `Ast` constructor) from already-validated args, plus an optional CONTEXT — the
* authenticated principal the query is scoped to. `Ctx` is **off-wire**: the client passes its own
* session ctx at the callsite, the server injects the AUTHORITATIVE ctx ({@link NamedQuery.resolve}
* via `registerQueries`), and the wire still carries only `name` + args. Both tiers run the same
* `build`, so whenever their ctx agrees the AST is byte-identical — and a client can never spoof it,
* since the server re-derives ctx from its trusted session and ignores anything the client claimed.
*
* The ctx is a *tuple* so a query opts into it by how it types `build`'s second parameter — and that
* shape becomes the call signature verbatim:
* - `(args) => Q` — no ctx (`q(args)`).
* - `(args, ctx: C) => Q` — ctx REQUIRED (`q(args, ctx)`); for always-authenticated queries.
* - `(args, ctx?: C) => Q` — ctx OPTIONAL (`q(args)` or `q(args, ctx)`); sound only when "no ctx"
* is a real, SYMMETRIC state — i.e. the build yields the SAME broad AST whether ctx is absent or
* present-with-no-user (anonymous / SSR), since the server always forwards a ctx (possibly
* anonymous). Otherwise type ctx required so the type catches an omitted ctx.
*/
export type QueryBuilder<Args, Q extends AnyQuery, Ctx extends readonly unknown[] = [
]> = (args: Args, ...ctx: Ctx) => Q;RealtimeQueryLabel
/**
* The realtime LABEL a named query may declare (RINDLE-REALTIME-QUERY-ENABLEMENT-DESIGN.md §2.1):
* which api-server room PROFILE the query wants to be served from, and how the query's args map
* to that profile's key args. This is the DECLARATION only — the serve decision (covering proof,
* lease routing) is the server's, and the final room key is minted server-side by the profile's
* own `key` under authoritative ctx, so a label can never place a query in a room the server
* didn't derive itself. Both tiers import the SAME `defineQuery` value, so they always agree
* *which profile* a query belongs to.
*/
export interface RealtimeQueryLabel<Args = any> {
/** The room profile name — must match a `realtime.rooms` key on the api-server (validated
* loudly at `createRindleApiServer` construction). May not contain `/` (the wire room-key
* delimiter). */
readonly room: string;
/** Map the query's VALIDATED args to the profile's key args (what the server feeds the
* profile's `key(args)`). Identity when omitted. Must be pure — both tiers may run it. */
readonly args?: (queryArgs: Args) => unknown;
}DefineQueryOptions
/** Options for {@link defineQuery}. */
export interface DefineQueryOptions<Args = any> {
/** Declare this query realtime-eligible — see {@link RealtimeQueryLabel}. */
realtime?: RealtimeQueryLabel<Args>;
}NamedQuery
/**
* A single, co-located NAMED query (see {@link defineQuery}). It is:
* - **callable on the client** — `q(args, ctx?)` validates + builds + stamps the result with its
* remote subscription identity (`name` + args — NOT ctx), so a component that imports it always
* SYNCS. There is no unstamped builder to import by accident.
* - **registerable on the server** — it carries its `queryName` and a `resolve` that re-runs the
* SAME validator on untrusted wire args and builds the AUTHORITATIVE `Query` from the server's
* own ctx ({@link registerQueries `registerQueries`} in `@rindle/api-server`).
*
* `Ctx` is the ctx parameter list mirrored from `build` — `[]`, `[ctx: C]`, or `[ctx?: C]`. It is
* never part of the wire identity.
*/
export interface NamedQuery<Args, Ctx extends readonly unknown[], Q extends AnyQuery> {
(args: Args, ...ctx: Ctx): Q;
/** The wire identity. The daemon leases by this name; client and server MUST agree on it — which
* they do, because both sides import the SAME `defineQuery` value. */
readonly queryName: string;
/** The §2.1 realtime label, when this query was defined with one ({@link DefineQueryOptions}).
* Absent on unlabeled queries. Carried onto the stamped built Query too, and preserved through
* `registerQueries` on the server. */
readonly realtime?: RealtimeQueryLabel<Args>;
/** Server-side: validate raw wire args, then build the authoritative `Query` from the server's
* authoritative ctx (forwarded by `registerQueries`). */
resolve(rawArgs: unknown, ...ctx: Ctx): Q;
}defineQuery
/**
* Define ONE co-located, named query. Keep it next to the component that reads it (a `*.queries.ts`
* file), so a query lives where its fragments and its component live.
*
* The returned value is callable on the client (it stamps its result with `name` + args, so the
* subscription SYNCS) and registerable on the server ({@link registerQueries}). The optional
* `validate` step turns untrusted wire args into the canonical args type — and that type flows to
* both the call signature and `build`, so the shape is written exactly once. `validate` runs on
* BOTH tiers (it builds the byte-identical authoritative AST on the server, and guards + guarantees
* the same AST on the client). If the server must DIVERGE from the client, define a second
* `defineQuery` with the same `name` for the server and register that one instead.
*
* `build` may take a second CONTEXT parameter (see {@link QueryBuilder}). Context is off-wire: the
* client passes its session ctx at the callsite, the server injects its authoritative ctx — so a
* per-user query stays symmetric without ever trusting (or transmitting) a client-supplied identity.
*
* ```ts
* // recentComments({ limit }) — validated, no ctx, byte-identical on both tiers
* export const recentCommentsQuery = defineQuery(
* "recentComments",
* (raw): { limit: number } => ({ limit: validateFeedLimit(raw) }),
* ({ limit }) => q.comment.orderBy("createdAt", "desc").limit(limit).include(FeedItemFragment),
* );
*
* // myIssues({ limit }, ctx) — ctx-scoped; the wire still carries only { limit }
* export const myIssuesQuery = defineQuery(
* "myIssues",
* (raw): { limit: number } => ({ limit: validateLimit(raw) }),
* ({ limit }, ctx: { user: string }) => q.issue.where.ownerId(ctx.user).limit(limit),
* );
* // client: myIssuesQuery({ limit: 20 }, { user: currentUser() })
* ```
*/
export declare function defineQuery<Q extends AnyQuery>(name: string, build: () => Q, options?: DefineQueryOptions<void>): NamedQuery<void, [
], Q>;
export declare function defineQuery<Args, Ctx extends readonly unknown[], Q extends AnyQuery>(name: string, build: (args: Args, ...ctx: Ctx) => Q, options?: DefineQueryOptions<Args>): NamedQuery<Args, Ctx, Q>;
export declare function defineQuery<Args, Ctx extends readonly unknown[], Q extends AnyQuery>(name: string, validate: QueryValidator<Args>, build: (args: Args, ...ctx: Ctx) => Q, options?: DefineQueryOptions<Args>): NamedQuery<Args, Ctx, Q>;FRAGMENT_BRAND
declare const FRAGMENT_BRAND: unique symbol;LOCAL_FRAGMENT_REF_BRAND
declare const LOCAL_FRAGMENT_REF_BRAND: unique symbol;Fragment
/**
* A reusable, typed *selection over a table* — Relay's "fragment", promoted to a first-class
* value. **Two verbs** compose a fragment, on one axis — does its data belong to THIS row or to a
* related one:
*
* - SAME node — `q.include(Frag)`: merge its selection into this node. This is also how you
* **root** a fragment onto a base query — `queries.t.where.id(x).include(Frag)`.
* - CHILD node — `q.sub(alias, child, corr, Frag)`: nest it under a relationship (`sub`'s 4th arg).
*
* A `Fragment` is therefore also a `build` transform (`(q: Query<C>) => Query<C, Rels>`); that
* call signature is the mechanism by which `sub` accepts a fragment as its build. Prefer
* `include` to root a fragment (canonical + merged) over calling it directly. It additionally
* carries its `table` (for {@link FragmentRef}/`useFragment` typing and masking). Composing
* fragments assembles ONE {@link Ast} → one materialization → one `/query` — the whole point
* (no request waterfall; design §1).
*/
export interface Fragment<C extends AnyCols, Rels = {}, Sel extends string = never, LocalRels = Rels> {
(q: Query<C>): Query<C, Rels, false, Sel, LocalRels>;
readonly table: TableLike<C>;
readonly [FRAGMENT_BRAND]: true;
}FragmentData
/**
* The data returned by `useFragment(fragment, ref)`: the fragment's own selected columns plus
* immediate relationship values. Relationships whose builder is another fragment surface as
* opaque {@link FragmentRef}s, so child-owned payload is read only by the child fragment reader.
*/
export type FragmentData<F> = F extends Fragment<infer C, unknown, infer Sel, infer LocalRels> ? Projected<C, Sel> & LocalRels : never;FragmentCoverage
export interface FragmentCoverage<Q extends AnyQuery = AnyQuery> {
readonly key: string;
readonly query: Q;
}LocalFragmentRef
export interface LocalFragmentRef<F extends Fragment<any, any, any, any> = Fragment<any, any, any, any>> {
readonly [LOCAL_FRAGMENT_REF_BRAND]: true;
readonly source: "local";
readonly table: string;
readonly pk: Readonly<Record<string, LitValue>>;
readonly coverage: FragmentCoverage;
readonly __fragment?: F;
}FragmentRef
/** The opaque token a parent passes to a component that reads {@link FragmentData} for `F`. */
export type FragmentRef<F> = F extends Fragment<any, any, any, any> ? LocalFragmentRef<F> : never;defineFragment
/**
* Define a co-located, composable {@link Fragment}: a named selection over `table`. The returned
* value is callable (the `build` transform), so it threads through the existing `sub`/`Rels`
* spine — no GraphQL, no codegen, no schema change (design §3).
*
* ```ts
* const UserAvatar = defineFragment(schema.user, (f) => f.select("id", "name", "avatarUrl"));
* const CommentRow = defineFragment(schema.comment, (f) =>
* f.select("id", "body", "authorId")
* .sub("author", schema.user, { parent: ["authorId"], child: ["id"] }, UserAvatar));
* ```
*/
export declare function defineFragment<C extends AnyCols, Rels = {}, Sel extends string = never, LocalRels = Rels>(table: TableLike<C>, build: (q: Query<C>) => Query<C, Rels, boolean, Sel, LocalRels>): Fragment<C, Rels, Sel, LocalRels>;isFragment
/** Runtime guard: is `v` a {@link Fragment} (a `defineFragment` value, not a plain build fn)? */
export declare function isFragment(v: unknown): v is Fragment<AnyCols, unknown, never, unknown>;isFragmentRelationship
export declare function isFragmentRelationship(rel: CorrelatedSubquery): boolean;fragmentKey
export declare function fragmentKey(ref: FragmentRef<any>): string;createLocalFragmentRef
export declare function createLocalFragmentRef<F extends Fragment<any, any, any>>(fragment: F, pk: Record<string, LitValue>, coverage: FragmentCoverage): LocalFragmentRef<F>;createLocalFragmentRefForTable
export declare function createLocalFragmentRefForTable<F extends Fragment<any, any, any>>(table: string, pk: Record<string, LitValue>, coverage: FragmentCoverage): LocalFragmentRef<F>;createRootFragmentRef
export declare function createRootFragmentRef<F extends Fragment<any, any, any>, Q extends AnyQuery>(fragment: F, query: Q, coverageKey?: string): LocalFragmentRef<F>;fragmentAst
export declare function fragmentAst<F extends Fragment<any, any, any>>(fragment: F): Ast;localFragmentReadAst
export declare function localFragmentReadAst<F extends Fragment<any, any, any>>(fragment: F, ref: LocalFragmentRef<F>, primaryKeyFor: (table: string) => readonly string[]): Ast;localRootFragmentRefsAst
export declare function localRootFragmentRefsAst<F extends Fragment<any, any, any>>(fragment: F, query: AnyQuery, primaryKeyFor: (table: string) => readonly string[]): Ast;localQueryReadAst
export declare function localQueryReadAst(query: AnyQuery, primaryKeyFor: (table: string) => readonly string[]): Ast;queryFromAst
export declare function queryFromAst(ast: Ast): AnyQuery;assertNoLocalTables
/** Throw if `ast` references a local-only table ANYWHERE — the complete form of the {@link queries}
* root guard (Q1 / E3 client half). The root proxy `get` only sees the table accessed off the
* builder root; a local table reached through a relationship / `sub` / `countAs` / `exists` CHILD is
* passed as a value and never touches the proxy, so it is caught here instead: at `.ast()` for a
* server-scope builder, and again as an SSR backstop in `ServerStore.preload`. A server/named query
* may never name a local table (`201-LOCAL-ONLY-TABLES-DESIGN.md` §5). */
export declare function assertNoLocalTables<S extends ColsMap>(ast: Ast, schema: Schema<S>): void;ExistsOpts
/** Options for `exists` / `notExists`. */
export interface ExistsOpts {
/**
* Fold this `EXISTS` as a build-time **scalar** subquery: when the child binds a
* statically-unique key, the engine reads it once, inlines the correlation value as a
* literal, and deletes the join. **Snapshot semantics** — the inlined value does not
* react to later child changes. Defaults to `false` (a live `EXISTS` join).
*/
scalar?: boolean;
}exists
/** `EXISTS` by a named {@link Relationship} — correlation from the rel; the parent row type is the
* relationship's parent, so the condition lands on the matching `.where()`. */
export declare function exists<PC extends AnyCols, CC extends AnyCols>(relationship: Relationship<PC, CC>, build?: (q: Query<CC>) => Query<CC, unknown>, opts?: ExistsOpts): Cond<RowOf<PC>>;
/** `EXISTS (<correlated subquery>)` — a condition (use inside `where`/`or`/`and`). */
export declare function exists<CC extends AnyCols, R = unknown>(child: TableLike<CC>, corr: {
parent: Array<keyof R & string>;
child: Array<keyof CC & string>;
}, build?: (q: Query<CC>) => Query<CC, unknown>, opts?: ExistsOpts): Cond<R>;notExists
/** `NOT EXISTS` by a named {@link Relationship}. */
export declare function notExists<PC extends AnyCols, CC extends AnyCols>(relationship: Relationship<PC, CC>, build?: (q: Query<CC>) => Query<CC, unknown>, opts?: ExistsOpts): Cond<RowOf<PC>>;
/** `NOT EXISTS (<correlated subquery>)`. */
export declare function notExists<CC extends AnyCols, R = unknown>(child: TableLike<CC>, corr: {
parent: Array<keyof R & string>;
child: Array<keyof CC & string>;
}, build?: (q: Query<CC>) => Query<CC, unknown>, opts?: ExistsOpts): Cond<R>;existsNoSync
/**
* `EXISTS (<correlated subquery>)` as a **server-only, non-syncing** gate (`exists_noSync`).
* Identical to {@link exists} for filtering parent visibility, but stamps the subquery
* `system: "permissions"`, so the engine's normalized serializer prunes its witnesses from the
* footprint — the permission table's rows are never synced to the client and the client never
* re-evaluates the gate. Use this when building the **server's** query (the user's API server);
* the client holds its own un-gated query.
*/
export declare function existsNoSync<PC extends AnyCols, CC extends AnyCols>(relationship: Relationship<PC, CC>, build?: (q: Query<CC>) => Query<CC, unknown>): Cond<RowOf<PC>>;
export declare function existsNoSync<CC extends AnyCols, R = unknown>(child: TableLike<CC>, corr: {
parent: Array<keyof R & string>;
child: Array<keyof CC & string>;
}, build?: (q: Query<CC>) => Query<CC, unknown>): Cond<R>;notExistsNoSync
/** `NOT EXISTS (<correlated subquery>)` as a **server-only, non-syncing** gate — the `NOT EXISTS` form of {@link existsNoSync} (a deny-style permission rule). */
export declare function notExistsNoSync<PC extends AnyCols, CC extends AnyCols>(relationship: Relationship<PC, CC>, build?: (q: Query<CC>) => Query<CC, unknown>): Cond<RowOf<PC>>;
export declare function notExistsNoSync<CC extends AnyCols, R = unknown>(child: TableLike<CC>, corr: {
parent: Array<keyof R & string>;
child: Array<keyof CC & string>;
}, build?: (q: Query<CC>) => Query<CC, unknown>): Cond<R>;QueryRoot
export type QueryRoot<S extends ColsMap> = {
[N in keyof S]: Query<S[N]>;
};QueriesOptions
/** Scoping for {@link queries} (`201-LOCAL-ONLY-TABLES-DESIGN.md` §5). */
export interface QueriesOptions {
/** Include {@link TableMeta.local local-only} tables in the builder's root scope. The **local**
* builder (`store.query`) sets this; the **server** builder ({@link newQueryBuilder}) does NOT,
* so naming a local table in a remote/named query is a build error (Q1 / E3 client half). */
includeLocal?: boolean;
}queries
/** A typed query entry over a schema: `queries(schema).issue.where.closed(false)…`. */
export declare function queries<S extends ColsMap>(schema: Schema<S>, onMaterialize?: (query: AnyQuery) => unknown, opts?: QueriesOptions): QueryRoot<S>;newQueryBuilder
/** A schema-bound query-builder factory for portable client/server query definitions. SERVER
* scope: local-only tables are excluded (a named/remote query may never reference one). */
export declare function newQueryBuilder<S extends ColsMap>(schema: Schema<S>): QueryRoot<S>;