@rindle/client 0.4.2 → 0.4.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -5,174 +5,44 @@ The shared core for the flat-change client: a **typed schema + query builder**,
5
5
  the **`Store`**, and the **`Backend`** seam. It talks to no engine directly — pair it with a
6
6
  backend such as [`@rindle/wasm`](../wasm) (local, in-process) or a remote (network) backend.
7
7
 
8
- ## Schema + queries
9
-
10
8
  ```ts
11
- import {
12
- table,
13
- string,
14
- number,
15
- boolean,
16
- json,
17
- createSchema,
18
- defineRelationships,
19
- rel,
20
- extendSchema,
21
- eq,
22
- gt,
23
- ilike,
24
- or,
25
- exists,
26
- } from "@rindle/client";
9
+ import { table, string, number, createSchema, gt } from "@rindle/client";
27
10
 
28
11
  const issue = table("issue")
29
- .columns({ id: number(), title: string(), priority: number(), meta: json<{ tags: string[] }>() })
30
- .primaryKey("id");
31
-
32
- const comment = table("comment")
33
- .columns({ id: number(), issueId: number(), body: string() })
34
- .primaryKey("id");
35
-
36
- const schema = createSchema({ tables: [issue, comment] }); // pass to `new Store(schema, backend)`
37
-
38
- const rels = defineRelationships({
39
- issueComments: rel(issue, comment, { id: "issueId" }),
40
- });
41
- ```
42
-
43
- - **Operators** are named value-functions: `eq / ne / gt / ge / lt / le / like / ilike / inList / …`.
44
- - **`where`** is a typed proxy — `where.closed(false)`, `where.priority(gt(3))` — with camelCase
45
- sugar `whereClosed(false)`. Multiple `where`s are AND-ed.
46
- - **`or` / `and` / `exists`** are plain top-level functions (no closure): conditions carry their
47
- table type, e.g. `where(or(issue.priority(gt(8)), exists(comment, { parent: ["id"], child: ["issueId"] })))`.
48
- - **Nesting** is `sub(alias, relationship, build?)`, or
49
- `sub(alias, childTable, correlation, build?)` when you want to spell the join inline.
50
- - **Paging / single-row**: `orderBy(col, dir)`, `limit(n)`, `start(cursor, { exclusive })` (cursor
51
- paging from a partial row over the sort columns), and `one()`.
52
-
53
- The result type flows through: `store.query.issue.sub("comments", …).materialize()` yields an
54
- `ArrayView` whose `.data` is typed `{ …issue, comments: Comment[] }[]`.
55
-
56
- A top-level **`.one()`** flips `materialize()` to a `SingularArrayView` whose `.data` is the single
57
- row or `null` (the engine caps the query to `limit 1`) — the unwrap is type-level too:
58
-
59
- ```ts
60
- const view = store.query.issue.where.id(id).one().materialize();
61
- view.subscribe((row) => render(row)); // row: Issue | null, not Issue[]
62
- ```
63
-
64
- ## Named queries + fragments
65
-
66
- Remote subscriptions should be named with `defineQuery`. The returned value is callable: it
67
- validates untrusted args, builds the query, and stamps it with the `(name, args)` wire identity that
68
- remote backends subscribe to.
69
-
70
- Fragments are reusable selections over a table. They compose into named queries with `include`
71
- (same row) and `sub` (related rows), so a React screen can open one root query while child
72
- components keep owning their own data declarations.
73
-
74
- ```ts
75
- import { defineFragment, defineQuery, newQueryBuilder } from "@rindle/client";
76
- import type { FragmentData, FragmentRef } from "@rindle/client";
77
-
78
- const q = newQueryBuilder(schema);
79
-
80
- export const IssueCardFragment = defineFragment(issue, (i) =>
81
- i
82
- .select("id", "title")
83
- .countAs("commentCount", rels.issueComments),
84
- );
85
-
86
- export type IssueCardData = FragmentData<typeof IssueCardFragment>;
87
- export type IssueCardRef = FragmentRef<typeof IssueCardFragment>;
88
-
89
- export const issuesPageQuery = defineQuery(
90
- "issuesPage",
91
- (raw): { limit: number } => {
92
- const limit = Number((raw as { limit?: unknown }).limit);
93
- if (!Number.isInteger(limit) || limit < 1 || limit > 100) throw new Error("bad limit");
94
- return { limit };
95
- },
96
- ({ limit }) => q.issue.orderBy("id", "asc").limit(limit).include(IssueCardFragment),
97
- );
98
- ```
99
-
100
- `FragmentData<F>` is the local data shape read by the component that owns `F`. `FragmentRef<F>` is
101
- the opaque token React passes between components; use `fragmentKey(ref)` from `@rindle/client` or
102
- `@rindle/react` for stable list keys. Passing a fragment directly to `sub(alias, rel, ChildFragment)`
103
- creates child refs in the React-facing local data. Passing an inline builder such as
104
- `sub(alias, rel, (q) => q.include(ChildFragment).orderBy(...))` keeps that child payload inline for
105
- the parent to read.
106
-
107
- ## Local-only tables
108
-
109
- Some UI state should live in the same reactive store as synced data but must never cross the
110
- wire: selections, draft text, view preferences, scratch rows. Mark those tables as
111
- **local-only** with `table(name, { local: true })` and include them in the same schema:
112
-
113
- ```ts
114
- const issue = table("issue").columns({ id: number(), title: string() }).primaryKey("id");
115
- const selection = table("selection", { local: true })
116
- .columns({ id: number(), issueId: number() })
117
- .primaryKey("id");
118
-
119
- const schema = createSchema({ tables: [issue, selection] });
120
- ```
121
-
122
- Local-only tables are client-authoritative: they are omitted from the normalized schema
123
- fingerprint, never advertised to the server, never synced, and never rewound during an
124
- optimistic rebase. `store.query` can join/query them locally, but `newQueryBuilder(schema)`
125
- (the server/named-query scope) rejects them so a named remote query cannot depend on private
126
- client state.
127
-
128
- Write local state with `store.writeLocal(...)`, not with a replayable mutator:
129
-
130
- ```ts
131
- await store.writeLocal((tx) => tx.add("selection", { id: 1, issueId: 42 }));
132
- ```
133
-
134
- `writeLocal` accepts only local-only tables and rejects synced tables. Conversely, predicted
135
- mutators cannot touch local-only tables: the server replays a mutator from `(name, args)` alone,
136
- so private client state must stay on the direct local-write path.
137
-
138
- SQL-first apps usually keep synced tables in a generated file. Do not edit that file to add
139
- local tables; extend it in hand-written code:
140
-
141
- ```ts
142
- // shared/schema.local.ts
143
- import { extendSchema, number, string, table } from "@rindle/client";
144
- import { schema as generatedSchema } from "./schema.gen.ts";
145
-
146
- export const draft = table("draft", { local: true })
147
- .columns({ id: string(), issueId: number(), body: string() })
12
+ .columns({ id: number(), title: string(), priority: number() })
148
13
  .primaryKey("id");
14
+ const schema = createSchema({ tables: [issue] }); // pass to `new Store(schema, backend)`
149
15
 
150
- export const clientSchema = extendSchema(generatedSchema, { tables: [draft] });
151
- ```
152
-
153
- Hand `clientSchema` to the browser store. Keep using the generated schema for API-server
154
- resolution and daemon-facing code; `extendSchema` intentionally accepts only local-only tables,
155
- so real synced tables still have to come from `rindle schema gen`.
156
-
157
- ## The Backend seam
158
-
159
- A `Backend` emits a per-query `ChangeEvent` stream (`hello` → `snapshot` → `batch`) and accepts
160
- mutations. The `Store` builds one `ArrayView` per query and routes events to it. The **same**
161
- `Store` / `ArrayView` / builder work behind a local (WASM) or remote (network) backend — only the
162
- backend differs.
163
-
164
- ```ts
165
- const store = new Store(schema, backend);
166
- const view = store.query.issue.where.closed(false).materialize();
167
- view.subscribe(render);
168
- await store.write((tx) => tx.add("issue", { id: 1, title: "x", priority: 3, meta: { tags: [] } }));
16
+ const view = store.query.issue.where.priority(gt(3)).orderBy("id", "asc").materialize();
17
+ view.subscribe(render); // typed, reference-stable, always == a fresh query
169
18
  ```
170
19
 
171
- ## Reads
172
-
173
- `view.data` is the materialized tree, reference-stable: an update re-projects only what changed, so
174
- unchanged subtrees keep their object identity (React/Solid memoize on it). JSON columns are parsed
175
- to objects on read.
20
+ Everything an app builds on lives here:
21
+
22
+ - the **query builder** (`where` proxies, `or`/`and`/`exists`, `sub`, `orderBy`/`limit`/`start`,
23
+ `.one()`, `countAs`/`count()`/`groupBy`/`having`, `select`);
24
+ - **named queries & fragments** (`defineQuery`, `defineFragment`, `defineRelationships`/`rel`) —
25
+ the co-located, waterfall-free composition surface;
26
+ - the **isomorphic-mutator vocabulary** (`defineMutators` → `shared(args, gen)`, `IsoTx`,
27
+ `MutationGen`, `MutatorCtx`) — one generator body per write, run on both tiers;
28
+ - **local-only tables** (`table(name, { local: true })` + `extendSchema` + `store.writeLocal`) —
29
+ client-authoritative state that never syncs or rebases.
30
+
31
+ ## Docs
32
+
33
+ - **[Supported query shapes](https://rindle.sh/docs/supported-queries-ts)** — the honest matrix of
34
+ what the builder can lower, and the build-time rejections.
35
+ - **[Compose the UI with fragments](https://rindle.sh/docs/fragments)** — `defineQuery` /
36
+ `defineFragment` / `defineRelationships` in full.
37
+ - **[Isomorphic mutators](https://rindle.sh/docs/mutators)** — the write contract: the op
38
+ vocabulary, reads, `ctx.user`, the determinism rules.
39
+ - **[The browser client](https://rindle.sh/docs/client)** — this core behind the optimistic synced
40
+ store, including local-only tables.
41
+ - **[Schema & migrations](https://rindle.sh/docs/schema)** — why the schema is generated from SQL,
42
+ and the one allowed hand-edit.
43
+
44
+ Markdown mirrors live at `https://rindle.sh/docs/<slug>.md`; for agents:
45
+ [llms.txt](https://rindle.sh/llms.txt).
176
46
 
177
47
  ## Build
178
48
 
package/dist/index.d.ts CHANGED
@@ -7,8 +7,8 @@ export * from "./ssr.ts";
7
7
  export { resolveChange, subRow } from "./resolve.ts";
8
8
  export type { NamedRow, ResolvedChange } from "./resolve.ts";
9
9
  export type { KeyedRow, MutationOp, ServerWriteTx } from "./mutation-ops.ts";
10
- export { driveMutationAsync, driveMutationSync, isGeneratorMutator, isoTx, shared, } from "./mutation-ops.ts";
11
- export type { ArgSchema, AsyncEffectExec, BatchEffect, IsoTx, MutationGen, MutatorCtx, ReadEffect, SharedMutator, SharedMutatorWithArgs, SyncEffectExec, YieldEffect, } from "./mutation-ops.ts";
10
+ export { defineMutators, driveMutationAsync, driveMutationSync, isGeneratorMutator, isoTx, shared, } from "./mutation-ops.ts";
11
+ export type { ArgSchema, AsyncEffectExec, BatchEffect, IsoTx, IsoTxOf, MutationGen, MutatorCtx, QueryArg, QueryEffect, QueryResultRow, ReadEffect, SharedMutator, SharedMutatorWithArgs, SyncEffectExec, YieldEffect, } from "./mutation-ops.ts";
12
12
  export { stableKey } from "./key.ts";
13
13
  export { COMPARATOR_VERSION, compareNumber, compareRows, compareString, compareValue } from "./compare.ts";
14
14
  export type { Backend, BackendDevObserver, BackendServerDelta, ChangeEvent, ColType, FlatChange, FlatOp, Mutation, MutationEnvelope, NormalizedEvent, NormalizedOp, NormalizedSource, NormalizedTableSchema, OptimisticSource, PathSeg, ProgressFrame, QueryId, RemoteQuery, ResultType, WireNode, WireProjection, WireRel, WireSchema, WireValue, } from "./types.ts";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAIA,cAAc,aAAa,CAAC;AAC5B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,YAAY,CAAC;AAC3B,cAAc,WAAW,CAAC;AAC1B,cAAc,YAAY,CAAC;AAC3B,cAAc,UAAU,CAAC;AAEzB,OAAO,EAAE,aAAa,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AACrD,YAAY,EAAE,QAAQ,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAE7D,YAAY,EAAE,QAAQ,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAE7E,OAAO,EACL,kBAAkB,EAClB,iBAAiB,EACjB,kBAAkB,EAClB,KAAK,EACL,MAAM,GACP,MAAM,mBAAmB,CAAC;AAC3B,YAAY,EACV,SAAS,EACT,eAAe,EACf,WAAW,EACX,KAAK,EACL,WAAW,EACX,UAAU,EACV,UAAU,EACV,aAAa,EACb,qBAAqB,EACrB,cAAc,EACd,WAAW,GACZ,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAErC,OAAO,EAAE,kBAAkB,EAAE,aAAa,EAAE,WAAW,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAE3G,YAAY,EACV,OAAO,EACP,kBAAkB,EAClB,kBAAkB,EAClB,WAAW,EACX,OAAO,EACP,UAAU,EACV,MAAM,EACN,QAAQ,EACR,gBAAgB,EAChB,eAAe,EACf,YAAY,EACZ,gBAAgB,EAChB,qBAAqB,EACrB,gBAAgB,EAChB,OAAO,EACP,aAAa,EACb,OAAO,EACP,WAAW,EACX,UAAU,EACV,QAAQ,EACR,cAAc,EACd,OAAO,EACP,UAAU,EACV,SAAS,GACV,MAAM,YAAY,CAAC;AAEpB,OAAO,EAAE,uBAAuB,EAAE,sBAAsB,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAG9F,YAAY,EACV,SAAS,EACT,GAAG,EACH,KAAK,EACL,SAAS,EACT,kBAAkB,EAClB,WAAW,EACX,GAAG,EACH,QAAQ,EACR,QAAQ,EACR,SAAS,EACT,QAAQ,EACR,aAAa,GACd,MAAM,UAAU,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAIA,cAAc,aAAa,CAAC;AAC5B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,YAAY,CAAC;AAC3B,cAAc,WAAW,CAAC;AAC1B,cAAc,YAAY,CAAC;AAC3B,cAAc,UAAU,CAAC;AAEzB,OAAO,EAAE,aAAa,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AACrD,YAAY,EAAE,QAAQ,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAE7D,YAAY,EAAE,QAAQ,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAE7E,OAAO,EACL,cAAc,EACd,kBAAkB,EAClB,iBAAiB,EACjB,kBAAkB,EAClB,KAAK,EACL,MAAM,GACP,MAAM,mBAAmB,CAAC;AAC3B,YAAY,EACV,SAAS,EACT,eAAe,EACf,WAAW,EACX,KAAK,EACL,OAAO,EACP,WAAW,EACX,UAAU,EACV,QAAQ,EACR,WAAW,EACX,cAAc,EACd,UAAU,EACV,aAAa,EACb,qBAAqB,EACrB,cAAc,EACd,WAAW,GACZ,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAErC,OAAO,EAAE,kBAAkB,EAAE,aAAa,EAAE,WAAW,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAE3G,YAAY,EACV,OAAO,EACP,kBAAkB,EAClB,kBAAkB,EAClB,WAAW,EACX,OAAO,EACP,UAAU,EACV,MAAM,EACN,QAAQ,EACR,gBAAgB,EAChB,eAAe,EACf,YAAY,EACZ,gBAAgB,EAChB,qBAAqB,EACrB,gBAAgB,EAChB,OAAO,EACP,aAAa,EACb,OAAO,EACP,WAAW,EACX,UAAU,EACV,QAAQ,EACR,cAAc,EACd,OAAO,EACP,UAAU,EACV,SAAS,GACV,MAAM,YAAY,CAAC;AAEpB,OAAO,EAAE,uBAAuB,EAAE,sBAAsB,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAG9F,YAAY,EACV,SAAS,EACT,GAAG,EACH,KAAK,EACL,SAAS,EACT,kBAAkB,EAClB,WAAW,EACX,GAAG,EACH,QAAQ,EACR,QAAQ,EACR,SAAS,EACT,QAAQ,EACR,aAAa,GACd,MAAM,UAAU,CAAC"}
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  // @rindle/client — the backend-agnostic flat-change client core: typed schema, query builder,
2
2
  // comparator, Backend seam, and the ArrayView contract. (The ArrayView folding impl + the
3
3
  // Store/backend wiring land in later slices.)
4
- export * from "./schema.js"; // table/columns/primaryKey, createSchema/extendSchema, refineTable/refineSchema, string/number/boolean/json, Col, RowOf, Row, TableDef, tableSpec, SCHEMA
4
+ export * from "./schema.js"; // table/columns/primaryKey, createSchema/extendSchema, refineTable/refineSchema, string/number/boolean/json, Col, RowOf, Row, InsertOf, Insert, insertPlan, insertCell, TableDef, tableSpec, SCHEMA
5
5
  export * from "./operators.js"; // eq/ne/gt/ge/lt/le/like/notLike/ilike/notIlike/inList/notInList/is/isNot, and/or, Pred, Cond, Arg
6
6
  export * from "./query.js"; // Query, QueryRoot, queries/newQueryBuilder, defineQuery/NamedQuery, exists, notExists, defineFragment/Fragment/FragmentRef/isFragment
7
7
  export * from "./view.js"; // ArrayView, SingularArrayView, FlatArrayView, SingularView, ViewTypes
@@ -9,7 +9,7 @@ export * from "./store.js"; // Store, WriteTx, AssembledNode, DehydratedQuery, D
9
9
  export * from "./ssr.js"; // createServerStore, ServerStore, OneShotBackend, OneShotQueryFn, OneShotResult, ServerStoreOptions
10
10
  export { resolveChange, subRow } from "./resolve.js"; // positional FlatChange → named rows (inverse of the wire encoder)
11
11
  // shared (generator) mutator seam — one body, sync on the client + async on the server
12
- export { driveMutationAsync, driveMutationSync, isGeneratorMutator, isoTx, shared, } from "./mutation-ops.js";
12
+ export { defineMutators, driveMutationAsync, driveMutationSync, isGeneratorMutator, isoTx, shared, } from "./mutation-ops.js";
13
13
  export { stableKey } from "./key.js"; // canonical viewKey for an AST (shared with @rindle/react)
14
14
  export { COMPARATOR_VERSION, compareNumber, compareRows, compareString, compareValue } from "./compare.js";
15
15
  export { CLIENT_MUTATIONS_SCHEMA, CLIENT_MUTATIONS_TABLE, LMID_QUERY_NAME } from "./types.js";
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,8FAA8F;AAC9F,0FAA0F;AAC1F,8CAA8C;AAE9C,cAAc,aAAa,CAAC,CAAC,0JAA0J;AACvL,cAAc,gBAAgB,CAAC,CAAC,mGAAmG;AACnI,cAAc,YAAY,CAAC,CAAC,uIAAuI;AACnK,cAAc,WAAW,CAAC,CAAC,uEAAuE;AAClG,cAAc,YAAY,CAAC,CAAC,kEAAkE;AAC9F,cAAc,UAAU,CAAC,CAAC,oGAAoG;AAE9H,OAAO,EAAE,aAAa,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC,CAAC,mEAAmE;AAIzH,uFAAuF;AACvF,OAAO,EACL,kBAAkB,EAClB,iBAAiB,EACjB,kBAAkB,EAClB,KAAK,EACL,MAAM,GACP,MAAM,mBAAmB,CAAC;AAe3B,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC,CAAC,2DAA2D;AAEjG,OAAO,EAAE,kBAAkB,EAAE,aAAa,EAAE,WAAW,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AA6B3G,OAAO,EAAE,uBAAuB,EAAE,sBAAsB,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,8FAA8F;AAC9F,0FAA0F;AAC1F,8CAA8C;AAE9C,cAAc,aAAa,CAAC,CAAC,oMAAoM;AACjO,cAAc,gBAAgB,CAAC,CAAC,mGAAmG;AACnI,cAAc,YAAY,CAAC,CAAC,uIAAuI;AACnK,cAAc,WAAW,CAAC,CAAC,uEAAuE;AAClG,cAAc,YAAY,CAAC,CAAC,kEAAkE;AAC9F,cAAc,UAAU,CAAC,CAAC,oGAAoG;AAE9H,OAAO,EAAE,aAAa,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC,CAAC,mEAAmE;AAIzH,uFAAuF;AACvF,OAAO,EACL,cAAc,EACd,kBAAkB,EAClB,iBAAiB,EACjB,kBAAkB,EAClB,KAAK,EACL,MAAM,GACP,MAAM,mBAAmB,CAAC;AAmB3B,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC,CAAC,2DAA2D;AAEjG,OAAO,EAAE,kBAAkB,EAAE,aAAa,EAAE,WAAW,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AA6B3G,OAAO,EAAE,uBAAuB,EAAE,sBAAsB,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC"}
@@ -1,3 +1,5 @@
1
+ import type { Ast } from "./ast.ts";
2
+ import type { ColsMap, InsertOf, PkColsOf, PkMap, PkOf, Schema, UpdateOf } from "./schema.ts";
1
3
  import type { WireValue } from "./types.ts";
2
4
  /** A keyed row: column name → cell. The ergonomic write shape (validated against the schema at
3
5
  * runtime). JSON columns carry their raw JSON string (a {@link WireValue}), never a parsed object. */
@@ -64,23 +66,60 @@ export type BatchEffect = {
64
66
  kind: "all";
65
67
  effects: readonly YieldEffect[];
66
68
  };
67
- /** Everything a generator mutator may `yield`: a write {@link MutationOp}, a {@link ReadEffect}, or a
68
- * {@link BatchEffect}. */
69
- export type YieldEffect = MutationOp | ReadEffect | BatchEffect;
69
+ /** A row returned by a {@link QueryEffect}: column name → cell, plus each materialized relationship
70
+ * name its nested row(s) — an array (a plural relationship) or a single row / `null` (a `.one()`
71
+ * relationship). Recursive. Presented identically on both tiers (a `view.data` row of the same
72
+ * query). */
73
+ export type QueryResultRow = {
74
+ [key: string]: WireValue | QueryResultRow | QueryResultRow[];
75
+ };
76
+ /** What {@link IsoTx.query} accepts: a query handle whose `.ast()` lowers to the wire {@link Ast} —
77
+ * exactly what the typed query builder produces (`newQueryBuilder(schema).<table>…`, the tier-agnostic
78
+ * server-scope builder both tiers can construct because it performs no I/O). Structural so the seam
79
+ * need not carry the builder's heavy generics. */
80
+ export type QueryArg = {
81
+ ast(): Ast;
82
+ };
83
+ /** A full-shape read a generator mutator yields — a `where`/`orderBy`/`limit`/join query over the
84
+ * state this mutator is mutating (read-your-writes, like {@link ReadEffect} but an arbitrary shape).
85
+ * Evaluates to {@link QueryResultRow}`[]` — ALWAYS an array of the matching rows, in the query's
86
+ * order, on BOTH tiers (a root `.one()` is not unwrapped here: take `[0]`). The single next-type is
87
+ * a row, so cast the yield (`(yield tx.query(q)) as unknown as QueryResultRow[]`), same as `all`. */
88
+ export type QueryEffect = {
89
+ kind: "query";
90
+ query: QueryArg;
91
+ };
92
+ /** Everything a generator mutator may `yield`: a write {@link MutationOp}, a point {@link ReadEffect},
93
+ * a full-query {@link QueryEffect}, or a {@link BatchEffect} fan-out. */
94
+ export type YieldEffect = MutationOp | ReadEffect | BatchEffect | QueryEffect;
70
95
  /** The tier-AGNOSTIC effect factory a generator mutator writes against. Every method just BUILDS an
71
96
  * effect to `yield` — it performs no I/O and holds no state, so the single {@link isoTx} instance is
72
97
  * shared by every mutator on both tiers; only the driver differs. `insert`/`upsert`/`insertIgnore`
73
98
  * take a FULL row; `update`/`delete` take the pk columns (`update` adds the columns to change). */
74
- export interface IsoTx {
75
- insert(table: string, row: KeyedRow): MutationOp;
76
- update(table: string, row: KeyedRow): MutationOp;
77
- upsert(table: string, row: KeyedRow): MutationOp;
78
- insertIgnore(table: string, row: KeyedRow): MutationOp;
79
- delete(table: string, pk: KeyedRow): MutationOp;
80
- row(table: string, pk: KeyedRow): ReadEffect;
99
+ export interface IsoTx<S extends ColsMap = ColsMap, P extends Record<string, string> = PkMap<S>> {
100
+ /** Insert a FULL row — nullable columns may be omitted (filled `null`, design 206 §6.2/§7). */
101
+ insert<N extends keyof S & string>(table: N, row: InsertOf<S[N]>): MutationOp;
102
+ /** Update the row identified by its pk columns (REQUIRED); only the named non-pk columns change. */
103
+ update<N extends keyof S & string>(table: N, row: UpdateOf<S[N], PkColsOf<S, P, N>>): MutationOp;
104
+ /** Insert, or fully replace on pk conflict (a FULL row, like {@link IsoTx.insert}). */
105
+ upsert<N extends keyof S & string>(table: N, row: InsertOf<S[N]>): MutationOp;
106
+ /** Insert a FULL row, or do nothing if the pk already exists. */
107
+ insertIgnore<N extends keyof S & string>(table: N, row: InsertOf<S[N]>): MutationOp;
108
+ /** Delete the row identified by its pk columns. */
109
+ delete<N extends keyof S & string>(table: N, pk: PkOf<S[N], PkColsOf<S, P, N>>): MutationOp;
110
+ /** Read one row by primary key (read-your-writes). */
111
+ row<N extends keyof S & string>(table: N, pk: PkOf<S[N], PkColsOf<S, P, N>>): ReadEffect;
112
+ /** Run a full query (`where`/`orderBy`/`limit`/join) over the state this mutator is mutating —
113
+ * read-your-writes, like {@link row} but for arbitrary shapes. Pass a query from the tier-agnostic
114
+ * builder, e.g. `tx.query(q.issue.where("ownerId", "=", ctx.user))` where `q = newQueryBuilder(schema)`.
115
+ * The `yield` evaluates to {@link QueryResultRow}`[]` (cast it — the generator's single next-type is a row). */
116
+ query(query: QueryArg): QueryEffect;
81
117
  all(effects: readonly YieldEffect[]): BatchEffect;
82
118
  }
83
- /** The one shared effect factory (stateless — see {@link IsoTx}). */
119
+ /** The one shared effect factory (stateless — see {@link IsoTx}). Its methods just BUILD a
120
+ * {@link MutationOp}, so the single instance serves every schema; the generic {@link IsoTx} view is
121
+ * applied at the authoring site (a `json<T>` cell is a parsed object here and is stringified by the
122
+ * funnels, {@link toCell}), hence the cast — the runtime shape is schema-agnostic. */
84
123
  export declare const isoTx: IsoTx;
85
124
  /** The minimal per-invocation context a shared mutator sees on BOTH tiers: the acting principal. The
86
125
  * server injects its AUTHENTICATED user; the client injects its local user. (The server's own
@@ -116,6 +155,23 @@ export type SharedMutatorWithArgs<Args, Ctx extends MutatorCtx = MutatorCtx> = S
116
155
  * registered value is byte-for-byte what the client drove before: {@link isGeneratorMutator} still
117
156
  * detects it and it still `satisfies ClientRegistry`. */
118
157
  export declare function shared<Args, Ctx extends MutatorCtx = MutatorCtx>(args: ArgSchema<Args>, run: SharedMutator<Args, Ctx>): SharedMutatorWithArgs<Args, Ctx>;
158
+ /** Bind a schema to the mutator authoring surface: `const { shared } = defineMutators(schema)`.
159
+ *
160
+ * The returned `shared` is the schema-typed twin of the bare {@link shared} — its `tx` is an
161
+ * {@link IsoTx} parameterized by THIS schema, so `tx.insert`/`update`/`upsert`/`insertIgnore`/`delete`
162
+ * check the table name, every column name, each column's value type, nullable-omit on inserts, and
163
+ * the exact primary-key columns on `update`/`delete` — all at compile time. It registers identically
164
+ * to the bare form (same runtime value, still `satisfies ClientRegistry`, still an isomorphic
165
+ * generator the server drives): only the AUTHORING types tighten. `schema` is read for its TYPE only
166
+ * (never at runtime). Reads (`yield tx.row(...)`) stay loosely typed — a generator's single
167
+ * next-type can't carry a per-table row. */
168
+ /** The typed {@link IsoTx} for a given schema — `IsoTxOf<typeof schema>`. Use it to annotate a helper
169
+ * that a mutator body passes its `tx` to (e.g. `const ensureUser = (tx: IsoTxOf<typeof schema>, …)`),
170
+ * so the helper gets the same table/column/pk typing the `defineMutators` `shared` callback does. */
171
+ export type IsoTxOf<Sch extends Schema> = Sch extends Schema<infer S, infer P> ? IsoTx<S, P> : never;
172
+ export declare function defineMutators<S extends ColsMap, P extends Record<string, string>>(_schema: Schema<S, P>): {
173
+ shared<Args, Ctx extends MutatorCtx = MutatorCtx>(args: ArgSchema<Args>, run: (tx: IsoTx<S, P>, args: Args, ctx: Ctx) => MutationGen): SharedMutatorWithArgs<Args, Ctx>;
174
+ };
119
175
  /** True iff `fn` is a generator function (a shared/isomorphic mutator) rather than a plain function —
120
176
  * the driver accepts both forms. Detected structurally (native `GeneratorFunction`). */
121
177
  export declare function isGeneratorMutator(fn: unknown): fn is (...args: never[]) => MutationGen;
@@ -124,17 +180,21 @@ export declare function isGeneratorMutator(fn: unknown): fn is (...args: never[]
124
180
  export interface SyncEffectExec {
125
181
  apply(op: MutationOp): void;
126
182
  read(table: string, pk: KeyedRow): KeyedRow | undefined;
183
+ query(q: QueryArg): QueryResultRow[];
127
184
  }
128
185
  /** Drive a generator mutator SYNCHRONOUSLY (the client, inside the wasm write transaction). Each
129
- * yielded write applies immediately; each read is resolved and fed back; a batch runs in order. */
186
+ * yielded write applies immediately; each read (point or query) is resolved and fed back; a batch
187
+ * runs in order. */
130
188
  export declare function driveMutationSync(gen: MutationGen, exec: SyncEffectExec): void;
131
189
  /** A tier's ASYNCHRONOUS effect executor (the server transaction): every op is a Promise. */
132
190
  export interface AsyncEffectExec {
133
191
  apply(op: MutationOp): Promise<void>;
134
192
  read(table: string, pk: KeyedRow): Promise<KeyedRow | undefined>;
193
+ query(q: QueryArg): Promise<QueryResultRow[]>;
135
194
  }
136
195
  /** Drive a generator mutator ASYNCHRONOUSLY (the server, against the open transaction). Writes are
137
196
  * awaited (harmless: a single interactive Postgres connection serializes statements anyway, and the
138
- * daemon backend resolves them instantly), reads suspend, and a batch fans out with `Promise.all`. */
197
+ * daemon backend resolves them instantly), reads (point or query) suspend, and a batch fans out with
198
+ * `Promise.all`. */
139
199
  export declare function driveMutationAsync(gen: MutationGen, exec: AsyncEffectExec): Promise<void>;
140
200
  //# sourceMappingURL=mutation-ops.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"mutation-ops.d.ts","sourceRoot":"","sources":["../src/mutation-ops.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"mutation-ops.d.ts","sourceRoot":"","sources":["../src/mutation-ops.ts"],"names":[],"mappings":"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"}
@@ -3,7 +3,10 @@
3
3
  // insertIgnore/delete over a keyed row), not HOW — the server renders dialect SQL and the
4
4
  // client applies to its local engine. This lives in `@rindle/client` (the leaf both tiers
5
5
  // import); the SQL renderer that consumes it is server-only (`@rindle/api-server`).
6
- /** The one shared effect factory (stateless — see {@link IsoTx}). */
6
+ /** The one shared effect factory (stateless — see {@link IsoTx}). Its methods just BUILD a
7
+ * {@link MutationOp}, so the single instance serves every schema; the generic {@link IsoTx} view is
8
+ * applied at the authoring site (a `json<T>` cell is a parsed object here and is stringified by the
9
+ * funnels, {@link toCell}), hence the cast — the runtime shape is schema-agnostic. */
7
10
  export const isoTx = {
8
11
  insert: (table, row) => ({ kind: "insert", table, row }),
9
12
  update: (table, row) => ({ kind: "update", table, row }),
@@ -11,6 +14,7 @@ export const isoTx = {
11
14
  insertIgnore: (table, row) => ({ kind: "insertIgnore", table, row }),
12
15
  delete: (table, pk) => ({ kind: "delete", table, pk }),
13
16
  row: (table, pk) => ({ kind: "row", table, pk }),
17
+ query: (query) => ({ kind: "query", query }),
14
18
  all: (effects) => ({ kind: "all", effects }),
15
19
  };
16
20
  /** Co-locate a shared (generator) mutator with the validator for its args — pairing the arg SHAPE
@@ -22,6 +26,15 @@ export const isoTx = {
22
26
  export function shared(args, run) {
23
27
  return Object.assign(run, { args });
24
28
  }
29
+ export function defineMutators(_schema) {
30
+ return {
31
+ shared(args, run) {
32
+ // The typed `tx: IsoTx<S, P>` is authoring-only; the driver invokes with the loose `isoTx`
33
+ // singleton (cast at the call boundary, like the bare `shared`), so the value is registry-shaped.
34
+ return Object.assign(run, { args });
35
+ },
36
+ };
37
+ }
25
38
  /** True iff `fn` is a generator function (a shared/isomorphic mutator) rather than a plain function —
26
39
  * the driver accepts both forms. Detected structurally (native `GeneratorFunction`). */
27
40
  export function isGeneratorMutator(fn) {
@@ -29,11 +42,14 @@ export function isGeneratorMutator(fn) {
29
42
  fn.constructor?.name === "GeneratorFunction");
30
43
  }
31
44
  /** Drive a generator mutator SYNCHRONOUSLY (the client, inside the wasm write transaction). Each
32
- * yielded write applies immediately; each read is resolved and fed back; a batch runs in order. */
45
+ * yielded write applies immediately; each read (point or query) is resolved and fed back; a batch
46
+ * runs in order. */
33
47
  export function driveMutationSync(gen, exec) {
34
48
  const run = (eff) => {
35
49
  if (eff.kind === "row")
36
50
  return exec.read(eff.table, eff.pk);
51
+ if (eff.kind === "query")
52
+ return exec.query(eff.query);
37
53
  if (eff.kind === "all")
38
54
  return eff.effects.map(run);
39
55
  exec.apply(eff);
@@ -44,11 +60,14 @@ export function driveMutationSync(gen, exec) {
44
60
  }
45
61
  /** Drive a generator mutator ASYNCHRONOUSLY (the server, against the open transaction). Writes are
46
62
  * awaited (harmless: a single interactive Postgres connection serializes statements anyway, and the
47
- * daemon backend resolves them instantly), reads suspend, and a batch fans out with `Promise.all`. */
63
+ * daemon backend resolves them instantly), reads (point or query) suspend, and a batch fans out with
64
+ * `Promise.all`. */
48
65
  export async function driveMutationAsync(gen, exec) {
49
66
  const run = async (eff) => {
50
67
  if (eff.kind === "row")
51
68
  return exec.read(eff.table, eff.pk);
69
+ if (eff.kind === "query")
70
+ return (await exec.query(eff.query));
52
71
  if (eff.kind === "all")
53
72
  return (await Promise.all(eff.effects.map(run)));
54
73
  await exec.apply(eff);
@@ -1 +1 @@
1
- {"version":3,"file":"mutation-ops.js","sourceRoot":"","sources":["../src/mutation-ops.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"mutation-ops.js","sourceRoot":"","sources":["../src/mutation-ops.ts"],"names":[],"mappings":"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"}