@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,53 +0,0 @@
1
- /**
2
- * @file The store: `openStore(model, options)` normalizes the model
3
- * document, opens a database through the injected driver, applies (or
4
- * verifies) the physical shape, and gives transactional,
5
- * schema-validated reads and writes.
6
- *
7
- * The public surface is ASYNCHRONOUS — every method returns a promise
8
- * — because the browser's OPFS story forces it regardless of any other
9
- * backend. Where the driver is synchronous the same operations exist
10
- * without the promise under `store.sync`, present only there — never a
11
- * throwing stub — so portable code pays one declared microsecond and
12
- * code that wants it back opts in knowingly. Internally everything
13
- * composes through the sync-capable {@link chain}, so the async
14
- * surface allocates exactly one promise per call, not one per step.
15
- *
16
- * Writes validate through an injected `compileSchema` hook with the
17
- * `compileTypeTest` signature; absent, writes are unvalidated and
18
- * `store.capabilities.validated === false` — a declared downgrade,
19
- * never a silent one. `@jarenjs/validate` is never imported here.
20
- */
21
- /** The model format version this store implements. */
22
- export declare const MODEL_VERSION = "0.1";
23
- /**
24
- * Normalize and check a model document. Every failure is `JD0005` with
25
- * a `docPath` into the model.
26
- * @param {any} model
27
- * @returns {Map<string, any>} collection name -> normalized collection
28
- */
29
- export declare function normalizeModel(model: any): Map<string, any>;
30
- /**
31
- * Open (or create) a store described by a model document.
32
- * @param {any} model - A `jaren-model` document (the 0.1 subset)
33
- * @param {{ driver: any, path?: string, compileSchema?: Function,
34
- * busyTimeout?: number, queueTimeout?: number, journalMode?: string,
35
- * statementCacheBound?: number, profile?: any, operators?: any,
36
- * functions?: any, extensions?: any,
37
- * readOnly?: boolean }} options
38
- * @returns {Promise<any>}
39
- */
40
- export declare function openStore(model: any, options: {
41
- driver: any;
42
- path?: string;
43
- compileSchema?: Function;
44
- busyTimeout?: number;
45
- queueTimeout?: number;
46
- journalMode?: string;
47
- statementCacheBound?: number;
48
- profile?: any;
49
- operators?: any;
50
- functions?: any;
51
- extensions?: any;
52
- readOnly?: boolean;
53
- }): Promise<any>;
@@ -1,43 +0,0 @@
1
- /**
2
- * @file The unit of work (§11): copy-on-write change tracking and
3
- * minimal writes. Materialised entities are plain, DEEP-FROZEN JSON —
4
- * no proxies anywhere — and the tracker retains exactly ONE reference
5
- * per tracked entity: the frozen document itself is the snapshot.
6
- * Mutation is replacement (`put(next)`); `saveChanges()` diffs
7
- * snapshot against current with the suite's own diff engine and plans
8
- * the MINIMAL set of parameterised statements: scalar/epoch/foreign-
9
- * key column writes, `jsonb_set`/`jsonb_remove` chains for document
10
- * paths, join-table synchronisation for many-to-many members, and a
11
- * counted whole-row fallback for anything untranslatable.
12
- *
13
- * Ordering never violates a foreign key mid-transaction: inserts run
14
- * parent-first, deletes child-first, updates in between, join rows
15
- * after both endpoints exist. A foreign-key cycle among the entities
16
- * being inserted or deleted is `JD0040`, reported, never a deadlock.
17
- * The whole save is one transaction; the tracker is mutated ONLY
18
- * after commit, so a failed save leaves it exactly as it was and a
19
- * retry is possible.
20
- */
21
- /** Rows per batched INSERT: bounded by the portable parameter budget. */
22
- export declare const BATCH_PARAM_BUDGET = 900;
23
- export declare const BATCH_ROW_BOUND = 100;
24
- /**
25
- * Deep-freeze a JSON value in place and return it. Idempotent; shared
26
- * substructure (a graph load's children) freezes once.
27
- * @template T
28
- * @param {T} value
29
- * @returns {T}
30
- */
31
- export declare function deepFreeze<T>(value: T): T;
32
- /**
33
- * The store-level unit of work.
34
- * @param {{ connection: any, entities: Map<string, any>, mapping: any,
35
- * coreFor: (name: string) => any }} context
36
- * @returns {any}
37
- */
38
- export declare function createTracker(context: {
39
- connection: any;
40
- entities: Map<string, any>;
41
- mapping: any;
42
- coreFor: (name: string) => any;
43
- }): any;
@@ -1,15 +0,0 @@
1
- /**
2
- * @file The typed-store binding: a zero-cost identity whose ONLY job
3
- * is carrying the generated `EntityMetaMap` into the type system —
4
- * `typedStore<EntityMetaMap>(store)` narrows `entity(name)` to the
5
- * generated document/input shapes and widens `load` results by their
6
- * include specification. The runtime is the store it was given; every
7
- * guarantee lives in `types/typed.d.ts` and the generated artifact.
8
- */
9
- /**
10
- * Bind a store to its generated entity metadata. Identity at runtime.
11
- * @template E
12
- * @param {any} store - an opened store whose model generated `E`
13
- * @returns {any}
14
- */
15
- export declare function typedStore<E>(store: any): any;
@@ -1,26 +0,0 @@
1
- /**
2
- * @file Schema-derived path typing: the collection's JSON Schema is the
3
- * planner's type source (there is no engine-side inference in this
4
- * phase — the store's own contract carries the types). Where the
5
- * schema says nothing, the answer is `'unknown'` and the planner emits
6
- * the defensive form; the guards in the truth table make `'unknown'`
7
- * safe, so typing here only ever IMPROVES a plan (column choice), it
8
- * never weakens one.
9
- */
10
- /**
11
- * The planner-facing type of a member path.
12
- * @param {any} schema - The collection's document schema
13
- * @param {({ name: string } | { index: number })[]} segments
14
- * @returns {'string' | 'integer' | 'number' | 'boolean' | 'unknown'}
15
- */
16
- export declare function typeOfPath(schema: any, segments: ({
17
- name: string;
18
- } | {
19
- index: number;
20
- })[]): 'string' | 'integer' | 'number' | 'boolean' | 'unknown';
21
- /**
22
- * Whether a planner type is numeric (SQL comparison family).
23
- * @param {string} type
24
- * @returns {boolean}
25
- */
26
- export declare function isNumericType(type: string): boolean;
@@ -1,75 +0,0 @@
1
- /**
2
- * @file The UDF escape hatch (capability-gated): between native SQL
3
- * and pulling rows sits registering a compiled predicate conjunct as a
4
- * DETERMINISTIC function used in the WHERE clause. Only fragments the
5
- * analysis proves deterministic and side-effect-free qualify — no
6
- * externals (their values change per call, and a deterministic
7
- * function must not close over changing state), no host functions, no
8
- * collations. Registration is keyed by the fragment's COLLISION-FREE
9
- * structural identity, so identical fragments share one registration
10
- * per store and different fragments never do. A fingerprint could not
11
- * decide this: two colliding fragments would claim one SQL function
12
- * name, the second would silently reuse the first's predicate, and the
13
- * WHERE clause would filter on the wrong condition. The SQL identifier
14
- * still derives from a short fingerprint — names must be short — but a
15
- * fingerprint clash between DIFFERENT identities is disambiguated with
16
- * a suffix rather than collapsed.
17
- *
18
- * WHERE-clause use only: an INDEX over a registered function would
19
- * make the database unwritable from any connection that has not
20
- * registered the identical function — that schema-dependency hazard is
21
- * why the model format declares no UDF-expression indexes.
22
- *
23
- * Ring 3 extends the hatch to registry `pushable:'scalar'`
24
- * operators: a predicate fragment that uses a registered scalar operator
25
- * (`$sqrt`, `$pow`, …) compiles WITH the store's `{ functions,
26
- * extensions }` and pushes as the same deterministic UDF — SQLite drives
27
- * the row iteration and the operator runs inside the callback, instead
28
- * of every candidate crossing into the residual. The determinism rule is
29
- * unchanged (no externals, no collations); a registered operator the
30
- * pack did NOT mark `pushable:'scalar'` (a whole-series `$npv`, an
31
- * aggregate) stays the residual — Ring 2 keeps it correct.
32
- */
33
- /**
34
- * Decide whether a raw predicate fragment qualifies for the hatch, and
35
- * build its registration if so.
36
- * @param {any} fragment - The raw conjunct (a JSON query expression
37
- * over `$it`)
38
- * @param {{ functions?: any, extensions?: any, pushableScalar?: Set<string> } | null}
39
- * [operators] - the store's registered operators (Ring 3); only its
40
- * `pushable:'scalar'` subset is admitted. `null`/absent keeps the
41
- * original engine-internal-only rule (no host function pushes).
42
- * @param {string} [binding='it'] - the name the caller's document gave
43
- * the collection binding. The fragment references it, so the wrapper
44
- * below must bind it: under any other name every reference reads as an
45
- * external, the determinism check below rejects the fragment, and the
46
- * hatch silently never engages.
47
- * @returns {{ key: string, name: string,
48
- * compile: () => (docText: string) => number } | null}
49
- */
50
- export declare function deterministicFragment(fragment: any, operators?: {
51
- functions?: any;
52
- extensions?: any;
53
- pushableScalar?: Set<string>;
54
- } | null, binding?: string): {
55
- key: string;
56
- name: string;
57
- compile: () => (docText: string) => number;
58
- } | null;
59
- /**
60
- * Register a qualified fragment once per store, and answer the SQL name
61
- * to call. Identity is the fragment's structural key, so the same
62
- * fragment registers once and two different fragments always get two
63
- * different functions — even when their short names fingerprint alike,
64
- * which the suffix resolves.
65
- * @param {any} connection
66
- * @param {Map<string, string>} registered - The store's registrations,
67
- * fragment identity → the SQL function name it owns
68
- * @param {{ key: string, name: string, compile: () => Function }} fragment
69
- * @returns {string} the function name to call in the WHERE clause
70
- */
71
- export declare function registerFragment(connection: any, registered: Map<string, string>, fragment: {
72
- key: string;
73
- name: string;
74
- compile: () => Function;
75
- }): string;
@@ -1,52 +0,0 @@
1
- /**
2
- * @file The maintained sorted window for `orderBy` (+ optional
3
- * `limit`) live queries — LIVE-FORMAT §7's window row. The structure
4
- * keeps EVERY matching row in sorted order (which is what makes a
5
- * delete inside the visible window answerable without a re-query: the
6
- * successor is already here), and the visible result is the first
7
- * `limit` entries. Ties are broken by the collection key token,
8
- * always ascending — the total order LIVE-FORMAT §9 promises.
9
- *
10
- * String comparison is CODEPOINT order (SQLite BINARY over UTF-8 —
11
- * probed, never assumed), which `<` on JS strings gets wrong for
12
- * astral-vs-BMP pairs; `compareCodepoint` walks code points.
13
- */
14
- /**
15
- * Compare two strings in Unicode code-point order.
16
- * @param {string} a
17
- * @param {string} b
18
- * @returns {number}
19
- */
20
- export declare function compareCodepoint(a: string, b: string): number;
21
- export type WindowEntry = {
22
- token: string;
23
- sortValues: any[];
24
- item: any;
25
- };
26
- /**
27
- * @typedef {{ token: string, sortValues: any[], item: any }} WindowEntry
28
- */
29
- /**
30
- * A maintained sorted set of rows under the declared order terms plus
31
- * the key-token tiebreaker.
32
- * @param {{ desc: boolean, emptyGreatest: boolean }[]} terms
33
- * @param {number | null} limit - visible size; `null` = everything
34
- */
35
- export declare function createSortedWindow(terms: {
36
- desc: boolean;
37
- emptyGreatest: boolean;
38
- }[], limit: number | null): {
39
- compare: (a: WindowEntry, b: WindowEntry) => number;
40
- size: () => number;
41
- /** The visible slice: the first `limit` entries (all, unbounded). */
42
- visible: () => WindowEntry[];
43
- /**
44
- * Insert a row; the token MUST not be present.
45
- * @param {string} token
46
- * @param {any[]} sortValues
47
- * @param {any} item
48
- */
49
- insert(token: string, sortValues: any[], item: any): void;
50
- /** Remove a row by token; absent tokens are a no-op. */
51
- remove(token: any): boolean;
52
- };