@jarenjs/db 0.49.2 → 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 (70) hide show
  1. package/ARCHITECTURE.md +27 -15
  2. package/README.md +141 -41
  3. package/docs/JOBS-FORMAT.md +24 -8
  4. package/docs/LIVE-FORMAT.md +38 -9
  5. package/docs/MIGRATION-FORMAT.md +118 -36
  6. package/docs/MODEL-FORMAT.md +232 -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/capture.js +66 -28
  11. package/src/cli.js +225 -44
  12. package/src/ddl.js +23 -3
  13. package/src/dialects/sqlite.js +2 -1
  14. package/src/driver.js +63 -16
  15. package/src/drivers/wasm.js +1 -0
  16. package/src/emit-model.js +14 -0
  17. package/src/emit.js +10 -3
  18. package/src/entity.js +92 -47
  19. package/src/errors.js +25 -0
  20. package/src/index.js +2 -2
  21. package/src/jobs.js +40 -5
  22. package/src/live-time.js +12 -3
  23. package/src/live.js +11 -1
  24. package/src/migrate.js +397 -191
  25. package/src/model.js +173 -8
  26. package/src/plan.js +135 -38
  27. package/src/query.js +138 -13
  28. package/src/store.js +221 -66
  29. package/src/tracker.js +173 -48
  30. package/types/index.d.ts +152 -10
  31. package/types/node.d.ts +3 -1
  32. package/types/typed.d.ts +58 -2
  33. package/types/wasm.d.ts +7 -0
  34. package/dist/types/algebra.d.ts +0 -230
  35. package/dist/types/app.d.ts +0 -49
  36. package/dist/types/capture.d.ts +0 -85
  37. package/dist/types/cli.d.ts +0 -2
  38. package/dist/types/dag-job.d.ts +0 -40
  39. package/dist/types/ddl.d.ts +0 -229
  40. package/dist/types/derive.d.ts +0 -250
  41. package/dist/types/dialect.d.ts +0 -154
  42. package/dist/types/dialects/sqlite.d.ts +0 -9
  43. package/dist/types/driver.d.ts +0 -110
  44. package/dist/types/drivers/bun.d.ts +0 -47
  45. package/dist/types/drivers/node.d.ts +0 -37
  46. package/dist/types/drivers/wasm.d.ts +0 -65
  47. package/dist/types/emit-model.d.ts +0 -44
  48. package/dist/types/emit.d.ts +0 -75
  49. package/dist/types/entity.d.ts +0 -23
  50. package/dist/types/errors.d.ts +0 -170
  51. package/dist/types/graph.d.ts +0 -28
  52. package/dist/types/index.d.ts +0 -37
  53. package/dist/types/jobs.d.ts +0 -140
  54. package/dist/types/knn.d.ts +0 -69
  55. package/dist/types/live-time.d.ts +0 -141
  56. package/dist/types/live.d.ts +0 -64
  57. package/dist/types/migrate.d.ts +0 -170
  58. package/dist/types/model.d.ts +0 -36
  59. package/dist/types/patch-sql.d.ts +0 -37
  60. package/dist/types/plan.d.ts +0 -142
  61. package/dist/types/profile.d.ts +0 -80
  62. package/dist/types/query.d.ts +0 -112
  63. package/dist/types/residual.d.ts +0 -64
  64. package/dist/types/series.d.ts +0 -227
  65. package/dist/types/store.d.ts +0 -60
  66. package/dist/types/tracker.d.ts +0 -43
  67. package/dist/types/typed.d.ts +0 -15
  68. package/dist/types/types.d.ts +0 -26
  69. package/dist/types/udf.d.ts +0 -75
  70. package/dist/types/window.d.ts +0 -52
@@ -1,140 +0,0 @@
1
- /**
2
- * @file The durable job queue (JOBS-FORMAT): enqueue, the
3
- * single-statement guarded claim (§3 — one statement is one
4
- * transaction, so no double-claim without any distributed lock),
5
- * retry with exponential backoff and jitter (§4), recovery as
6
- * re-claim of expired leases (§5), polling workers with same-process
7
- * wake-on-enqueue (§6), and the per-job flow checkpoint store the DAG
8
- * composition binds (§7) — completion marks the job done and records
9
- * the result in ONE guarded transaction.
10
- *
11
- * Every worker transition is guarded by `state='leased' AND
12
- * lease_owner=?`: execution is at-least-once, completion is
13
- * exactly-once. `now` and `random` are injectable — the runtime
14
- * defaults are the clock and `Math.random`; every test injects.
15
- *
16
- * The worker LIFECYCLE holds two invariants that a long-running process
17
- * depends on, and neither is a detail:
18
- *
19
- * - **No handler value can break the loop.** A handler is host code and
20
- * may resolve with something JSON cannot express, or reject with a
21
- * value whose own `message` throws when read. Both are normalized
22
- * totally, and `runOne` is isolated inside the loop, so the worst a
23
- * single job can do is fail its own attempt. A rejected claim-execute
24
- * loop would stop draining the queue silently.
25
- * - **Shutdown is bounded.** Handlers receive an `AbortSignal` and
26
- * `stop()` takes a deadline, so a handler that never settles cannot
27
- * hold `stop()` — and therefore `store.close()`, and therefore the
28
- * database file — open forever. A loop the deadline could not drain
29
- * is CANCELLED, not merely left behind: when its handler finally
30
- * settles it exits without another claim, store write or poll
31
- * timer, and its abandoned job recovers by lease expiry (§5).
32
- */
33
- export declare const JOBS_TABLE = "_jaren_jobs";
34
- export declare const JOB_CHECKPOINTS_TABLE = "_jaren_job_checkpoints";
35
- /** §4 defaults, all overridable per worker. */
36
- export declare const JOB_DEFAULTS: Readonly<{
37
- maxAttempts: 5;
38
- leaseMs: 30000;
39
- pollInterval: 500;
40
- backoffBase: 1000;
41
- backoffCap: 60000;
42
- /** How long `stop()` waits for in-flight handlers after signalling
43
- * abort, before it stops waiting and reports what is still running.
44
- * Bounded on purpose: an unbounded wait makes one stuck handler
45
- * indistinguishable from a hung process. */
46
- stopGraceMs: 5000;
47
- }>;
48
- /**
49
- * A diagnostic string for ANY value, including ones that fight back — a
50
- * getter that throws, a null-prototype object, a revoked proxy, a
51
- * symbol. Total by construction: an error report is never the thing that
52
- * fails.
53
- * @param {any} value
54
- * @returns {string}
55
- */
56
- export declare function describeValue(value: any): string;
57
- /**
58
- * JSON text for a job result, or `null` when the value cannot be
59
- * expressed — a BigInt, a cycle, a `toJSON` that throws. The caller
60
- * treats that as a failed attempt, never as a broken worker.
61
- * @param {any} value
62
- * @returns {{ text: string | null } | { reason: string }}
63
- */
64
- export declare function serializeResult(value: any): {
65
- text: string | null;
66
- } | {
67
- reason: string;
68
- };
69
- /**
70
- * The queue engine over one open connection.
71
- * @param {{ connection: any, now?: () => number,
72
- * random?: () => number,
73
- * defaults?: Partial<typeof JOB_DEFAULTS> }} options
74
- */
75
- export declare function createJobEngine(options: {
76
- connection: any;
77
- now?: () => number;
78
- random?: () => number;
79
- defaults?: Partial<typeof JOB_DEFAULTS>;
80
- }): {
81
- ready: any;
82
- enqueue: (kind: any, payload: any, enqueueOptions: any) => any;
83
- get: (id: any) => any;
84
- counts: () => any;
85
- claim: (claimOptions: {
86
- kinds: string[];
87
- owner: string;
88
- leaseMs?: number;
89
- }) => any;
90
- complete: (id: any, owner: any, result: any) => any;
91
- fail: (id: any, owner: any, error: any, workerDefaults: any) => any;
92
- checkpointsFor: (job: {
93
- id: string;
94
- leaseOwner: string | null;
95
- }) => {
96
- load: (runId: any) => any;
97
- save: (runId: any, nodeId: any, value: any) => any;
98
- complete: (runId: any, result: any) => any;
99
- };
100
- createWorker: (workerOptions: {
101
- handlers: Record<string, Function>;
102
- concurrency?: number;
103
- pollInterval?: number;
104
- leaseMs?: number;
105
- owner?: string;
106
- backoffBase?: number;
107
- backoffCap?: number;
108
- }) => {
109
- stats: () => {
110
- claims: number;
111
- completions: number;
112
- failures: number;
113
- polls: number;
114
- wakes: number;
115
- inFlight: number;
116
- };
117
- start(): /*elided*/ any;
118
- /**
119
- * Stop claiming, signal in-flight handlers to abort, and wait for
120
- * the loops — but only up to `graceMs`. A handler that ignores its
121
- * signal cannot hold the process open; the resolved record says so
122
- * instead, and the lease expiry (§5) lets another worker re-claim.
123
- * A loop the grace period could not drain is cancelled outright:
124
- * when its handler finally settles it exits without another
125
- * claim, store write or poll timer.
126
- * @param {{ graceMs?: number }} [stopOptions]
127
- * @returns {Promise<{ drained: boolean, inFlight: number }>}
128
- */
129
- stop(stopOptions?: {
130
- graceMs?: number;
131
- }): Promise<{
132
- drained: boolean;
133
- inFlight: number;
134
- }>;
135
- };
136
- /** Stop every worker, bounded. Resolves to the per-worker outcome so
137
- * `close()` can report a handler it could not wait out rather than
138
- * hanging on it. */
139
- stopAll: (stopOptions: any) => Promise<any[]>;
140
- };
@@ -1,69 +0,0 @@
1
- /**
2
- * @file The candidate cut of a k-nearest plan: the arithmetic between
3
- * the scores a statement fetched and the row identities the engine
4
- * will decide over. No vector arithmetic lives here — a score is
5
- * `derive.js`'s, through `@jarenjs/core/vector` — and no SQL: the
6
- * fetch of the winners is the dialect's. This is the one place the
7
- * margin is applied and the one place candidate identities are
8
- * batched for it.
9
- */
10
- /**
11
- * The inclusive score margin of the cut. The column's score is a dot
12
- * product over binary32-normalized forms; the engine's key is the
13
- * cosine of the raw doubles; measured, the two differ by at most
14
- * ~1e-8. Any margin of at least twice that makes the engine's top
15
- * `offset + limit` a SUBSET of the candidates: were a row the engine
16
- * ranks inside the window cut, some candidate the engine ranks outside
17
- * it would have to score higher by the column and lower by the engine,
18
- * which two scores within half the margin of each other cannot do.
19
- * This is a hundred times that bound — it admits, in practice, only
20
- * true ties, and those the engine breaks by the document's own keys.
21
- */
22
- export declare const KNN_MARGIN = 0.000001;
23
- /**
24
- * The most identities one fetch statement binds: under the parameter
25
- * cap of every SQLite build the store runs on. A guard, not a design —
26
- * a k-nearest window is a handful of rows, and this only matters for a
27
- * collection of many exact duplicates.
28
- */
29
- export declare const IDENTITY_CHUNK = 512;
30
- /**
31
- * The rows a k-nearest window can contain, from the scored fetch.
32
- *
33
- * `m = offset + limit` rows are needed. When at least `m` rows scored,
34
- * the candidates are every scored row within `margin` of the m-th best
35
- * score — ties at the boundary included by construction. When fewer
36
- * did, the window reaches the unrankable tail (NULL columns, or a
37
- * collection smaller than the window), which only the documents can
38
- * order: every row is then a candidate, and the collection is no
39
- * larger than the window.
40
- * @param {{ identity: any, score: number | null }[]} rows - one per
41
- * fetched row; `score` is `null` where the column held no vector
42
- * @param {number} m - `offset + limit`
43
- * @param {number} margin
44
- * @returns {{ identities: any[], scored: number, full: boolean }} the
45
- * candidate identities in ascending identity order — the
46
- * collection's own order, which a stable sort over the candidates
47
- * must see — with how many rows scored and whether every row was
48
- * taken
49
- */
50
- export declare function cutCandidates(rows: {
51
- identity: any;
52
- score: number | null;
53
- }[], m: number, margin: number): {
54
- identities: any[];
55
- scored: number;
56
- full: boolean;
57
- };
58
- /**
59
- * The identities sliced into fetch batches: at most `IDENTITY_CHUNK`
60
- * each, and each padded with `null` to the next power of two — a NULL
61
- * in an IN list matches no row — so a handful of prepared statements
62
- * serve every candidate count instead of one per count seen.
63
- * @param {any[]} identities - in the order they should be fetched
64
- * @returns {{ size: number, params: any[] }[]}
65
- */
66
- export declare function identityBatches(identities: any[]): {
67
- size: number;
68
- params: any[];
69
- }[];
@@ -1,141 +0,0 @@
1
- /**
2
- * @file Event-time live views (LIVE-FORMAT §13): a `$resample` or
3
- * `$rolling` document over a collection, maintained against an
4
- * explicit watermark.
5
- *
6
- * There is no clock in this file, and there is none anywhere under it.
7
- * A live view over time needs to know what "now" is — which bucket is
8
- * still open, which reading counts as late — and the only honest
9
- * source of that is the host, because the machine's clock is a
10
- * different quantity from the instant a reading carries. So the
11
- * watermark ARRIVES: it is a finite epoch supplied at registration and
12
- * moved forward by `advance()`, it never goes backwards, and a test can
13
- * put it wherever the story needs it without waiting for a timer.
14
- *
15
- * What the maintenance actually does:
16
- *
17
- * - **A bucket view keeps its rows by bucket.** A write touches one
18
- * bucket (two, when it moves a reading across a boundary), and only
19
- * those are folded again — through `resampleSeries` itself, over that
20
- * bucket's own rows, so the aggregate is the kernel's and cannot
21
- * drift from what a fresh query would answer.
22
- * - **A rolling view keeps its rows in instant order.** A write at `t`
23
- * can only change the windows ending in `[t, t + width)`, so exactly
24
- * that stretch is recomputed — again by the kernel, over the slice
25
- * that stretch can see.
26
- *
27
- * And what it refuses. A calendar ladder walks a wall clock, a named
28
- * zone needs host code, `locf`/`linear` couple every bucket to its
29
- * neighbours, and `first`/`last` name a row by a position a maintained
30
- * map does not preserve. Each of those re-runs with its own reason
31
- * rather than being approximated. So does a reading older than the
32
- * declared lateness: the view re-runs, the emission carries a
33
- * `lateData` record naming the instant and the boundary, and the row is
34
- * never quietly folded into a bucket its reader already believed
35
- * closed.
36
- *
37
- * `retention` is the horizon this view claims to work over. It is
38
- * checked, not assumed: it must cover a whole window plus the lateness
39
- * the caller allows, which is the span a single repair can read. It is
40
- * NOT a compaction policy — the maintained state is bounded by
41
- * `live.maxMaintained` exactly as every other strategy's is, and this
42
- * file drops nothing that an answer still depends on.
43
- */
44
- /**
45
- * Validate the `eventTime` option into the record the classifier and
46
- * the strategies read, or `null` when the caller declared none.
47
- * @param {any} options - the live options
48
- * @param {string} collection - for the error's `collection` property
49
- * @returns {null | { member: string, watermark: number,
50
- * allowedLateness: number, retention: number }}
51
- * @throws {DbCompileError} `JD0053` for any member this does not admit
52
- */
53
- export declare function normalizeEventTime(options: any, collection: string): null | {
54
- member: string;
55
- watermark: number;
56
- allowedLateness: number;
57
- retention: number;
58
- };
59
- /**
60
- * Classify a document as an event-time view, or say why it is not one.
61
- *
62
- * Returns `null` when the document does not name `$resample` or
63
- * `$rolling` over this collection at all — the caller then goes on to
64
- * §7's ordinary table. Every other outcome is a decision: a maintained
65
- * description, or `{ strategy: 'rerun', reason }`.
66
- * @param {any} inner - the unwrapped document
67
- * @param {boolean} windowed - whether a `$subsequence` wrapped it
68
- * @param {boolean} keyed
69
- * @param {null | { member: string, watermark: number,
70
- * allowedLateness: number, retention: number }} eventTime
71
- * @returns {any}
72
- */
73
- export declare function classifyEventTime(inner: any, windowed: boolean, keyed: boolean, eventTime: null | {
74
- member: string;
75
- watermark: number;
76
- allowedLateness: number;
77
- retention: number;
78
- }): any;
79
- /**
80
- * `$resample` over a fixed ladder: one maintained fold per bucket.
81
- * @param {any} description
82
- * @param {any} context
83
- */
84
- export declare function bucketStrategy(description: any, context: any): {
85
- advance: (next: any) => void;
86
- stats: () => {
87
- lateData: number;
88
- reruns: number;
89
- recomputes: number;
90
- watermark: any;
91
- };
92
- entries: () => number;
93
- init: () => any;
94
- apply(record: any): {
95
- rebuild: boolean;
96
- late: any;
97
- rows?: undefined;
98
- } | {
99
- rebuild?: undefined;
100
- late?: undefined;
101
- rows: {
102
- at: any;
103
- value: number | null;
104
- count: number;
105
- }[] | ({
106
- at: number;
107
- value: number | null;
108
- count: number;
109
- } | undefined)[];
110
- } | null;
111
- /** A re-run rebuilds the whole state from the store — the only
112
- * answer to a reading the maintained state cannot place. */
113
- rebuild(): any;
114
- };
115
- /**
116
- * `$rolling` over a fixed width: one output per input instant, with
117
- * only the stretch a write can reach recomputed.
118
- * @param {any} description
119
- * @param {any} context
120
- */
121
- export declare function rollingStrategy(description: any, context: any): {
122
- advance: (next: any) => void;
123
- stats: () => {
124
- lateData: number;
125
- reruns: number;
126
- recomputes: number;
127
- watermark: any;
128
- };
129
- entries: () => number;
130
- init: () => any;
131
- apply(record: any): {
132
- rows?: undefined;
133
- rebuild: boolean;
134
- late: any;
135
- } | {
136
- rebuild?: undefined;
137
- late?: undefined;
138
- rows: any[];
139
- } | null;
140
- rebuild(): any;
141
- };
@@ -1,64 +0,0 @@
1
- /**
2
- * @file Live queries (LIVE-FORMAT §§7–12): a registered query document
3
- * whose result is maintained as capture records arrive, emitting
4
- * RFC 6902 patches against its own `{ rows }` result document.
5
- *
6
- * The CLASSIFIER implements §7's normative table and nothing more —
7
- * it unwraps the one-element array pack and literal `$subsequence`
8
- * windows the same way the planner does, then reads the compiled
9
- * plan: translated filters, order terms and aggregates are exactly
10
- * the planner's, never a re-implementation. Everything outside the
11
- * table re-runs on invalidation with the reason named (`live.mode`).
12
- *
13
- * Maintenance is synchronous inside capture delivery (§8): inserts
14
- * carry their document in the patch, updates point-read the touched
15
- * row, deletes are answered from maintained state. Per-row semantics
16
- * reuse the ENGINE via packed one-row compilation (the residual
17
- * discipline) — a live row evaluates exactly as the query would.
18
- */
19
- /** The store-level live bounds and their defaults (§12: printed,
20
- * never silent). */
21
- export declare const LIVE_DEFAULTS: Readonly<{
22
- maxQueries: 64;
23
- maxMaintained: 10000;
24
- }>;
25
- /**
26
- * Classify a collection query document against §7's table. Pure —
27
- * given the document and the collection's planner shape, returns the
28
- * strategy description, or a re-run description with the reason.
29
- * @param {any} document
30
- * @param {any} queryShape - the planner shape (collection, schema,
31
- * columnByCanonical)
32
- * @param {boolean} keyed - whether documents carry their key (a
33
- * declared key pointer); unkeyed rows cannot be tracked by key
34
- * @param {any} [eventTime] - the normalized `eventTime` option
35
- * (`live-time.js`), or null when the caller declared none
36
- * @returns {any}
37
- */
38
- export declare function classifyLiveQuery(document: any, queryShape: any, keyed: boolean, eventTime?: any): any;
39
- /**
40
- * Diff two row arrays into sequential add/remove/replace ops under
41
- * `/rows`, relying on REFERENCE identity for unchanged rows (the §9
42
- * sharing contract makes identity the equality that matters). A
43
- * working copy is replayed op by op, so the emitted patch transforms
44
- * the old array into the new one BY CONSTRUCTION; a remove re-filled
45
- * at the same index merges into a replace.
46
- * @param {any[]} oldRows
47
- * @param {any[]} newRows
48
- * @returns {any[]} ops
49
- */
50
- export declare function diffRows(oldRows: any[], newRows: any[]): any[];
51
- /**
52
- * The store-level live-query registry: registration against the §12
53
- * bounds, capture-record delivery in commit order, lifecycle.
54
- * @param {{ maxQueries: number, maxMaintained: number }} bounds
55
- */
56
- export declare function createLiveRegistry(bounds: {
57
- maxQueries: number;
58
- maxMaintained: number;
59
- }): {
60
- register: (definition: any) => any;
61
- count: () => number;
62
- deliver(record: any): void;
63
- closeAll(): void;
64
- };
@@ -1,170 +0,0 @@
1
- /**
2
- * @file Document migrations (D12): two model documents diff into a
3
- * migration document whose steps are rendered DDL, JSLT data
4
- * transforms and query assertions; the migration replays on a shadow
5
- * database first; a history table records what ran with a
6
- * signature-grade checksum. This is the phase-A payoff for storing
7
- * documents rather than rows: a shape change is a transformation of
8
- * VALUES, not a table rebuild.
9
- *
10
- * Identity is a hash, not a version number: `from`/`to` are
11
- * `hashContent(canonicalizeJson(model))` — the identity of a SHAPE,
12
- * which nobody has to remember to bump. The checksum discipline is
13
- * D12's: `canonicalizeJson` + `hashContent` (signature-grade — throws
14
- * on the unserializable), never the memo-grade `contentKey`.
15
- *
16
- * Like the query emitter, this module is part of the emitter layer:
17
- * the structural SQL it composes (the history table's statements, the
18
- * batched row walk) is built from dialect primitives, and every
19
- * planner-produced statement is rendered by the dialect into the
20
- * migration DOCUMENT — shown before it is ever executed.
21
- */
22
- /** The migration format version. */
23
- export declare const MIGRATION_VERSION = "0.1";
24
- /** The history table name (outside the model's identifier namespace
25
- * conventions on purpose — a collection cannot collide with it). */
26
- export declare const HISTORY_TABLE = "_jaren_migrations";
27
- /**
28
- * The signature-grade identity of a model SHAPE.
29
- * @param {any} model - A jaren-model document
30
- * @returns {string}
31
- */
32
- export declare function shapeHash(model: any): string;
33
- /**
34
- * The signature-grade checksum of a migration document.
35
- * @param {any} migration
36
- * @returns {string}
37
- */
38
- export declare function migrationChecksum(migration: any): string;
39
- /**
40
- * Plan a migration between two model documents. The planner diffs the
41
- * PHYSICAL plans (columns, indexes) and renders DDL through the
42
- * dialect; a changed schema gets a DRAFT identity transform that
43
- * refuses to run until the author fills it in — the planner cannot
44
- * infer a data transform and does not pretend to. Renames are declared
45
- * (`x-rename` on the target collection), never guessed.
46
- * The physical mapping of a DERIVED index column depends on the driver
47
- * that will run the migration (`derived`), because the two mappings
48
- * really are different columns; a migration document planned for one is
49
- * not the document the other needs.
50
- * @param {any} fromModel
51
- * @param {any} toModel
52
- * @param {{ id?: string, dialect?: any,
53
- * derived?: 'virtual' | 'stored', rtree?: boolean }} [options]
54
- * @returns {{ migration: any, report: {
55
- * renamed: { from: string, to: string }[],
56
- * added: string[], removed: string[],
57
- * schemaChanged: string[], drafts: string[],
58
- * destructive: boolean } }}
59
- */
60
- export declare function planMigration(fromModel: any, toModel: any, options?: {
61
- id?: string;
62
- dialect?: any;
63
- derived?: 'virtual' | 'stored';
64
- rtree?: boolean;
65
- }): {
66
- migration: any;
67
- report: {
68
- renamed: {
69
- from: string;
70
- to: string;
71
- }[];
72
- added: string[];
73
- removed: string[];
74
- schemaChanged: string[];
75
- drafts: string[];
76
- destructive: boolean;
77
- };
78
- };
79
- /** `planMigration` handles the whole model — collections AND entities
80
- * — since the relational order; this name says so. */
81
- export declare const planModelMigration: typeof planMigration;
82
- /**
83
- * Create a model's WHOLE physical shape on a connection: collections,
84
- * entity tables and join tables, exactly as `openStore` would. Used
85
- * by the shadow baseline, the fresh reference database that shape
86
- * equality compares against, and the tests.
87
- * @param {any} connection
88
- * @param {any} model
89
- * @returns {any} value-or-promise
90
- */
91
- export declare function createModelShape(connection: any, model: any): any;
92
- /**
93
- * The declared schema of a database, normalized for comparison: every
94
- * object carrying SQL text (tables, indexes), whitespace-collapsed,
95
- * history table excluded, sorted. Shape equality after a migration —
96
- * this dump versus a fresh {@link createModelShape} — is the
97
- * acceptance criterion for every rebuild.
98
- * @param {any} connection
99
- * @returns {any} value-or-promise of `{ type, name, owner, sql }[]`
100
- */
101
- export declare function schemaShapeOf(connection: any): any;
102
- /**
103
- * Compare a migrated database's schema against the shape a fresh
104
- * `createModelShape(model)` produces, via a throwaway reference
105
- * database. Returns `null` when equal, or a one-line difference.
106
- * @param {any} driver
107
- * @param {any} connection - the migrated database
108
- * @param {any} model - the target model
109
- * @param {((connection: any) => any) | undefined} registerFunctions
110
- * @returns {any} value-or-promise of `string | null`
111
- */
112
- export declare function compareShapeToModel(driver: any, connection: any, model: any, registerFunctions: ((connection: any) => any) | undefined): any;
113
- /**
114
- * Report a database's migration state without touching it: what is
115
- * applied, what is pending, whether an applied migration was edited,
116
- * and — once the chain is fully applied — whether the physical shape
117
- * DRIFTED from the model (someone changed the database by hand, §12).
118
- * @param {{ driver: any, path?: string }} target
119
- * @param {any[]} migrations - the full ordered list
120
- * @param {{ baseline: any, model?: any,
121
- * registerFunctions?: (connection: any) => any }} options
122
- * @returns {Promise<{ applied: string[], pending: string[],
123
- * drift: string | null, upToDate: boolean }>}
124
- */
125
- export declare function migrationStatus(target: {
126
- driver: any;
127
- path?: string;
128
- }, migrations: any[], options: {
129
- baseline: any;
130
- model?: any;
131
- registerFunctions?: (connection: any) => any;
132
- }): Promise<{
133
- applied: string[];
134
- pending: string[];
135
- drift: string | null;
136
- upToDate: boolean;
137
- }>;
138
- /**
139
- * Apply pending migrations to a database.
140
- *
141
- * The contract: `migrations` is the FULL ordered list (applied and
142
- * pending — the migrations directory); `baseline` is the model the
143
- * store was first created with (the chain's anchor and the shadow's
144
- * starting shape); `model` is the target model the code now carries.
145
- * Each pending migration runs in ONE exclusive transaction with a
146
- * savepoint per step; a failing step rolls the whole migration back.
147
- * The whole chain replays on a `:memory:` shadow before the real
148
- * store is touched.
149
- *
150
- * @param {{ driver: any, path?: string, busyTimeout?: number }} target
151
- * @param {any[]} migrations
152
- * @param {{ baseline: any, model?: any, compileSchema?: Function,
153
- * dryRun?: boolean, batchSize?: number, onProgress?: Function,
154
- * shadow?: boolean, shadowPath?: string }} options
155
- * @returns {Promise<any>}
156
- */
157
- export declare function migrate(target: {
158
- driver: any;
159
- path?: string;
160
- busyTimeout?: number;
161
- }, migrations: any[], options: {
162
- baseline: any;
163
- model?: any;
164
- compileSchema?: Function;
165
- dryRun?: boolean;
166
- batchSize?: number;
167
- onProgress?: Function;
168
- shadow?: boolean;
169
- shadowPath?: string;
170
- }): Promise<any>;
@@ -1,36 +0,0 @@
1
- /**
2
- * @file The entity model walk: `x-entity` normalization with a CLOSED
3
- * vocabulary, relation resolution with inverse agreement, and
4
- * `explainMapping` — the derived physical shape as plain data, so the
5
- * hybrid mapping rule is golden-testable rather than folklore.
6
- *
7
- * THE DESCENT DECISION (recorded here because TODO's D22 demands it
8
- * be explicit): six copies of the `properties`/`prefixItems`/`items`/
9
- * `allOf` descent spine exist in this repository, and this walk was
10
- * the candidate seventh. It is NOT one. The entity walk is
11
- * deliberately ONE level deep — it enumerates the TOP-LEVEL
12
- * properties of an entity schema, resolves `$ref` and shallow-merges
13
- * `allOf` at each property through the resolvers
14
- * `@jarenjs/validate/normalize` exports for exactly this purpose, and
15
- * never recurses further, because the mapping rule sends every nested
16
- * shape to the JSONB document wholesale. A consumer with no recursion
17
- * has no descent spine to share, so the shared-enumerator question
18
- * (three different termination strategies across the six copies)
19
- * stays open for the first consumer that actually recurses. No
20
- * seventh copy was added.
21
- */
22
- /**
23
- * Normalize the `entities` member of a model document.
24
- * @param {any} model
25
- * @returns {Map<string, any>} entity name -> normalized entity
26
- */
27
- export declare function normalizeEntities(model: any): Map<string, any>;
28
- /**
29
- * The hybrid mapping, derived mechanically from §9.3's table and
30
- * returned as DATA: per entity, the columns (name, type, source),
31
- * the checks, the foreign keys, the indexes, and which properties
32
- * live in the JSONB document.
33
- * @param {any} model - a model document with `entities`
34
- * @returns {any}
35
- */
36
- export declare function explainMapping(model: any): any;
@@ -1,37 +0,0 @@
1
- /**
2
- * @file RFC 6902 → dialect JSON-set primitives, so a one-field update
3
- * does not rewrite a large document. The translation is decided
4
- * AGAINST THE LIVE DOCUMENT: an RFC 6901 pointer cannot say whether
5
- * `/a/0` names an array position or an object member called `"0"`, so
6
- * each segment is discriminated by walking the document the patch was
7
- * validated against, and the walked state is advanced op by op so a
8
- * later operation sees what the earlier ones produced.
9
- *
10
- * Translatable in 0.1: `replace` anywhere, `add` of an object member,
11
- * `add` at an array's end (`/-` or the index equal to its length), and
12
- * `remove`. Everything else — `test`, `move`, `copy`, a mid-array
13
- * insert (the shift has no single JSON-function spelling) — returns
14
- * `null` and the store falls back to a whole-document write. The
15
- * fallback is counted and exposed by the store, measured rather than
16
- * assumed.
17
- */
18
- export type JsonPathSegment = import('./dialect.js').JsonPathSegment;
19
- /**
20
- * Translate a whole patch into a dialect expression builder, or `null`
21
- * when any operation needs the whole-document fallback. The caller has
22
- * already applied the patch in memory (the copy-on-write engine
23
- * validates the RESULT); this translation only decides how the same
24
- * outcome reaches the database.
25
- * @param {any[]} ops - RFC 6902 operations, already known applicable
26
- * @param {any} doc - The stored document the patch applies to
27
- * @param {any} dialect
28
- * @returns {{ build: (docColumnSql: string,
29
- * parameterIndexBase: number) => { expression: string,
30
- * params: string[] } } | null}
31
- */
32
- export declare function translatePatch(ops: any[], doc: any, dialect: any): {
33
- build: (docColumnSql: string, parameterIndexBase: number) => {
34
- expression: string;
35
- params: string[];
36
- };
37
- } | null;