@orkestrel/database 0.0.11 → 0.0.13
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 +2 -2
- package/dist/src/browser/index.d.ts +48 -26
- package/dist/src/browser/index.js +87 -63
- package/dist/src/browser/index.js.map +1 -1
- package/dist/src/core/index.cjs +502 -384
- package/dist/src/core/index.cjs.map +1 -1
- package/dist/src/core/index.d.cts +455 -269
- package/dist/src/core/index.d.ts +455 -269
- package/dist/src/core/index.js +495 -383
- package/dist/src/core/index.js.map +1 -1
- package/dist/src/server/index.cjs +190 -306
- package/dist/src/server/index.cjs.map +1 -1
- package/dist/src/server/index.d.cts +126 -153
- package/dist/src/server/index.d.ts +126 -153
- package/dist/src/server/index.js +184 -298
- package/dist/src/server/index.js.map +1 -1
- package/package.json +23 -17
|
@@ -7,11 +7,38 @@ import { FieldPath } from '@orkestrel/contract';
|
|
|
7
7
|
import { Infer } from '@orkestrel/contract';
|
|
8
8
|
import { JSONSchema } from '@orkestrel/contract';
|
|
9
9
|
|
|
10
|
-
/**
|
|
10
|
+
/**
|
|
11
|
+
* Represents the admission boundary a scoped operation enters before it runs.
|
|
12
|
+
*
|
|
13
|
+
* @remarks
|
|
14
|
+
* The one contract the root database context and a transaction scope both
|
|
15
|
+
* expose: `accepting` reports whether the boundary still admits work, and
|
|
16
|
+
* `track` enters an operation into the boundary's ledger so whoever stops the
|
|
17
|
+
* boundary can contain everything already accepted. A streamed read enters each
|
|
18
|
+
* continuation independently through the same pair, so an idle iterator never
|
|
19
|
+
* pins the boundary open.
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* ```ts
|
|
23
|
+
* import type { AdmissionInterface } from '@orkestrel/database'
|
|
24
|
+
*
|
|
25
|
+
* const boundary: AdmissionInterface = {
|
|
26
|
+
* accepting: true,
|
|
27
|
+
* track: (operation) => operation(),
|
|
28
|
+
* }
|
|
29
|
+
* await boundary.track(async () => 42) // 42
|
|
30
|
+
* ```
|
|
31
|
+
*/
|
|
32
|
+
export declare interface AdmissionInterface {
|
|
33
|
+
readonly accepting: boolean;
|
|
34
|
+
track<R>(operation: () => Promise<R>): Promise<R>;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/** Names an aggregate computed over a numeric column. */
|
|
11
38
|
export declare type AggregateOperation = 'count' | 'sum' | 'average' | 'minimum' | 'maximum';
|
|
12
39
|
|
|
13
40
|
/**
|
|
14
|
-
*
|
|
41
|
+
* Applies a {@link QueryInput} to rows — filter, then sort, then page.
|
|
15
42
|
*
|
|
16
43
|
* @remarks
|
|
17
44
|
* The whole portable read pipeline in one place: conditions filter, `order`
|
|
@@ -26,12 +53,12 @@ export declare type AggregateOperation = 'count' | 'sum' | 'average' | 'minimum'
|
|
|
26
53
|
export declare function applyQuery(rows: readonly Row[], input?: QueryInput): readonly Row[];
|
|
27
54
|
|
|
28
55
|
/**
|
|
29
|
-
*
|
|
56
|
+
* Runs the FULL driver-conformance battery and collects every violation — the
|
|
30
57
|
* audit entry point for a driver author who wants a complete report rather
|
|
31
58
|
* than a single fail-fast throw.
|
|
32
59
|
*
|
|
33
60
|
* @remarks
|
|
34
|
-
* Drains {@link
|
|
61
|
+
* Drains {@link scanDriver} to completion: every phase runs regardless
|
|
35
62
|
* of earlier violations, so a driver breaking two independent invariants
|
|
36
63
|
* reports both. An empty array means the driver is fully conformant.
|
|
37
64
|
*
|
|
@@ -49,7 +76,7 @@ export declare function applyQuery(rows: readonly Row[], input?: QueryInput): re
|
|
|
49
76
|
export declare function auditDriver(factory: () => DriverInterface): Promise<readonly ConformanceFinding[]>;
|
|
50
77
|
|
|
51
78
|
/**
|
|
52
|
-
*
|
|
79
|
+
* Returns a fresh row whose primary column is authoritatively bound to its storage key.
|
|
53
80
|
*
|
|
54
81
|
* @param row - The caller row
|
|
55
82
|
* @param primary - The primary column
|
|
@@ -59,7 +86,7 @@ export declare function auditDriver(factory: () => DriverInterface): Promise<rea
|
|
|
59
86
|
export declare function bindRowKey(row: Row, primary: string, key: Key): Row;
|
|
60
87
|
|
|
61
88
|
/**
|
|
62
|
-
*
|
|
89
|
+
* Throws when an {@link OperationOptions.signal | AbortSignal} has fired — the shared
|
|
63
90
|
* abort gate checked at operation boundaries and between streamed rows.
|
|
64
91
|
*
|
|
65
92
|
* @remarks
|
|
@@ -86,7 +113,7 @@ export declare function bindRowKey(row: Row, primary: string, key: Key): Row;
|
|
|
86
113
|
export declare function checkAbort(signal: AbortSignal | undefined): void;
|
|
87
114
|
|
|
88
115
|
/**
|
|
89
|
-
*
|
|
116
|
+
* Clones unknown driver metadata into a distinct deeply frozen snapshot.
|
|
90
117
|
*
|
|
91
118
|
* @param value - Unknown metadata
|
|
92
119
|
* @returns Owned driver metadata
|
|
@@ -94,7 +121,7 @@ export declare function checkAbort(signal: AbortSignal | undefined): void;
|
|
|
94
121
|
export declare function cloneDriverMetadata(value: unknown): DriverMetadata;
|
|
95
122
|
|
|
96
123
|
/**
|
|
97
|
-
*
|
|
124
|
+
* Clones unknown driver schema into a distinct deeply frozen snapshot.
|
|
98
125
|
*
|
|
99
126
|
* @param value - Unknown table schema collection
|
|
100
127
|
* @returns Owned driver schema
|
|
@@ -102,7 +129,7 @@ export declare function cloneDriverMetadata(value: unknown): DriverMetadata;
|
|
|
102
129
|
export declare function cloneDriverSchema(value: unknown): readonly TableSchema[];
|
|
103
130
|
|
|
104
131
|
/**
|
|
105
|
-
*
|
|
132
|
+
* Clones unknown migration input into a distinct deeply frozen snapshot.
|
|
106
133
|
*
|
|
107
134
|
* @param value - Unknown migration input
|
|
108
135
|
* @returns Owned migration input
|
|
@@ -110,7 +137,7 @@ export declare function cloneDriverSchema(value: unknown): readonly TableSchema[
|
|
|
110
137
|
export declare function cloneMigrationInput(value: unknown): MigrationInput;
|
|
111
138
|
|
|
112
139
|
/**
|
|
113
|
-
*
|
|
140
|
+
* Represents one table's columns — a map of column name to its value {@link ContractShape}.
|
|
114
141
|
*
|
|
115
142
|
* @remarks
|
|
116
143
|
* This is exactly the property map an `objectShape` takes. A table row is always
|
|
@@ -122,7 +149,7 @@ export declare function cloneMigrationInput(value: unknown): MigrationInput;
|
|
|
122
149
|
export declare type ColumnMap = Readonly<Record<string, ContractShape>>;
|
|
123
150
|
|
|
124
151
|
/**
|
|
125
|
-
*
|
|
152
|
+
* Represents one column of a {@link TableSchema} — its name, portable {@link ColumnStorage}, and
|
|
126
153
|
* whether it independently accepts absence (`optional`) and explicit `null`
|
|
127
154
|
* (`nullable`).
|
|
128
155
|
*/
|
|
@@ -134,7 +161,7 @@ export declare interface ColumnSchema {
|
|
|
134
161
|
}
|
|
135
162
|
|
|
136
163
|
/**
|
|
137
|
-
*
|
|
164
|
+
* Names a portable storage type for a column — the backend maps it to its native type
|
|
138
165
|
* (SQLite affinity, an IndexedDB value). Derived from a column's `ContractShape`
|
|
139
166
|
* by `shapeToColumnStorage`; `json` covers object/array/union/raw values a backend stores
|
|
140
167
|
* as JSON text and can `json_extract` for nested-field queries.
|
|
@@ -142,8 +169,8 @@ export declare interface ColumnSchema {
|
|
|
142
169
|
export declare type ColumnStorage = 'text' | 'integer' | 'real' | 'boolean' | 'json' | 'blob';
|
|
143
170
|
|
|
144
171
|
/**
|
|
145
|
-
*
|
|
146
|
-
* range operators.
|
|
172
|
+
* Compares two arbitrary values under one total order — the comparator behind
|
|
173
|
+
* sorting and the range operators.
|
|
147
174
|
*
|
|
148
175
|
* @remarks
|
|
149
176
|
* Values of different types order by a fixed type rank (`undefined` < `null` <
|
|
@@ -158,7 +185,7 @@ export declare type ColumnStorage = 'text' | 'integer' | 'real' | 'boolean' | 'j
|
|
|
158
185
|
export declare function compareValues(left: unknown, right: unknown): number;
|
|
159
186
|
|
|
160
187
|
/**
|
|
161
|
-
*
|
|
188
|
+
* Computes an aggregate over a column across rows.
|
|
162
189
|
*
|
|
163
190
|
* @remarks
|
|
164
191
|
* `count` returns the row count. The numeric aggregates coerce each cell with
|
|
@@ -174,7 +201,7 @@ export declare function compareValues(left: unknown, right: unknown): number;
|
|
|
174
201
|
export declare function computeAggregate(rows: readonly unknown[], operation: AggregateOperation, column: FieldPath): number | undefined;
|
|
175
202
|
|
|
176
203
|
/**
|
|
177
|
-
*
|
|
204
|
+
* Represents one compiled WHERE condition.
|
|
178
205
|
*
|
|
179
206
|
* @remarks
|
|
180
207
|
* `values` carries the operands the operator needs — none for `absent` /
|
|
@@ -191,11 +218,11 @@ export declare interface Condition {
|
|
|
191
218
|
readonly connector: ConditionConnector;
|
|
192
219
|
}
|
|
193
220
|
|
|
194
|
-
/**
|
|
221
|
+
/** Names how a {@link Condition} joins to the running result of the conditions before it. */
|
|
195
222
|
export declare type ConditionConnector = 'and' | 'or';
|
|
196
223
|
|
|
197
224
|
/**
|
|
198
|
-
*
|
|
225
|
+
* Represents a WHERE operator — the comparison a single {@link Condition} applies.
|
|
199
226
|
*
|
|
200
227
|
* @remarks
|
|
201
228
|
* Each maps to a SQL operator and an IndexedDB read strategy (a key range where
|
|
@@ -205,7 +232,38 @@ export declare type ConditionConnector = 'and' | 'or';
|
|
|
205
232
|
export declare type ConditionOperator = 'equals' | 'not' | 'above' | 'below' | 'from' | 'to' | 'between' | 'like' | 'glob' | 'starts' | 'ends' | 'any' | 'none' | 'absent' | 'present';
|
|
206
233
|
|
|
207
234
|
/**
|
|
208
|
-
*
|
|
235
|
+
* Describes the `posts` table the driver-conformance battery opens — keyed by a non-`id`
|
|
236
|
+
* `slug` primary column.
|
|
237
|
+
*
|
|
238
|
+
* @remarks
|
|
239
|
+
* Pairs with {@link CONFORMANCE_USERS_SCHEMA} so one battery exercises both
|
|
240
|
+
* primary-key shapes: the default `id` and an explicit override.
|
|
241
|
+
*/
|
|
242
|
+
export declare const CONFORMANCE_POSTS_SCHEMA: TableSchema;
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
* Holds the fixed two-table schema every driver-conformance phase opens.
|
|
246
|
+
*
|
|
247
|
+
* @remarks
|
|
248
|
+
* Each phase mints a fresh driver and opens this exact schema, so a finding
|
|
249
|
+
* names a violated invariant rather than a setup difference between phases.
|
|
250
|
+
*/
|
|
251
|
+
export declare const CONFORMANCE_SCHEMA: readonly TableSchema[];
|
|
252
|
+
|
|
253
|
+
/**
|
|
254
|
+
* Describes the `users` table the driver-conformance battery opens — keyed by the default
|
|
255
|
+
* `id` primary column.
|
|
256
|
+
*
|
|
257
|
+
* @remarks
|
|
258
|
+
* `age` is optional and `meta` is a declared `json` column, so the battery's
|
|
259
|
+
* nested-round-trip phase is fair to a typed-column backend: a SQL driver
|
|
260
|
+
* persists only declared columns, while a schemaless backend ignores the
|
|
261
|
+
* declarations entirely.
|
|
262
|
+
*/
|
|
263
|
+
export declare const CONFORMANCE_USERS_SCHEMA: TableSchema;
|
|
264
|
+
|
|
265
|
+
/**
|
|
266
|
+
* Represents one violated invariant from the driver-conformance battery.
|
|
209
267
|
*
|
|
210
268
|
* @remarks
|
|
211
269
|
* Mirrors the payload shape of a `DatabaseError` `CONFORMANCE` `context` —
|
|
@@ -219,14 +277,14 @@ export declare interface ConformanceFinding {
|
|
|
219
277
|
}
|
|
220
278
|
|
|
221
279
|
/**
|
|
222
|
-
*
|
|
280
|
+
* Runs the driver-conformance battery, throwing on the first violated
|
|
223
281
|
* invariant — the fail-fast entry point most callers (test setup, CI smoke
|
|
224
282
|
* checks) want.
|
|
225
283
|
*
|
|
226
284
|
* @remarks
|
|
227
|
-
*
|
|
228
|
-
* lazy,
|
|
229
|
-
*
|
|
285
|
+
* Consumes only the first value {@link scanDriver} yields: because that
|
|
286
|
+
* generator is lazy, every LATER phase never runs — true fail-fast, not
|
|
287
|
+
* merely "report only the first". The
|
|
230
288
|
* thrown error is byte-compatible with the historical shape: a
|
|
231
289
|
* `CONFORMANCE` {@link DatabaseError} whose `message` is the finding's
|
|
232
290
|
* `message` and whose `context` is `{ check, ...finding.context }`.
|
|
@@ -245,15 +303,15 @@ export declare interface ConformanceFinding {
|
|
|
245
303
|
export declare function conformDriver(factory: () => DriverInterface): Promise<void>;
|
|
246
304
|
|
|
247
305
|
/**
|
|
248
|
-
*
|
|
306
|
+
* Creates a database over a driver and a declared `tables` schema.
|
|
249
307
|
*
|
|
250
308
|
* @remarks
|
|
251
309
|
* `tables` maps each name to its columns (a `column → shape` map); the database
|
|
252
310
|
* wraps each in an `objectShape`, so you never write `objectShape` at the table
|
|
253
311
|
* level. The `const` type parameter captures the literal names and columns, so
|
|
254
312
|
* `db.table('users')` is checked against the schema and typed by `Infer` of its
|
|
255
|
-
* columns — no annotations. Name a non-`id` primary-key column per table
|
|
256
|
-
* optional `primary` and `indexes` maps.
|
|
313
|
+
* columns — no annotations. Name a non-`id` primary-key column per table through
|
|
314
|
+
* the optional `primary` and `indexes` maps.
|
|
257
315
|
*
|
|
258
316
|
* @param options - The driver, `tables`, and optional `primary`, `indexes`,
|
|
259
317
|
* `name`, `generator`, `version`, and emitter hooks
|
|
@@ -278,7 +336,7 @@ export declare function conformDriver(factory: () => DriverInterface): Promise<v
|
|
|
278
336
|
export declare function createDatabase<const T extends TableMap>(options: DatabaseOptions<T>): DatabaseInterface<T>;
|
|
279
337
|
|
|
280
338
|
/**
|
|
281
|
-
*
|
|
339
|
+
* Creates the in-memory reference {@link DriverInterface}.
|
|
282
340
|
*
|
|
283
341
|
* @remarks
|
|
284
342
|
* Backed by nested maps with no I/O — the same driver runs in a browser or on a
|
|
@@ -289,7 +347,7 @@ export declare function createDatabase<const T extends TableMap>(options: Databa
|
|
|
289
347
|
export declare function createMemoryDriver(): DriverInterface;
|
|
290
348
|
|
|
291
349
|
/**
|
|
292
|
-
*
|
|
350
|
+
* Walks a table's rows forward for bulk in-place mutation.
|
|
293
351
|
*
|
|
294
352
|
* @remarks
|
|
295
353
|
* Iterates a snapshot of the table's keys taken at creation; `update` and
|
|
@@ -311,7 +369,7 @@ export declare interface CursorInterface<T = Row> {
|
|
|
311
369
|
}
|
|
312
370
|
|
|
313
371
|
/**
|
|
314
|
-
*
|
|
372
|
+
* Exposes a typed view over one shared internal lifecycle and storage context.
|
|
315
373
|
*
|
|
316
374
|
* @remarks
|
|
317
375
|
* Each view owns only its table contracts, primary columns, indexes, and key
|
|
@@ -335,7 +393,7 @@ export declare class Database<T extends TableMap = TableMap> implements Database
|
|
|
335
393
|
}
|
|
336
394
|
|
|
337
395
|
/**
|
|
338
|
-
*
|
|
396
|
+
* Represents an error thrown by the database layer.
|
|
339
397
|
*
|
|
340
398
|
* @remarks
|
|
341
399
|
* Carries a {@link DatabaseErrorCode} and an optional `context` bag naming the
|
|
@@ -346,7 +404,7 @@ export declare class Database<T extends TableMap = TableMap> implements Database
|
|
|
346
404
|
* `context`), an inapplicable {@link Migration} plan (`MIGRATION`), a
|
|
347
405
|
* driver that violates a {@link DriverInterface} invariant, thrown by the
|
|
348
406
|
* `conformDriver` helper (`CONFORMANCE`), and an unexpected infrastructure
|
|
349
|
-
* fault surfaced by a driver seam —
|
|
407
|
+
* fault surfaced by a driver seam — for example a filesystem failure while
|
|
350
408
|
* persisting (`DRIVER`) — as opposed to expected domain conditions, which
|
|
351
409
|
* keep their specific codes.
|
|
352
410
|
*/
|
|
@@ -356,48 +414,48 @@ export declare class DatabaseError extends Error {
|
|
|
356
414
|
constructor(code: DatabaseErrorCode, message: string, context?: Readonly<Record<string, unknown>>);
|
|
357
415
|
}
|
|
358
416
|
|
|
359
|
-
/**
|
|
417
|
+
/** Names a machine-readable {@link DatabaseError} code. */
|
|
360
418
|
export declare type DatabaseErrorCode = 'CLOSED' | 'NOT_FOUND' | 'CONFLICT' | 'VALIDATION' | 'ABORTED' | 'MIGRATION' | 'CONFORMANCE' | 'DRIVER';
|
|
361
419
|
|
|
362
420
|
/**
|
|
363
|
-
*
|
|
421
|
+
* Describes the push observation surface of a {@link DatabaseInterface} — the
|
|
364
422
|
* connection + transaction lifecycle a fire-and-forget observer (logging, metrics,
|
|
365
423
|
* tracing, cache invalidation) subscribes to.
|
|
366
424
|
*
|
|
367
425
|
* @remarks
|
|
368
426
|
* Pure signals carrying no row data — these are the database-level (not per-row)
|
|
369
427
|
* moments, so a non-generic map stays lean (per-row writes are {@link TableEventMap}).
|
|
370
|
-
* Listener isolation is the emitter's
|
|
428
|
+
* Listener isolation is the emitter's: every event is emitted directly and a
|
|
371
429
|
* listener throw is routed to the emitter's OWN `error` handler (the `error` option), never
|
|
372
430
|
* onto this domain map and never into the snapshot / commit / rollback flow — so a buggy
|
|
373
431
|
* observer can never reorder, throw into, or corrupt a transaction. Every emit sits AFTER the
|
|
374
432
|
* relevant transition: `commit` only after the scope succeeds, `rollback` only after the
|
|
375
433
|
* rollback operation completes (it OBSERVES the propagated scope error; that exact reason
|
|
376
434
|
* still propagates). A rollback failure propagates instead and emits no misleading
|
|
377
|
-
* `rollback` event. Subscribe
|
|
435
|
+
* `rollback` event. Subscribe through `database.emitter.on(...)`.
|
|
378
436
|
*
|
|
379
|
-
* Declared as a `type` alias (not `interface extends EventMap
|
|
437
|
+
* Declared as a `type` alias (not `interface extends EventMap` — `EventMap` is a
|
|
380
438
|
* `type` kind): a type-literal satisfies the `EventMap` constraint
|
|
381
439
|
* (`Record<string, readonly unknown[]>`) structurally, whereas an interface lacks the
|
|
382
440
|
* required index signature.
|
|
383
441
|
*/
|
|
384
442
|
export declare type DatabaseEventMap = {
|
|
385
|
-
/**
|
|
443
|
+
/** Signals that the driver connected (`open`, or the lazy first-use connect completed). */
|
|
386
444
|
readonly open: readonly [];
|
|
387
|
-
/**
|
|
445
|
+
/** Signals that the database was closed (the driver released). */
|
|
388
446
|
readonly close: readonly [];
|
|
389
|
-
/**
|
|
447
|
+
/** Signals that a transaction scope began after its native boundary or fallback snapshot was acquired. */
|
|
390
448
|
readonly transaction: readonly [];
|
|
391
|
-
/**
|
|
449
|
+
/** Signals that a transaction scope completed successfully (no rollback). */
|
|
392
450
|
readonly commit: readonly [];
|
|
393
|
-
/**
|
|
451
|
+
/** Signals that a transaction scope failed and rollback completed — the exact propagated scope error. */
|
|
394
452
|
readonly rollback: readonly [error: unknown];
|
|
395
|
-
/**
|
|
453
|
+
/** Signals that a {@link Migration} plan was applied through `migrate` — the applied plan. */
|
|
396
454
|
readonly migrate: readonly [migration: Migration];
|
|
397
455
|
};
|
|
398
456
|
|
|
399
457
|
/**
|
|
400
|
-
*
|
|
458
|
+
* Represents a database — the ergonomic entry point that owns the driver and its tables.
|
|
401
459
|
*
|
|
402
460
|
* @remarks
|
|
403
461
|
* A database is a typed view over a set of tables on one driver. Tables are
|
|
@@ -422,9 +480,9 @@ export declare interface DatabaseInterface<T extends TableMap = TableMap> {
|
|
|
422
480
|
close(): Promise<void>;
|
|
423
481
|
transaction<R>(scope: (transaction: DatabaseStorageInterface<T>) => Promise<R>, options?: OperationOptions): Promise<R>;
|
|
424
482
|
/**
|
|
425
|
-
*
|
|
426
|
-
* schema (its `tables`, as configured)
|
|
427
|
-
* resulting plan through the driver's optional `migrate` hook, and
|
|
483
|
+
* Diffs a caller-supplied deployed schema against this database's declared
|
|
484
|
+
* schema (its `tables`, as configured) through `planMigration`, applies the
|
|
485
|
+
* resulting plan through the driver's optional `migrate` hook, and returns
|
|
428
486
|
* the applied plan.
|
|
429
487
|
*
|
|
430
488
|
* @param deployed - The schema currently deployed, as {@link TableSchema}s
|
|
@@ -459,8 +517,8 @@ export declare interface DatabaseInterface<T extends TableMap = TableMap> {
|
|
|
459
517
|
* `primary` overrides the primary-key column per table ({@link DEFAULT_PRIMARY}
|
|
460
518
|
* otherwise); `indexes` declares secondary indexes per table (contracts don't
|
|
461
519
|
* express them) that flow into each derived {@link TableSchema}; `name` labels
|
|
462
|
-
* the database; `on` wires initial {@link DatabaseEventMap} listeners
|
|
463
|
-
* is the emitter's listener-error handler (
|
|
520
|
+
* the database; `on` wires initial {@link DatabaseEventMap} listeners; `error`
|
|
521
|
+
* is the emitter's listener-error handler (a listener throw routes here);
|
|
464
522
|
* `generator` is the authoritative key-generation override a table uses when a
|
|
465
523
|
* written row's primary is exactly `undefined`. When omitted, the table uses
|
|
466
524
|
* global `crypto.randomUUID()`; numeric primary keys require a custom generator.
|
|
@@ -468,7 +526,7 @@ export declare interface DatabaseInterface<T extends TableMap = TableMap> {
|
|
|
468
526
|
export declare interface DatabaseOptions<T extends TableMap = TableMap> {
|
|
469
527
|
readonly on?: EmitterHooks<DatabaseEventMap>;
|
|
470
528
|
/**
|
|
471
|
-
*
|
|
529
|
+
* Holds the listener-error handler shared by the database and every table emitter.
|
|
472
530
|
*
|
|
473
531
|
* @remarks
|
|
474
532
|
* Listener throws from root, imported, and transaction-scoped handles route
|
|
@@ -482,31 +540,31 @@ export declare interface DatabaseOptions<T extends TableMap = TableMap> {
|
|
|
482
540
|
readonly indexes?: IndexMap;
|
|
483
541
|
readonly name?: string;
|
|
484
542
|
/**
|
|
485
|
-
*
|
|
543
|
+
* Holds the authoritative key-generation override for a keyless write.
|
|
486
544
|
*
|
|
487
545
|
* @remarks
|
|
488
546
|
* Omit it to use global `crypto.randomUUID()`. A numeric primary requires a
|
|
489
547
|
* custom generator. Explicit primary values never invoke this function. A
|
|
490
|
-
* custom generator throw is `VALIDATION`; a host
|
|
491
|
-
*
|
|
492
|
-
*
|
|
548
|
+
* custom generator throw is `VALIDATION`; a host `crypto.randomUUID()` failure
|
|
549
|
+
* is `DRIVER`. An invalid returned key is `VALIDATION`; neither branch falls
|
|
550
|
+
* back or retries.
|
|
493
551
|
*/
|
|
494
552
|
readonly generator?: KeyFunction;
|
|
495
553
|
/**
|
|
496
|
-
*
|
|
554
|
+
* Holds the declared schema version.
|
|
497
555
|
*
|
|
498
556
|
* @remarks
|
|
499
557
|
* Only meaningful when the driver implements BOTH {@link DriverInterface.metadata}
|
|
500
558
|
* and {@link DriverInterface.stamp} (a versioning driver); unset, or a
|
|
501
559
|
* non-versioning driver, leaves `open()` unchanged from today's behavior.
|
|
502
|
-
* When set and the driver versions, `open()` reconciles against the
|
|
503
|
-
*
|
|
560
|
+
* When set and the driver versions, `open()` reconciles against the driver's
|
|
561
|
+
* persisted {@link DriverMetadata}:
|
|
504
562
|
* - **Fresh store** (`metadata()` returns `undefined` after the durable
|
|
505
563
|
* driver proves absence) — no migration is possible (there is nothing
|
|
506
|
-
* deployed to diff against), so `open()`
|
|
507
|
-
*
|
|
564
|
+
* deployed to diff against), so `open()` stamps `{ version, schema }` for
|
|
565
|
+
* next time.
|
|
508
566
|
* - **Stored version < `version`** — `planMigration(stored.schema, declared
|
|
509
|
-
* schema)` computes the upgrade plan, applied
|
|
567
|
+
* schema)` computes the upgrade plan, applied through the driver's optional
|
|
510
568
|
* `migrate` hook. If `migrate` is absent and the plan is non-empty,
|
|
511
569
|
* `open()` throws `DatabaseError` `MIGRATION`. On success, `open()`
|
|
512
570
|
* `stamp`s the new `{ version, schema }` and emits the `migrate` event.
|
|
@@ -524,11 +582,11 @@ export declare interface DatabaseOptions<T extends TableMap = TableMap> {
|
|
|
524
582
|
readonly version?: number;
|
|
525
583
|
}
|
|
526
584
|
|
|
527
|
-
/**
|
|
585
|
+
/** Names the lifecycle state of a {@link DatabaseInterface}. */
|
|
528
586
|
export declare type DatabaseStatus = 'idle' | 'open' | 'closed';
|
|
529
587
|
|
|
530
588
|
/**
|
|
531
|
-
*
|
|
589
|
+
* Represents a database view valid only inside one {@link DatabaseInterface.transaction}
|
|
532
590
|
* scope.
|
|
533
591
|
*
|
|
534
592
|
* @remarks
|
|
@@ -542,7 +600,7 @@ export declare interface DatabaseStorageInterface<T extends TableMap = TableMap>
|
|
|
542
600
|
}
|
|
543
601
|
|
|
544
602
|
/**
|
|
545
|
-
*
|
|
603
|
+
* Supplies the primary-key column assumed when {@link PrimaryMap} does not name one.
|
|
546
604
|
*
|
|
547
605
|
* @remarks
|
|
548
606
|
* `id` is the convention IndexedDB (`keyPath: 'id'`) and SQL (`id` / rowid) both
|
|
@@ -551,84 +609,24 @@ export declare interface DatabaseStorageInterface<T extends TableMap = TableMap>
|
|
|
551
609
|
export declare const DEFAULT_PRIMARY = "id";
|
|
552
610
|
|
|
553
611
|
/**
|
|
554
|
-
*
|
|
555
|
-
* per phase, yielding one {@link ConformanceFinding} per violated invariant —
|
|
556
|
-
* the shared invariant suite every backend (in-memory, SQLite, IndexedDB)
|
|
557
|
-
* must uphold to be a drop-in {@link DriverInterface}.
|
|
558
|
-
*
|
|
559
|
-
* @remarks
|
|
560
|
-
* Framework-agnostic: no test-runner or Node imports, only sibling core
|
|
561
|
-
* modules — so it runs equally from a unit test, a smoke script, or a new
|
|
562
|
-
* driver's own README. Opens a fixed two-table schema (`users` keyed by the
|
|
563
|
-
* default `id`, `posts` keyed by a non-id `slug`) and, calling `factory()`
|
|
564
|
-
* fresh for each phase so failures stay isolated, verifies: `open`/`close`;
|
|
565
|
-
* `read` of a missing key returns `undefined`; `write`/`read` round-trip with
|
|
566
|
-
* DEEP copy-in/copy-out isolation (mutating the caller's row — including a
|
|
567
|
-
* NESTED field — after `write`, or a row `read` returns, never perturbs
|
|
568
|
-
* stored state) and upsert-overwrite; simultaneous same-key `insert` calls
|
|
569
|
-
* produce exactly one commit and one `CONFLICT`; pre-aborted `write`,
|
|
570
|
-
* `insert`, and `delete` calls leave storage unchanged; `delete` returns
|
|
571
|
-
* `true` then `false`;
|
|
572
|
-
* `keys`/`scan` yield in ascending key order; `clear` empties only its target
|
|
573
|
-
* table; `snapshot`'s rollback thunk restores pre-snapshot state, including a
|
|
574
|
-
* NESTED field mutated in place on a read-back row between capture and
|
|
575
|
-
* restore; a scoped `snapshot(['users'])` rolls back only the named table,
|
|
576
|
-
* leaving a concurrent mutation to another table intact; a
|
|
577
|
-
* non-`id` primary key (`posts.slug`) round-trips; a nested-object row
|
|
578
|
-
* round-trips structurally (via {@link equalsValue}). The optional surface is
|
|
579
|
-
* presence-gated: when `migrate` exists, a `column.remove` plan strips the
|
|
580
|
-
* column from stored rows and a plan referencing an unknown table throws
|
|
581
|
-
* `DatabaseError` `MIGRATION`; when `stream` exists, it yields only
|
|
582
|
-
* condition-matching rows and honors `offset`/`limit`; when `transaction`
|
|
583
|
-
* exists, `commit` persists and `rollback` restores; when both `metadata` and
|
|
584
|
-
* `stamp` exist, a fresh store's `metadata()` is `undefined`, and after
|
|
585
|
-
* `stamp({ version, schema })`, `metadata()` returns the exact stamped value.
|
|
586
|
-
*
|
|
587
|
-
* Each phase runs within a `try`/`catch`: an EXPECTED mismatch yields a
|
|
588
|
-
* finding built from the assertion, while an UNEXPECTED throw (a driver
|
|
589
|
-
* crash mid-phase) is caught and yielded as a finding too, naming the phase
|
|
590
|
-
* as `check` and carrying the caught error in `context.error` — a broken
|
|
591
|
-
* driver can never escape the battery as an unhandled rejection. Within a
|
|
592
|
-
* phase, the FIRST violated assertion yields and the phase stops (matching
|
|
593
|
-
* the historical fail-fast shape at phase granularity); the generator then
|
|
594
|
-
* moves on to the next phase regardless. Because this is a **generator**,
|
|
595
|
-
* consuming only the first yielded value reproduces true fail-fast (later
|
|
596
|
-
* phases never run) — that is exactly what {@link conformDriver} does.
|
|
597
|
-
*
|
|
598
|
-
* @param factory - Mints a fresh, unopened driver instance (called once per phase)
|
|
599
|
-
* @yields One {@link ConformanceFinding} per violated invariant, in phase order
|
|
600
|
-
*
|
|
601
|
-
* @example
|
|
602
|
-
* ```ts
|
|
603
|
-
* import { createMemoryDriver, driverFindings } from '@orkestrel/database'
|
|
604
|
-
*
|
|
605
|
-
* for await (const finding of driverFindings(() => createMemoryDriver())) {
|
|
606
|
-
* console.log(finding.check, finding.message)
|
|
607
|
-
* }
|
|
608
|
-
* ```
|
|
609
|
-
*/
|
|
610
|
-
export declare function driverFindings(factory: () => DriverInterface): AsyncIterable<ConformanceFinding>;
|
|
611
|
-
|
|
612
|
-
/**
|
|
613
|
-
* The storage primitive every backend implements — the whole of the bridge.
|
|
612
|
+
* Declares the storage primitive every backend implements — the whole of the bridge.
|
|
614
613
|
*
|
|
615
614
|
* @remarks
|
|
616
615
|
* The REQUIRED surface is deliberately minimal: keyed read / write / atomic
|
|
617
|
-
* insert / delete, an ordered `scan`, a key listing, and a `snapshot` that
|
|
618
|
-
* transactions — the irreducible primitive. There is **no** required
|
|
619
|
-
* count, or aggregate
|
|
620
|
-
*
|
|
621
|
-
*
|
|
622
|
-
*
|
|
623
|
-
*
|
|
624
|
-
*
|
|
625
|
-
*
|
|
626
|
-
*
|
|
627
|
-
*
|
|
628
|
-
* `false` rather than throwing (AGENTS §12). Metadata has the same ownership
|
|
616
|
+
* insert / delete, an ordered `scan`, a key listing, and a `snapshot` that
|
|
617
|
+
* backs transactions — the irreducible primitive. There is **no** required
|
|
618
|
+
* query, count, or aggregate here: all of that is one query engine in the core
|
|
619
|
+
* (`helpers.ts`) running over `scan`, so a new backend implements a handful of
|
|
620
|
+
* tiny methods rather than re-deriving WHERE compilation. `open` receives a
|
|
621
|
+
* derived {@link TableSchema}`[]` (columns, types, primary, indexes) so a
|
|
622
|
+
* native backend can build real tables and indexes; a scan-only backend reads
|
|
623
|
+
* only `name`. The optional `records?` / `aggregate?` are native overrides the
|
|
624
|
+
* engine falls back from. The API is async (Promises) because IndexedDB is;
|
|
625
|
+
* synchronous backends resolve immediately. Lookups that may miss return
|
|
626
|
+
* `undefined` / `false` rather than throwing. Metadata has the same ownership
|
|
629
627
|
* boundary across every implementation: `stamp` and `migrate` snapshot
|
|
630
|
-
* {@link DriverMetadata} at entry, while `metadata` returns a distinct deeply
|
|
631
|
-
* snapshot. A durable driver returns `undefined` only when it proves the
|
|
628
|
+
* {@link DriverMetadata} at entry, while `metadata` returns a distinct deeply
|
|
629
|
+
* frozen snapshot. A durable driver returns `undefined` only when it proves the
|
|
632
630
|
* metadata record or durable store is absent. Existing unreadable or malformed
|
|
633
631
|
* durable state fails `open` / `metadata` closed; it is never treated as fresh,
|
|
634
632
|
* rewritten, or repaired automatically.
|
|
@@ -637,7 +635,7 @@ export declare interface DriverInterface extends StorageInterface {
|
|
|
637
635
|
open(schema: readonly TableSchema[]): Promise<void>;
|
|
638
636
|
close(): Promise<void>;
|
|
639
637
|
/**
|
|
640
|
-
*
|
|
638
|
+
* Captures table rows and returns a repeatable thunk that restores those rows —
|
|
641
639
|
* the primitive transactions are built on.
|
|
642
640
|
*
|
|
643
641
|
* @remarks
|
|
@@ -648,14 +646,61 @@ export declare interface DriverInterface extends StorageInterface {
|
|
|
648
646
|
*/
|
|
649
647
|
snapshot(tables?: readonly string[]): Promise<() => Promise<void>>;
|
|
650
648
|
/**
|
|
651
|
-
*
|
|
652
|
-
* rollback, release, and invalidation of the scoped capability.
|
|
649
|
+
* Opens a native transaction scope — an optional driver hook. The driver owns acquisition,
|
|
650
|
+
* commit or rollback, release, and invalidation of the scoped capability.
|
|
653
651
|
*/
|
|
654
652
|
transaction?<R>(scope: (storage: StorageInterface) => Promise<R>): Promise<R>;
|
|
655
653
|
}
|
|
656
654
|
|
|
657
655
|
/**
|
|
658
|
-
*
|
|
656
|
+
* Forms the internal continuation boundary for a root driver async iterator.
|
|
657
|
+
*
|
|
658
|
+
* @remarks
|
|
659
|
+
* A driver transaction can begin while a caller holds an idle root iterator.
|
|
660
|
+
* Every `next` therefore checks the driver's root-state guard immediately
|
|
661
|
+
* before and after advancing the source. A failed continuation terminalizes the
|
|
662
|
+
* iterator, discards any row produced before the post-advance guard failed, and
|
|
663
|
+
* attempts source cleanup exactly once.
|
|
664
|
+
*
|
|
665
|
+
* A driver implementing the published `DriverInterface` extension seam wraps its
|
|
666
|
+
* own source iterator in one so a root `scan` / `stream` cannot outlive the
|
|
667
|
+
* driver state it was opened against.
|
|
668
|
+
*
|
|
669
|
+
* @typeParam T - The value the wrapped source yields
|
|
670
|
+
*
|
|
671
|
+
* @example
|
|
672
|
+
* ```ts
|
|
673
|
+
* import type { Row } from '@orkestrel/database'
|
|
674
|
+
* import { DatabaseError, DriverIterator } from '@orkestrel/database'
|
|
675
|
+
*
|
|
676
|
+
* // Inside a driver's `scan`, over its own row source and root-state guard.
|
|
677
|
+
* declare const rows: AsyncIterator<Row>
|
|
678
|
+
* declare const transacting: () => boolean
|
|
679
|
+
* const scan = new DriverIterator(rows, () => {
|
|
680
|
+
* if (transacting()) {
|
|
681
|
+
* throw new DatabaseError('CONFLICT', 'scan: a transaction is active')
|
|
682
|
+
* }
|
|
683
|
+
* })
|
|
684
|
+
* for await (const row of scan) row // one row at a time, guarded around each advance
|
|
685
|
+
* ```
|
|
686
|
+
*/
|
|
687
|
+
export declare class DriverIterator<T> implements AsyncIterableIterator<T> {
|
|
688
|
+
#private;
|
|
689
|
+
/**
|
|
690
|
+
* Wraps one source iterator in the continuation boundary.
|
|
691
|
+
*
|
|
692
|
+
* @param source - The driver's own row iterator, advanced once per `next`
|
|
693
|
+
* @param guard - The root-state check, run immediately before and after each advance; it throws to terminalize the iteration
|
|
694
|
+
*/
|
|
695
|
+
constructor(source: AsyncIterator<T>, guard: () => void);
|
|
696
|
+
[Symbol.asyncIterator](): AsyncIterableIterator<T>;
|
|
697
|
+
next(): Promise<IteratorResult<T>>;
|
|
698
|
+
return(): Promise<IteratorResult<T>>;
|
|
699
|
+
throw(error?: unknown): Promise<IteratorResult<T>>;
|
|
700
|
+
}
|
|
701
|
+
|
|
702
|
+
/**
|
|
703
|
+
* Represents persisted schema metadata a versioning driver owns as an immutable snapshot.
|
|
659
704
|
*
|
|
660
705
|
* @remarks
|
|
661
706
|
* A driver snapshots metadata when it enters through `stamp` or a
|
|
@@ -671,13 +716,14 @@ export declare interface DriverMetadata {
|
|
|
671
716
|
}
|
|
672
717
|
|
|
673
718
|
/**
|
|
674
|
-
*
|
|
675
|
-
* checks and any test/fixture that needs "same data", not
|
|
719
|
+
* Compares two values structurally by SameValueZero leaves — the comparator
|
|
720
|
+
* behind conformance checks and any test/fixture that needs "same data", not
|
|
721
|
+
* "same reference".
|
|
676
722
|
*
|
|
677
723
|
* @remarks
|
|
678
724
|
* Primitives compare by SameValueZero (`NaN` equals itself; `+0` equals `-0`).
|
|
679
725
|
* Arrays compare by index (same length, every element `equalsValue`). Plain
|
|
680
|
-
* records (
|
|
726
|
+
* records (through `isRecord`) compare by their OWN enumerable keys: same key
|
|
681
727
|
* COUNT and, for every key in `left`, `right` has that key (`Object.hasOwn`)
|
|
682
728
|
* with a `equalsValue` value — so a key present with value `undefined` is NOT
|
|
683
729
|
* equal to that key being absent (both differ in `Object.keys` membership).
|
|
@@ -688,7 +734,7 @@ export declare interface DriverMetadata {
|
|
|
688
734
|
*
|
|
689
735
|
* @param left - The left value
|
|
690
736
|
* @param right - The right value
|
|
691
|
-
* @returns
|
|
737
|
+
* @returns True if `left` and `right` are structurally equal; false otherwise
|
|
692
738
|
*
|
|
693
739
|
* @example
|
|
694
740
|
* ```ts
|
|
@@ -700,7 +746,7 @@ export declare interface DriverMetadata {
|
|
|
700
746
|
export declare function equalsValue(left: unknown, right: unknown): boolean;
|
|
701
747
|
|
|
702
748
|
/**
|
|
703
|
-
*
|
|
749
|
+
* Reads a row's primary key from a column, when it is a usable {@link Key}.
|
|
704
750
|
*
|
|
705
751
|
* @param row - The row to read
|
|
706
752
|
* @param column - The primary-key column name
|
|
@@ -709,7 +755,7 @@ export declare function equalsValue(left: unknown, right: unknown): boolean;
|
|
|
709
755
|
export declare function extractKey(row: Row, column: string): Key | undefined;
|
|
710
756
|
|
|
711
757
|
/**
|
|
712
|
-
*
|
|
758
|
+
* Filters rows by a list of conditions — the shared basis for a table's count
|
|
713
759
|
* and aggregate paths (no sort/page, unlike {@link applyQuery}).
|
|
714
760
|
*
|
|
715
761
|
* @remarks
|
|
@@ -731,7 +777,29 @@ export declare function extractKey(row: Row, column: string): Key | undefined;
|
|
|
731
777
|
export declare function filterRows(rows: readonly Row[], conditions: readonly Condition[]): readonly Row[];
|
|
732
778
|
|
|
733
779
|
/**
|
|
734
|
-
*
|
|
780
|
+
* Reads one flat column's declaration out of a table schema.
|
|
781
|
+
*
|
|
782
|
+
* @remarks
|
|
783
|
+
* The single lookup behind every declared-column question — storage type,
|
|
784
|
+
* optionality, and nullability all come off the returned {@link ColumnSchema},
|
|
785
|
+
* so a caller that needs more than one of them reads them from one result. A
|
|
786
|
+
* nested {@link FieldPath} names no declared column, so resolve the path's head
|
|
787
|
+
* before calling. A schema that does not declare the column returns `undefined`.
|
|
788
|
+
*
|
|
789
|
+
* @param name - The flat column name
|
|
790
|
+
* @param schema - The table's schema
|
|
791
|
+
* @returns The column's {@link ColumnSchema}, or `undefined` when the schema does not declare it
|
|
792
|
+
*
|
|
793
|
+
* @example
|
|
794
|
+
* ```ts
|
|
795
|
+
* findColumn('age', schema)?.storage // 'integer'
|
|
796
|
+
* findColumn('absent', schema) // undefined
|
|
797
|
+
* ```
|
|
798
|
+
*/
|
|
799
|
+
export declare function findColumn(name: string, schema: TableSchema): ColumnSchema | undefined;
|
|
800
|
+
|
|
801
|
+
/**
|
|
802
|
+
* Holds per-table secondary indexes — `{ [table]: groups }`, each group one
|
|
735
803
|
* (possibly compound) index of column names.
|
|
736
804
|
*
|
|
737
805
|
* @remarks
|
|
@@ -742,18 +810,18 @@ export declare function filterRows(rows: readonly Row[], conditions: readonly Co
|
|
|
742
810
|
export declare type IndexMap = Readonly<Record<string, ReadonlyArray<readonly string[]>>>;
|
|
743
811
|
|
|
744
812
|
/**
|
|
745
|
-
*
|
|
813
|
+
* Checks whether a value is a portable column schema.
|
|
746
814
|
*
|
|
747
815
|
* @param value - The value to test
|
|
748
|
-
* @returns
|
|
816
|
+
* @returns True if `value` is a complete {@link ColumnSchema}; false otherwise
|
|
749
817
|
*/
|
|
750
818
|
export declare function isColumnSchema(value: unknown): value is ColumnSchema;
|
|
751
819
|
|
|
752
820
|
/**
|
|
753
|
-
*
|
|
821
|
+
* Narrows an unknown caught value to a {@link DatabaseError}.
|
|
754
822
|
*
|
|
755
823
|
* @param value - The value to test (typically a `catch` binding)
|
|
756
|
-
* @returns
|
|
824
|
+
* @returns True if `value` is a {@link DatabaseError}; false otherwise
|
|
757
825
|
*
|
|
758
826
|
* @example
|
|
759
827
|
* ```ts
|
|
@@ -767,63 +835,63 @@ export declare function isColumnSchema(value: unknown): value is ColumnSchema;
|
|
|
767
835
|
export declare function isDatabaseError(value: unknown): value is DatabaseError;
|
|
768
836
|
|
|
769
837
|
/**
|
|
770
|
-
*
|
|
838
|
+
* Checks whether a value is persisted driver metadata.
|
|
771
839
|
*
|
|
772
840
|
* @param value - The value to test
|
|
773
|
-
* @returns
|
|
841
|
+
* @returns True if `value` is complete {@link DriverMetadata}; false otherwise
|
|
774
842
|
*/
|
|
775
843
|
export declare function isDriverMetadata(value: unknown): value is DriverMetadata;
|
|
776
844
|
|
|
777
845
|
/**
|
|
778
|
-
*
|
|
846
|
+
* Checks whether a value is a complete portable driver schema.
|
|
779
847
|
*
|
|
780
848
|
* @param value - The value to test
|
|
781
|
-
* @returns
|
|
849
|
+
* @returns True if `value` is a table-schema collection with unique table names; false otherwise
|
|
782
850
|
*/
|
|
783
851
|
export declare function isDriverSchema(value: unknown): value is readonly TableSchema[];
|
|
784
852
|
|
|
785
853
|
/**
|
|
786
|
-
*
|
|
854
|
+
* Checks whether a value is a usable database key.
|
|
787
855
|
*
|
|
788
856
|
* @param value - The value to test
|
|
789
|
-
* @returns
|
|
857
|
+
* @returns True if `value` is a string or a finite number; false otherwise
|
|
790
858
|
*/
|
|
791
859
|
export declare function isKey(value: unknown): value is Key;
|
|
792
860
|
|
|
793
861
|
/**
|
|
794
|
-
*
|
|
862
|
+
* Checks whether a value is an ordered migration plan.
|
|
795
863
|
*
|
|
796
864
|
* @param value - The value to test
|
|
797
|
-
* @returns
|
|
865
|
+
* @returns True if `value` is a complete {@link Migration}; false otherwise
|
|
798
866
|
*/
|
|
799
867
|
export declare function isMigration(value: unknown): value is Migration;
|
|
800
868
|
|
|
801
869
|
/**
|
|
802
|
-
*
|
|
870
|
+
* Checks whether a value is one atomic migration request.
|
|
803
871
|
*
|
|
804
872
|
* @param value - The value to test
|
|
805
|
-
* @returns
|
|
873
|
+
* @returns True if `value` is a complete {@link MigrationInput}; false otherwise
|
|
806
874
|
*/
|
|
807
875
|
export declare function isMigrationInput(value: unknown): value is MigrationInput;
|
|
808
876
|
|
|
809
877
|
/**
|
|
810
|
-
*
|
|
878
|
+
* Checks whether a value is one ordered migration step.
|
|
811
879
|
*
|
|
812
880
|
* @param value - The value to test
|
|
813
|
-
* @returns
|
|
881
|
+
* @returns True if `value` is a complete {@link MigrationStep}; false otherwise
|
|
814
882
|
*/
|
|
815
883
|
export declare function isMigrationStep(value: unknown): value is MigrationStep;
|
|
816
884
|
|
|
817
885
|
/**
|
|
818
|
-
*
|
|
886
|
+
* Checks whether a value is a portable table schema.
|
|
819
887
|
*
|
|
820
888
|
* @param value - The value to test
|
|
821
|
-
* @returns
|
|
889
|
+
* @returns True if `value` is a complete {@link TableSchema}; false otherwise
|
|
822
890
|
*/
|
|
823
891
|
export declare function isTableSchema(value: unknown): value is TableSchema;
|
|
824
892
|
|
|
825
893
|
/**
|
|
826
|
-
*
|
|
894
|
+
* Represents a primary key — the value identifying a row within its table.
|
|
827
895
|
*
|
|
828
896
|
* @remarks
|
|
829
897
|
* `string | number` is the intersection of what IndexedDB key ranges and SQL
|
|
@@ -833,7 +901,7 @@ export declare function isTableSchema(value: unknown): value is TableSchema;
|
|
|
833
901
|
export declare type Key = string | number;
|
|
834
902
|
|
|
835
903
|
/**
|
|
836
|
-
*
|
|
904
|
+
* Represents a key-generating function.
|
|
837
905
|
*
|
|
838
906
|
* @remarks
|
|
839
907
|
* Supplied through {@link DatabaseOptions.generator} as an authoritative
|
|
@@ -844,7 +912,7 @@ export declare type Key = string | number;
|
|
|
844
912
|
export declare type KeyFunction = () => Key;
|
|
845
913
|
|
|
846
914
|
/**
|
|
847
|
-
*
|
|
915
|
+
* Evaluates one {@link Condition} against a row — the per-operator predicate.
|
|
848
916
|
*
|
|
849
917
|
* @remarks
|
|
850
918
|
* Reads the condition's column — a `FieldPath`, resolved with `resolveField` (a
|
|
@@ -858,42 +926,61 @@ export declare type KeyFunction = () => Key;
|
|
|
858
926
|
* on leaves, so `NaN` now equals `NaN` under `equals` / `any` (it never matched
|
|
859
927
|
* anything under the old rank-based comparison). `like` / `glob` / `starts` /
|
|
860
928
|
* `ends` match only strings; `absent` / `present` test nullishness. Total — a
|
|
861
|
-
* type mismatch is
|
|
929
|
+
* type mismatch is a non-match.
|
|
862
930
|
*
|
|
863
931
|
* @param row - The row to test
|
|
864
932
|
* @param condition - The condition to apply
|
|
865
|
-
* @returns
|
|
933
|
+
* @returns True if the row satisfies the condition; false otherwise
|
|
866
934
|
*/
|
|
867
935
|
export declare function matchesCondition(row: Row, condition: Condition): boolean;
|
|
868
936
|
|
|
869
937
|
/**
|
|
870
|
-
*
|
|
938
|
+
* Matches a value against a `GLOB` pattern, preserving case.
|
|
871
939
|
*
|
|
872
940
|
* @remarks
|
|
873
|
-
*
|
|
874
|
-
*
|
|
875
|
-
*
|
|
876
|
-
*
|
|
877
|
-
*
|
|
941
|
+
* `*` matches any run of characters (including none) and `?` matches exactly one
|
|
942
|
+
* character; every other pattern character matches itself literally, so a
|
|
943
|
+
* character class such as `[a-z]` is NOT interpreted. Runs on
|
|
944
|
+
* {@link matchesWildcardPattern}, so the match is linear in the value length and
|
|
945
|
+
* the pattern is capped at {@link MAX_PATTERN_LENGTH}.
|
|
878
946
|
*
|
|
879
|
-
* @param value - The
|
|
880
|
-
* @param
|
|
881
|
-
* @returns
|
|
947
|
+
* @param value - The value to test
|
|
948
|
+
* @param pattern - The `GLOB` pattern
|
|
949
|
+
* @returns True if `value` matches `pattern` case-sensitively; false otherwise
|
|
950
|
+
* @throws A `VALIDATION` {@link DatabaseError} when `pattern` exceeds {@link MAX_PATTERN_LENGTH}
|
|
882
951
|
*
|
|
883
952
|
* @example
|
|
884
953
|
* ```ts
|
|
885
|
-
*
|
|
886
|
-
*
|
|
954
|
+
* matchesGlobPattern('hello', 'h*o') // true — `*` spans any run
|
|
955
|
+
* matchesGlobPattern('Hello', 'h*o') // false — `GLOB` is case-sensitive
|
|
887
956
|
* ```
|
|
888
957
|
*/
|
|
889
|
-
export declare function matchesFuzzy(value: string, query: string): boolean;
|
|
890
|
-
|
|
891
958
|
export declare function matchesGlobPattern(value: string, pattern: string): boolean;
|
|
892
959
|
|
|
960
|
+
/**
|
|
961
|
+
* Matches a value against a SQL `LIKE` pattern, folding case.
|
|
962
|
+
*
|
|
963
|
+
* @remarks
|
|
964
|
+
* `%` matches any run of characters (including none) and `_` matches exactly one
|
|
965
|
+
* character; every other pattern character matches itself literally. Runs on
|
|
966
|
+
* {@link matchesWildcardPattern}, so the match is linear in the value length and
|
|
967
|
+
* the pattern is capped at {@link MAX_PATTERN_LENGTH}.
|
|
968
|
+
*
|
|
969
|
+
* @param value - The value to test
|
|
970
|
+
* @param pattern - The `LIKE` pattern
|
|
971
|
+
* @returns True if `value` matches `pattern` under case folding; false otherwise
|
|
972
|
+
* @throws A `VALIDATION` {@link DatabaseError} when `pattern` exceeds {@link MAX_PATTERN_LENGTH}
|
|
973
|
+
*
|
|
974
|
+
* @example
|
|
975
|
+
* ```ts
|
|
976
|
+
* matchesLikePattern('Hello', 'h%o') // true — `%` spans any run, and case folds
|
|
977
|
+
* matchesLikePattern('Hello', 'h_llo') // true — `_` matches exactly one character
|
|
978
|
+
* ```
|
|
979
|
+
*/
|
|
893
980
|
export declare function matchesLikePattern(value: string, pattern: string): boolean;
|
|
894
981
|
|
|
895
982
|
/**
|
|
896
|
-
*
|
|
983
|
+
* Folds a row through a list of conditions, joining each by its connector.
|
|
897
984
|
*
|
|
898
985
|
* @remarks
|
|
899
986
|
* Evaluated left-to-right: the first condition seeds the result, and each later
|
|
@@ -903,20 +990,20 @@ export declare function matchesLikePattern(value: string, pattern: string): bool
|
|
|
903
990
|
*
|
|
904
991
|
* @param row - The row to test
|
|
905
992
|
* @param conditions - The conditions to fold
|
|
906
|
-
* @returns
|
|
993
|
+
* @returns True if the row satisfies the combined conditions; false otherwise
|
|
907
994
|
*/
|
|
908
995
|
export declare function matchesQuery(row: Row, conditions: readonly Condition[]): boolean;
|
|
909
996
|
|
|
910
997
|
/**
|
|
911
|
-
*
|
|
998
|
+
* Matches a value against a wildcard pattern in LINEAR time — the shared, ReDoS-SAFE
|
|
912
999
|
* engine behind {@link matchesLikePattern} and {@link matchesGlobPattern}.
|
|
913
1000
|
*
|
|
914
1001
|
* @remarks
|
|
915
1002
|
* A backtracking RegExp (`a%b%c` → `^a.*b.*c$`) is CATASTROPHIC on a hostile pattern:
|
|
916
1003
|
* `.*` segments separated by literals, matched against a long non-matching input, blow
|
|
917
|
-
* up super-linearly — and JS has no atomic groups / possessive quantifiers to bound it
|
|
918
|
-
*
|
|
919
|
-
*
|
|
1004
|
+
* up super-linearly — and JS has no atomic groups / possessive quantifiers to bound it,
|
|
1005
|
+
* while a `LIKE` / `GLOB` pattern is a caller-supplied operand this package cannot
|
|
1006
|
+
* trust. So this builds NO regex. It runs the classic GREEDY TWO-POINTER wildcard match:
|
|
920
1007
|
* the `any` wildcard records its position and, on a later mismatch, backtracks ONLY to
|
|
921
1008
|
* that last `any` (letting it absorb one more char) — so the work is O(value × pattern),
|
|
922
1009
|
* never the exponential / polynomial backtracking a regex would do. The pattern length
|
|
@@ -935,18 +1022,18 @@ export declare function matchesQuery(row: Row, conditions: readonly Condition[])
|
|
|
935
1022
|
* @param any - The any-run wildcard char (`%` for `LIKE`, `*` for `GLOB`)
|
|
936
1023
|
* @param single - The single-char wildcard char (`_` for `LIKE`, `?` for `GLOB`)
|
|
937
1024
|
* @param fold - Whether to match case-INSENSITIVELY (`LIKE` folds; `GLOB` does not)
|
|
938
|
-
* @returns
|
|
1025
|
+
* @returns True if `value` matches `pattern`; false otherwise
|
|
939
1026
|
* @throws A `VALIDATION` {@link DatabaseError} when `pattern` exceeds {@link MAX_PATTERN_LENGTH}
|
|
940
1027
|
*/
|
|
941
1028
|
export declare function matchesWildcardPattern(value: string, pattern: string, any: string, single: string, fold: boolean): boolean;
|
|
942
1029
|
|
|
943
1030
|
/**
|
|
944
|
-
*
|
|
1031
|
+
* Sets the longest `LIKE` / `GLOB` pattern the wildcard matcher accepts before rejecting it.
|
|
945
1032
|
*
|
|
946
1033
|
* @remarks
|
|
947
|
-
* A
|
|
948
|
-
*
|
|
949
|
-
*
|
|
1034
|
+
* A `LIKE` / `GLOB` pattern is a caller-supplied operand, so
|
|
1035
|
+
* `matchesLikePattern` / `matchesGlobPattern` run patterns this package cannot
|
|
1036
|
+
* trust. The matcher is the LINEAR greedy two-pointer wildcard match — never a
|
|
950
1037
|
* backtracking regex (`.*`-segments-separated-by-literals against a long input is the
|
|
951
1038
|
* catastrophic shape JS cannot bound without atomic groups), so it is O(value ×
|
|
952
1039
|
* pattern). Capping the pattern length bounds that pattern factor, leaving a match
|
|
@@ -956,16 +1043,16 @@ export declare function matchesWildcardPattern(value: string, pattern: string, a
|
|
|
956
1043
|
export declare const MAX_PATTERN_LENGTH = 1024;
|
|
957
1044
|
|
|
958
1045
|
/**
|
|
959
|
-
*
|
|
1046
|
+
* Implements the reference {@link DriverInterface} — nested maps, no I/O.
|
|
960
1047
|
*
|
|
961
1048
|
* @remarks
|
|
962
1049
|
* The in-between made concrete: it runs identically in a browser or on a server,
|
|
963
1050
|
* so it is the storage behind tests, ephemeral caches, and any code that wants
|
|
964
|
-
* the database API without a persistent backend. Rows are DEEP-copied (
|
|
1051
|
+
* the database API without a persistent backend. Rows are DEEP-copied (through
|
|
965
1052
|
* `structuredClone`) in and out — at `write`, `read`, `scan`, `stream`, and both
|
|
966
1053
|
* snapshot capture and restore — so a caller mutating a nested field of an input
|
|
967
1054
|
* row, a returned row, or a row mutated in place between snapshot and rollback
|
|
968
|
-
* can never perturb stored state
|
|
1055
|
+
* can never perturb stored state; a shallow `{ ...row }` spread
|
|
969
1056
|
* would still share nested object/array references. Metadata instead routes
|
|
970
1057
|
* through `cloneDriverMetadata`: `stamp` and migration snapshot exact JSON at
|
|
971
1058
|
* ingress, and `metadata` returns a distinct deeply frozen owned copy. `snapshot`
|
|
@@ -987,19 +1074,19 @@ export declare class MemoryDriver implements DriverInterface {
|
|
|
987
1074
|
keys(table: string): Promise<readonly Key[]>;
|
|
988
1075
|
scan(table: string): AsyncIterable<Row>;
|
|
989
1076
|
/**
|
|
990
|
-
*
|
|
1077
|
+
* Iterates rows lazily with native filtering — the {@link DriverInterface.stream} hook.
|
|
991
1078
|
*
|
|
992
1079
|
* @remarks
|
|
993
1080
|
* Iterates the table's keys in the same key order `scan` and `keys` yield
|
|
994
1081
|
* (sorted by {@link compareValues}), testing each row against
|
|
995
|
-
* `input.conditions` (
|
|
1082
|
+
* `input.conditions` (through {@link matchesQuery}) before counting it
|
|
996
1083
|
* toward `offset` / `limit`. Both are applied lazily as matches are found —
|
|
997
1084
|
* `offset` matches are skipped without being yielded, and iteration stops the
|
|
998
1085
|
* instant `limit` yields have been produced, so a large table is never fully
|
|
999
1086
|
* walked for a small page. `input.order` is IGNORED (the same contract as
|
|
1000
1087
|
* `TableInterface.scan` and `QueryInterface.stream`): streaming yields key
|
|
1001
|
-
* order, sorted output is `records()`'s job. Rows yield copy-out
|
|
1002
|
-
*
|
|
1088
|
+
* order, sorted output is `records()`'s job. Rows yield copy-out, and an
|
|
1089
|
+
* unknown table mirrors `scan`'s empty-yield behavior.
|
|
1003
1090
|
*
|
|
1004
1091
|
* @param table - The table to stream
|
|
1005
1092
|
* @param input - The filter / offset / limit to apply lazily
|
|
@@ -1014,7 +1101,7 @@ export declare class MemoryDriver implements DriverInterface {
|
|
|
1014
1101
|
stream(table: string, input: QueryInput): AsyncIterable<Row>;
|
|
1015
1102
|
clear(table: string): Promise<void>;
|
|
1016
1103
|
/**
|
|
1017
|
-
*
|
|
1104
|
+
* Captures the current state and returns a thunk that rolls back to it.
|
|
1018
1105
|
*
|
|
1019
1106
|
* @remarks
|
|
1020
1107
|
* Capture owns rows, schema, and one session-local table identity. Replay
|
|
@@ -1028,7 +1115,7 @@ export declare class MemoryDriver implements DriverInterface {
|
|
|
1028
1115
|
*/
|
|
1029
1116
|
snapshot(tables?: readonly string[]): Promise<() => Promise<void>>;
|
|
1030
1117
|
/**
|
|
1031
|
-
*
|
|
1118
|
+
* Returns the persisted {@link DriverMetadata}, or `undefined` when the store has
|
|
1032
1119
|
* never been stamped.
|
|
1033
1120
|
*
|
|
1034
1121
|
* @remarks
|
|
@@ -1041,13 +1128,13 @@ export declare class MemoryDriver implements DriverInterface {
|
|
|
1041
1128
|
*/
|
|
1042
1129
|
metadata(): Promise<DriverMetadata | undefined>;
|
|
1043
1130
|
/**
|
|
1044
|
-
*
|
|
1131
|
+
* Persists an owned snapshot for a later `metadata()` to return.
|
|
1045
1132
|
*
|
|
1046
1133
|
* @param metadata - The {@link DriverMetadata} to persist
|
|
1047
1134
|
*/
|
|
1048
1135
|
stamp(metadata: DriverMetadata): Promise<void>;
|
|
1049
1136
|
/**
|
|
1050
|
-
*
|
|
1137
|
+
* Applies a {@link Migration} plan's steps against the in-memory store.
|
|
1051
1138
|
*
|
|
1052
1139
|
* @remarks
|
|
1053
1140
|
* Steps apply against an isolated candidate. Rows, schema changes, and
|
|
@@ -1059,11 +1146,11 @@ export declare class MemoryDriver implements DriverInterface {
|
|
|
1059
1146
|
}
|
|
1060
1147
|
|
|
1061
1148
|
/**
|
|
1062
|
-
*
|
|
1149
|
+
* Applies one table's {@link MigrationStep}s to its rows — a pure row transform.
|
|
1063
1150
|
*
|
|
1064
1151
|
* @remarks
|
|
1065
1152
|
* `column.remove` drops that field from every row (a fresh copy — inputs are
|
|
1066
|
-
* never mutated
|
|
1153
|
+
* never mutated); `column.add` leaves rows as-is (an absent field
|
|
1067
1154
|
* reads as `undefined`, backfill is application policy). `table.add` /
|
|
1068
1155
|
* `table.remove` / `index.add` / `index.remove` are no-ops here (they operate
|
|
1069
1156
|
* on storage shape, not row shape). Steps for tables other than the one
|
|
@@ -1083,12 +1170,12 @@ export declare class MemoryDriver implements DriverInterface {
|
|
|
1083
1170
|
export declare function migrateRows(rows: readonly Row[], steps: readonly MigrationStep[]): readonly Row[];
|
|
1084
1171
|
|
|
1085
1172
|
/**
|
|
1086
|
-
*
|
|
1173
|
+
* Represents a schema migration plan — an ordered set of {@link MigrationStep}s moving a
|
|
1087
1174
|
* database from one schema version to another.
|
|
1088
1175
|
*
|
|
1089
1176
|
* @remarks
|
|
1090
1177
|
* `from` / `to` are the source and target schema versions; `steps` runs in
|
|
1091
|
-
* order. Applied natively
|
|
1178
|
+
* order. Applied natively through {@link DriverInterface.migrate} when a driver
|
|
1092
1179
|
* implements it.
|
|
1093
1180
|
*/
|
|
1094
1181
|
export declare interface Migration {
|
|
@@ -1098,7 +1185,7 @@ export declare interface Migration {
|
|
|
1098
1185
|
}
|
|
1099
1186
|
|
|
1100
1187
|
/**
|
|
1101
|
-
*
|
|
1188
|
+
* Represents one atomic migration request.
|
|
1102
1189
|
*
|
|
1103
1190
|
* @remarks
|
|
1104
1191
|
* `plan` carries the schema changes. `metadata`, when present, is the snapshot that
|
|
@@ -1111,11 +1198,11 @@ export declare interface MigrationInput {
|
|
|
1111
1198
|
}
|
|
1112
1199
|
|
|
1113
1200
|
/**
|
|
1114
|
-
*
|
|
1201
|
+
* Represents one step of a {@link Migration} plan — a single schema change applied to one
|
|
1115
1202
|
* table.
|
|
1116
1203
|
*
|
|
1117
1204
|
* @remarks
|
|
1118
|
-
* `operation` names the axis it splits on
|
|
1205
|
+
* `operation` names the axis it splits on: adding / removing a
|
|
1119
1206
|
* whole table, a column, or an index. A driver's optional `migrate` applies each
|
|
1120
1207
|
* step natively; a step referencing an unknown table throws `DatabaseError`
|
|
1121
1208
|
* `MIGRATION`.
|
|
@@ -1145,7 +1232,7 @@ export declare type MigrationStep = {
|
|
|
1145
1232
|
};
|
|
1146
1233
|
|
|
1147
1234
|
/**
|
|
1148
|
-
*
|
|
1235
|
+
* Canonicalizes an unknown driver schema into a distinct deeply frozen snapshot.
|
|
1149
1236
|
*
|
|
1150
1237
|
* @remarks
|
|
1151
1238
|
* Table and column lists are sorted by name. The index list is sorted by the
|
|
@@ -1171,17 +1258,17 @@ export declare interface OperationOptions {
|
|
|
1171
1258
|
readonly signal?: AbortSignal;
|
|
1172
1259
|
}
|
|
1173
1260
|
|
|
1174
|
-
/**
|
|
1261
|
+
/** Represents one ordering term — a column ({@link FieldPath}, flat or nested) and its direction. */
|
|
1175
1262
|
export declare interface Order {
|
|
1176
1263
|
readonly column: FieldPath;
|
|
1177
1264
|
readonly direction: OrderDirection;
|
|
1178
1265
|
}
|
|
1179
1266
|
|
|
1180
|
-
/**
|
|
1267
|
+
/** Names a sort direction. */
|
|
1181
1268
|
export declare type OrderDirection = 'ascending' | 'descending';
|
|
1182
1269
|
|
|
1183
1270
|
/**
|
|
1184
|
-
*
|
|
1271
|
+
* Diffs a deployed and a declared table set structurally into a {@link Migration}
|
|
1185
1272
|
* plan.
|
|
1186
1273
|
*
|
|
1187
1274
|
* @remarks
|
|
@@ -1198,13 +1285,12 @@ export declare type OrderDirection = 'ascending' | 'descending';
|
|
|
1198
1285
|
*
|
|
1199
1286
|
* A column present in BOTH schemas under the same name but with a different
|
|
1200
1287
|
* `storage`, `optional`, or `nullable` value throws a `MIGRATION`
|
|
1201
|
-
* {@link DatabaseError} naming the
|
|
1202
|
-
*
|
|
1203
|
-
*
|
|
1204
|
-
*
|
|
1205
|
-
*
|
|
1206
|
-
*
|
|
1207
|
-
* plans, never a single implicit "alter" step.
|
|
1288
|
+
* {@link DatabaseError} naming the table, the column, and the from→to
|
|
1289
|
+
* difference — a name-only diff would otherwise silently produce NO step for
|
|
1290
|
+
* the drift, and versioned reconciliation would stamp over it. There is no
|
|
1291
|
+
* automatic in-place type-change step: the manual path is to add a new column,
|
|
1292
|
+
* copy/convert the data at the application layer, then remove the old column —
|
|
1293
|
+
* two separate plans, never a single implicit "alter" step.
|
|
1208
1294
|
*
|
|
1209
1295
|
* @param deployed - The table schemas currently applied
|
|
1210
1296
|
* @param declared - The table schemas the caller wants applied
|
|
@@ -1228,7 +1314,7 @@ export declare type OrderDirection = 'ascending' | 'descending';
|
|
|
1228
1314
|
export declare function planMigration(deployed: readonly TableSchema[], declared: readonly TableSchema[], from?: number, to?: number): Migration;
|
|
1229
1315
|
|
|
1230
1316
|
/**
|
|
1231
|
-
*
|
|
1317
|
+
* Holds per-table primary-key column overrides — `{ [table]: column }`.
|
|
1232
1318
|
*
|
|
1233
1319
|
* @remarks
|
|
1234
1320
|
* A table absent from this map keys its rows by {@link DEFAULT_PRIMARY} (`id`).
|
|
@@ -1237,7 +1323,7 @@ export declare function planMigration(deployed: readonly TableSchema[], declared
|
|
|
1237
1323
|
export declare type PrimaryMap = Readonly<Record<string, string>>;
|
|
1238
1324
|
|
|
1239
1325
|
/**
|
|
1240
|
-
*
|
|
1326
|
+
* Projects migration steps sequentially over a canonical validated owned schema.
|
|
1241
1327
|
* Adding a required non-null column to an existing table rejects with
|
|
1242
1328
|
* `MIGRATION`; optional-only and nullable-only additions remain portable.
|
|
1243
1329
|
*
|
|
@@ -1248,7 +1334,7 @@ export declare type PrimaryMap = Readonly<Record<string, string>>;
|
|
|
1248
1334
|
export declare function projectMigrationSchema(schema: readonly TableSchema[], steps: readonly MigrationStep[]): readonly TableSchema[];
|
|
1249
1335
|
|
|
1250
1336
|
/**
|
|
1251
|
-
*
|
|
1337
|
+
* Represents a serializable read specification — everything a backend needs to compile one
|
|
1252
1338
|
* read, free of JS callbacks so any backend can honor it.
|
|
1253
1339
|
*
|
|
1254
1340
|
* @remarks
|
|
@@ -1265,16 +1351,15 @@ export declare interface QueryInput {
|
|
|
1265
1351
|
}
|
|
1266
1352
|
|
|
1267
1353
|
/**
|
|
1268
|
-
*
|
|
1354
|
+
* Builds a read through a fluent chain.
|
|
1269
1355
|
*
|
|
1270
1356
|
* @remarks
|
|
1271
1357
|
* `condition` appends one portable condition and `order` appends one portable
|
|
1272
1358
|
* ordering term. `filter` adds a post-fetch JavaScript predicate (applied after
|
|
1273
1359
|
* the backend read, before paging). The terminals (`collect` / `find` / `count`
|
|
1274
|
-
* / `aggregate`) execute against the table; each
|
|
1275
|
-
*
|
|
1276
|
-
*
|
|
1277
|
-
* descends a nested value.
|
|
1360
|
+
* / `aggregate`) execute against the table; each call mutates and returns the
|
|
1361
|
+
* same builder, so a chain reads as one statement. Every `column` is a
|
|
1362
|
+
* {@link FieldPath} — a string is one column, an array descends a nested value.
|
|
1278
1363
|
*/
|
|
1279
1364
|
export declare interface QueryInterface<T = Row> {
|
|
1280
1365
|
condition(input: Condition): QueryInterface<T>;
|
|
@@ -1286,8 +1371,8 @@ export declare interface QueryInterface<T = Row> {
|
|
|
1286
1371
|
find(): Promise<T | undefined>;
|
|
1287
1372
|
count(): Promise<number>;
|
|
1288
1373
|
/**
|
|
1289
|
-
*
|
|
1290
|
-
*
|
|
1374
|
+
* Evaluates this query's conditions / filters / offset / limit lazily, row
|
|
1375
|
+
* by row.
|
|
1291
1376
|
*
|
|
1292
1377
|
* @remarks
|
|
1293
1378
|
* `order` and its comparators are IGNORED (streaming yields unsorted, as
|
|
@@ -1299,16 +1384,58 @@ export declare interface QueryInterface<T = Row> {
|
|
|
1299
1384
|
aggregate(operation: AggregateOperation, column: FieldPath): Promise<number | undefined>;
|
|
1300
1385
|
}
|
|
1301
1386
|
|
|
1302
|
-
/**
|
|
1387
|
+
/**
|
|
1388
|
+
* Requires one declared table's columns out of a table map.
|
|
1389
|
+
*
|
|
1390
|
+
* @remarks
|
|
1391
|
+
* The overload preserves the map's own value type for a statically known table
|
|
1392
|
+
* name, so a typed view keeps its row type without an assertion. An undeclared
|
|
1393
|
+
* table is a caller error rather than an absence, so it throws instead of
|
|
1394
|
+
* returning `undefined`.
|
|
1395
|
+
*
|
|
1396
|
+
* @param tables - The declared table map
|
|
1397
|
+
* @param name - The table name
|
|
1398
|
+
* @returns The table's {@link ColumnMap}
|
|
1399
|
+
* @throws A `NOT_FOUND` {@link DatabaseError} when `tables` does not declare `name`
|
|
1400
|
+
*
|
|
1401
|
+
* @example
|
|
1402
|
+
* ```ts
|
|
1403
|
+
* requireColumns({ users: { id: stringShape() } }, 'users') // { id: … }
|
|
1404
|
+
* ```
|
|
1405
|
+
*/
|
|
1406
|
+
export declare function requireColumns<T extends TableMap, K extends keyof T & string>(tables: T, name: K): T[K];
|
|
1407
|
+
|
|
1408
|
+
export declare function requireColumns(tables: TableMap, name: string): ColumnMap;
|
|
1409
|
+
|
|
1410
|
+
/**
|
|
1411
|
+
* Resolves the primary-key column one table keys its rows by.
|
|
1412
|
+
*
|
|
1413
|
+
* @remarks
|
|
1414
|
+
* A table absent from the {@link PrimaryMap} keys its rows by
|
|
1415
|
+
* {@link DEFAULT_PRIMARY}, so this is total over any table name.
|
|
1416
|
+
*
|
|
1417
|
+
* @param primary - The per-table primary-key overrides
|
|
1418
|
+
* @param name - The table name
|
|
1419
|
+
* @returns The table's primary-key column
|
|
1420
|
+
*
|
|
1421
|
+
* @example
|
|
1422
|
+
* ```ts
|
|
1423
|
+
* resolvePrimary({ posts: 'slug' }, 'posts') // 'slug'
|
|
1424
|
+
* resolvePrimary({ posts: 'slug' }, 'users') // 'id' — the default primary
|
|
1425
|
+
* ```
|
|
1426
|
+
*/
|
|
1427
|
+
export declare function resolvePrimary(primary: PrimaryMap, name: string): string;
|
|
1428
|
+
|
|
1429
|
+
/** Represents a table row — a plain record of column values keyed by column name. */
|
|
1303
1430
|
export declare type Row = Record<string, unknown>;
|
|
1304
1431
|
|
|
1305
1432
|
/**
|
|
1306
|
-
*
|
|
1433
|
+
* Represents the row type a table's {@link ColumnMap} describe — `Infer` of the `objectShape`
|
|
1307
1434
|
* the database wraps them in.
|
|
1308
1435
|
*
|
|
1309
1436
|
* @remarks
|
|
1310
1437
|
* Contract 0.0.4's non-distributive `Infer` resolves the OPEN case (the broad
|
|
1311
|
-
* `ColumnMap` —
|
|
1438
|
+
* `ColumnMap` — for example when a database is held at its default type) directly:
|
|
1312
1439
|
* `RowOf<ColumnMap>` and {@link Row} are mutually assignable, so no short-circuit
|
|
1313
1440
|
* to `Row` and no `additionalProperties: false` pin are needed — `Infer` no
|
|
1314
1441
|
* longer trips TS's instantiation-depth guard over the open shape, and the
|
|
@@ -1317,12 +1444,71 @@ export declare type Row = Record<string, unknown>;
|
|
|
1317
1444
|
* concrete column map.
|
|
1318
1445
|
*/
|
|
1319
1446
|
export declare type RowOf<C extends ColumnMap> = Infer<{
|
|
1320
|
-
readonly
|
|
1447
|
+
readonly category: 'object';
|
|
1321
1448
|
readonly properties: C;
|
|
1322
1449
|
}>;
|
|
1323
1450
|
|
|
1324
1451
|
/**
|
|
1325
|
-
*
|
|
1452
|
+
* Walks the driver-conformance battery against a fresh {@link DriverInterface}
|
|
1453
|
+
* per phase, yielding one {@link ConformanceFinding} per violated invariant —
|
|
1454
|
+
* the shared invariant suite every backend (in-memory, SQLite, IndexedDB)
|
|
1455
|
+
* must uphold to be a drop-in {@link DriverInterface}.
|
|
1456
|
+
*
|
|
1457
|
+
* @remarks
|
|
1458
|
+
* Framework-agnostic: no test-runner or Node imports, only sibling core
|
|
1459
|
+
* modules — so it runs equally from a unit test, a smoke script, or a new
|
|
1460
|
+
* driver's own README. Opens a fixed two-table schema (`users` keyed by the
|
|
1461
|
+
* default `id`, `posts` keyed by a non-id `slug`) and, calling `factory()`
|
|
1462
|
+
* fresh for each phase so failures stay isolated, verifies: `open`/`close`;
|
|
1463
|
+
* `read` of a missing key returns `undefined`; `write`/`read` round-trip
|
|
1464
|
+
* with DEEP copy-in/copy-out isolation (mutating the caller's row —
|
|
1465
|
+
* including a NESTED field — after `write`, or a row `read` returns, never
|
|
1466
|
+
* perturbs stored state) and upsert-overwrite; simultaneous same-key
|
|
1467
|
+
* `insert` calls produce exactly one commit and one `CONFLICT`; pre-aborted
|
|
1468
|
+
* `write`, `insert`, and `delete` calls leave storage unchanged; `delete`
|
|
1469
|
+
* returns `true` then `false`; `keys`/`scan` yield in ascending key order;
|
|
1470
|
+
* `clear` empties only its target table; `snapshot`'s rollback thunk
|
|
1471
|
+
* restores pre-snapshot state, including a NESTED field mutated in place on
|
|
1472
|
+
* a read-back row between capture and restore; a scoped
|
|
1473
|
+
* `snapshot(['users'])` rolls back only the named table, leaving a
|
|
1474
|
+
* concurrent mutation to another table intact; a non-`id` primary key
|
|
1475
|
+
* (`posts.slug`) round-trips; a nested-object row round-trips structurally
|
|
1476
|
+
* (through {@link equalsValue}). The optional surface is presence-gated: when
|
|
1477
|
+
* `migrate` exists, a `column.remove` plan strips the column from stored
|
|
1478
|
+
* rows and a plan referencing an unknown table throws `DatabaseError`
|
|
1479
|
+
* `MIGRATION`; when `stream` exists, it yields only condition-matching rows
|
|
1480
|
+
* and honors `offset`/`limit`; when `transaction` exists, `commit` persists
|
|
1481
|
+
* and `rollback` restores; when both `metadata` and `stamp` exist, a fresh
|
|
1482
|
+
* store's `metadata()` is `undefined`, and after
|
|
1483
|
+
* `stamp({ version, schema })`, `metadata()` returns the exact stamped value.
|
|
1484
|
+
*
|
|
1485
|
+
* Each phase runs within a `try`/`catch`: an EXPECTED mismatch yields a
|
|
1486
|
+
* finding built from the assertion, while an UNEXPECTED throw (a driver
|
|
1487
|
+
* crash mid-phase) is caught and yielded as a finding too, naming the phase
|
|
1488
|
+
* as `check` and carrying the caught error in `context.error` — a broken
|
|
1489
|
+
* driver can never escape the battery as an unhandled rejection. Within a
|
|
1490
|
+
* phase, the FIRST violated assertion yields and the phase stops (matching
|
|
1491
|
+
* the historical fail-fast shape at phase granularity); the generator then
|
|
1492
|
+
* moves on to the next phase regardless. Because this is a **generator**,
|
|
1493
|
+
* consuming only the first yielded value reproduces true fail-fast (later
|
|
1494
|
+
* phases never run) — that is exactly what {@link conformDriver} does.
|
|
1495
|
+
*
|
|
1496
|
+
* @param factory - Mints a fresh, unopened driver instance (called once per phase)
|
|
1497
|
+
* @yields One {@link ConformanceFinding} per violated invariant, in phase order
|
|
1498
|
+
*
|
|
1499
|
+
* @example
|
|
1500
|
+
* ```ts
|
|
1501
|
+
* import { createMemoryDriver, scanDriver } from '@orkestrel/database'
|
|
1502
|
+
*
|
|
1503
|
+
* for await (const finding of scanDriver(() => createMemoryDriver())) {
|
|
1504
|
+
* console.log(finding.check, finding.message)
|
|
1505
|
+
* }
|
|
1506
|
+
* ```
|
|
1507
|
+
*/
|
|
1508
|
+
export declare function scanDriver(factory: () => DriverInterface): AsyncIterable<ConformanceFinding>;
|
|
1509
|
+
|
|
1510
|
+
/**
|
|
1511
|
+
* Projects one contract shape into a portable column schema.
|
|
1326
1512
|
*
|
|
1327
1513
|
* @param name - The column name
|
|
1328
1514
|
* @param shape - The column contract shape
|
|
@@ -1331,7 +1517,7 @@ export declare type RowOf<C extends ColumnMap> = Infer<{
|
|
|
1331
1517
|
export declare function shapeToColumnSchema(name: string, shape: ContractShape): ColumnSchema;
|
|
1332
1518
|
|
|
1333
1519
|
/**
|
|
1334
|
-
*
|
|
1520
|
+
* Maps a column's {@link ContractShape} to its portable {@link ColumnStorage} — the
|
|
1335
1521
|
* value a `TableSchema` carries so a native backend can declare a real column.
|
|
1336
1522
|
*
|
|
1337
1523
|
* @remarks
|
|
@@ -1357,7 +1543,7 @@ export declare function shapeToColumnSchema(name: string, shape: ContractShape):
|
|
|
1357
1543
|
export declare function shapeToColumnStorage(shape: ContractShape): ColumnStorage;
|
|
1358
1544
|
|
|
1359
1545
|
/**
|
|
1360
|
-
*
|
|
1546
|
+
* Sorts rows by an ordering specification, leaving the input untouched.
|
|
1361
1547
|
*
|
|
1362
1548
|
* @remarks
|
|
1363
1549
|
* Applies the terms in priority order — the first term that distinguishes two
|
|
@@ -1370,7 +1556,7 @@ export declare function shapeToColumnStorage(shape: ContractShape): ColumnStorag
|
|
|
1370
1556
|
export declare function sortRows(rows: readonly Row[], order: readonly Order[]): readonly Row[];
|
|
1371
1557
|
|
|
1372
1558
|
/**
|
|
1373
|
-
*
|
|
1559
|
+
* Declares the storage operations available only inside a driver's transaction scope.
|
|
1374
1560
|
*
|
|
1375
1561
|
* @remarks
|
|
1376
1562
|
* A driver owns acquisition, commit or rollback, release, and lifetime. This
|
|
@@ -1396,12 +1582,12 @@ export declare interface StorageInterface {
|
|
|
1396
1582
|
}
|
|
1397
1583
|
|
|
1398
1584
|
/**
|
|
1399
|
-
*
|
|
1585
|
+
* Represents one table's portable definition, produced by `export` — the unit of schema /
|
|
1400
1586
|
* migration exchange across environments.
|
|
1401
1587
|
*
|
|
1402
1588
|
* @remarks
|
|
1403
1589
|
* `schema` is the JSON Schema (universally portable, serializable); `columns` is
|
|
1404
|
-
* the source column map, which re-imports losslessly
|
|
1590
|
+
* the source column map, which re-imports losslessly through `import` within a
|
|
1405
1591
|
* TypeScript environment. `primary` is the primary-key column.
|
|
1406
1592
|
*/
|
|
1407
1593
|
export declare interface TableDefinition {
|
|
@@ -1411,7 +1597,7 @@ export declare interface TableDefinition {
|
|
|
1411
1597
|
}
|
|
1412
1598
|
|
|
1413
1599
|
/**
|
|
1414
|
-
*
|
|
1600
|
+
* Describes the push observation surface of a {@link TableInterface} — the per-row
|
|
1415
1601
|
* mutation moments a fire-and-forget observer (cache invalidation, sync, an audit log)
|
|
1416
1602
|
* subscribes to, ALONGSIDE the database-level {@link DatabaseEventMap}.
|
|
1417
1603
|
*
|
|
@@ -1421,24 +1607,24 @@ export declare interface TableDefinition {
|
|
|
1421
1607
|
* value re-reads it by key. Any row put — `set`, `add`, or `update` — emits a single
|
|
1422
1608
|
* `write` (the consumer re-reads if it needs to know what changed); a delete emits
|
|
1423
1609
|
* `remove`; emptying the table emits `clear`. Reads / queries / counts are NOT emitted
|
|
1424
|
-
* (too hot, and a reader does not mutate). Listener isolation is the emitter's
|
|
1610
|
+
* (too hot, and a reader does not mutate). Listener isolation is the emitter's:
|
|
1425
1611
|
* every event is emitted directly and a listener throw is routed to the emitter's `error`
|
|
1426
1612
|
* handler (the `error` option), never onto this map, and sits AFTER the driver write / delete
|
|
1427
1613
|
* / clear has completed — so a throwing observer can never corrupt a write or perturb a
|
|
1428
|
-
* transaction. Subscribe
|
|
1614
|
+
* transaction. Subscribe through `table.emitter.on(...)`. Declared as a `type` alias (
|
|
1429
1615
|
* `EventMap` is a `type` kind).
|
|
1430
1616
|
*/
|
|
1431
1617
|
export declare type TableEventMap = {
|
|
1432
|
-
/**
|
|
1618
|
+
/** Signals that a row was written (set / added / updated) — the affected key (no value payload). */
|
|
1433
1619
|
readonly write: readonly [key: Key];
|
|
1434
|
-
/**
|
|
1620
|
+
/** Signals that a row was removed — the affected key. */
|
|
1435
1621
|
readonly remove: readonly [key: Key];
|
|
1436
|
-
/**
|
|
1622
|
+
/** Signals that the table was cleared (every row removed). */
|
|
1437
1623
|
readonly clear: readonly [];
|
|
1438
1624
|
};
|
|
1439
1625
|
|
|
1440
1626
|
/**
|
|
1441
|
-
*
|
|
1627
|
+
* Exposes typed keyed CRUD plus fluent query and cursor access.
|
|
1442
1628
|
*
|
|
1443
1629
|
* @remarks
|
|
1444
1630
|
* Writes are coerced through the table's contract: a string input to a numeric
|
|
@@ -1448,7 +1634,7 @@ export declare type TableEventMap = {
|
|
|
1448
1634
|
* inserts and throws `CONFLICT` on a duplicate key. `contract` exposes the
|
|
1449
1635
|
* compiled contract for introspection (`schema`) and fixtures (`generate`).
|
|
1450
1636
|
*
|
|
1451
|
-
* The keyed methods batch by overload
|
|
1637
|
+
* The keyed methods batch by overload: pass one key/row for one
|
|
1452
1638
|
* result, or an array for an array of results in the same order — a single verb,
|
|
1453
1639
|
* never `getMany` / `setAll`. Batches run as independent sequential operations;
|
|
1454
1640
|
* wrap them in `transaction` for atomicity.
|
|
@@ -1467,7 +1653,7 @@ export declare interface TableInterface<T = Row> {
|
|
|
1467
1653
|
keys(): Promise<readonly Key[]>;
|
|
1468
1654
|
records(input?: QueryInput, options?: OperationOptions): Promise<readonly T[]>;
|
|
1469
1655
|
/**
|
|
1470
|
-
*
|
|
1656
|
+
* Counts contract-valid rows matching `input`'s conditions.
|
|
1471
1657
|
*
|
|
1472
1658
|
* @remarks
|
|
1473
1659
|
* Paging is ignored. Like `records()` / `scan()`, `count()` narrows every
|
|
@@ -1476,7 +1662,7 @@ export declare interface TableInterface<T = Row> {
|
|
|
1476
1662
|
*/
|
|
1477
1663
|
count(input?: QueryInput, options?: OperationOptions): Promise<number>;
|
|
1478
1664
|
/**
|
|
1479
|
-
*
|
|
1665
|
+
* Computes an aggregate over `column` across rows matching `input`'s
|
|
1480
1666
|
* conditions.
|
|
1481
1667
|
*
|
|
1482
1668
|
* @remarks
|
|
@@ -1488,7 +1674,7 @@ export declare interface TableInterface<T = Row> {
|
|
|
1488
1674
|
*/
|
|
1489
1675
|
aggregate(operation: AggregateOperation, column: FieldPath, input?: QueryInput, options?: OperationOptions): Promise<number | undefined>;
|
|
1490
1676
|
/**
|
|
1491
|
-
*
|
|
1677
|
+
* Iterates the table's rows lazily with filtering.
|
|
1492
1678
|
*
|
|
1493
1679
|
* @remarks
|
|
1494
1680
|
* `input`'s `conditions` / `offset` / `limit` are honored lazily as rows
|
|
@@ -1499,7 +1685,7 @@ export declare interface TableInterface<T = Row> {
|
|
|
1499
1685
|
*/
|
|
1500
1686
|
scan(input?: QueryInput, options?: OperationOptions): AsyncIterable<T>;
|
|
1501
1687
|
/**
|
|
1502
|
-
*
|
|
1688
|
+
* Upserts one or more rows.
|
|
1503
1689
|
*
|
|
1504
1690
|
* @param row - The row to upsert
|
|
1505
1691
|
* @param options - Optional abort signal
|
|
@@ -1507,7 +1693,7 @@ export declare interface TableInterface<T = Row> {
|
|
|
1507
1693
|
*/
|
|
1508
1694
|
set(row: T, options?: OperationOptions): Promise<Key>;
|
|
1509
1695
|
/**
|
|
1510
|
-
*
|
|
1696
|
+
* Upserts one or more rows.
|
|
1511
1697
|
*
|
|
1512
1698
|
* @param rows - The rows to upsert
|
|
1513
1699
|
* @param options - Optional abort signal, checked at entry and between items
|
|
@@ -1520,7 +1706,7 @@ export declare interface TableInterface<T = Row> {
|
|
|
1520
1706
|
*/
|
|
1521
1707
|
set(rows: readonly T[], options?: OperationOptions): Promise<readonly Key[]>;
|
|
1522
1708
|
/**
|
|
1523
|
-
*
|
|
1709
|
+
* Inserts one or more rows, throwing `CONFLICT` on a duplicate key.
|
|
1524
1710
|
*
|
|
1525
1711
|
* @param row - The row to insert
|
|
1526
1712
|
* @param options - Optional abort signal
|
|
@@ -1528,7 +1714,7 @@ export declare interface TableInterface<T = Row> {
|
|
|
1528
1714
|
*/
|
|
1529
1715
|
add(row: T, options?: OperationOptions): Promise<Key>;
|
|
1530
1716
|
/**
|
|
1531
|
-
*
|
|
1717
|
+
* Inserts one or more rows, throwing `CONFLICT` on a duplicate key.
|
|
1532
1718
|
*
|
|
1533
1719
|
* @param rows - The rows to insert
|
|
1534
1720
|
* @param options - Optional abort signal, checked at entry and between items
|
|
@@ -1541,16 +1727,16 @@ export declare interface TableInterface<T = Row> {
|
|
|
1541
1727
|
*/
|
|
1542
1728
|
add(rows: readonly T[], options?: OperationOptions): Promise<readonly Key[]>;
|
|
1543
1729
|
/**
|
|
1544
|
-
*
|
|
1730
|
+
* Applies a partial change to one or more rows.
|
|
1545
1731
|
*
|
|
1546
1732
|
* @param key - The key of the row to update
|
|
1547
1733
|
* @param changes - The partial changes to apply
|
|
1548
1734
|
* @param options - Optional abort signal
|
|
1549
|
-
* @returns
|
|
1735
|
+
* @returns True if the row existed and was updated; false otherwise
|
|
1550
1736
|
*/
|
|
1551
1737
|
update(key: Key, changes: Partial<T>, options?: OperationOptions): Promise<boolean>;
|
|
1552
1738
|
/**
|
|
1553
|
-
*
|
|
1739
|
+
* Applies a partial change to one or more rows.
|
|
1554
1740
|
*
|
|
1555
1741
|
* @param keys - The keys of the rows to update
|
|
1556
1742
|
* @param changes - The partial changes to apply to each row
|
|
@@ -1564,15 +1750,15 @@ export declare interface TableInterface<T = Row> {
|
|
|
1564
1750
|
*/
|
|
1565
1751
|
update(keys: readonly Key[], changes: Partial<T>, options?: OperationOptions): Promise<readonly boolean[]>;
|
|
1566
1752
|
/**
|
|
1567
|
-
*
|
|
1753
|
+
* Deletes one or more rows.
|
|
1568
1754
|
*
|
|
1569
1755
|
* @param key - The key of the row to remove
|
|
1570
1756
|
* @param options - Optional abort signal
|
|
1571
|
-
* @returns
|
|
1757
|
+
* @returns True if the row existed and was removed; false otherwise
|
|
1572
1758
|
*/
|
|
1573
1759
|
remove(key: Key, options?: OperationOptions): Promise<boolean>;
|
|
1574
1760
|
/**
|
|
1575
|
-
*
|
|
1761
|
+
* Deletes one or more rows.
|
|
1576
1762
|
*
|
|
1577
1763
|
* @param keys - The keys of the rows to remove
|
|
1578
1764
|
* @param options - Optional abort signal, checked at entry and between items
|
|
@@ -1590,21 +1776,21 @@ export declare interface TableInterface<T = Row> {
|
|
|
1590
1776
|
}
|
|
1591
1777
|
|
|
1592
1778
|
/**
|
|
1593
|
-
*
|
|
1779
|
+
* Represents a database's table schema — a map of table name to its {@link ColumnMap}.
|
|
1594
1780
|
*
|
|
1595
1781
|
* @remarks
|
|
1596
1782
|
* Each table's row type is `Infer` of its columns (see {@link RowOf}); primary-key
|
|
1597
|
-
* columns are named separately
|
|
1783
|
+
* columns are named separately through {@link PrimaryMap}.
|
|
1598
1784
|
*/
|
|
1599
1785
|
export declare type TableMap = Readonly<Record<string, ColumnMap>>;
|
|
1600
1786
|
|
|
1601
1787
|
/**
|
|
1602
|
-
*
|
|
1788
|
+
* Represents a backend-agnostic description of one table — what `open` hands each driver so a
|
|
1603
1789
|
* native backend can create real tables and indexes.
|
|
1604
1790
|
*
|
|
1605
1791
|
* @remarks
|
|
1606
1792
|
* Derived by the database from its `tables` contract shapes ({@link ColumnSchema}
|
|
1607
|
-
* per column,
|
|
1793
|
+
* per column, through `shapeToColumnStorage`), its `primary`, and its `indexes` option
|
|
1608
1794
|
* (`indexes`, each entry one possibly-compound index of column names). A scan-only
|
|
1609
1795
|
* backend (the reference `MemoryDriver`) ignores everything but `name`.
|
|
1610
1796
|
*/
|
|
@@ -1616,7 +1802,7 @@ export declare interface TableSchema {
|
|
|
1616
1802
|
}
|
|
1617
1803
|
|
|
1618
1804
|
/**
|
|
1619
|
-
*
|
|
1805
|
+
* Validates the paging fields of a portable query.
|
|
1620
1806
|
*
|
|
1621
1807
|
* @remarks
|
|
1622
1808
|
* A present `limit` or `offset` must be a finite nonnegative integer; zero is
|