@jarenjs/db 0.46.5 → 0.56.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 (72) hide show
  1. package/ARCHITECTURE.md +133 -17
  2. package/README.md +270 -36
  3. package/docs/JOBS-FORMAT.md +24 -8
  4. package/docs/LIVE-FORMAT.md +139 -7
  5. package/docs/MIGRATION-FORMAT.md +118 -36
  6. package/docs/MODEL-FORMAT.md +251 -30
  7. package/package.json +4 -5
  8. package/schemas/jaren-migration.draft-07.schema.json +73 -0
  9. package/schemas/jaren-migration.schema.json +73 -0
  10. package/src/algebra.js +22 -3
  11. package/src/capture.js +66 -28
  12. package/src/cli.js +225 -44
  13. package/src/ddl.js +23 -3
  14. package/src/dialect.js +13 -0
  15. package/src/dialects/sqlite.js +21 -1
  16. package/src/driver.js +63 -16
  17. package/src/drivers/wasm.js +1 -0
  18. package/src/emit-model.js +14 -0
  19. package/src/emit.js +42 -9
  20. package/src/entity.js +92 -47
  21. package/src/errors.js +28 -0
  22. package/src/index.js +2 -2
  23. package/src/jobs.js +40 -5
  24. package/src/live-time.js +605 -0
  25. package/src/live.js +52 -9
  26. package/src/migrate.js +397 -191
  27. package/src/model.js +173 -8
  28. package/src/plan.js +834 -47
  29. package/src/query.js +296 -22
  30. package/src/residual.js +15 -6
  31. package/src/series.js +349 -0
  32. package/src/store.js +243 -69
  33. package/src/tracker.js +173 -48
  34. package/types/index.d.ts +206 -12
  35. package/types/node.d.ts +3 -1
  36. package/types/typed.d.ts +58 -2
  37. package/types/wasm.d.ts +7 -0
  38. package/dist/types/algebra.d.ts +0 -199
  39. package/dist/types/app.d.ts +0 -49
  40. package/dist/types/capture.d.ts +0 -85
  41. package/dist/types/cli.d.ts +0 -2
  42. package/dist/types/dag-job.d.ts +0 -40
  43. package/dist/types/ddl.d.ts +0 -229
  44. package/dist/types/derive.d.ts +0 -250
  45. package/dist/types/dialect.d.ts +0 -149
  46. package/dist/types/dialects/sqlite.d.ts +0 -9
  47. package/dist/types/driver.d.ts +0 -110
  48. package/dist/types/drivers/bun.d.ts +0 -47
  49. package/dist/types/drivers/node.d.ts +0 -37
  50. package/dist/types/drivers/wasm.d.ts +0 -65
  51. package/dist/types/emit-model.d.ts +0 -44
  52. package/dist/types/emit.d.ts +0 -75
  53. package/dist/types/entity.d.ts +0 -23
  54. package/dist/types/errors.d.ts +0 -167
  55. package/dist/types/graph.d.ts +0 -28
  56. package/dist/types/index.d.ts +0 -37
  57. package/dist/types/jobs.d.ts +0 -140
  58. package/dist/types/knn.d.ts +0 -69
  59. package/dist/types/live.d.ts +0 -62
  60. package/dist/types/migrate.d.ts +0 -170
  61. package/dist/types/model.d.ts +0 -36
  62. package/dist/types/patch-sql.d.ts +0 -37
  63. package/dist/types/plan.d.ts +0 -140
  64. package/dist/types/profile.d.ts +0 -80
  65. package/dist/types/query.d.ts +0 -111
  66. package/dist/types/residual.d.ts +0 -61
  67. package/dist/types/store.d.ts +0 -53
  68. package/dist/types/tracker.d.ts +0 -43
  69. package/dist/types/typed.d.ts +0 -15
  70. package/dist/types/types.d.ts +0 -26
  71. package/dist/types/udf.d.ts +0 -75
  72. package/dist/types/window.d.ts +0 -52
@@ -1,199 +0,0 @@
1
- /**
2
- * @file The Plan algebra: the dialect-neutral middle stage between the
3
- * engine's AST and a dialect's SQL. A plan is a plain JSON value —
4
- * inspectable, golden-testable without a database — and it carries NO
5
- * SQL text: every string in a plan is a member name, a type tag, an
6
- * external name or a reason sentence, never a fragment of any query
7
- * language. `assertNoSqlText` is the tripwire the tests run over every
8
- * golden.
9
- *
10
- * One plan shape covers this version: a guarded selection over ONE
11
- * collection with optional ordering, window, aggregate and a
12
- * whole-document projection — or, instead of an ordering and a window,
13
- * a k-nearest RANK the engine finishes over the rows the plan fetches.
14
- * Constructs beyond it are residuals by design (see ARCHITECTURE.md's
15
- * deliberate-residual table).
16
- */
17
- /** The plan format version, carried on every plan. */
18
- export declare const PLAN_VERSION = 2;
19
- export type PlanRef = {
20
- segments: ({
21
- name: string;
22
- } | {
23
- index: number;
24
- })[];
25
- type: string;
26
- column: string | null;
27
- };
28
- export type PlanOperand = {
29
- lit: unknown;
30
- } | {
31
- ext: string;
32
- };
33
- export type PlanPredicate = ({
34
- p: 'and' | 'or';
35
- items: PlanPredicate[];
36
- } | {
37
- p: 'not';
38
- item: PlanPredicate;
39
- } | {
40
- p: 'cmp';
41
- op: 'eq' | 'ne' | 'lt' | 'le' | 'gt' | 'ge';
42
- ref: PlanRef;
43
- operand: PlanOperand;
44
- } | {
45
- p: 'typeIs';
46
- ref: PlanRef;
47
- types: string[];
48
- positive: boolean;
49
- } | {
50
- p: 'strop';
51
- kind: 'starts' | 'ends' | 'contains';
52
- ref: PlanRef;
53
- operand: PlanOperand;
54
- } | {
55
- p: 'const';
56
- value: boolean;
57
- } | {
58
- p: 'udf';
59
- name: string;
60
- key: string;
61
- } | {
62
- p: 'bboxOverlap';
63
- columns: {
64
- w: string;
65
- s: string;
66
- e: string;
67
- n: string;
68
- };
69
- probe: {
70
- box: number[];
71
- } | {
72
- ext: string;
73
- };
74
- } | {
75
- p: 'cellIn';
76
- column: string;
77
- cells: string[];
78
- } | {
79
- p: 'cellPrefix';
80
- column: string;
81
- prefix: string;
82
- });
83
- export type PlanOrderTerm = {
84
- ref: PlanRef;
85
- desc: boolean;
86
- emptyGreatest: boolean;
87
- };
88
- export type PlanRank = {
89
- column: string;
90
- dims: number;
91
- probe: {
92
- lit: number[];
93
- } | {
94
- ext: string;
95
- };
96
- offset: number;
97
- limit: number;
98
- margin: number;
99
- };
100
- export type Plan = {
101
- planVersion: number;
102
- alg: 'select';
103
- collection: string;
104
- filter: PlanPredicate | null;
105
- order: PlanOrderTerm[] | null;
106
- window: {
107
- offset: number;
108
- limit: number | null;
109
- } | null;
110
- rank: PlanRank | null;
111
- aggregate: {
112
- fn: 'count' | 'sum' | 'avg' | 'min' | 'max';
113
- ref: PlanRef | null;
114
- } | null;
115
- project: 'document';
116
- };
117
- /**
118
- * @typedef {{ segments: ({ name: string } | { index: number })[],
119
- * type: string, column: string | null }} PlanRef
120
- * A typed reference into the stored document: `type` is the
121
- * schema-declared type or `'unknown'`; `column` is the generated
122
- * column name when the collection indexes this path.
123
- *
124
- * @typedef {{ lit: unknown } | { ext: string }} PlanOperand
125
- *
126
- * @typedef {(
127
- * { p: 'and' | 'or', items: PlanPredicate[] } |
128
- * { p: 'not', item: PlanPredicate } |
129
- * { p: 'cmp', op: 'eq' | 'ne' | 'lt' | 'le' | 'gt' | 'ge',
130
- * ref: PlanRef, operand: PlanOperand } |
131
- * { p: 'typeIs', ref: PlanRef, types: string[], positive: boolean } |
132
- * { p: 'strop', kind: 'starts' | 'ends' | 'contains',
133
- * ref: PlanRef, operand: PlanOperand } |
134
- * { p: 'const', value: boolean } |
135
- * { p: 'udf', name: string, key: string } |
136
- * { p: 'bboxOverlap', columns: { w: string, s: string, e: string,
137
- * n: string }, probe: { box: number[] } | { ext: string } } |
138
- * { p: 'cellIn', column: string, cells: string[] } |
139
- * { p: 'cellPrefix', column: string, prefix: string }
140
- * )} PlanPredicate
141
- * The last three are the SPATIAL forms: predicates over the derived
142
- * index columns a model declares, which a spatial conjunct either
143
- * translates to exactly or is proven to IMPLY. `bboxOverlap` is true
144
- * when the row's stored box meets the probe's (touching edges count,
145
- * as the kernel's `bboxIntersects` does); `cellIn` when the row's
146
- * cell is one of the listed ones (the nine-cell neighbourhood, or a
147
- * single whole cell); `cellPrefix` when it begins with a shorter one.
148
- * None carries a `json_type` guard — the derived column IS the value
149
- * — but each is TOTAL through its own `IS NOT NULL`, so a row with no
150
- * box or no cell answers FALSE rather than SQL's NULL and negation
151
- * still composes classically.
152
- *
153
- * @typedef {{ ref: PlanRef, desc: boolean, emptyGreatest: boolean }} PlanOrderTerm
154
- *
155
- * @typedef {{ column: string, dims: number,
156
- * probe: { lit: number[] } | { ext: string },
157
- * offset: number, limit: number, margin: number }} PlanRank
158
- * The k-nearest stage: the packed vector column the ranking reads,
159
- * its declared width, the probe (a plan-time literal vector, or the
160
- * external that carries one at call time), the window the ENGINE
161
- * will apply, and the inclusive score margin of the candidate cut.
162
- * The column cuts — every row whose column score is within `margin`
163
- * of the `offset + limit`-th best is a candidate — and the engine
164
- * decides: the original document, its whole ordering and window
165
- * included, runs over the candidates' documents. A plan carrying a
166
- * rank carries no order and no window of its own: nothing in SQL
167
- * orders or limits the fetch.
168
- *
169
- * @typedef {{
170
- * planVersion: number,
171
- * alg: 'select',
172
- * collection: string,
173
- * filter: PlanPredicate | null,
174
- * order: PlanOrderTerm[] | null,
175
- * window: { offset: number, limit: number | null } | null,
176
- * rank: PlanRank | null,
177
- * aggregate: { fn: 'count' | 'sum' | 'avg' | 'min' | 'max',
178
- * ref: PlanRef | null } | null,
179
- * project: 'document',
180
- * }} Plan
181
- */
182
- /**
183
- * A fresh select plan over one collection.
184
- * @param {string} collection
185
- * @returns {Plan}
186
- */
187
- export declare function selectPlan(collection: string): Plan;
188
- /**
189
- * Conjoin a predicate onto a plan's filter.
190
- * @param {PlanPredicate | null} filter
191
- * @param {PlanPredicate} predicate
192
- * @returns {PlanPredicate}
193
- */
194
- export declare function conjoin(filter: PlanPredicate | null, predicate: PlanPredicate): PlanPredicate;
195
- /**
196
- * Throw when a plan value carries anything that smells like SQL.
197
- * @param {unknown} plan
198
- */
199
- export declare function assertNoSqlText(plan: unknown): void;
@@ -1,49 +0,0 @@
1
- /**
2
- * @file The app binding for live queries (LIVE-FORMAT §10): GENERATED
3
- * documents plus a handler factory — the `fsmToApp` precedent. The db
4
- * package never imports `@jarenjs/app`; the app document declares a
5
- * subscription (`APP-FORMAT §5.3`) whose registered handler is
6
- * `createLiveSubscription(store)`, and a two-line action whose whole
7
- * body is `{ patch: '$payload' }` — the handler prefixes every op
8
- * with the declared state path, so the app loop applies live patches
9
- * with the machinery it already has.
10
- */
11
- /**
12
- * Prefix every op path in a live patch with the state slot.
13
- * @param {any[]} patch
14
- * @param {string} statePath - JSON Pointer to the slot holding the
15
- * live result document
16
- */
17
- export declare function prefixLivePatch(patch: any[], statePath: string): any[];
18
- /**
19
- * The generated documents (§10): a subscription entry and the
20
- * patch-forwarding action, both plain data for the app document.
21
- * @param {{ run?: string, action?: string, statePath: string,
22
- * collection?: string, query: any, externals?: any, mode?: string,
23
- * when?: any }} options
24
- * @returns {{ subscription: any, actions: any }}
25
- */
26
- export declare function liveAppBinding(options: {
27
- run?: string;
28
- action?: string;
29
- statePath: string;
30
- collection?: string;
31
- query: any;
32
- externals?: any;
33
- mode?: string;
34
- when?: any;
35
- }): {
36
- subscription: any;
37
- actions: any;
38
- };
39
- /**
40
- * The subscription handler factory: registers the live query when the
41
- * subscription starts, dispatches ONE initializing patch (a `replace`
42
- * of the whole slot), forwards each emission prefixed, and closes on
43
- * cleanup. An emission error surfaces as a dispatch of
44
- * `<action>/error` so the app can render it — silence is not an
45
- * option the format allows.
46
- * @param {any} store - an open store with capture
47
- * @returns {(props: any, dispatch: Function) => Function}
48
- */
49
- export declare function createLiveSubscription(store: any): (props: any, dispatch: Function) => Function;
@@ -1,85 +0,0 @@
1
- /**
2
- * @file Change capture (D13): committed writes become an observable,
3
- * ordered stream of RFC 6902 patches — derived from SQLite's own
4
- * session changesets where the binding has them, from a write-path
5
- * journal where it does not (`bun:sqlite` has no `createSession`), or
6
- * off entirely. One diff format then runs end to end: store → patch →
7
- * live query → patch → O(k) render.
8
- *
9
- * The pointer contract (LIVE-FORMAT §2): `/<table>/<key>/<path…>`,
10
- * every token escaped per RFC 6901. A single key renders as its
11
- * scalar text (integers in decimal); a composite key renders as the
12
- * JSON text of its parts array. Join-table rows are tiny documents
13
- * under the join table's name — membership changes are part of the
14
- * stream, not a blind spot.
15
- *
16
- * Session facts this file is built on (probed, 3.51.2):
17
- * - a changeset carries ONE NET OP PER ROW (insert+update coalesce;
18
- * insert+delete vanish; a no-op update is absent), and within-table
19
- * order is NOT statement order — every row op targets a distinct
20
- * pointer, so application order across rows cannot matter;
21
- * - `ROLLBACK TO` a savepoint removes the undone rows from the
22
- * session (pinned by test — the classic caveat does NOT hold here);
23
- * - a rolled-back transaction yields an empty changeset;
24
- * - virtual generated columns are invisible;
25
- * - an UPDATE's old record carries the primary key and the CHANGED
26
- * columns only — which is exactly enough for property-level ops,
27
- * and why the doc column's old/new blobs make a minimal nested
28
- * diff possible (`SELECT json(?)` turns JSONB back into text).
29
- */
30
- /** The persisted change log (LIVE-FORMAT §5). */
31
- export declare const CHANGES_TABLE = "_jaren_changes";
32
- export declare const DEFAULT_RETENTION = 1000;
33
- /**
34
- * Decode a binary changeset into row operations.
35
- * @param {Uint8Array} bytes
36
- * @returns {{ table: string, pk: boolean[], op: 'insert'|'update'|'delete',
37
- * indirect: boolean, oldValues: any[] | null, newValues: any[] | null }[]}
38
- */
39
- export declare function parseChangeset(bytes: Uint8Array): {
40
- table: string;
41
- pk: boolean[];
42
- op: 'insert' | 'update' | 'delete';
43
- indirect: boolean;
44
- oldValues: any[] | null;
45
- newValues: any[] | null;
46
- }[];
47
- /**
48
- * The key token (LIVE-FORMAT §2): a single key is its scalar text;
49
- * a composite key is the JSON text of its parts array.
50
- * @param {any[]} parts
51
- * @returns {string}
52
- */
53
- export declare function keyToken(parts: any[]): string;
54
- export type TableShape = {
55
- kind: 'collection' | 'entity' | 'join';
56
- columns: {
57
- name: string;
58
- role: 'key' | 'doc' | 'scalar' | 'fk' | 'epoch';
59
- storage?: string;
60
- }[];
61
- keyIndexes: number[];
62
- docIndex: number;
63
- };
64
- /**
65
- * Translate parsed row operations into RFC 6902 ops, resolving JSONB
66
- * blobs through the connection (`SELECT json(?)`).
67
- * @param {any} connection
68
- * @param {Map<string, TableShape>} shapes
69
- * @param {any[]} operations
70
- * @returns {any} value-or-promise of RFC 6902 ops
71
- */
72
- export declare function translateOperations(connection: any, shapes: Map<string, TableShape>, operations: any[]): any;
73
- /**
74
- * @param {{ connection: any, shapes: Map<string, TableShape>,
75
- * mode: 'session' | 'journal',
76
- * log: boolean, retention: number }} options
77
- * @returns {any}
78
- */
79
- export declare function createCaptureEngine(options: {
80
- connection: any;
81
- shapes: Map<string, TableShape>;
82
- mode: 'session' | 'journal';
83
- log: boolean;
84
- retention: number;
85
- }): any;
@@ -1,2 +0,0 @@
1
- #!/usr/bin/env node
2
- export {};
@@ -1,40 +0,0 @@
1
- /**
2
- * @file The composition (JOBS-FORMAT §7): a persisted `@jarenjs/flow`
3
- * DAG run wired to a queue job. THE FLOW ENGINE IS INJECTED, NEVER
4
- * IMPORTED — the shared invariant forbids `@jarenjs/db` importing
5
- * `@jarenjs/flow`, so `compileDag` arrives as a capability (the D10
6
- * shape applied to flow) and a test asserts the manifest and import
7
- * graph name flow nowhere.
8
- *
9
- * Each kind's document compiles ONCE against a delegating checkpoint
10
- * store; per claimed job, the delegate binds the engine's guarded
11
- * per-job store (`checkpointsFor`) — `save` refuses once the lease is
12
- * lost and `complete` records the DAG result, marks the job done and
13
- * prunes the checkpoint rows in ONE transaction, so a failure leaves
14
- * neither and a crash resumes instead of restarting.
15
- */
16
- /**
17
- * Build a worker whose handlers run checkpointed DAG documents.
18
- * @param {any} store - an open store with `{ jobs: true }`
19
- * @param {{ compileDag: Function,
20
- * documents: Record<string, any>,
21
- * tasks?: Record<string, Function>,
22
- * concurrency?: number, pollInterval?: number, leaseMs?: number,
23
- * owner?: string, backoffBase?: number, backoffCap?: number }} options
24
- * @returns {{ start: () => any, stop: () => Promise<void>, stats: () => any }}
25
- */
26
- export declare function createDagJobRunner(store: any, options: {
27
- compileDag: Function;
28
- documents: Record<string, any>;
29
- tasks?: Record<string, Function>;
30
- concurrency?: number;
31
- pollInterval?: number;
32
- leaseMs?: number;
33
- owner?: string;
34
- backoffBase?: number;
35
- backoffCap?: number;
36
- }): {
37
- start: () => any;
38
- stop: () => Promise<void>;
39
- stats: () => any;
40
- };
@@ -1,229 +0,0 @@
1
- /**
2
- * @file DDL planning: a normalized collection becomes one physical
3
- * table — a key column, a JSON document column, a virtual generated
4
- * column per indexed path, and the declared indexes — with every byte
5
- * of SQL rendered by the dialect.
6
- *
7
- * Index paths are JSONPath expressions analyzed through the engine's
8
- * PUBLISHED AST (`analyzeQuery`): a path is indexable exactly when the
9
- * analysis says it is singular and every segment is a plain member or
10
- * index selection. That reuses the one grammar authority instead of
11
- * re-parsing, and it fails loudly (`JD0004`) on everything else —
12
- * wildcards, slices, filters, descendants, functions — rather than
13
- * silently indexing the wrong thing.
14
- */
15
- /** The fixed physical column names of the 0.1 mapping. */
16
- export declare const KEY_COLUMN = "key";
17
- export declare const DOC_COLUMN = "doc";
18
- /**
19
- * Analyze one index path expression down to typed segments.
20
- * @param {string} expression - A JSONPath expression (`$.email`)
21
- * @param {string} docPath - Model-document pointer for diagnostics
22
- * @returns {{ segments: import('./dialect.js').JsonPathSegment[],
23
- * canonical: string }}
24
- */
25
- export declare function compileIndexPath(expression: string, docPath: string): {
26
- segments: import('./dialect.js').JsonPathSegment[];
27
- canonical: string;
28
- };
29
- /**
30
- * The schema subschema at a segment path, walked structurally through
31
- * `properties` / `items` / `prefixItems`. The collection's schema is
32
- * the type source — that is why the physical mapping needs no
33
- * engine-side inference. `undefined` where the walk leaves the schema.
34
- * @param {any} schema
35
- * @param {import('./dialect.js').JsonPathSegment[]} segments
36
- * @returns {any}
37
- */
38
- export declare function schemaNodeAt(schema: any, segments: import('./dialect.js').JsonPathSegment[]): any;
39
- /**
40
- * The declared schema type at a segment path: the first non-`null`
41
- * member of a union, which is the type a COLUMN takes its storage
42
- * from. A caller that must know the whole union (a promotion refusing
43
- * a member that may also be `null`) reads {@link schemaNodeAt}.
44
- * @param {any} schema
45
- * @param {import('./dialect.js').JsonPathSegment[]} segments
46
- * @returns {string | undefined}
47
- */
48
- export declare function schemaTypeAt(schema: any, segments: import('./dialect.js').JsonPathSegment[]): string | undefined;
49
- /**
50
- * Plan one collection's physical shape: the DDL statements to create
51
- * it and the structural facts an existing table must match (the
52
- * `JD0002` comparison set).
53
- * A derived index (`derive: 'geohash' | 'bbox'`) maps to the same
54
- * shape through a registered deterministic function, EXCEPT where the
55
- * driver cannot index one (`capabilities.deterministicIndexableFunctions`
56
- * is false): there the columns are ordinary ones the store writes. The
57
- * two mappings produce different declared text on purpose — a database
58
- * built under one and opened under the other really does disagree, and
59
- * `verifyShape` says so rather than papering over it. A
60
- * `derive: 'vector'` column is the stored shape under BOTH mappings
61
- * (`derivedMappingFor`), so for it the two agree.
62
- * @param {string} name - The collection name (also the table name)
63
- * @param {{ schema: any, keySegments: { name: string }[] | null,
64
- * identity: string, indexes: { name: string, paths: string[],
65
- * unique: boolean, derive?: string | null, precision?: number,
66
- * dims?: number, docPath: string }[] }} collection - normalized
67
- * @param {any} dialect
68
- * @param {{ derived?: 'virtual' | 'stored', rtree?: boolean }} [options]
69
- * - `derived` is the physical mapping for derived columns:
70
- * `'virtual'` (a generated column over a registered function) unless
71
- * the driver says it cannot index one. `rtree` is whether the driver
72
- * carries the R\*Tree module; when it does not, a column set that
73
- * declared `physical: 'rtree'` falls back to the B-tree over its
74
- * columns and `explain().prefilters[].via` reports which shape ran
75
- * (MODEL-FORMAT §4) — a report, not a silent degradation
76
- * @returns {{
77
- * table: string, keyColumn: string, docColumn: string,
78
- * keyType: string,
79
- * generated: { name: string, type: string, pathText: string,
80
- * canonical: string }[],
81
- * derived: { name: string, derive: string, precision?: number,
82
- * component?: string, dims?: number, segments: any[] }[],
83
- * columnByCanonical: Map<string, string>,
84
- * createSql: string[],
85
- * virtualTables: { stem: string, name: string, columns: string[],
86
- * edges: string[], createSql: string, fillSql: string,
87
- * triggers: { name: string, sql: string }[] }[],
88
- * expected: { columns: { name: string, type: string,
89
- * generated: boolean }[], indexes: { name: string, unique: boolean,
90
- * columns: string[] }[] },
91
- * }}
92
- */
93
- export declare function planCollection(name: string, collection: {
94
- schema: any;
95
- keySegments: {
96
- name: string;
97
- }[] | null;
98
- identity: string;
99
- indexes: {
100
- name: string;
101
- paths: string[];
102
- unique: boolean;
103
- derive?: string | null;
104
- precision?: number;
105
- dims?: number;
106
- docPath: string;
107
- }[];
108
- }, dialect: any, options?: {
109
- derived?: 'virtual' | 'stored';
110
- rtree?: boolean;
111
- }): {
112
- table: string;
113
- keyColumn: string;
114
- docColumn: string;
115
- keyType: string;
116
- generated: {
117
- name: string;
118
- type: string;
119
- pathText: string;
120
- canonical: string;
121
- }[];
122
- derived: {
123
- name: string;
124
- derive: string;
125
- precision?: number;
126
- component?: string;
127
- dims?: number;
128
- segments: any[];
129
- }[];
130
- columnByCanonical: Map<string, string>;
131
- createSql: string[];
132
- virtualTables: {
133
- stem: string;
134
- name: string;
135
- columns: string[];
136
- edges: string[];
137
- createSql: string;
138
- fillSql: string;
139
- triggers: {
140
- name: string;
141
- sql: string;
142
- }[];
143
- }[];
144
- expected: {
145
- columns: {
146
- name: string;
147
- type: string;
148
- generated: boolean;
149
- }[];
150
- indexes: {
151
- name: string;
152
- unique: boolean;
153
- columns: string[];
154
- }[];
155
- };
156
- };
157
- /**
158
- * Normalize a stored `CREATE` statement for comparison: collapse runs of
159
- * whitespace, drop whitespace around punctuation, and strip the
160
- * `IF NOT EXISTS` SQLite does not keep. What survives is every token that
161
- * carries meaning, so two statements compare equal exactly when they
162
- * declare the same physical object.
163
- * @param {string} sql
164
- * @returns {string}
165
- */
166
- export declare function normalizeDeclaredSql(sql: string): string;
167
- /**
168
- * A comparable form of one `CREATE` statement.
169
- *
170
- * For a TABLE the column definitions compare as a SET, because
171
- * `ALTER TABLE … ADD COLUMN` can only append — so a migrated table and a
172
- * freshly built one legitimately differ in column order, and this store
173
- * never reads a column positionally. Everything else is exact: each
174
- * column's full definition (type, `PRIMARY KEY`, `NOT NULL`, `DEFAULT`,
175
- * `CHECK`, `GENERATED … AS`, `REFERENCES … ON DELETE …`), the table
176
- * constraints, and the trailing table options (`STRICT`,
177
- * `WITHOUT ROWID`).
178
- *
179
- * For an INDEX the text compares whole, because an index IS its order —
180
- * `(a,b)` and `(b,a)` serve different lookups — as are its partial
181
- * predicate and each term's collation and direction.
182
- * @param {string} sql
183
- * @returns {string}
184
- */
185
- export declare function comparableDeclaredSql(sql: string): string;
186
- /**
187
- * Verify an existing table against the planned shape; any difference
188
- * is `JD0002` and nothing is altered. Shared by the store's open path
189
- * and the migration engine's shadow validation.
190
- * @param {any} connection
191
- * @param {any} plan
192
- * @param {string} collection
193
- * @param {string} docPath
194
- * @returns {any} value-or-promise
195
- */
196
- export declare function verifyShape(connection: any, plan: any, collection: string, docPath: string): any;
197
- /**
198
- * Plan one ENTITY's physical shape from the mapping data
199
- * `explainMapping` derived: the relational table (typed columns,
200
- * checks, foreign keys, the JSONB document column), its indexes, and
201
- * the structural facts an existing table must match. One verify path
202
- * serves both document kinds.
203
- * @param {string} name
204
- * @param {any} entityMapping - `explainMapping(model).entities[name]`
205
- * @param {any} entities - the full `explainMapping` result (key types
206
- * come from the referenced entity's columns)
207
- * @param {any} dialect
208
- * @returns {{ table: string, createSql: string[], expected: any,
209
- * columnNames: Set<string> }}
210
- */
211
- export declare function planEntity(name: string, entityMapping: any, entities: any, dialect: any): {
212
- table: string;
213
- createSql: string[];
214
- expected: any;
215
- columnNames: Set<string>;
216
- };
217
- /**
218
- * Plan a many-to-many join table.
219
- * @param {string} tableName
220
- * @param {any} join - `explainMapping(model).joinTables[tableName]`
221
- * @param {any} entities - the full mapping
222
- * @param {any} dialect
223
- * @returns {{ table: string, createSql: string[], expected: any }}
224
- */
225
- export declare function planJoinTable(tableName: string, join: any, entities: any, dialect: any): {
226
- table: string;
227
- createSql: string[];
228
- expected: any;
229
- };