@orkestrel/database 0.0.13 → 0.0.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +10 -6
- package/dist/src/browser/index.d.ts +54 -51
- package/dist/src/browser/index.js +35 -30
- package/dist/src/browser/index.js.map +1 -1
- package/dist/src/core/index.cjs +109 -42
- package/dist/src/core/index.cjs.map +1 -1
- package/dist/src/core/index.d.cts +274 -61
- package/dist/src/core/index.d.ts +274 -61
- package/dist/src/core/index.js +109 -42
- package/dist/src/core/index.js.map +1 -1
- package/dist/src/server/index.cjs +54 -34
- package/dist/src/server/index.cjs.map +1 -1
- package/dist/src/server/index.d.cts +93 -76
- package/dist/src/server/index.d.ts +93 -76
- package/dist/src/server/index.js +54 -34
- package/dist/src/server/index.js.map +1 -1
- package/package.json +15 -16
|
@@ -6,22 +6,22 @@ let node_path = require("node:path");
|
|
|
6
6
|
let _orkestrel_sqlite = require("@orkestrel/sqlite");
|
|
7
7
|
//#region src/server/constants.ts
|
|
8
8
|
/**
|
|
9
|
-
* Lists the declared {@link ColumnStorage}s whose SQL
|
|
9
|
+
* Lists the declared {@link ColumnStorage}s whose SQL equality comparisons (`equals` /
|
|
10
10
|
* `not` / `any` / `none`) and `starts` / `ends` compiles are provably
|
|
11
11
|
* engine-exact under declared-type trust — `text` / `integer` / `real` /
|
|
12
12
|
* `boolean`; a `json` or `blob` column always refines instead.
|
|
13
13
|
*
|
|
14
14
|
* @remarks
|
|
15
|
-
* This set governs equality and prefix/suffix matching only.
|
|
15
|
+
* This set governs equality and prefix/suffix matching only. Range
|
|
16
16
|
* comparisons (`above` / `below` / `from` / `to` / `between`) and `ORDER BY`
|
|
17
|
-
* are exact for `integer` / `real` / `boolean` but
|
|
17
|
+
* are exact for `integer` / `real` / `boolean` but not for `text`: compiled
|
|
18
18
|
* SQL orders/ranges under SQLite's default BINARY collation, which compares
|
|
19
|
-
* TEXT byte-for-byte as UTF-8 — equivalent to Unicode
|
|
19
|
+
* TEXT byte-for-byte as UTF-8 — equivalent to Unicode code-point order —
|
|
20
20
|
* while the core engine's `compareValues` orders JS strings with `<`, which
|
|
21
|
-
* compares UTF-16
|
|
21
|
+
* compares UTF-16 code-unit order. The two orders diverge for supplementary-
|
|
22
22
|
* plane characters (code points ≥ U+10000, for example many emoji): a lead surrogate
|
|
23
|
-
* (`\uD800`–`\uDBFF`) sorts
|
|
24
|
-
* its code point sorts
|
|
23
|
+
* (`\uD800`–`\uDBFF`) sorts below ``–`` in code-unit order, while
|
|
24
|
+
* its code point sorts above them. So `matchesConditionExactly`'s range family and
|
|
25
25
|
* `matchesOrderExactly` exclude `text`, refining through the core engine instead.
|
|
26
26
|
*/
|
|
27
27
|
var EXACT_COLUMN_STORAGE = Object.freeze([
|
|
@@ -31,7 +31,7 @@ var EXACT_COLUMN_STORAGE = Object.freeze([
|
|
|
31
31
|
"boolean"
|
|
32
32
|
]);
|
|
33
33
|
/**
|
|
34
|
-
* Lists the declared {@link ColumnStorage}s whose SQL
|
|
34
|
+
* Lists the declared {@link ColumnStorage}s whose SQL range comparisons
|
|
35
35
|
* (`above` / `below` / `from` / `to` / `between`) and `ORDER BY` compiles are
|
|
36
36
|
* provably engine-exact — `integer` / `real` / `boolean` only. `text` is
|
|
37
37
|
* excluded: see {@link EXACT_COLUMN_STORAGE}'s remarks for the BINARY-collation
|
|
@@ -91,7 +91,7 @@ function matchesAbsentPath(error) {
|
|
|
91
91
|
* — the operand side of the declared-type-trust proof.
|
|
92
92
|
*
|
|
93
93
|
* @remarks
|
|
94
|
-
* `text` ↔ string, `integer` / `real` ↔
|
|
94
|
+
* `text` ↔ string, `integer` / `real` ↔ finite number (`NaN` / `±Infinity`
|
|
95
95
|
* fail), `boolean` ↔ boolean. Backs {@link matchesConditionExactly}'s operand checks.
|
|
96
96
|
*
|
|
97
97
|
* @param value - The condition operand to test
|
|
@@ -110,7 +110,7 @@ function matchesDeclaredStorage(value, storage) {
|
|
|
110
110
|
return (0, _orkestrel_contract.isFiniteNumber)(value);
|
|
111
111
|
}
|
|
112
112
|
/**
|
|
113
|
-
* Reports whether one {@link Condition} compiles to SQL that is
|
|
113
|
+
* Reports whether one {@link Condition} compiles to SQL that is provably
|
|
114
114
|
* identical to the core engine's `matchesCondition` for every value its
|
|
115
115
|
* column's declared type can store.
|
|
116
116
|
*
|
|
@@ -124,18 +124,18 @@ function matchesDeclaredStorage(value, storage) {
|
|
|
124
124
|
* Required non-null `equals` / `not` require an operand matching the declared
|
|
125
125
|
* storage and exclude `json` / `blob`. `above` / `below` / `from` / `to` /
|
|
126
126
|
* `between` are exact only for {@link EXACT_RANGE_COLUMN_STORAGE} (`integer` /
|
|
127
|
-
* `real` / `boolean`) — a `text` column's range conditions
|
|
128
|
-
* SQLite's default BINARY collation orders TEXT by Unicode
|
|
129
|
-
* the core engine's `compareValues` orders JS strings by UTF-16
|
|
127
|
+
* `real` / `boolean`) — a `text` column's range conditions refine, because
|
|
128
|
+
* SQLite's default BINARY collation orders TEXT by Unicode code point while
|
|
129
|
+
* the core engine's `compareValues` orders JS strings by UTF-16 code unit,
|
|
130
130
|
* and the two diverge for supplementary-plane characters (see
|
|
131
131
|
* {@link EXACT_COLUMN_STORAGE}'s remarks for the full rationale).
|
|
132
|
-
* `any` / `none` require a
|
|
132
|
+
* `any` / `none` require a non-empty list where every element matches (an empty
|
|
133
133
|
* list is exact under neither: the engine's `any([])` matches nothing while
|
|
134
134
|
* `none([])` matches everything, and SQL `IN ()` is a syntax error) — these
|
|
135
135
|
* stay exact on `text` (byte equality is collation-independent and engine-
|
|
136
136
|
* identical). `starts` / `ends` are exact only on a `text` column with a
|
|
137
137
|
* string operand (case-sensitive `substr` compile, see {@link compileConditionSQL}) —
|
|
138
|
-
* likewise collation-independent. `like` / `glob` are
|
|
138
|
+
* likewise collation-independent. `like` / `glob` are never exact — SQLite
|
|
139
139
|
* `LIKE` folds case ASCII-only against the engine's Unicode fold, and `GLOB`
|
|
140
140
|
* has character classes the engine treats literally.
|
|
141
141
|
*
|
|
@@ -175,11 +175,14 @@ function matchesConditionExactly(condition, schema) {
|
|
|
175
175
|
* @remarks
|
|
176
176
|
* `false` for a nested `FieldPath`, a column absent from `schema`, or a
|
|
177
177
|
* declared type outside {@link EXACT_RANGE_COLUMN_STORAGE} (`integer` / `real` /
|
|
178
|
-
* `boolean`). `text` is
|
|
178
|
+
* `boolean`). `text` is not exact here: SQLite's default BINARY collation
|
|
179
179
|
* orders TEXT by Unicode code point while the core engine's `compareValues`
|
|
180
180
|
* orders JS strings by UTF-16 code unit, and the two diverge for
|
|
181
181
|
* supplementary-plane characters (see {@link EXACT_COLUMN_STORAGE}'s remarks) —
|
|
182
|
-
* a `text` order term
|
|
182
|
+
* a `text` order term refines through the core engine instead. The column must
|
|
183
|
+
* also be required and non-null: an optional or nullable column refines, because
|
|
184
|
+
* SQL orders its `NULL`s ahead of every value while the core total order ranks
|
|
185
|
+
* `undefined` before `null` before every other value.
|
|
183
186
|
*
|
|
184
187
|
* @param order - The order term to test
|
|
185
188
|
* @param schema - The table's schema
|
|
@@ -196,6 +199,10 @@ function matchesOrderExactly(order, schema) {
|
|
|
196
199
|
* every order term is exact. `limit` / `offset` never affect exactness (SQL
|
|
197
200
|
* `LIMIT` / `OFFSET` are always engine-identical).
|
|
198
201
|
*
|
|
202
|
+
* @remarks
|
|
203
|
+
* The gate {@link import('./drivers/SQLiteDriver.js').SQLiteDriver} checks before
|
|
204
|
+
* trusting a native SQL read over a full-scan refine through the core engine.
|
|
205
|
+
*
|
|
199
206
|
* @param input - The query input to test
|
|
200
207
|
* @param schema - The table's schema
|
|
201
208
|
* @returns True if every part of `input` is exact; false otherwise
|
|
@@ -427,7 +434,7 @@ function decodeRow(row, schema) {
|
|
|
427
434
|
* so a plan-built index name always matches one `open` would have created.
|
|
428
435
|
*
|
|
429
436
|
* @remarks
|
|
430
|
-
* A naive `idx_<table>_<cols joined by _>` is
|
|
437
|
+
* A naive `idx_<table>_<cols joined by _>` is ambiguous: table `'a_b'` with
|
|
431
438
|
* column `'c'` and table `'a'` with columns `['b', 'c']` both produce
|
|
432
439
|
* `idx_a_b_c`. This encodes each part (the table name, then each column name)
|
|
433
440
|
* length-prefixed (`<len>_<part>`) so the boundary between parts is always
|
|
@@ -451,7 +458,7 @@ function deriveSQLiteIndexName(table, columns) {
|
|
|
451
458
|
//#region src/server/inferers.ts
|
|
452
459
|
/**
|
|
453
460
|
* Reads the storage type a nested (`json_extract`) operand encodes as from its
|
|
454
|
-
*
|
|
461
|
+
* runtime value, never as `json`.
|
|
455
462
|
*
|
|
456
463
|
* @remarks
|
|
457
464
|
* `json_extract` returns the unquoted, natively-typed scalar (a JSON boolean as
|
|
@@ -498,6 +505,10 @@ function compileColumnSQL(storage) {
|
|
|
498
505
|
/**
|
|
499
506
|
* Compiles a {@link FieldPath} to the SQL expression that reads it.
|
|
500
507
|
*
|
|
508
|
+
* @remarks
|
|
509
|
+
* A flat path compiles to the quoted column; a nested path compiles to a
|
|
510
|
+
* `json_extract` over the head column with the rest of the path as its accessor.
|
|
511
|
+
*
|
|
501
512
|
* @param path - The field path
|
|
502
513
|
* @returns The SQL expression selecting the value
|
|
503
514
|
*/
|
|
@@ -525,9 +536,9 @@ function compileAggregateSQL(operation, column) {
|
|
|
525
536
|
}
|
|
526
537
|
}
|
|
527
538
|
/**
|
|
528
|
-
* Compiles a
|
|
539
|
+
* Compiles a nested {@link FieldPath} to the `json_type(<col>, <path>)` SQL
|
|
529
540
|
* expression — the {@link compileFieldSQL} `json_extract` sibling used to tell a
|
|
530
|
-
*
|
|
541
|
+
* present JSON `null` apart from an absent path (both read back as SQL `NULL`
|
|
531
542
|
* through `json_extract`, but `json_type` reports `'null'` for the former and
|
|
532
543
|
* SQL `NULL` for the latter).
|
|
533
544
|
*
|
|
@@ -551,20 +562,20 @@ function compileJSONTypeSQL(path) {
|
|
|
551
562
|
*
|
|
552
563
|
* @remarks
|
|
553
564
|
* Every operand is run through `encodeValue`, so a bound value matches the SQL
|
|
554
|
-
* the column side compiles to. A flat column encodes operands with its
|
|
565
|
+
* the column side compiles to. A flat column encodes operands with its declared
|
|
555
566
|
* schema type (a flat `json` column → `JSON.stringify`); a nested `FieldPath`
|
|
556
|
-
* encodes each operand as the
|
|
567
|
+
* encodes each operand as the native scalar `json_extract` returns, derived from
|
|
557
568
|
* the operand's runtime type (per-operand, since `between` / `any` / `none` can
|
|
558
569
|
* mix types). `any` / `none` collapse an empty list to a constant (`0` matches
|
|
559
570
|
* nothing, `1` matches all) with no parameters.
|
|
560
571
|
*
|
|
561
|
-
* The core engine's total order ranks `undefined` (rank 0)
|
|
562
|
-
* (rank 1) (see `compareValues`), so a
|
|
572
|
+
* The core engine's total order ranks `undefined` (rank 0) below `null`
|
|
573
|
+
* (rank 1) (see `compareValues`), so a missing/`NULL` column matches
|
|
563
574
|
* `below` / `to` / a scalar `not` / `none` — the opposite of raw SQL, where a
|
|
564
575
|
* comparison against `NULL` is `NULL` (excluded). This fragment replicates the
|
|
565
576
|
* engine exactly. Truth table (`value` = the engine's decoded field read; a
|
|
566
|
-
*
|
|
567
|
-
* flat `value` is
|
|
577
|
+
* flat column's stored `NULL` decodes to `undefined` per `decodeRow`, so a
|
|
578
|
+
* flat `value` is never a present `null` — only a nested path can be
|
|
568
579
|
* present-but-`null`):
|
|
569
580
|
*
|
|
570
581
|
* ```text
|
|
@@ -590,15 +601,15 @@ function compileJSONTypeSQL(path) {
|
|
|
590
601
|
* refines every optional or nullable scalar comparison through the core engine.
|
|
591
602
|
* This compiler still emits a total SQL fragment for direct consumers.
|
|
592
603
|
*
|
|
593
|
-
* A
|
|
594
|
-
* `json_extract` reads back as SQL `NULL` — indistinguishable from an
|
|
604
|
+
* A nested path can be present-but-`null` (a stored JSON `null`), which
|
|
605
|
+
* `json_extract` reads back as SQL `NULL` — indistinguishable from an absent
|
|
595
606
|
* path. `json_type(col, path)` disambiguates them (`'null'` for present-null,
|
|
596
607
|
* SQL `NULL` for absent), so nested `equals` / `not` against a `null` operand
|
|
597
608
|
* compile through `json_type` instead of `IS NULL` / `IS NOT NULL`.
|
|
598
609
|
*
|
|
599
610
|
* Every other MATCH-on-null-or-absent row is expressed uniformly (flat and
|
|
600
611
|
* nested alike) as `(<column> <op> ? OR <column> IS NULL)` — for a nested
|
|
601
|
-
* path, `json_extract` already collapses
|
|
612
|
+
* path, `json_extract` already collapses both absent and present-null to SQL
|
|
602
613
|
* `NULL`, so `IS NULL` catches both in one clause; for a flat column there is
|
|
603
614
|
* only the absent case to catch.
|
|
604
615
|
*
|
|
@@ -742,7 +753,7 @@ function compileConditionSQL(condition, schema) {
|
|
|
742
753
|
* @remarks
|
|
743
754
|
* The first condition's connector is ignored, per the {@link Condition} types.
|
|
744
755
|
* Every fragment (see {@link compileConditionSQL}'s truth table) replicates the core
|
|
745
|
-
* engine's total order
|
|
756
|
+
* engine's total order exactly under SQL's three-valued NULL logic, so this
|
|
746
757
|
* clause matches `applyQuery` row-for-row over the same table — a native
|
|
747
758
|
* `records` / `count` read never disagrees with a scan-and-filter fallback.
|
|
748
759
|
*
|
|
@@ -860,7 +871,7 @@ function compilePageSQL(limit, offset) {
|
|
|
860
871
|
* `FieldPath` (a `json_extract` read) encodes each operand as the native scalar
|
|
861
872
|
* the extract returns — derived from the operand's runtime type — so it compares.
|
|
862
873
|
* Every operator maps per the databases guide's operator table, with
|
|
863
|
-
* `starts` / `ends` compiling to a
|
|
874
|
+
* `starts` / `ends` compiling to a code-point `substr` slice guarded by
|
|
864
875
|
* `typeof(<column>) = 'text'` (case-sensitive, matching the engine's
|
|
865
876
|
* `String.prototype.startsWith` / `endsWith`) and an empty `any` / `none` list
|
|
866
877
|
* collapsing to a constant. An `undefined` input (or one with no parts)
|
|
@@ -903,6 +914,10 @@ function schemaToTable(schema) {
|
|
|
903
914
|
/**
|
|
904
915
|
* Projects a {@link TableSchema} to its declared SQLite indexes.
|
|
905
916
|
*
|
|
917
|
+
* @remarks
|
|
918
|
+
* Each statement is a `CREATE INDEX IF NOT EXISTS` named by
|
|
919
|
+
* {@link deriveSQLiteIndexName}, so a reopen re-issues the set safely.
|
|
920
|
+
*
|
|
906
921
|
* @param schema - The table schema
|
|
907
922
|
* @returns One statement per declared index
|
|
908
923
|
*/
|
|
@@ -912,6 +927,10 @@ function schemaToIndexes(schema) {
|
|
|
912
927
|
/**
|
|
913
928
|
* Projects one {@link MigrationStep} to SQLite DDL.
|
|
914
929
|
*
|
|
930
|
+
* @remarks
|
|
931
|
+
* These are the statements the SQLite driver's `migrate` executes for the step,
|
|
932
|
+
* inside whichever native transaction is active.
|
|
933
|
+
*
|
|
915
934
|
* @param step - The migration step
|
|
916
935
|
* @returns The statements that apply the step
|
|
917
936
|
*/
|
|
@@ -2298,7 +2317,7 @@ var SQLiteDriver = class {
|
|
|
2298
2317
|
//#endregion
|
|
2299
2318
|
//#region src/server/factories.ts
|
|
2300
2319
|
/**
|
|
2301
|
-
* Creates a persistent JSON-file {@link DriverInterface} for
|
|
2320
|
+
* Creates a persistent JSON-file {@link DriverInterface} for a given path.
|
|
2302
2321
|
*
|
|
2303
2322
|
* @remarks
|
|
2304
2323
|
* Pass it to `createDatabase` from `@orkestrel/database` to run the typed
|
|
@@ -2331,7 +2350,8 @@ function createJSONDriver(path) {
|
|
|
2331
2350
|
return new JSONDriver(path);
|
|
2332
2351
|
}
|
|
2333
2352
|
/**
|
|
2334
|
-
* Creates a trusted-mode SQLite {@link DriverInterface} for
|
|
2353
|
+
* Creates a trusted-mode, server-native SQLite {@link DriverInterface} for a database path,
|
|
2354
|
+
* or for `:memory:` when the options bag omits one.
|
|
2335
2355
|
*
|
|
2336
2356
|
* @remarks
|
|
2337
2357
|
* Pass it to `createDatabase` from `@orkestrel/database` to run the typed
|