@rindle/client 0.4.2 → 0.4.3
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/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/mutation-ops.d.ts +73 -13
- package/dist/mutation-ops.d.ts.map +1 -1
- package/dist/mutation-ops.js +22 -3
- package/dist/mutation-ops.js.map +1 -1
- package/dist/schema.d.ts +100 -16
- package/dist/schema.d.ts.map +1 -1
- package/dist/schema.js +26 -1
- package/dist/schema.js.map +1 -1
- package/dist/store.d.ts +7 -3
- package/dist/store.d.ts.map +1 -1
- package/dist/store.js.map +1 -1
- package/package.json +1 -1
- package/src/index.ts +6 -1
- package/src/mutation-ops.ts +98 -24
- package/src/schema.ts +139 -28
- package/src/store.ts +7 -3
package/src/schema.ts
CHANGED
|
@@ -8,13 +8,19 @@
|
|
|
8
8
|
|
|
9
9
|
import type { Arg, Cond } from "./operators.ts";
|
|
10
10
|
import { fieldCondition } from "./operators.ts";
|
|
11
|
-
import type { ColType } from "./types.ts";
|
|
11
|
+
import type { ColType, WireValue } from "./types.ts";
|
|
12
12
|
|
|
13
13
|
/** A column descriptor. `type` drives the comparator + JSON parsing; `__t` is a phantom. A
|
|
14
14
|
* nullable column is a `Col<T | null>` — that is the ONLY thing nullability changes at the type
|
|
15
|
-
* level, so `RowOf` (and the field-condition factory) widen automatically.
|
|
15
|
+
* level, so `RowOf` (and the field-condition factory) widen automatically.
|
|
16
|
+
*
|
|
17
|
+
* `optional` is the runtime companion of that phantom: set by {@link ColBuilder.nullable}, it is
|
|
18
|
+
* what the write funnels read to make a nullable column omittable from an insert (filled with
|
|
19
|
+
* `null`, design 206 §6.2). It mirrors the engine's `ColumnDef.optional`
|
|
20
|
+
* (`pragma_table_info.notnull == 0`); absent ⇒ `NOT NULL` / required. */
|
|
16
21
|
export interface Col<T> {
|
|
17
22
|
readonly type: ColType;
|
|
23
|
+
readonly optional?: boolean;
|
|
18
24
|
readonly __t?: T;
|
|
19
25
|
}
|
|
20
26
|
export type ColT<X> = X extends Col<infer T> ? T : never;
|
|
@@ -24,13 +30,18 @@ export type RowOf<C extends AnyCols> = { [K in keyof C]: ColT<C[K]> };
|
|
|
24
30
|
/** The chainable form returned by the column factories: a {@link Col} plus `.nullable()`.
|
|
25
31
|
*
|
|
26
32
|
* `.nullable()` widens the column's value type to `T | null` — its `Row<…>` field becomes
|
|
27
|
-
* `T | null
|
|
28
|
-
* `.nullable()` for every nullable (non-`NOT NULL`) SQL
|
|
29
|
-
* local-only table's columns. It is idempotent and stays
|
|
33
|
+
* `T | null` — and sets the runtime {@link Col.optional} marker so it may be omitted from an insert
|
|
34
|
+
* (design 206 §6.2). `rindle schema gen` emits `.nullable()` for every nullable (non-`NOT NULL`) SQL
|
|
35
|
+
* column; you can also call it by hand on a local-only table's columns. It is idempotent and stays
|
|
36
|
+
* chainable. */
|
|
30
37
|
export interface ColBuilder<T> extends Col<T> {
|
|
31
38
|
nullable(): ColBuilder<T | null>;
|
|
32
39
|
}
|
|
33
|
-
const makeCol = <T>(type: ColType): ColBuilder<T> => ({
|
|
40
|
+
const makeCol = <T>(type: ColType, optional = false): ColBuilder<T> => ({
|
|
41
|
+
type,
|
|
42
|
+
...(optional ? { optional: true } : null),
|
|
43
|
+
nullable: () => makeCol<T | null>(type, true),
|
|
44
|
+
});
|
|
34
45
|
|
|
35
46
|
export const string = <T extends string = string>(): ColBuilder<T> => makeCol<T>("string");
|
|
36
47
|
export const number = <T extends number = number>(): ColBuilder<T> => makeCol<T>("number");
|
|
@@ -40,13 +51,15 @@ export const json = <T = unknown>(): ColBuilder<T> => makeCol<T>("json");
|
|
|
40
51
|
/** Metadata key on a {@link TableDef} (a `unique symbol`, so no column name collides). */
|
|
41
52
|
export const SCHEMA: unique symbol = Symbol("rindle.schema");
|
|
42
53
|
|
|
43
|
-
export interface TableMeta<N extends string = string, C extends AnyCols = AnyCols> {
|
|
54
|
+
export interface TableMeta<N extends string = string, C extends AnyCols = AnyCols, PK extends string = string> {
|
|
44
55
|
readonly name: N;
|
|
45
56
|
readonly columns: C;
|
|
46
|
-
//
|
|
47
|
-
// `TableMeta` non-covariant in `C
|
|
48
|
-
// validity is enforced on the `primaryKey()` builder
|
|
49
|
-
|
|
57
|
+
// `PK` is an INDEPENDENT param (a plain string union), NOT `keyof C`: `keyof C` would be
|
|
58
|
+
// contravariant and make `TableMeta` non-covariant in `C`, breaking `TableDef<concrete>` →
|
|
59
|
+
// `AnyTable`. Key validity is enforced on the `primaryKey()` builder (`K extends keyof C`); PK is
|
|
60
|
+
// captured there so the mutator tx can type `update`/`delete` pk args (`PkOf`/`UpdateOf`). The
|
|
61
|
+
// default `string` erases it (older 2-arg `TableMeta<N, C>` refs still resolve).
|
|
62
|
+
readonly primaryKey: readonly PK[];
|
|
50
63
|
/** A **local-only** table (`201-LOCAL-ONLY-TABLES-DESIGN.md`): client-authoritative,
|
|
51
64
|
* never synced/tracked/rebased. The single marker the whole design keys off (§4) — it is
|
|
52
65
|
* immutable for the table's lifetime (N2) and never crosses the wire (C2). Absent ⇒ an
|
|
@@ -62,8 +75,8 @@ export interface TableOptions {
|
|
|
62
75
|
local?: boolean;
|
|
63
76
|
}
|
|
64
77
|
|
|
65
|
-
export type TableDef<N extends string, C extends AnyCols> = {
|
|
66
|
-
readonly [SCHEMA]: TableMeta<N, C>;
|
|
78
|
+
export type TableDef<N extends string, C extends AnyCols, PK extends string = string> = {
|
|
79
|
+
readonly [SCHEMA]: TableMeta<N, C, PK>;
|
|
67
80
|
} & {
|
|
68
81
|
readonly [K in keyof C]: (arg: Arg<ColT<C[K]>>) => Cond<RowOf<C>>;
|
|
69
82
|
};
|
|
@@ -79,28 +92,77 @@ export type AnyTable = TableLike<AnyCols>;
|
|
|
79
92
|
* the schema instead of hand-maintaining a parallel twin. */
|
|
80
93
|
export type Row<T extends AnyTable> = RowOf<T[typeof SCHEMA]["columns"]>;
|
|
81
94
|
|
|
95
|
+
/** Flatten an intersection of mapped types into a single object type (preserving `?`/`readonly`) so
|
|
96
|
+
* {@link InsertOf} reads as one clean shape in editor hovers, not `A & B`. */
|
|
97
|
+
type Simplify<T> = { [K in keyof T]: T[K] };
|
|
98
|
+
|
|
99
|
+
/** True for the top types `unknown`/`any` (`unknown extends any` too), where `[null] extends [T]` is
|
|
100
|
+
* vacuously true and so can't tell a `.nullable()` apart. */
|
|
101
|
+
type IsTop<T> = unknown extends T ? true : false;
|
|
102
|
+
|
|
103
|
+
/** Whether column `X` may be OMITTED from an insert: it admits `null` at the type level — EXCLUDING
|
|
104
|
+
* the top types. A bare `json()` is `json<unknown>()`, and `unknown | null` collapses back to
|
|
105
|
+
* `unknown`, erasing whether `.nullable()` was applied; treating it as required is the safe
|
|
106
|
+
* direction (a `NOT NULL` json column is never wrongly made optional). Declare `json<T>()` to make a
|
|
107
|
+
* nullable json column omittable. The runtime companion is `Col.optional` (design 206 §6.2/§7). */
|
|
108
|
+
type InsertOptional<X> = IsTop<ColT<X>> extends true ? false : [null] extends [ColT<X>] ? true : false;
|
|
109
|
+
|
|
110
|
+
/** The INSERT shape of a column map: {@link RowOf} with every NULLABLE column made OPTIONAL (`?`) —
|
|
111
|
+
* it may be omitted and is filled with `null` by both write funnels (design 206 §6.2/§7). `NOT NULL`
|
|
112
|
+
* columns stay required. The insert-side twin of {@link RowOf}, mirroring Drizzle's `$inferInsert`
|
|
113
|
+
* vs `$inferSelect` split. */
|
|
114
|
+
export type InsertOf<C extends AnyCols> = Simplify<
|
|
115
|
+
{ [K in keyof C as InsertOptional<C[K]> extends true ? never : K]: ColT<C[K]> } & {
|
|
116
|
+
[K in keyof C as InsertOptional<C[K]> extends true ? K : never]?: ColT<C[K]>;
|
|
117
|
+
}
|
|
118
|
+
>;
|
|
119
|
+
|
|
120
|
+
/** The insert type of a table def: `Insert<typeof issue>` → `{ id: string; … assignee?: string | null }`.
|
|
121
|
+
* The whole-table ergonomic form of {@link InsertOf} (the insert-side twin of {@link Row}). */
|
|
122
|
+
export type Insert<T extends AnyTable> = InsertOf<T[typeof SCHEMA]["columns"]>;
|
|
123
|
+
|
|
124
|
+
/** The exact PRIMARY-KEY columns of a table (each typed), required — the identity a `delete`/`row`,
|
|
125
|
+
* and the WHERE half of an `update`, take. `PK` is the table's pk-column union (the schema's `__pk`). */
|
|
126
|
+
export type PkOf<C extends AnyCols, PK extends string> = { [K in PK & keyof C]: ColT<C[K & keyof C]> };
|
|
127
|
+
|
|
128
|
+
/** The UPDATE shape of a table: its {@link PkOf primary-key columns} REQUIRED (they identify the row)
|
|
129
|
+
* plus every non-pk column OPTIONAL (`?`) and typed — a nullable one stays `T | null` (settable to
|
|
130
|
+
* null), a `NOT NULL` one is `T`. Omitted non-pk columns are left unchanged. */
|
|
131
|
+
export type UpdateOf<C extends AnyCols, PK extends string> = Simplify<
|
|
132
|
+
PkOf<C, PK> & { [K in Exclude<keyof C, PK>]?: ColT<C[K]> }
|
|
133
|
+
>;
|
|
134
|
+
|
|
135
|
+
/** The primary-key column union for table `N` of a schema, read from its `__pk` map `P` and narrowed
|
|
136
|
+
* to `N`'s actual columns (falling back to all columns when `P` doesn't name `N` — e.g. the loose
|
|
137
|
+
* default schema). Feeds {@link PkOf}/{@link UpdateOf} in the typed mutator tx. */
|
|
138
|
+
export type PkColsOf<S extends ColsMap, P extends Record<string, string>, N extends keyof S> = (N extends keyof P
|
|
139
|
+
? P[N]
|
|
140
|
+
: keyof S[N] & string) &
|
|
141
|
+
keyof S[N] &
|
|
142
|
+
string;
|
|
143
|
+
|
|
82
144
|
/** `table("issue").columns({ id: string(), … }).primaryKey("id")`. Pass `{ local: true }` for a
|
|
83
145
|
* {@link TableMeta.local local-only} table (`201-LOCAL-ONLY-TABLES-DESIGN.md`). */
|
|
84
146
|
export function table<N extends string>(name: N, opts?: TableOptions) {
|
|
85
147
|
return {
|
|
86
148
|
columns<C extends AnyCols>(cols: C) {
|
|
87
149
|
return {
|
|
88
|
-
primaryKey<K extends keyof C & string>(...keys: K[]): TableDef<N, C> {
|
|
89
|
-
return makeTableDef<N, C>({ name, columns: cols, primaryKey: keys, local: opts?.local });
|
|
150
|
+
primaryKey<K extends keyof C & string>(...keys: K[]): TableDef<N, C, K> {
|
|
151
|
+
return makeTableDef<N, C, K>({ name, columns: cols, primaryKey: keys, local: opts?.local });
|
|
90
152
|
},
|
|
91
153
|
};
|
|
92
154
|
},
|
|
93
155
|
};
|
|
94
156
|
}
|
|
95
157
|
|
|
96
|
-
function makeTableDef<N extends string, C extends AnyCols>(meta: TableMeta<N, C>): TableDef<N, C> {
|
|
158
|
+
function makeTableDef<N extends string, C extends AnyCols, PK extends string>(meta: TableMeta<N, C, PK>): TableDef<N, C, PK> {
|
|
97
159
|
return new Proxy({} as Record<string | symbol, unknown>, {
|
|
98
160
|
get(_target, prop) {
|
|
99
161
|
if (prop === SCHEMA) return meta;
|
|
100
162
|
if (typeof prop === "string") return (arg: unknown) => fieldCondition(prop, arg);
|
|
101
163
|
return undefined;
|
|
102
164
|
},
|
|
103
|
-
}) as unknown as TableDef<N, C>;
|
|
165
|
+
}) as unknown as TableDef<N, C, PK>;
|
|
104
166
|
}
|
|
105
167
|
|
|
106
168
|
/** Read a table's metadata (columns / PK / name). */
|
|
@@ -113,13 +175,25 @@ export type SchemaOf<T extends readonly AnyTable[]> = {
|
|
|
113
175
|
[E in T[number] as E[typeof SCHEMA]["name"]]: E[typeof SCHEMA]["columns"];
|
|
114
176
|
};
|
|
115
177
|
|
|
178
|
+
/** name → its primary-key column union, derived from the tables array (the PK captured by the
|
|
179
|
+
* `primaryKey(...)` builder). Powers the mutator tx's typed `update`/`delete`/`row` pk args. */
|
|
180
|
+
export type PkMapOf<T extends readonly AnyTable[]> = {
|
|
181
|
+
[E in T[number] as E[typeof SCHEMA]["name"]]: E[typeof SCHEMA]["primaryKey"][number];
|
|
182
|
+
};
|
|
183
|
+
|
|
116
184
|
/** name → columns, the resolved schema map carried in the {@link Schema} type. */
|
|
117
185
|
export type ColsMap = Record<string, AnyCols>;
|
|
118
186
|
|
|
119
|
-
|
|
187
|
+
/** name → (some subset of its column names): the loose shape a {@link Schema}'s pk-map satisfies. The
|
|
188
|
+
* fallback when a schema wasn't built through {@link createSchema} — every column could be the pk. */
|
|
189
|
+
export type PkMap<S extends ColsMap> = { [N in keyof S]: keyof S[N] & string };
|
|
190
|
+
|
|
191
|
+
export interface Schema<S extends ColsMap = ColsMap, P extends Record<string, string> = PkMap<S>> {
|
|
120
192
|
readonly tables: Readonly<Record<string, TableMeta>>;
|
|
121
193
|
/** Phantom carrying name→columns for query-root inference (never read at runtime). */
|
|
122
194
|
readonly __cols: S;
|
|
195
|
+
/** Phantom carrying name→pk-column-union for the typed mutator tx (never read at runtime). */
|
|
196
|
+
readonly __pk: P;
|
|
123
197
|
}
|
|
124
198
|
|
|
125
199
|
/** Table-name prefixes reserved by the engine for SYNTHETIC tables — `__agg_<fnv>` aggregate
|
|
@@ -138,13 +212,13 @@ export function isReservedTableName(name: string): boolean {
|
|
|
138
212
|
|
|
139
213
|
export function createSchema<const T extends readonly AnyTable[]>(opts: {
|
|
140
214
|
tables: T;
|
|
141
|
-
}): Schema<SchemaOf<T>> {
|
|
215
|
+
}): Schema<SchemaOf<T>, PkMapOf<T>> {
|
|
142
216
|
const tables: Record<string, TableMeta> = {};
|
|
143
217
|
for (const t of opts.tables) {
|
|
144
218
|
const m = t[SCHEMA];
|
|
145
219
|
addTableMeta(tables, m, "createSchema");
|
|
146
220
|
}
|
|
147
|
-
return { tables } as Schema<SchemaOf<T>>;
|
|
221
|
+
return { tables } as unknown as Schema<SchemaOf<T>, PkMapOf<T>>;
|
|
148
222
|
}
|
|
149
223
|
|
|
150
224
|
/** Extend a generated/synced schema with client-authoritative local-only tables.
|
|
@@ -154,10 +228,10 @@ export function createSchema<const T extends readonly AnyTable[]>(opts: {
|
|
|
154
228
|
* client. The added tables MUST be `table(name, { local: true })`: `extendSchema` deliberately
|
|
155
229
|
* refuses to append ordinary synced tables, because those need to come from daemon introspection
|
|
156
230
|
* (`rindle schema gen`) so the server and client cannot drift. */
|
|
157
|
-
export function extendSchema<S extends ColsMap, const T extends readonly AnyTable[]>(
|
|
158
|
-
base: Schema<S>,
|
|
231
|
+
export function extendSchema<S extends ColsMap, P extends Record<string, string>, const T extends readonly AnyTable[]>(
|
|
232
|
+
base: Schema<S, P>,
|
|
159
233
|
opts: { tables: T },
|
|
160
|
-
): Schema<S & SchemaOf<T>> {
|
|
234
|
+
): Schema<S & SchemaOf<T>, P & PkMapOf<T>> {
|
|
161
235
|
const tables: Record<string, TableMeta> = { ...base.tables };
|
|
162
236
|
for (const t of opts.tables) {
|
|
163
237
|
const m = t[SCHEMA];
|
|
@@ -168,7 +242,7 @@ export function extendSchema<S extends ColsMap, const T extends readonly AnyTabl
|
|
|
168
242
|
}
|
|
169
243
|
addTableMeta(tables, m, "extendSchema");
|
|
170
244
|
}
|
|
171
|
-
return { tables } as Schema<S & SchemaOf<T>>;
|
|
245
|
+
return { tables } as unknown as Schema<S & SchemaOf<T>, P & PkMapOf<T>>;
|
|
172
246
|
}
|
|
173
247
|
|
|
174
248
|
function addTableMeta(tables: Record<string, TableMeta>, m: TableMeta, caller: "createSchema" | "extendSchema") {
|
|
@@ -257,10 +331,10 @@ export type RefinedColsMap<S extends ColsMap, T extends readonly AnyTable[]> = {
|
|
|
257
331
|
* Runtime-validated identity: each def must name a table already in the schema and match its
|
|
258
332
|
* runtime shape exactly (same columns, kinds, primary key, and locality) — refinement narrows TS
|
|
259
333
|
* types, never what's on the wire. Composes with {@link extendSchema} in either order. */
|
|
260
|
-
export function refineSchema<S extends ColsMap, const T extends readonly RefinableTable<S>[]>(
|
|
261
|
-
base: Schema<S>,
|
|
334
|
+
export function refineSchema<S extends ColsMap, P extends Record<string, string>, const T extends readonly RefinableTable<S>[]>(
|
|
335
|
+
base: Schema<S, P>,
|
|
262
336
|
opts: { tables: T },
|
|
263
|
-
): Schema<RefinedColsMap<S, T
|
|
337
|
+
): Schema<RefinedColsMap<S, T>, P> {
|
|
264
338
|
const seen = new Set<string>();
|
|
265
339
|
for (const t of opts.tables) {
|
|
266
340
|
const m = t[SCHEMA];
|
|
@@ -277,7 +351,7 @@ export function refineSchema<S extends ColsMap, const T extends readonly Refinab
|
|
|
277
351
|
seen.add(m.name);
|
|
278
352
|
assertRefinementMatches(m, baseMeta);
|
|
279
353
|
}
|
|
280
|
-
return base as unknown as Schema<RefinedColsMap<S, T
|
|
354
|
+
return base as unknown as Schema<RefinedColsMap<S, T>, P>;
|
|
281
355
|
}
|
|
282
356
|
|
|
283
357
|
/** The refined def must be the same table the schema already carries — identical column set, kinds,
|
|
@@ -372,6 +446,43 @@ export function tableSpec(meta: TableMeta): { columns: string[]; primaryKey: num
|
|
|
372
446
|
return { columns, primaryKey };
|
|
373
447
|
}
|
|
374
448
|
|
|
449
|
+
/** A table's insert-completeness plan, derived once from its `Col` markers and shared by BOTH write
|
|
450
|
+
* funnels — the client `trackingTx` and the server `renderOp` — so their required-sets can't drift
|
|
451
|
+
* (design 206 §6.1/§6.2). A `NOT NULL` column is `required`; a nullable column (`.nullable()` set
|
|
452
|
+
* `Col.optional`) may be omitted and is filled with `null` (see {@link insertCell}). PK columns are
|
|
453
|
+
* never nullable (introspection forces them non-null), so they are always required. */
|
|
454
|
+
export interface InsertPlan {
|
|
455
|
+
/** Every column, in wire order. */
|
|
456
|
+
readonly columns: string[];
|
|
457
|
+
/** Columns that MUST be present on a full insert — the non-nullable ones. */
|
|
458
|
+
readonly required: string[];
|
|
459
|
+
/** The nullable (omittable-to-null) columns, for a fast membership test in the fill. */
|
|
460
|
+
readonly nullable: ReadonlySet<string>;
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
/** Derive a table's {@link InsertPlan} from its column markers. */
|
|
464
|
+
export function insertPlan(meta: TableMeta): InsertPlan {
|
|
465
|
+
const columns = Object.keys(meta.columns);
|
|
466
|
+
const nullable = new Set(columns.filter((c) => meta.columns[c].optional === true));
|
|
467
|
+
return { columns, required: columns.filter((c) => !nullable.has(c)), nullable };
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
/** The cell a full insert writes for column `c`: the given value, or `null` when a nullable column
|
|
471
|
+
* is omitted (design 206 §6.2). The caller's completeness check ({@link InsertPlan.required})
|
|
472
|
+
* guarantees a non-nullable column is present, so its omission never reaches here. */
|
|
473
|
+
export function insertCell(row: Record<string, WireValue>, c: string): WireValue {
|
|
474
|
+
return c in row ? row[c] : null;
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
/** Encode a keyed-row cell to its wire {@link WireValue} for a column KIND — the one place both write
|
|
478
|
+
* funnels stringify a `json<T>` object (the typed mutator surface / design 206 §7). An
|
|
479
|
+
* already-stringified json value (a `string`) or any non-json cell passes through unchanged, so a
|
|
480
|
+
* mutator may pass EITHER a parsed object OR a JSON string. Mirrors `store.positionalize`. */
|
|
481
|
+
export function toCell(v: WireValue | object, type: ColType): WireValue {
|
|
482
|
+
if (type === "json" && v !== null && typeof v === "object") return JSON.stringify(v);
|
|
483
|
+
return v as WireValue;
|
|
484
|
+
}
|
|
485
|
+
|
|
375
486
|
/** The client's per-table flat schema (name + column order + PK indices), the shape a
|
|
376
487
|
* normalized `hello` advertises (NORMALIZED-CHANGES-DESIGN.md §3). Used to validate a
|
|
377
488
|
* server hello against the CLIENT's own typed schema so a column-order / PK skew is caught
|
package/src/store.ts
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
import type { Ast } from "./ast.ts";
|
|
11
11
|
import { stableKey } from "./key.ts";
|
|
12
12
|
import { queries, type Query, type QueryRoot } from "./query.ts";
|
|
13
|
-
import type { ColsMap, RowOf, Schema } from "./schema.ts";
|
|
13
|
+
import type { ColsMap, InsertOf, RowOf, Schema } from "./schema.ts";
|
|
14
14
|
import type { Backend, ChangeEvent, ColType, FlatChange, Mutation, QueryId, RemoteQuery, ResultType, WireSchema, WireValue } from "./types.ts";
|
|
15
15
|
import { type ArrayView, FlatArrayView, type SingularArrayView, SingularView, type ViewTypes } from "./view.ts";
|
|
16
16
|
|
|
@@ -36,9 +36,13 @@ export interface AssembledNode {
|
|
|
36
36
|
}
|
|
37
37
|
|
|
38
38
|
/** The write transaction handed to `store.write(tx => …)`. Rows are objects keyed by column;
|
|
39
|
-
* the Store positionalizes them (and stringifies json columns) before the backend sees them.
|
|
39
|
+
* the Store positionalizes them (and stringifies json columns) before the backend sees them.
|
|
40
|
+
*
|
|
41
|
+
* `add` takes an {@link InsertOf} row — a nullable column may be omitted (it is filled with `null`,
|
|
42
|
+
* design 206 §7). `remove`/`edit` take a full {@link RowOf} row: they identify an EXISTING row, so
|
|
43
|
+
* every column (nullable ones as their actual `T | null` value) must be present. */
|
|
40
44
|
export interface WriteTx<S extends ColsMap> {
|
|
41
|
-
add<N extends keyof S & string>(table: N, row:
|
|
45
|
+
add<N extends keyof S & string>(table: N, row: InsertOf<S[N]>): void;
|
|
42
46
|
remove<N extends keyof S & string>(table: N, row: RowOf<S[N]>): void;
|
|
43
47
|
edit<N extends keyof S & string>(table: N, oldRow: RowOf<S[N]>, newRow: RowOf<S[N]>): void;
|
|
44
48
|
}
|