@orkestrel/database 0.0.13 → 0.0.15
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 +37 -31
- package/dist/src/browser/index.js.map +1 -1
- package/dist/src/core/index.cjs +170 -117
- 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 +171 -118
- package/dist/src/core/index.js.map +1 -1
- package/dist/src/server/index.cjs +78 -58
- 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 +79 -59
- package/dist/src/server/index.js.map +1 -1
- package/package.json +17 -18
package/dist/src/server/index.js
CHANGED
|
@@ -1,26 +1,26 @@
|
|
|
1
1
|
import { DatabaseError, DriverIterator, MemoryDriver, applyQuery, bindRowKey, checkAbort, cloneDriverMetadata, cloneMigrationInput, computeAggregate, equalsValue, extractKey, filterRows, findColumn, isDatabaseError, isKey, matchesQuery, migrateRows, normalizeDriverSchema, planMigration, projectMigrationSchema, validatePage } from "../core/index.js";
|
|
2
|
-
import { cloneJSONValue, isBoolean, isFiniteNumber, isRecord, isString } from "@orkestrel/contract";
|
|
2
|
+
import { cloneJSONValue, isArray, isBigInt, isBoolean, isError, isFiniteNumber, isInteger, isNumber, isObject, isRecord, isString, isUint8Array } from "@orkestrel/contract";
|
|
3
3
|
import { mkdir, readFile, rename, rm, writeFile } from "node:fs/promises";
|
|
4
4
|
import { dirname } from "node:path";
|
|
5
5
|
import { createSQLiteDatabase, isSQLiteError } from "@orkestrel/sqlite";
|
|
6
6
|
//#region src/server/constants.ts
|
|
7
7
|
/**
|
|
8
|
-
* Lists the declared {@link ColumnStorage}s whose SQL
|
|
8
|
+
* Lists the declared {@link ColumnStorage}s whose SQL equality comparisons (`equals` /
|
|
9
9
|
* `not` / `any` / `none`) and `starts` / `ends` compiles are provably
|
|
10
10
|
* engine-exact under declared-type trust — `text` / `integer` / `real` /
|
|
11
11
|
* `boolean`; a `json` or `blob` column always refines instead.
|
|
12
12
|
*
|
|
13
13
|
* @remarks
|
|
14
|
-
* This set governs equality and prefix/suffix matching only.
|
|
14
|
+
* This set governs equality and prefix/suffix matching only. Range
|
|
15
15
|
* comparisons (`above` / `below` / `from` / `to` / `between`) and `ORDER BY`
|
|
16
|
-
* are exact for `integer` / `real` / `boolean` but
|
|
16
|
+
* are exact for `integer` / `real` / `boolean` but not for `text`: compiled
|
|
17
17
|
* SQL orders/ranges under SQLite's default BINARY collation, which compares
|
|
18
|
-
* TEXT byte-for-byte as UTF-8 — equivalent to Unicode
|
|
18
|
+
* TEXT byte-for-byte as UTF-8 — equivalent to Unicode code-point order —
|
|
19
19
|
* while the core engine's `compareValues` orders JS strings with `<`, which
|
|
20
|
-
* compares UTF-16
|
|
20
|
+
* compares UTF-16 code-unit order. The two orders diverge for supplementary-
|
|
21
21
|
* plane characters (code points ≥ U+10000, for example many emoji): a lead surrogate
|
|
22
|
-
* (`\uD800`–`\uDBFF`) sorts
|
|
23
|
-
* its code point sorts
|
|
22
|
+
* (`\uD800`–`\uDBFF`) sorts below ``–`` in code-unit order, while
|
|
23
|
+
* its code point sorts above them. So `matchesConditionExactly`'s range family and
|
|
24
24
|
* `matchesOrderExactly` exclude `text`, refining through the core engine instead.
|
|
25
25
|
*/
|
|
26
26
|
var EXACT_COLUMN_STORAGE = Object.freeze([
|
|
@@ -30,7 +30,7 @@ var EXACT_COLUMN_STORAGE = Object.freeze([
|
|
|
30
30
|
"boolean"
|
|
31
31
|
]);
|
|
32
32
|
/**
|
|
33
|
-
* Lists the declared {@link ColumnStorage}s whose SQL
|
|
33
|
+
* Lists the declared {@link ColumnStorage}s whose SQL range comparisons
|
|
34
34
|
* (`above` / `below` / `from` / `to` / `between`) and `ORDER BY` compiles are
|
|
35
35
|
* provably engine-exact — `integer` / `real` / `boolean` only. `text` is
|
|
36
36
|
* excluded: see {@link EXACT_COLUMN_STORAGE}'s remarks for the BINARY-collation
|
|
@@ -82,7 +82,7 @@ var METADATA_TABLE = "_metadata";
|
|
|
82
82
|
* ```
|
|
83
83
|
*/
|
|
84
84
|
function matchesAbsentPath(error) {
|
|
85
|
-
if (!(error
|
|
85
|
+
if (!isError(error) || !("code" in error)) return false;
|
|
86
86
|
return error.code === "ENOENT" || error.code === "ENOTDIR";
|
|
87
87
|
}
|
|
88
88
|
/**
|
|
@@ -90,7 +90,7 @@ function matchesAbsentPath(error) {
|
|
|
90
90
|
* — the operand side of the declared-type-trust proof.
|
|
91
91
|
*
|
|
92
92
|
* @remarks
|
|
93
|
-
* `text` ↔ string, `integer` / `real` ↔
|
|
93
|
+
* `text` ↔ string, `integer` / `real` ↔ finite number (`NaN` / `±Infinity`
|
|
94
94
|
* fail), `boolean` ↔ boolean. Backs {@link matchesConditionExactly}'s operand checks.
|
|
95
95
|
*
|
|
96
96
|
* @param value - The condition operand to test
|
|
@@ -109,7 +109,7 @@ function matchesDeclaredStorage(value, storage) {
|
|
|
109
109
|
return isFiniteNumber(value);
|
|
110
110
|
}
|
|
111
111
|
/**
|
|
112
|
-
* Reports whether one {@link Condition} compiles to SQL that is
|
|
112
|
+
* Reports whether one {@link Condition} compiles to SQL that is provably
|
|
113
113
|
* identical to the core engine's `matchesCondition` for every value its
|
|
114
114
|
* column's declared type can store.
|
|
115
115
|
*
|
|
@@ -123,18 +123,18 @@ function matchesDeclaredStorage(value, storage) {
|
|
|
123
123
|
* Required non-null `equals` / `not` require an operand matching the declared
|
|
124
124
|
* storage and exclude `json` / `blob`. `above` / `below` / `from` / `to` /
|
|
125
125
|
* `between` are exact only for {@link EXACT_RANGE_COLUMN_STORAGE} (`integer` /
|
|
126
|
-
* `real` / `boolean`) — a `text` column's range conditions
|
|
127
|
-
* SQLite's default BINARY collation orders TEXT by Unicode
|
|
128
|
-
* the core engine's `compareValues` orders JS strings by UTF-16
|
|
126
|
+
* `real` / `boolean`) — a `text` column's range conditions refine, because
|
|
127
|
+
* SQLite's default BINARY collation orders TEXT by Unicode code point while
|
|
128
|
+
* the core engine's `compareValues` orders JS strings by UTF-16 code unit,
|
|
129
129
|
* and the two diverge for supplementary-plane characters (see
|
|
130
130
|
* {@link EXACT_COLUMN_STORAGE}'s remarks for the full rationale).
|
|
131
|
-
* `any` / `none` require a
|
|
131
|
+
* `any` / `none` require a non-empty list where every element matches (an empty
|
|
132
132
|
* list is exact under neither: the engine's `any([])` matches nothing while
|
|
133
133
|
* `none([])` matches everything, and SQL `IN ()` is a syntax error) — these
|
|
134
134
|
* stay exact on `text` (byte equality is collation-independent and engine-
|
|
135
135
|
* identical). `starts` / `ends` are exact only on a `text` column with a
|
|
136
136
|
* string operand (case-sensitive `substr` compile, see {@link compileConditionSQL}) —
|
|
137
|
-
* likewise collation-independent. `like` / `glob` are
|
|
137
|
+
* likewise collation-independent. `like` / `glob` are never exact — SQLite
|
|
138
138
|
* `LIKE` folds case ASCII-only against the engine's Unicode fold, and `GLOB`
|
|
139
139
|
* has character classes the engine treats literally.
|
|
140
140
|
*
|
|
@@ -174,11 +174,14 @@ function matchesConditionExactly(condition, schema) {
|
|
|
174
174
|
* @remarks
|
|
175
175
|
* `false` for a nested `FieldPath`, a column absent from `schema`, or a
|
|
176
176
|
* declared type outside {@link EXACT_RANGE_COLUMN_STORAGE} (`integer` / `real` /
|
|
177
|
-
* `boolean`). `text` is
|
|
177
|
+
* `boolean`). `text` is not exact here: SQLite's default BINARY collation
|
|
178
178
|
* orders TEXT by Unicode code point while the core engine's `compareValues`
|
|
179
179
|
* orders JS strings by UTF-16 code unit, and the two diverge for
|
|
180
180
|
* supplementary-plane characters (see {@link EXACT_COLUMN_STORAGE}'s remarks) —
|
|
181
|
-
* a `text` order term
|
|
181
|
+
* a `text` order term refines through the core engine instead. The column must
|
|
182
|
+
* also be required and non-null: an optional or nullable column refines, because
|
|
183
|
+
* SQL orders its `NULL`s ahead of every value while the core total order ranks
|
|
184
|
+
* `undefined` before `null` before every other value.
|
|
182
185
|
*
|
|
183
186
|
* @param order - The order term to test
|
|
184
187
|
* @param schema - The table's schema
|
|
@@ -195,6 +198,10 @@ function matchesOrderExactly(order, schema) {
|
|
|
195
198
|
* every order term is exact. `limit` / `offset` never affect exactness (SQL
|
|
196
199
|
* `LIMIT` / `OFFSET` are always engine-identical).
|
|
197
200
|
*
|
|
201
|
+
* @remarks
|
|
202
|
+
* The gate {@link import('./drivers/SQLiteDriver.js').SQLiteDriver} checks before
|
|
203
|
+
* trusting a native SQL read over a full-scan refine through the core engine.
|
|
204
|
+
*
|
|
198
205
|
* @param input - The query input to test
|
|
199
206
|
* @param schema - The table's schema
|
|
200
207
|
* @returns True if every part of `input` is exact; false otherwise
|
|
@@ -285,16 +292,16 @@ function encodeValue(value, column) {
|
|
|
285
292
|
return column.storage === "text" || column.storage === "json" ? /* @__PURE__ */ new Uint8Array() : String(null);
|
|
286
293
|
}
|
|
287
294
|
switch (column.storage) {
|
|
288
|
-
case "boolean": return
|
|
295
|
+
case "boolean": return isBoolean(value) ? value ? 1 : 0 : null;
|
|
289
296
|
case "json": try {
|
|
290
297
|
return JSON.stringify(cloneJSONValue(value));
|
|
291
298
|
} catch {
|
|
292
299
|
return null;
|
|
293
300
|
}
|
|
294
|
-
case "integer": return
|
|
295
|
-
case "real": return
|
|
296
|
-
case "text": return
|
|
297
|
-
case "blob": return value
|
|
301
|
+
case "integer": return isBigInt(value) || isFiniteNumber(value) && isInteger(value) ? value : null;
|
|
302
|
+
case "real": return isBigInt(value) || isFiniteNumber(value) ? value : null;
|
|
303
|
+
case "text": return isString(value) ? value : null;
|
|
304
|
+
case "blob": return isUint8Array(value) ? value : null;
|
|
298
305
|
}
|
|
299
306
|
}
|
|
300
307
|
/**
|
|
@@ -319,23 +326,23 @@ function encodeValue(value, column) {
|
|
|
319
326
|
*/
|
|
320
327
|
function decodeValue(value, column) {
|
|
321
328
|
if (value === null) return column.nullable && !column.optional ? null : void 0;
|
|
322
|
-
if (column.optional && column.nullable && (column.storage === "text" || column.storage === "json" ? value
|
|
329
|
+
if (column.optional && column.nullable && (column.storage === "text" || column.storage === "json" ? isUint8Array(value) && value.byteLength === 0 : value === String(null))) return null;
|
|
323
330
|
switch (column.storage) {
|
|
324
331
|
case "boolean":
|
|
325
332
|
if (value === 0 || value === 0n) return false;
|
|
326
333
|
if (value === 1 || value === 1n) return true;
|
|
327
334
|
return;
|
|
328
335
|
case "json":
|
|
329
|
-
if (
|
|
336
|
+
if (!isString(value)) return void 0;
|
|
330
337
|
try {
|
|
331
338
|
return structuredClone(cloneJSONValue(JSON.parse(value)));
|
|
332
339
|
} catch {
|
|
333
340
|
return;
|
|
334
341
|
}
|
|
335
|
-
case "integer": return
|
|
336
|
-
case "real": return
|
|
337
|
-
case "text": return
|
|
338
|
-
case "blob": return value
|
|
342
|
+
case "integer": return isBigInt(value) || isFiniteNumber(value) && isInteger(value) ? value : void 0;
|
|
343
|
+
case "real": return isBigInt(value) || isFiniteNumber(value) ? value : void 0;
|
|
344
|
+
case "text": return isString(value) ? value : void 0;
|
|
345
|
+
case "blob": return isUint8Array(value) ? value : void 0;
|
|
339
346
|
}
|
|
340
347
|
}
|
|
341
348
|
/**
|
|
@@ -426,7 +433,7 @@ function decodeRow(row, schema) {
|
|
|
426
433
|
* so a plan-built index name always matches one `open` would have created.
|
|
427
434
|
*
|
|
428
435
|
* @remarks
|
|
429
|
-
* A naive `idx_<table>_<cols joined by _>` is
|
|
436
|
+
* A naive `idx_<table>_<cols joined by _>` is ambiguous: table `'a_b'` with
|
|
430
437
|
* column `'c'` and table `'a'` with columns `['b', 'c']` both produce
|
|
431
438
|
* `idx_a_b_c`. This encodes each part (the table name, then each column name)
|
|
432
439
|
* length-prefixed (`<len>_<part>`) so the boundary between parts is always
|
|
@@ -450,7 +457,7 @@ function deriveSQLiteIndexName(table, columns) {
|
|
|
450
457
|
//#region src/server/inferers.ts
|
|
451
458
|
/**
|
|
452
459
|
* Reads the storage type a nested (`json_extract`) operand encodes as from its
|
|
453
|
-
*
|
|
460
|
+
* runtime value, never as `json`.
|
|
454
461
|
*
|
|
455
462
|
* @remarks
|
|
456
463
|
* `json_extract` returns the unquoted, natively-typed scalar (a JSON boolean as
|
|
@@ -470,10 +477,10 @@ function deriveSQLiteIndexName(table, columns) {
|
|
|
470
477
|
* ```
|
|
471
478
|
*/
|
|
472
479
|
function inferValueStorage(value) {
|
|
473
|
-
if (
|
|
474
|
-
if (
|
|
475
|
-
if (
|
|
476
|
-
if (
|
|
480
|
+
if (isBoolean(value)) return "boolean";
|
|
481
|
+
if (isNumber(value)) return isInteger(value) ? "integer" : "real";
|
|
482
|
+
if (isBigInt(value)) return "integer";
|
|
483
|
+
if (isObject(value)) return "json";
|
|
477
484
|
return "text";
|
|
478
485
|
}
|
|
479
486
|
//#endregion
|
|
@@ -497,6 +504,10 @@ function compileColumnSQL(storage) {
|
|
|
497
504
|
/**
|
|
498
505
|
* Compiles a {@link FieldPath} to the SQL expression that reads it.
|
|
499
506
|
*
|
|
507
|
+
* @remarks
|
|
508
|
+
* A flat path compiles to the quoted column; a nested path compiles to a
|
|
509
|
+
* `json_extract` over the head column with the rest of the path as its accessor.
|
|
510
|
+
*
|
|
500
511
|
* @param path - The field path
|
|
501
512
|
* @returns The SQL expression selecting the value
|
|
502
513
|
*/
|
|
@@ -524,9 +535,9 @@ function compileAggregateSQL(operation, column) {
|
|
|
524
535
|
}
|
|
525
536
|
}
|
|
526
537
|
/**
|
|
527
|
-
* Compiles a
|
|
538
|
+
* Compiles a nested {@link FieldPath} to the `json_type(<col>, <path>)` SQL
|
|
528
539
|
* expression — the {@link compileFieldSQL} `json_extract` sibling used to tell a
|
|
529
|
-
*
|
|
540
|
+
* present JSON `null` apart from an absent path (both read back as SQL `NULL`
|
|
530
541
|
* through `json_extract`, but `json_type` reports `'null'` for the former and
|
|
531
542
|
* SQL `NULL` for the latter).
|
|
532
543
|
*
|
|
@@ -550,20 +561,20 @@ function compileJSONTypeSQL(path) {
|
|
|
550
561
|
*
|
|
551
562
|
* @remarks
|
|
552
563
|
* Every operand is run through `encodeValue`, so a bound value matches the SQL
|
|
553
|
-
* the column side compiles to. A flat column encodes operands with its
|
|
564
|
+
* the column side compiles to. A flat column encodes operands with its declared
|
|
554
565
|
* schema type (a flat `json` column → `JSON.stringify`); a nested `FieldPath`
|
|
555
|
-
* encodes each operand as the
|
|
566
|
+
* encodes each operand as the native scalar `json_extract` returns, derived from
|
|
556
567
|
* the operand's runtime type (per-operand, since `between` / `any` / `none` can
|
|
557
568
|
* mix types). `any` / `none` collapse an empty list to a constant (`0` matches
|
|
558
569
|
* nothing, `1` matches all) with no parameters.
|
|
559
570
|
*
|
|
560
|
-
* The core engine's total order ranks `undefined` (rank 0)
|
|
561
|
-
* (rank 1) (see `compareValues`), so a
|
|
571
|
+
* The core engine's total order ranks `undefined` (rank 0) below `null`
|
|
572
|
+
* (rank 1) (see `compareValues`), so a missing/`NULL` column matches
|
|
562
573
|
* `below` / `to` / a scalar `not` / `none` — the opposite of raw SQL, where a
|
|
563
574
|
* comparison against `NULL` is `NULL` (excluded). This fragment replicates the
|
|
564
575
|
* engine exactly. Truth table (`value` = the engine's decoded field read; a
|
|
565
|
-
*
|
|
566
|
-
* flat `value` is
|
|
576
|
+
* flat column's stored `NULL` decodes to `undefined` per `decodeRow`, so a
|
|
577
|
+
* flat `value` is never a present `null` — only a nested path can be
|
|
567
578
|
* present-but-`null`):
|
|
568
579
|
*
|
|
569
580
|
* ```text
|
|
@@ -589,15 +600,15 @@ function compileJSONTypeSQL(path) {
|
|
|
589
600
|
* refines every optional or nullable scalar comparison through the core engine.
|
|
590
601
|
* This compiler still emits a total SQL fragment for direct consumers.
|
|
591
602
|
*
|
|
592
|
-
* A
|
|
593
|
-
* `json_extract` reads back as SQL `NULL` — indistinguishable from an
|
|
603
|
+
* A nested path can be present-but-`null` (a stored JSON `null`), which
|
|
604
|
+
* `json_extract` reads back as SQL `NULL` — indistinguishable from an absent
|
|
594
605
|
* path. `json_type(col, path)` disambiguates them (`'null'` for present-null,
|
|
595
606
|
* SQL `NULL` for absent), so nested `equals` / `not` against a `null` operand
|
|
596
607
|
* compile through `json_type` instead of `IS NULL` / `IS NOT NULL`.
|
|
597
608
|
*
|
|
598
609
|
* Every other MATCH-on-null-or-absent row is expressed uniformly (flat and
|
|
599
610
|
* nested alike) as `(<column> <op> ? OR <column> IS NULL)` — for a nested
|
|
600
|
-
* path, `json_extract` already collapses
|
|
611
|
+
* path, `json_extract` already collapses both absent and present-null to SQL
|
|
601
612
|
* `NULL`, so `IS NULL` catches both in one clause; for a flat column there is
|
|
602
613
|
* only the absent case to catch.
|
|
603
614
|
*
|
|
@@ -741,7 +752,7 @@ function compileConditionSQL(condition, schema) {
|
|
|
741
752
|
* @remarks
|
|
742
753
|
* The first condition's connector is ignored, per the {@link Condition} types.
|
|
743
754
|
* Every fragment (see {@link compileConditionSQL}'s truth table) replicates the core
|
|
744
|
-
* engine's total order
|
|
755
|
+
* engine's total order exactly under SQL's three-valued NULL logic, so this
|
|
745
756
|
* clause matches `applyQuery` row-for-row over the same table — a native
|
|
746
757
|
* `records` / `count` read never disagrees with a scan-and-filter fallback.
|
|
747
758
|
*
|
|
@@ -859,7 +870,7 @@ function compilePageSQL(limit, offset) {
|
|
|
859
870
|
* `FieldPath` (a `json_extract` read) encodes each operand as the native scalar
|
|
860
871
|
* the extract returns — derived from the operand's runtime type — so it compares.
|
|
861
872
|
* Every operator maps per the databases guide's operator table, with
|
|
862
|
-
* `starts` / `ends` compiling to a
|
|
873
|
+
* `starts` / `ends` compiling to a code-point `substr` slice guarded by
|
|
863
874
|
* `typeof(<column>) = 'text'` (case-sensitive, matching the engine's
|
|
864
875
|
* `String.prototype.startsWith` / `endsWith`) and an empty `any` / `none` list
|
|
865
876
|
* collapsing to a constant. An `undefined` input (or one with no parts)
|
|
@@ -902,6 +913,10 @@ function schemaToTable(schema) {
|
|
|
902
913
|
/**
|
|
903
914
|
* Projects a {@link TableSchema} to its declared SQLite indexes.
|
|
904
915
|
*
|
|
916
|
+
* @remarks
|
|
917
|
+
* Each statement is a `CREATE INDEX IF NOT EXISTS` named by
|
|
918
|
+
* {@link deriveSQLiteIndexName}, so a reopen re-issues the set safely.
|
|
919
|
+
*
|
|
905
920
|
* @param schema - The table schema
|
|
906
921
|
* @returns One statement per declared index
|
|
907
922
|
*/
|
|
@@ -911,6 +926,10 @@ function schemaToIndexes(schema) {
|
|
|
911
926
|
/**
|
|
912
927
|
* Projects one {@link MigrationStep} to SQLite DDL.
|
|
913
928
|
*
|
|
929
|
+
* @remarks
|
|
930
|
+
* These are the statements the SQLite driver's `migrate` executes for the step,
|
|
931
|
+
* inside whichever native transaction is active.
|
|
932
|
+
*
|
|
914
933
|
* @param step - The migration step
|
|
915
934
|
* @returns The statements that apply the step
|
|
916
935
|
*/
|
|
@@ -1376,7 +1395,7 @@ var JSONDriver = class {
|
|
|
1376
1395
|
async #hydrate(memory, schema, tables) {
|
|
1377
1396
|
for (const table of schema) {
|
|
1378
1397
|
const rows = tables[table.name];
|
|
1379
|
-
if (!
|
|
1398
|
+
if (!isArray(rows)) throw new DatabaseError("DRIVER", "Stored JSON table is invalid", {
|
|
1380
1399
|
path: this.#path,
|
|
1381
1400
|
table: table.name,
|
|
1382
1401
|
aspect: "container"
|
|
@@ -1954,7 +1973,7 @@ var SQLiteDriver = class {
|
|
|
1954
1973
|
const keys = [];
|
|
1955
1974
|
for (const row of rows) {
|
|
1956
1975
|
const value = row[schema.primary];
|
|
1957
|
-
if (
|
|
1976
|
+
if (isString(value) || isNumber(value)) keys.push(value);
|
|
1958
1977
|
}
|
|
1959
1978
|
return keys;
|
|
1960
1979
|
});
|
|
@@ -2087,7 +2106,7 @@ var SQLiteDriver = class {
|
|
|
2087
2106
|
});
|
|
2088
2107
|
for (const [position, column] of group.entries()) {
|
|
2089
2108
|
const entry = entries.find((candidate) => candidate.seqno === position || candidate.seqno === BigInt(position));
|
|
2090
|
-
const stored = entry !== void 0 && (
|
|
2109
|
+
const stored = entry !== void 0 && (isInteger(entry.cid) && entry.cid >= 0 || isBigInt(entry.cid) && entry.cid >= 0n);
|
|
2091
2110
|
if (entry === void 0 || entry.name !== column || !stored || entry.desc !== 0 && entry.desc !== 0n || entry.coll !== "BINARY") throw new DatabaseError("DRIVER", "SQLite index column does not match its declaration", {
|
|
2092
2111
|
table: schema.name,
|
|
2093
2112
|
aspect: "index",
|
|
@@ -2104,11 +2123,11 @@ var SQLiteDriver = class {
|
|
|
2104
2123
|
if (row === void 0) return void 0;
|
|
2105
2124
|
const version = row.version;
|
|
2106
2125
|
const text = row.schema;
|
|
2107
|
-
if (
|
|
2126
|
+
if (!isString(text)) throw new DatabaseError("DRIVER", "Stored SQLite metadata schema is invalid", {
|
|
2108
2127
|
table: METADATA_TABLE,
|
|
2109
2128
|
aspect: "metadata"
|
|
2110
2129
|
});
|
|
2111
|
-
if (
|
|
2130
|
+
if (!isNumber(version) && !isBigInt(version)) throw new DatabaseError("DRIVER", "Stored SQLite metadata version is invalid", {
|
|
2112
2131
|
table: METADATA_TABLE,
|
|
2113
2132
|
aspect: "metadata"
|
|
2114
2133
|
});
|
|
@@ -2122,7 +2141,7 @@ var SQLiteDriver = class {
|
|
|
2122
2141
|
cause: error
|
|
2123
2142
|
});
|
|
2124
2143
|
}
|
|
2125
|
-
if (!
|
|
2144
|
+
if (!isArray(parsed)) throw new DatabaseError("DRIVER", "Stored SQLite metadata schema is invalid", {
|
|
2126
2145
|
table: METADATA_TABLE,
|
|
2127
2146
|
aspect: "metadata"
|
|
2128
2147
|
});
|
|
@@ -2241,7 +2260,7 @@ var SQLiteDriver = class {
|
|
|
2241
2260
|
try {
|
|
2242
2261
|
return operation();
|
|
2243
2262
|
} catch (error) {
|
|
2244
|
-
if (error
|
|
2263
|
+
if (isDatabaseError(error)) throw error;
|
|
2245
2264
|
if (isSQLiteError(error)) {
|
|
2246
2265
|
if (error.code === "CONSTRAINT") throw new DatabaseError("CONFLICT", error.message, {
|
|
2247
2266
|
cause: error,
|
|
@@ -2261,7 +2280,7 @@ var SQLiteDriver = class {
|
|
|
2261
2280
|
code: error.code
|
|
2262
2281
|
});
|
|
2263
2282
|
}
|
|
2264
|
-
throw new DatabaseError("DRIVER", error
|
|
2283
|
+
throw new DatabaseError("DRIVER", isError(error) ? error.message : String(error), { cause: error });
|
|
2265
2284
|
}
|
|
2266
2285
|
}
|
|
2267
2286
|
#require() {
|
|
@@ -2297,7 +2316,7 @@ var SQLiteDriver = class {
|
|
|
2297
2316
|
//#endregion
|
|
2298
2317
|
//#region src/server/factories.ts
|
|
2299
2318
|
/**
|
|
2300
|
-
* Creates a persistent JSON-file {@link DriverInterface} for
|
|
2319
|
+
* Creates a persistent JSON-file {@link DriverInterface} for a given path.
|
|
2301
2320
|
*
|
|
2302
2321
|
* @remarks
|
|
2303
2322
|
* Pass it to `createDatabase` from `@orkestrel/database` to run the typed
|
|
@@ -2330,7 +2349,8 @@ function createJSONDriver(path) {
|
|
|
2330
2349
|
return new JSONDriver(path);
|
|
2331
2350
|
}
|
|
2332
2351
|
/**
|
|
2333
|
-
* Creates a trusted-mode SQLite {@link DriverInterface} for
|
|
2352
|
+
* Creates a trusted-mode, server-native SQLite {@link DriverInterface} for a database path,
|
|
2353
|
+
* or for `:memory:` when the options bag omits one.
|
|
2334
2354
|
*
|
|
2335
2355
|
* @remarks
|
|
2336
2356
|
* Pass it to `createDatabase` from `@orkestrel/database` to run the typed
|