@jarenjs/db 0.34.0

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.
Files changed (83) hide show
  1. package/ARCHITECTURE.md +397 -0
  2. package/README.md +218 -0
  3. package/dist/types/algebra.d.ts +133 -0
  4. package/dist/types/app.d.ts +49 -0
  5. package/dist/types/capture.d.ts +85 -0
  6. package/dist/types/cli.d.ts +2 -0
  7. package/dist/types/dag-job.d.ts +40 -0
  8. package/dist/types/ddl.d.ts +170 -0
  9. package/dist/types/dialect.d.ts +130 -0
  10. package/dist/types/dialects/sqlite.d.ts +9 -0
  11. package/dist/types/driver.d.ts +128 -0
  12. package/dist/types/drivers/bun.d.ts +47 -0
  13. package/dist/types/drivers/node.d.ts +37 -0
  14. package/dist/types/drivers/wasm.d.ts +65 -0
  15. package/dist/types/emit-model.d.ts +44 -0
  16. package/dist/types/emit.d.ts +72 -0
  17. package/dist/types/entity.d.ts +23 -0
  18. package/dist/types/errors.d.ts +165 -0
  19. package/dist/types/graph.d.ts +28 -0
  20. package/dist/types/index.d.ts +35 -0
  21. package/dist/types/jobs.d.ts +134 -0
  22. package/dist/types/live.d.ts +62 -0
  23. package/dist/types/migrate.d.ts +163 -0
  24. package/dist/types/model.d.ts +36 -0
  25. package/dist/types/patch-sql.d.ts +37 -0
  26. package/dist/types/plan.d.ts +119 -0
  27. package/dist/types/profile.d.ts +80 -0
  28. package/dist/types/query.d.ts +100 -0
  29. package/dist/types/residual.d.ts +50 -0
  30. package/dist/types/store.d.ts +53 -0
  31. package/dist/types/tracker.d.ts +43 -0
  32. package/dist/types/typed.d.ts +15 -0
  33. package/dist/types/types.d.ts +26 -0
  34. package/dist/types/udf.d.ts +70 -0
  35. package/dist/types/window.d.ts +52 -0
  36. package/docs/JOBS-FORMAT.md +218 -0
  37. package/docs/LIVE-FORMAT.md +348 -0
  38. package/docs/MIGRATION-FORMAT.md +302 -0
  39. package/docs/MODEL-FORMAT.md +928 -0
  40. package/package.json +81 -0
  41. package/schemas/jaren-migration.draft-07.schema.json +144 -0
  42. package/schemas/jaren-migration.schema.json +144 -0
  43. package/schemas/jaren-model.draft-07.schema.json +149 -0
  44. package/schemas/jaren-model.schema.json +149 -0
  45. package/src/algebra.js +105 -0
  46. package/src/app.js +108 -0
  47. package/src/capture.js +584 -0
  48. package/src/cli.js +264 -0
  49. package/src/dag-job.js +86 -0
  50. package/src/ddl.js +588 -0
  51. package/src/dialect.js +297 -0
  52. package/src/dialects/sqlite.js +175 -0
  53. package/src/driver.js +419 -0
  54. package/src/drivers/bun.js +101 -0
  55. package/src/drivers/node.js +93 -0
  56. package/src/drivers/wasm.js +178 -0
  57. package/src/emit-model.js +208 -0
  58. package/src/emit.js +393 -0
  59. package/src/entity.js +367 -0
  60. package/src/errors.js +173 -0
  61. package/src/graph.js +101 -0
  62. package/src/index.js +64 -0
  63. package/src/jobs.js +507 -0
  64. package/src/live.js +899 -0
  65. package/src/migrate.js +1411 -0
  66. package/src/model.js +476 -0
  67. package/src/patch-sql.js +150 -0
  68. package/src/plan.js +1038 -0
  69. package/src/profile.js +131 -0
  70. package/src/query.js +1010 -0
  71. package/src/residual.js +91 -0
  72. package/src/store.js +1422 -0
  73. package/src/tracker.js +776 -0
  74. package/src/typed.js +19 -0
  75. package/src/types.js +36 -0
  76. package/src/udf.js +132 -0
  77. package/src/window.js +125 -0
  78. package/types/app.d.ts +36 -0
  79. package/types/bun.d.ts +9 -0
  80. package/types/index.d.ts +592 -0
  81. package/types/node.d.ts +15 -0
  82. package/types/typed.d.ts +108 -0
  83. package/types/wasm.d.ts +5 -0
@@ -0,0 +1,128 @@
1
+ /**
2
+ * @file The driver seam: the contract every binding satisfies, the
3
+ * capability probe that runs once at open, and the sync-capable-async
4
+ * helpers the store composes with.
5
+ *
6
+ * A driver is `{ name, dialect, open(path, options) }`; `open` returns
7
+ * a `Connection` or a promise of one. Every connection method may
8
+ * return a value or a promise — the store never assumes either, and
9
+ * composes through {@link chain}, which does not allocate a promise
10
+ * when the driver answered with a value. That is what keeps the public
11
+ * asynchronous surface from paying twice while the synchronous fast
12
+ * path stays exact.
13
+ *
14
+ * The runtime builtin behind a binding is imported LAZILY inside
15
+ * `open()` via {@link lazyOpen} — never at module scope — because the
16
+ * packed-consumer gate imports every export subpath under Node *and*
17
+ * Bun, Bun ships no `node:sqlite`, and Node cannot resolve `bun:`
18
+ * specifiers. `open()` is where "this driver does not exist here"
19
+ * becomes the coded `JD0003` instead of a module-load crash.
20
+ *
21
+ * `capabilities` is read once at open — from the library's version
22
+ * report, its compile options and the binding's declaration — and is
23
+ * the single source of truth for feature gating; never a `typeof`
24
+ * sniff at a call site. Two slots are deliberately EMPTY on every
25
+ * SQLite driver: `statementTimeout` (no interrupt or progress handler
26
+ * exists to build one on) and `rowEstimates` (the query plan is prose,
27
+ * not numbers). They exist so a driver that has the facts can fill
28
+ * them without a contract change; pretending SQLite has them is the
29
+ * silent degradation this suite refuses.
30
+ */
31
+ /** The minimum SQLite the store accepts, asserted at open. */
32
+ export declare const SQLITE_FLOOR = "3.45.0";
33
+ /**
34
+ * How long work may wait for an open transaction to settle before it is
35
+ * rejected with `JD0012`. Matches the store's default busy timeout: the
36
+ * question "has this waited unreasonably long?" has one answer per
37
+ * connection whether the contention is another process (SQLite's own
38
+ * busy timeout) or another transaction on this one.
39
+ */
40
+ export declare const DEFAULT_QUEUE_TIMEOUT = 5000;
41
+ /**
42
+ * @param {any} value
43
+ * @returns {boolean} true when the value is a thenable
44
+ */
45
+ export declare function isThenable(value: any): boolean;
46
+ /**
47
+ * Sync-capable-async composition: apply `next` to a driver result
48
+ * without allocating a promise when the result is already a value.
49
+ * @param {any} value - A driver return: a value or a promise
50
+ * @param {(value: any) => any} next
51
+ * @returns {any} `next`'s result, promise-wrapped only if the input was
52
+ */
53
+ export declare function chain(value: any, next: (value: any) => any): any;
54
+ /**
55
+ * Lift a driver result into a promise — the ONE allocation the public
56
+ * asynchronous surface pays per call.
57
+ * @param {any} value
58
+ * @returns {Promise<any>}
59
+ */
60
+ export declare function toPromise(value: any): Promise<any>;
61
+ /**
62
+ * Compare two dotted version strings numerically.
63
+ * @param {string} a
64
+ * @param {string} b
65
+ * @returns {number} negative when a < b, zero when equal
66
+ */
67
+ export declare function compareVersions(a: string, b: string): number;
68
+ /**
69
+ * Load a runtime builtin lazily and hand it to the binding's adapter.
70
+ * A failed import — the specifier does not exist on this runtime —
71
+ * becomes `JD0003` carrying the loader's error as `cause`.
72
+ * @param {string} specifier - The builtin module specifier
73
+ * @param {string} reason - The `JD0003` reason for this binding
74
+ * @param {(mod: any, ...args: any[]) => any} use - The binding's
75
+ * module-to-connection adapter (a named export so the suite can
76
+ * exercise it with a substitute module on any runtime)
77
+ * @param {any[]} args - Extra arguments forwarded to `use`
78
+ * @returns {Promise<any>}
79
+ */
80
+ export declare function lazyOpen(specifier: string, reason: string, use: (mod: any, ...args: any[]) => any, args: any[]): Promise<any>;
81
+ /**
82
+ * Normalize a raw statement to the contract shape. A binding without a
83
+ * native `iterate` gets one composed over `all` — eager, but the same
84
+ * rows in the same order.
85
+ * @param {{ run: Function, get: Function, all: Function,
86
+ * iterate?: Function }} statement
87
+ * @returns {{ run: Function, get: Function, all: Function,
88
+ * iterate: Function }}
89
+ */
90
+ export declare function wrapStatement(statement: {
91
+ run: Function;
92
+ get: Function;
93
+ all: Function;
94
+ iterate?: Function;
95
+ }): {
96
+ run: Function;
97
+ get: Function;
98
+ all: Function;
99
+ iterate: Function;
100
+ };
101
+ /**
102
+ * Finish a raw binding into the connection contract: probe the library
103
+ * once, assert the version floor, freeze the capability table, and
104
+ * attach the savepoint-nested `transaction`.
105
+ *
106
+ * The raw shape a binding supplies:
107
+ * `{ exec(sql), prepare(sql) -> { run, get, all, iterate? }, close(),
108
+ * registerFunction?, registerAggregate?, session? }` — every method
109
+ * value-or-promise.
110
+ *
111
+ * @param {any} raw
112
+ * @param {{ dialect: any, synchronous?: boolean, queueTimeout?: number,
113
+ * declared?: { sessions?: boolean, userFunctions?: boolean,
114
+ * deterministicIndexableFunctions?: boolean,
115
+ * aggregateFunctions?: boolean } }} options
116
+ * @returns {any} a Connection, or a promise of one
117
+ */
118
+ export declare function openConnection(raw: any, options: {
119
+ dialect: any;
120
+ synchronous?: boolean;
121
+ queueTimeout?: number;
122
+ declared?: {
123
+ sessions?: boolean;
124
+ userFunctions?: boolean;
125
+ deterministicIndexableFunctions?: boolean;
126
+ aggregateFunctions?: boolean;
127
+ };
128
+ }): any;
@@ -0,0 +1,47 @@
1
+ /**
2
+ * @file The Bun binding: `bun:sqlite` behind the driver contract. The
3
+ * builtin is imported lazily inside `open()` — never at module scope —
4
+ * so this module itself loads under any runtime; on a runtime that
5
+ * cannot resolve `bun:` specifiers the open fails with the coded
6
+ * `JD0003`.
7
+ *
8
+ * Probed reality this binding declares rather than papers over:
9
+ * `bun:sqlite`'s `Database` exposes no `function`, no `aggregate` and
10
+ * no `createSession` — on Bun the UDF hatch does not exist and there
11
+ * is no session-based change capture. The capability table says so.
12
+ *
13
+ * What it DOES expose is a native lazy row iterator, forwarded below.
14
+ * Without it the driver's generic fallback composes a cursor over
15
+ * `all()`, which materialises every row first — so a query that streams
16
+ * on Node would spike memory in a compiled Bun binary, on the same code
17
+ * and the same data. A cursor that is not lazy is not a cursor.
18
+ */
19
+ /**
20
+ * Adapt an already-constructed `bun:sqlite` `Database` (or any object
21
+ * with its shape) into a probed connection. Exported so the adapter is
22
+ * exercisable without the builtin.
23
+ * @param {any} db - A Bun `Database`-shaped database
24
+ * @param {{ queueTimeout?: number }} [options]
25
+ * @returns {any} a Connection, or a promise of one
26
+ */
27
+ export declare function adaptBunDatabase(db: any, options?: {
28
+ queueTimeout?: number;
29
+ }): any;
30
+ /**
31
+ * Construct and adapt the database from a loaded `bun:sqlite` module.
32
+ * Exported so the whole open path runs under any runtime with a
33
+ * substitute module.
34
+ * @param {any} mod - The `bun:sqlite` module (or a substitute)
35
+ * @param {string} path
36
+ * @param {{ readOnly?: boolean, queueTimeout?: number }} [options]
37
+ * @returns {any}
38
+ */
39
+ export declare function fromBunModule(mod: any, path: string, options?: {
40
+ readOnly?: boolean;
41
+ queueTimeout?: number;
42
+ }): any;
43
+ /**
44
+ * The Bun driver: `{ name, dialect, open }` over `bun:sqlite`.
45
+ * @returns {any}
46
+ */
47
+ export declare function bunDriver(): any;
@@ -0,0 +1,37 @@
1
+ /**
2
+ * @file The Node binding: `node:sqlite` behind the driver contract.
3
+ * The builtin is imported lazily inside `open()` — never at module
4
+ * scope — so this module itself loads under any runtime; on a runtime
5
+ * without `node:sqlite` the open fails with the coded `JD0003`.
6
+ */
7
+ /**
8
+ * Adapt an already-constructed `node:sqlite` `DatabaseSync` (or any
9
+ * object with its shape) into a probed connection. Exported so the
10
+ * adapter is exercisable without the builtin.
11
+ * @param {any} db - A `DatabaseSync`-shaped database
12
+ * @param {{ queueTimeout?: number }} [options]
13
+ * @returns {any} a Connection, or a promise of one
14
+ */
15
+ export declare function adaptNodeDatabase(db: any, options?: {
16
+ queueTimeout?: number;
17
+ }): any;
18
+ /**
19
+ * Construct and adapt the database from a loaded `node:sqlite` module.
20
+ * The seam {@link nodeDriver} feeds through `lazyOpen`; exported so the
21
+ * whole open path runs under any runtime with a substitute module.
22
+ * @param {any} mod - The `node:sqlite` module (or a substitute)
23
+ * @param {string} path
24
+ * @param {{ timeout?: number, readOnly?: boolean,
25
+ * queueTimeout?: number }} [options]
26
+ * @returns {any}
27
+ */
28
+ export declare function fromNodeModule(mod: any, path: string, options?: {
29
+ timeout?: number;
30
+ readOnly?: boolean;
31
+ queueTimeout?: number;
32
+ }): any;
33
+ /**
34
+ * The Node driver: `{ name, dialect, open }` over `node:sqlite`.
35
+ * @returns {any}
36
+ */
37
+ export declare function nodeDriver(): any;
@@ -0,0 +1,65 @@
1
+ /**
2
+ * @file The wasm binding: an INJECTED handle behind the driver
3
+ * contract. This module imports no runtime builtin at all — the host
4
+ * (a browser, a worker) supplies the SQLite build, and this driver
5
+ * only adapts it. Every handle method may return a value or a promise;
6
+ * a main-thread OPFS-backed build is asynchronous and that is exactly
7
+ * why the public store surface is.
8
+ *
9
+ * The injected contract:
10
+ *
11
+ * handle = {
12
+ * open(path, options) -> raw | Promise<raw>,
13
+ * synchronous?: boolean, // default false
14
+ * declares?: { userFunctions?, deterministicIndexableFunctions?,
15
+ * sessions? } // default all false
16
+ * }
17
+ * raw = { exec(sql), prepare(sql) -> { run, get, all, iterate? },
18
+ * close(), registerFunction?, registerAggregate?, session? }
19
+ *
20
+ * Capability truth still comes from the probe: whatever the handle
21
+ * declares is intersected with what the loaded library actually
22
+ * compiled in.
23
+ */
24
+ /**
25
+ * Adapt an already-constructed `sqlite3.oo1` database (the official
26
+ * SQLite wasm build's object API) into the raw contract. The oo1 API
27
+ * is SYNCHRONOUS — wasm SQLite computes in place and the SAH-pool
28
+ * OPFS VFS does synchronous I/O inside a dedicated worker — which is
29
+ * exactly what keeps journal capture, live queries and the job queue
30
+ * working unchanged in a browser.
31
+ *
32
+ * Statements are REUSED by the store's prepared caches: every
33
+ * operation ends in `reset()`, never `finalize()`. oo1 user functions
34
+ * receive a context pointer first — stripped here — and register
35
+ * variadic (`arity: -1`), matching the engine's fragment shapes.
36
+ * @param {any} sqlite3 - the loaded sqlite3 module (for `capi`)
37
+ * @param {any} db - an `sqlite3.oo1.DB`-shaped database
38
+ * @returns {any} the raw binding for {@link openConnection}
39
+ */
40
+ export declare function adaptOo1Database(sqlite3: any, db: any): any;
41
+ /**
42
+ * Build the injected HANDLE from a loaded sqlite3 module — the D6
43
+ * recipe: the host loads the wasm build and picks the database class
44
+ * (`sqlite3.oo1.DB` for `:memory:`, the SAH-pool util's `OpfsSAHPoolDb`
45
+ * for OPFS persistence), and this package only adapts it.
46
+ *
47
+ * `sessions` is deliberately NOT declared even though the canonical
48
+ * wasm build compiles `ENABLE_SESSION`: this adapter does not yet map
49
+ * the session C API, so capture runs in the journal mode — stated in
50
+ * the capability matrix, adapting it is a roadmap item.
51
+ * @param {any} sqlite3 - the loaded sqlite3 module
52
+ * @param {{ DbClass?: any }} [handleOptions] - the database class to
53
+ * construct (default `sqlite3.oo1.DB`)
54
+ * @returns {any} a handle for {@link wasmDriver}
55
+ */
56
+ export declare function sqlite3Handle(sqlite3: any, handleOptions?: {
57
+ DbClass?: any;
58
+ }): any;
59
+ /**
60
+ * The wasm driver over an injected handle.
61
+ * @param {any} handle - The host-supplied SQLite handle (see the file
62
+ * header for the contract)
63
+ * @returns {any}
64
+ */
65
+ export declare function wasmDriver(handle: any): any;
@@ -0,0 +1,44 @@
1
+ /**
2
+ * @file Entity types from models (D17): build an EMIT MODEL DOCUMENT
3
+ * — the published contract from EMIT-FORMAT.md — that renders entity
4
+ * interfaces, input variants and the typed-store metadata from the
5
+ * same model document the runtime validates against.
6
+ *
7
+ * The seam (EMIT-FORMAT §4.1, recorded here as the order demanded):
8
+ * the schema compiler is INJECTED (`options.compile` is
9
+ * `compileEmitModel` from `@jarenjs/emit`), called with
10
+ * `extensions: ['x-entity']` so the vocabulary rides the member nodes
11
+ * verbatim; this module then post-processes the MODEL DOCUMENT —
12
+ * replacing relation member types with references, flipping
13
+ * optionality, adding declarations — and never renders a character of
14
+ * TypeScript itself. Emit stays database-free, db stays
15
+ * renderer-free, and the injection keeps `@jarenjs/emit` out of db's
16
+ * dependency graph (the generator script wires the two).
17
+ *
18
+ * What the artifact says, deliberately:
19
+ * - entity interfaces are CLOSED objects (excess-property checking is
20
+ * the point of generated types; the runtime validator stays
21
+ * authoritative for what a database accepts);
22
+ * - relation members are optional references — present only when a
23
+ * graph load included them; `date-time`/`date` strings carry the
24
+ * `DateTime` brand so the linq date operators light up;
25
+ * - the `<Name>Input` variant makes defaulted and generated members
26
+ * optional, drops to-one/to-many relation members (`create`/`add`
27
+ * refuse them), and types many-to-many members as key-or-document
28
+ * arrays (what `add()` accepts);
29
+ * - `EntityMetaMap` carries doc/input/key/relations per entity — the
30
+ * generic typed-store surface (`@jarenjs/db/typed`) binds to it.
31
+ */
32
+ /**
33
+ * Build the emit-model document for a model's entities.
34
+ * @param {any} model - a jaren-model document with `entities`
35
+ * @param {{ compile: (schema: any, options?: any) => any,
36
+ * source?: string, reserved?: string[] }} options - `compile` is
37
+ * `compileEmitModel` (injected; see the header)
38
+ * @returns {any} an EMIT-FORMAT `0.1` model document
39
+ */
40
+ export declare function entityEmitModel(model: any, options: {
41
+ compile: (schema: any, options?: any) => any;
42
+ source?: string;
43
+ reserved?: string[];
44
+ }): any;
@@ -0,0 +1,72 @@
1
+ /**
2
+ * @file Plan → SQL through a dialect. This is the query layer's shared
3
+ * emitter, the same division of labour as `createDialect`'s DDL/DML
4
+ * builders: structural SQL composition lives here, every
5
+ * dialect-varying spelling (identifiers, parameters, string literals,
6
+ * JSON access, `json_type`, `typeof`, string-operator forms, NULLS
7
+ * placement, EXPLAIN phrasing) comes from the dialect. Values are
8
+ * NEVER interpolated into the text: every literal and every external
9
+ * becomes an ordered parameter slot, which is what makes injection
10
+ * structurally impossible.
11
+ *
12
+ * Every emitted predicate is TOTAL (two-valued) by construction — the
13
+ * `json_type` guards from the truth table in ARCHITECTURE.md — so
14
+ * `NOT`/`AND`/`OR` compose classically and SQL's three-valued NULL
15
+ * logic never decides a row.
16
+ */
17
+ export type ParamSlot = {
18
+ external: string;
19
+ } | {
20
+ literal: unknown;
21
+ };
22
+ /**
23
+ * @typedef {{ external: string } | { literal: unknown }} ParamSlot
24
+ */
25
+ /**
26
+ * Emit one plan as SQL plus its ordered parameter slots.
27
+ * @param {import('./algebra.js').Plan} plan
28
+ * @param {any} dialect
29
+ * @param {{ table: string, keyColumn: string, docColumn: string }} physical
30
+ * @returns {{ sql: string, slots: ParamSlot[] }}
31
+ */
32
+ export declare function emitPlan(plan: import('./algebra.js').Plan, dialect: any, physical: {
33
+ table: string;
34
+ keyColumn: string;
35
+ docColumn: string;
36
+ }): {
37
+ sql: string;
38
+ slots: ParamSlot[];
39
+ };
40
+ /**
41
+ * The entity predicate emitters, shared by the entity plan emitter
42
+ * and the graph-load builder: given an alias and its document column,
43
+ * emit one predicate with the flavor-correct forms.
44
+ * @param {any} dialect
45
+ * @param {(slot: ParamSlot) => string} param
46
+ * @returns {{ emitPred: (aliasSql: string, docSql: string, pred: any) => string }}
47
+ */
48
+ export declare function createEntityPredicateEmitters(dialect: any, param: (slot: ParamSlot) => string): {
49
+ emitPred: (aliasSql: string, docSql: string, pred: any) => string;
50
+ };
51
+ /**
52
+ * Emit an entity plan (`entity-select` or `entity-join`) as SQL plus
53
+ * ordered parameter slots. Entity-COLUMN refs compare real typed
54
+ * columns with TOTAL forms and no `json_type` guard — a column-mapped
55
+ * property has no present-`null` (§9.3), so presence IS `IS NOT
56
+ * NULL`; entity-EPOCH refs compare the derived integer column against
57
+ * a plan-time epoch translation; entity-DOC refs ride the phase-A
58
+ * guarded truth table over the entity's JSONB column. Join emission
59
+ * appends BOTH bindings' row identities in binding order, which is
60
+ * exactly the engine's nested-loop order — determinism the oracle
61
+ * depends on.
62
+ * @param {any} plan - from `planEntityQuery`
63
+ * @param {any} dialect
64
+ * @param {(entity: string) => { table: string }} physicalOf
65
+ * @returns {{ sql: string, slots: ParamSlot[] }}
66
+ */
67
+ export declare function emitEntityPlan(plan: any, dialect: any, physicalOf: (entity: string) => {
68
+ table: string;
69
+ }): {
70
+ sql: string;
71
+ slots: ParamSlot[];
72
+ };
@@ -0,0 +1,23 @@
1
+ /**
2
+ * @file Entity sets: create / read by key / update / delete over the
3
+ * hybrid mapping. The physical row is the mapped scalar columns, the
4
+ * foreign-key columns, and one JSONB `doc` column for everything
5
+ * else; a write SPLITS the completed document along the mapping and a
6
+ * read MERGES it back. Defaults apply in JavaScript before validation
7
+ * — the value the application sees and the value stored are the same
8
+ * — and identity follows the declared strategy (caller, uuid, auto).
9
+ *
10
+ * Epoch date columns are DERIVED: the document keeps the RFC 3339
11
+ * string, the column carries `getEpochOf…RFC3339(value)` so range
12
+ * predicates are index-friendly; reads take the string from the
13
+ * document and skip the derived column.
14
+ */
15
+ /**
16
+ * The write/read machinery for one entity, prepared once.
17
+ * @param {any} connection
18
+ * @param {any} entity - the normalized entity (model.js)
19
+ * @param {any} entityMapping - `explainMapping(...).entities[name]`
20
+ * @param {((doc: any) => any) | null} validate
21
+ * @returns {any}
22
+ */
23
+ export declare function entityCore(connection: any, entity: any, entityMapping: any, validate: ((doc: any) => any) | null): any;
@@ -0,0 +1,165 @@
1
+ /**
2
+ * @file Error types for @jarenjs/db, built on `@jarenjs/core`'s coded
3
+ * contract: every failure carries a stable `code` (JD0xxx compile-time,
4
+ * JD2xxx runtime), a bare `reason`, a composed `message`, and — where a
5
+ * position in the model document exists — a `docPath`. Runtime errors
6
+ * additionally carry the `collection` and, where one exists, the `key`
7
+ * as own properties. Database errors are wrapped, never leaked raw: the
8
+ * reason keeps the original text, `cause` keeps the original error. The
9
+ * normative table lives in docs/MODEL-FORMAT.md §7, proven in sync with
10
+ * `DB_CODES` below by a test.
11
+ */
12
+ import { CodedError } from '@jarenjs/core/errors';
13
+ /**
14
+ * The runtime code table (the `CSV_CODES` shape): one entry per code
15
+ * this package can raise, proven in sync with MODEL-FORMAT.md §7's
16
+ * normative table by a test.
17
+ */
18
+ export declare const DB_CODES: Readonly<{
19
+ JD0001: "the SQLite library is below the supported floor";
20
+ JD0002: "the declared model disagrees with the existing database";
21
+ JD0003: "the driver binding is unavailable on this runtime";
22
+ JD0004: "an index path is not a singular member selection";
23
+ JD0005: "the model document is invalid";
24
+ JD0010: "strict mode refused a residual";
25
+ JD0011: "the profile refused the document";
26
+ JD0012: "work waited too long for the open transaction to settle";
27
+ JD0030: "an unknown x-entity member was declared";
28
+ JD0031: "relation declarations contradict each other";
29
+ JD0032: "the include specification is invalid";
30
+ JD0040: "the save spans a relation cycle";
31
+ JD0050: "live queries require change capture";
32
+ JD0051: "the demanded live mode is unavailable";
33
+ JD0052: "the live-query bound was reached";
34
+ JD0020: "the migration's from-shape does not match the database";
35
+ JD0021: "the migration is missing a required data transform";
36
+ JD0022: "an applied migration disagrees with the history record";
37
+ JD0023: "a migration step failed";
38
+ JD2001: "insert found the key already present";
39
+ JD2002: "a usable key could not be resolved for the write";
40
+ JD2003: "the write failed schema validation";
41
+ JD2004: "an undeclared collection was requested";
42
+ JD2005: "a database operation failed";
43
+ JD2006: "patch found no document at the key";
44
+ JD2007: "the result exceeded the profile row bound";
45
+ JD2040: "the row changed under an optimistic update";
46
+ JD2050: "a changeset could not be decoded";
47
+ JD2051: "the change log is not enabled";
48
+ JD2060: "the maintained live state exceeded its bound";
49
+ JD2061: "another context owns the database";
50
+ JD2062: "the store closed with job handlers still in flight";
51
+ }>;
52
+ /**
53
+ * A defect found while opening a store — in the model document, the
54
+ * declared indexes, the driver binding, or the database's agreement
55
+ * with the declaration. Codes:
56
+ *
57
+ * - `JD0001` — the SQLite library reported a version below the
58
+ * supported floor; the reason names the version found
59
+ * - `JD0002` — a declared collection already exists in the database
60
+ * with a different shape; nothing was altered — changing shape is
61
+ * the migration story, a later capability
62
+ * - `JD0003` — the runtime builtin behind a driver could not be
63
+ * loaded here (Node cannot resolve `bun:`; Bun ships no
64
+ * `node:sqlite`), or an injected handle is missing
65
+ * - `JD0004` — an index path does not select exactly one member
66
+ * (wildcards, slices, filters and descendants are not indexable);
67
+ * the reason names the expression
68
+ * - `JD0005` — the model document is invalid; `docPath` points at
69
+ * the offending member
70
+ * - `JD0010` — `strict: true` and part of the query would have run
71
+ * outside the database; the reason names the forcing construct
72
+ * - `JD0011` — the active profile refused the document before any
73
+ * execution: an undeclared external, host function, collation or
74
+ * collection, or a refused full-table scan; the reason names it
75
+ * - `JD0030` — an unknown member inside an `x-entity` block; a
76
+ * silently ignored mapping directive is a data-loss bug waiting
77
+ * - `JD0031` — two relation declarations whose inverses contradict
78
+ * (different `via`, impossible `many` pairings)
79
+ * - `JD0032` — a graph-load include specification is invalid: an
80
+ * unknown relation, a cycle, an untranslatable filter, or the
81
+ * depth bound exceeded (the bound is printed, never silent)
82
+ * - `JD0040` — `saveChanges()` cannot order its statements: the
83
+ * entities being inserted or deleted form a foreign-key cycle
84
+ * (self-references included); break the save in two
85
+ * - `JD0050` — a live query was registered on a store opened without
86
+ * `capture`; the patch stream is the invalidation source
87
+ * - `JD0051` — `mode: 'incremental'` was demanded but the document
88
+ * classifies as re-run; the reason names the forcing construct
89
+ * - `JD0052` — registering would exceed the store's `live.maxQueries`
90
+ * bound; the bound is printed, never silent
91
+ * - `JD0020` — a migration's `from` hash does not match the
92
+ * database's recorded shape; running it would corrupt
93
+ * - `JD0021` — a draft transform was not filled in, or a document no
94
+ * longer validates after the migration (a narrowing without an
95
+ * adequate transform)
96
+ * - `JD0022` — the migration list disagrees with the applied history
97
+ * (an edited file, a missing file, a reordered sequence)
98
+ * - `JD0023` — a step failed: an assertion returned rows, DDL was
99
+ * rejected, or a transform produced an unstorable value
100
+ */
101
+ export declare class DbCompileError extends CodedError {
102
+ /**
103
+ * @param {string} code
104
+ * @param {string} reason - The bare reason; `message` is composed per
105
+ * the coded contract.
106
+ * @param {string} [docPath] - JSON Pointer into the model document,
107
+ * where one exists.
108
+ * @param {Error} [cause]
109
+ */
110
+ constructor(code: string, reason: string, docPath?: string, cause?: Error);
111
+ }
112
+ /**
113
+ * A failure while reading or writing an open store. Codes:
114
+ *
115
+ * - `JD2001` — `insert` hit a document already stored under the key
116
+ * - `JD2002` — the declared key pointer resolved to nothing or to a
117
+ * non-scalar, or an explicit key argument is not a string or number
118
+ * - `JD2003` — the injected validation hook rejected the document
119
+ * that a write would have stored; `errors` carries the hook's
120
+ * findings when it produced any
121
+ * - `JD2004` — `collection()` named a collection the model does not
122
+ * declare
123
+ * - `JD2005` — the database rejected an operation for a reason that
124
+ * is not a duplicate key; the original error is the `cause`
125
+ * - `JD2006` — `patch` addressed a key with no stored document
126
+ * - `JD2007` — a fetch crossed the profile's `maxRows` bound; the
127
+ * result is refused whole, never silently truncated
128
+ * - `JD2040` — an optimistic update or delete matched no row: the
129
+ * declared version changed under the save (or the row is gone);
130
+ * the error names the entity and key, and the whole save rolled
131
+ * back
132
+ * - `JD2050` — a session changeset carried bytes this decoder does
133
+ * not recognise (a future SQLite format change would land here)
134
+ * - `JD2051` — `changesSince` was called on a store whose capture
135
+ * has no persisted log
136
+ * - `JD2060` — maintenance crossed the live query's `maxMaintained`
137
+ * bound; the query delivered this error and closed rather than
138
+ * degrade
139
+ * - `JD2061` — a second context tried to open a database whose
140
+ * storage grants one context exclusive access (the owner topology
141
+ * of LIVE-FORMAT §11); connect to the owner instead
142
+ */
143
+ export declare class DbRuntimeError extends CodedError {
144
+ collection: string | undefined;
145
+ key: string | number | undefined;
146
+ errors: unknown[] | undefined;
147
+ /**
148
+ * @param {string} code
149
+ * @param {string} reason - The bare reason; `message` is composed per
150
+ * the coded contract.
151
+ * @param {{ docPath?: string, collection?: string,
152
+ * key?: string | number, errors?: unknown[], cause?: unknown }} [details]
153
+ * - `docPath` points into the model document (the collection the
154
+ * failure belongs to); `collection`/`key` are installed as own
155
+ * properties; `errors` carries validation findings; `cause` follows
156
+ * the coded contract's `hasOwn` form.
157
+ */
158
+ constructor(code: string, reason: string, details?: {
159
+ docPath?: string;
160
+ collection?: string;
161
+ key?: string | number;
162
+ errors?: unknown[];
163
+ cause?: unknown;
164
+ });
165
+ }
@@ -0,0 +1,28 @@
1
+ /**
2
+ * @file Row → entity-graph reconstruction. One place owns the merge
3
+ * discipline (§9.3): mapped scalar columns fold back into the JSONB
4
+ * document's parse (booleans un-integer, SQL NULL reads back ABSENT,
5
+ * derived epoch columns are skipped because the string never left the
6
+ * document), foreign-key columns fold in the same way, and — for the
7
+ * one-statement graph loads — projected relation JSON parses
8
+ * recursively into child arrays or single children.
9
+ */
10
+ /**
11
+ * Merge one database row back into its entity document.
12
+ * @param {any} entityMapping - `explainMapping(...).entities[name]`
13
+ * @param {any} row - a row carrying the entity's columns plus the
14
+ * rendered document text
15
+ * @param {string} [docField] - the column the document text rides in
16
+ * @returns {any}
17
+ */
18
+ export declare function mergeEntityRow(entityMapping: any, row: any, docField?: string): any;
19
+ /**
20
+ * Parse one graph-load row: the root entity's merge plus every
21
+ * included relation's projected JSON, recursively.
22
+ * @param {any} node - the include-plan node
23
+ * `{ entityMapping, includes: { name, field, many, count, child }[] }`
24
+ * @param {any} row
25
+ * @param {string} docField
26
+ * @returns {any}
27
+ */
28
+ export declare function parseGraphRow(node: any, row: any, docField?: string): any;
@@ -0,0 +1,35 @@
1
+ /**
2
+ * @file @jarenjs/db — document storage over SQLite through two seams:
3
+ * a driver (how a connection is made: `@jarenjs/db/node`, `/bun`, or
4
+ * `/wasm` with an injected handle) and a dialect (how SQL is spelled).
5
+ * This root subpath never touches a runtime builtin — a browser
6
+ * bundler resolves it clean; the bindings live behind their own
7
+ * subpaths and load their builtin lazily inside `open()`.
8
+ */
9
+ export { openStore, normalizeModel, MODEL_VERSION } from './store.js';
10
+ export { createDialect } from './dialect.js';
11
+ export { sqliteDialect } from './dialects/sqlite.js';
12
+ export { SQLITE_FLOOR, chain, toPromise, isThenable, compareVersions, openConnection, wrapStatement, lazyOpen, } from './driver.js';
13
+ export { planCollection, compileIndexPath, schemaTypeAt, KEY_COLUMN, DOC_COLUMN, normalizeDeclaredSql, comparableDeclaredSql, } from './ddl.js';
14
+ export { planQuery, assertDecidedKind, entityShape, entityPathRef, planEntityPredicate, planEntityQuery, } from './plan.js';
15
+ export { emitPlan, createEntityPredicateEmitters, emitEntityPlan } from './emit.js';
16
+ export { mergeEntityRow, parseGraphRow } from './graph.js';
17
+ export { selectPlan, conjoin, assertNoSqlText, PLAN_VERSION } from './algebra.js';
18
+ export { typeOfPath, isNumericType } from './types.js';
19
+ export { compileSetResidual, compileRowResidual, sequenceResult } from './residual.js';
20
+ export { deterministicFragment, registerFragment } from './udf.js';
21
+ export { createQueryEngine, createQueryState, createEntityQueryEngine, createLoadEngine, INCLUDE_DEPTH_DEFAULT, } from './query.js';
22
+ export { normalizeProfile, SAFE_PROFILE, translateProfilePredicate, applyMandatoryPredicate, applyRowBound, } from './profile.js';
23
+ export { translatePatch } from './patch-sql.js';
24
+ export { normalizeEntities, explainMapping } from './model.js';
25
+ export { planEntity, planJoinTable } from './ddl.js';
26
+ export { entityCore } from './entity.js';
27
+ export { entityEmitModel } from './emit-model.js';
28
+ export { parseChangeset, translateOperations, keyToken, createCaptureEngine, CHANGES_TABLE, DEFAULT_RETENTION, } from './capture.js';
29
+ export { createTracker, deepFreeze, BATCH_PARAM_BUDGET, BATCH_ROW_BOUND, } from './tracker.js';
30
+ export { planMigration, planModelMigration, migrate, migrationStatus, shapeHash, migrationChecksum, createModelShape, schemaShapeOf, compareShapeToModel, MIGRATION_VERSION, HISTORY_TABLE, } from './migrate.js';
31
+ export { DbCompileError, DbRuntimeError, DB_CODES } from './errors.js';
32
+ export { classifyLiveQuery, createLiveRegistry, diffRows, LIVE_DEFAULTS } from './live.js';
33
+ export { createSortedWindow, compareCodepoint } from './window.js';
34
+ export { createJobEngine, JOBS_TABLE, JOB_CHECKPOINTS_TABLE, JOB_DEFAULTS, describeValue, serializeResult, } from './jobs.js';
35
+ export { createDagJobRunner } from './dag-job.js';