@orkestrel/database 0.0.5 → 0.0.6
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/dist/src/browser/index.d.ts +13 -13
- package/dist/src/browser/index.js +26 -13
- package/dist/src/browser/index.js.map +1 -1
- package/dist/src/core/index.cjs +677 -525
- package/dist/src/core/index.cjs.map +1 -1
- package/dist/src/core/index.js +677 -525
- package/dist/src/core/index.js.map +1 -1
- package/dist/src/server/index.cjs +178 -136
- package/dist/src/server/index.cjs.map +1 -1
- package/dist/src/server/index.d.cts +40 -19
- package/dist/src/server/index.d.ts +40 -19
- package/dist/src/server/index.js +178 -137
- package/dist/src/server/index.js.map +1 -1
- package/package.json +20 -17
package/dist/src/server/index.js
CHANGED
|
@@ -1,28 +1,10 @@
|
|
|
1
|
+
import { DatabaseError, MemoryDriver, applyCriteria, computeAggregate, extractKey, filterRows, isDriverMeta, matchesCriteria } from "../core/index.js";
|
|
1
2
|
import { isBoolean, isFiniteNumber, isRecord, isString } from "@orkestrel/contract";
|
|
2
3
|
import { randomUUID } from "node:crypto";
|
|
3
|
-
import { DatabaseError, MemoryDriver, applyCriteria, computeAggregate, extractKey, filterRows, isDriverMeta, matchesCriteria } from "../core/index.js";
|
|
4
4
|
import { mkdir, readFile, rename, rm, writeFile } from "node:fs/promises";
|
|
5
5
|
import { dirname } from "node:path";
|
|
6
6
|
import { createSQLiteDatabase, isSQLiteError } from "@orkestrel/sqlite";
|
|
7
|
-
//#region src/server/
|
|
8
|
-
/**
|
|
9
|
-
* Generate a fresh unique key — a v4 UUID string, backed by `node:crypto`.
|
|
10
|
-
*
|
|
11
|
-
* @remarks
|
|
12
|
-
* Supply this as {@link import('@orkestrel/database').DatabaseOptions.key} so a table mints
|
|
13
|
-
* a key when a written row lacks its primary-key value. Strings work as keys on
|
|
14
|
-
* every backend; supply your own key values directly to use numeric keys instead.
|
|
15
|
-
*
|
|
16
|
-
* @returns A new UUID string
|
|
17
|
-
*
|
|
18
|
-
* @example
|
|
19
|
-
* ```ts
|
|
20
|
-
* const db = createDatabase({ driver, tables, key: generateKey })
|
|
21
|
-
* ```
|
|
22
|
-
*/
|
|
23
|
-
function generateKey() {
|
|
24
|
-
return randomUUID();
|
|
25
|
-
}
|
|
7
|
+
//#region src/server/constants.ts
|
|
26
8
|
/**
|
|
27
9
|
* The declared {@link ColumnType}s whose SQL EQUALITY comparisons (`equals` /
|
|
28
10
|
* `not` / `any` / `none`) and `starts` / `ends` compiles are provably
|
|
@@ -45,12 +27,12 @@ function generateKey() {
|
|
|
45
27
|
* values are BMP-only, or a custom SQLite collation matching `compareValues`
|
|
46
28
|
* is registered) could restore native text ranges/ordering.
|
|
47
29
|
*/
|
|
48
|
-
var EXACT_COLUMN_TYPES = [
|
|
30
|
+
var EXACT_COLUMN_TYPES = Object.freeze([
|
|
49
31
|
"text",
|
|
50
32
|
"integer",
|
|
51
33
|
"real",
|
|
52
34
|
"boolean"
|
|
53
|
-
];
|
|
35
|
+
]);
|
|
54
36
|
/**
|
|
55
37
|
* The declared {@link ColumnType}s whose SQL RANGE comparisons
|
|
56
38
|
* (`above` / `below` / `from` / `to` / `between`) and `ORDER BY` compiles are
|
|
@@ -59,11 +41,41 @@ var EXACT_COLUMN_TYPES = [
|
|
|
59
41
|
* (code-point) vs. JS `<` (code-unit) divergence on supplementary-plane
|
|
60
42
|
* characters.
|
|
61
43
|
*/
|
|
62
|
-
var EXACT_RANGE_COLUMN_TYPES = [
|
|
44
|
+
var EXACT_RANGE_COLUMN_TYPES = Object.freeze([
|
|
63
45
|
"integer",
|
|
64
46
|
"real",
|
|
65
47
|
"boolean"
|
|
66
|
-
];
|
|
48
|
+
]);
|
|
49
|
+
/**
|
|
50
|
+
* The reserved metadata table the {@link SQLiteDriver} creates on `open` to
|
|
51
|
+
* persist its stamped `DriverMeta` (`version` + declared schema JSON) — the
|
|
52
|
+
* SQLite realization of the `meta` / `stamp` driver hooks.
|
|
53
|
+
*
|
|
54
|
+
* @remarks
|
|
55
|
+
* A single-row table (`id = 1`). A user table named `_meta` collides with the
|
|
56
|
+
* reservation — the caller's concern to avoid, documented on the driver class.
|
|
57
|
+
*/
|
|
58
|
+
var META_TABLE = "_meta";
|
|
59
|
+
//#endregion
|
|
60
|
+
//#region src/server/helpers.ts
|
|
61
|
+
/**
|
|
62
|
+
* Generate a fresh unique key — a v4 UUID string, backed by `node:crypto`.
|
|
63
|
+
*
|
|
64
|
+
* @remarks
|
|
65
|
+
* Supply this as {@link import('@orkestrel/database').DatabaseOptions.key} so a table mints
|
|
66
|
+
* a key when a written row lacks its primary-key value. Strings work as keys on
|
|
67
|
+
* every backend; supply your own key values directly to use numeric keys instead.
|
|
68
|
+
*
|
|
69
|
+
* @returns A new UUID string
|
|
70
|
+
*
|
|
71
|
+
* @example
|
|
72
|
+
* ```ts
|
|
73
|
+
* const db = createDatabase({ driver, tables, key: generateKey })
|
|
74
|
+
* ```
|
|
75
|
+
*/
|
|
76
|
+
function generateKey() {
|
|
77
|
+
return randomUUID();
|
|
78
|
+
}
|
|
67
79
|
/**
|
|
68
80
|
* Whether a value's runtime type matches a column's declared exact type —
|
|
69
81
|
* the operand side of the declared-type-trust proof.
|
|
@@ -253,8 +265,10 @@ function quote(identifier) {
|
|
|
253
265
|
*/
|
|
254
266
|
function fieldColumn(path) {
|
|
255
267
|
if (isString(path)) return quote(path);
|
|
256
|
-
const
|
|
257
|
-
|
|
268
|
+
const [column, ...nested] = path;
|
|
269
|
+
if (column === void 0) throw new DatabaseError("VALIDATION", "A field path must contain at least one column");
|
|
270
|
+
const rest = nested.map((key) => "." + key.replaceAll("'", "''")).join("");
|
|
271
|
+
return "json_extract(" + quote(column) + ", '$" + rest + "')";
|
|
258
272
|
}
|
|
259
273
|
/**
|
|
260
274
|
* Compile an {@link AggregateFunction} over a {@link FieldPath} to its SQL
|
|
@@ -372,6 +386,37 @@ function encodeRow(row, schema) {
|
|
|
372
386
|
return result;
|
|
373
387
|
}
|
|
374
388
|
/**
|
|
389
|
+
* Extract a stored row's values in a declared positional order.
|
|
390
|
+
*
|
|
391
|
+
* @remarks
|
|
392
|
+
* SQLite statements bind arrays positionally. Every requested column must be
|
|
393
|
+
* present in `row`; an incomplete backend row is a typed `DRIVER` fault carrying
|
|
394
|
+
* the table and missing column in its context.
|
|
395
|
+
*
|
|
396
|
+
* @param row - The stored SQLite row
|
|
397
|
+
* @param names - The column names in binding order
|
|
398
|
+
* @param table - The owning table name for fault context
|
|
399
|
+
* @returns The row values in the same order as `names`
|
|
400
|
+
* @throws A `DRIVER` {@link DatabaseError} when a requested column is missing
|
|
401
|
+
*
|
|
402
|
+
* @example
|
|
403
|
+
* ```ts
|
|
404
|
+
* extractValues({ id: 'u1', age: 36 }, ['age', 'id'], 'users') // [36, 'u1']
|
|
405
|
+
* ```
|
|
406
|
+
*/
|
|
407
|
+
function extractValues(row, names, table) {
|
|
408
|
+
const values = [];
|
|
409
|
+
for (const name of names) {
|
|
410
|
+
const value = row[name];
|
|
411
|
+
if (value === void 0) throw new DatabaseError("DRIVER", "SQLite row is missing a declared column", {
|
|
412
|
+
table,
|
|
413
|
+
column: name
|
|
414
|
+
});
|
|
415
|
+
values.push(value);
|
|
416
|
+
}
|
|
417
|
+
return values;
|
|
418
|
+
}
|
|
419
|
+
/**
|
|
375
420
|
* Decode a stored {@link SQLiteRow} back to a {@link Row} by its table's schema.
|
|
376
421
|
*
|
|
377
422
|
* @remarks
|
|
@@ -394,7 +439,9 @@ function encodeRow(row, schema) {
|
|
|
394
439
|
function decodeRow(row, schema) {
|
|
395
440
|
const result = {};
|
|
396
441
|
for (const column of schema.columns) {
|
|
397
|
-
const
|
|
442
|
+
const value = row[column.name];
|
|
443
|
+
if (value === void 0) continue;
|
|
444
|
+
const decoded = decodeValue(value, column.type);
|
|
398
445
|
if (decoded !== void 0) result[column.name] = decoded;
|
|
399
446
|
}
|
|
400
447
|
return result;
|
|
@@ -567,8 +614,10 @@ function stepToSchema(schema, step) {
|
|
|
567
614
|
* ```
|
|
568
615
|
*/
|
|
569
616
|
function jsonTypeColumn(path) {
|
|
570
|
-
const
|
|
571
|
-
|
|
617
|
+
const [column, ...nested] = path;
|
|
618
|
+
if (column === void 0) throw new DatabaseError("VALIDATION", "A field path must contain at least one column");
|
|
619
|
+
const rest = nested.map((key) => "." + key.replaceAll("'", "''")).join("");
|
|
620
|
+
return "json_type(" + quote(column) + ", '$" + rest + "')";
|
|
572
621
|
}
|
|
573
622
|
/**
|
|
574
623
|
* Escape `\`, `%`, and `_` (each with a leading `\`) so a `starts` / `ends`
|
|
@@ -703,21 +752,21 @@ function fragment(condition, schema) {
|
|
|
703
752
|
const column = fieldColumn(condition.column);
|
|
704
753
|
const nested = !isString(condition.column);
|
|
705
754
|
const declared = isString(condition.column) ? declaredType(condition.column, schema) : void 0;
|
|
706
|
-
const encode = (value) => encodeValue(value, nested ? valueType(value) : declared ?? "json");
|
|
707
755
|
const first = condition.values[0];
|
|
708
756
|
const second = condition.values[1];
|
|
709
757
|
const nullOperand = first === null || first === void 0;
|
|
710
758
|
const jsonType = !isString(condition.column) ? jsonTypeColumn(condition.column) : "";
|
|
759
|
+
let sql;
|
|
760
|
+
let values;
|
|
711
761
|
switch (condition.operator) {
|
|
712
762
|
case "equals":
|
|
713
763
|
if (nullOperand && nested) return {
|
|
714
764
|
sql: jsonType + " = 'null'",
|
|
715
765
|
params: []
|
|
716
766
|
};
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
};
|
|
767
|
+
sql = column + " = ?";
|
|
768
|
+
values = [first];
|
|
769
|
+
break;
|
|
721
770
|
case "not":
|
|
722
771
|
if (nullOperand) {
|
|
723
772
|
if (nested) return {
|
|
@@ -729,38 +778,37 @@ function fragment(condition, schema) {
|
|
|
729
778
|
params: []
|
|
730
779
|
};
|
|
731
780
|
}
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
};
|
|
781
|
+
sql = "(" + column + " != ? OR " + column + " IS NULL)";
|
|
782
|
+
values = [first];
|
|
783
|
+
break;
|
|
784
|
+
case "above":
|
|
785
|
+
sql = column + " > ?";
|
|
786
|
+
values = [first];
|
|
787
|
+
break;
|
|
788
|
+
case "below":
|
|
789
|
+
sql = "(" + column + " < ? OR " + column + " IS NULL)";
|
|
790
|
+
values = [first];
|
|
791
|
+
break;
|
|
792
|
+
case "from":
|
|
793
|
+
sql = column + " >= ?";
|
|
794
|
+
values = [first];
|
|
795
|
+
break;
|
|
796
|
+
case "to":
|
|
797
|
+
sql = "(" + column + " <= ? OR " + column + " IS NULL)";
|
|
798
|
+
values = [first];
|
|
799
|
+
break;
|
|
800
|
+
case "between":
|
|
801
|
+
sql = column + " BETWEEN ? AND ?";
|
|
802
|
+
values = [first, second];
|
|
803
|
+
break;
|
|
804
|
+
case "like":
|
|
805
|
+
sql = column + " LIKE ?";
|
|
806
|
+
values = [first];
|
|
807
|
+
break;
|
|
808
|
+
case "glob":
|
|
809
|
+
sql = column + " GLOB ?";
|
|
810
|
+
values = [first];
|
|
811
|
+
break;
|
|
764
812
|
case "starts": {
|
|
765
813
|
const text = isString(first) ? first : "";
|
|
766
814
|
if (text === "") return {
|
|
@@ -768,10 +816,9 @@ function fragment(condition, schema) {
|
|
|
768
816
|
params: []
|
|
769
817
|
};
|
|
770
818
|
const length = Array.from(text).length;
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
};
|
|
819
|
+
sql = "(typeof(" + column + ") = 'text' AND substr(" + column + ", 1, " + length + ") = ?)";
|
|
820
|
+
values = [first];
|
|
821
|
+
break;
|
|
775
822
|
}
|
|
776
823
|
case "ends": {
|
|
777
824
|
const text = isString(first) ? first : "";
|
|
@@ -780,29 +827,26 @@ function fragment(condition, schema) {
|
|
|
780
827
|
params: []
|
|
781
828
|
};
|
|
782
829
|
const length = Array.from(text).length;
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
};
|
|
830
|
+
sql = "(typeof(" + column + ") = 'text' AND substr(" + column + ", -" + length + ") = ?)";
|
|
831
|
+
values = [first];
|
|
832
|
+
break;
|
|
787
833
|
}
|
|
788
834
|
case "any":
|
|
789
835
|
if (condition.values.length === 0) return {
|
|
790
836
|
sql: "0",
|
|
791
837
|
params: []
|
|
792
838
|
};
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
};
|
|
839
|
+
sql = column + " IN (" + condition.values.map(() => "?").join(", ") + ")";
|
|
840
|
+
values = condition.values;
|
|
841
|
+
break;
|
|
797
842
|
case "none":
|
|
798
843
|
if (condition.values.length === 0) return {
|
|
799
844
|
sql: "1",
|
|
800
845
|
params: []
|
|
801
846
|
};
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
};
|
|
847
|
+
sql = "(" + column + " NOT IN (" + condition.values.map(() => "?").join(", ") + ") OR " + column + " IS NULL)";
|
|
848
|
+
values = condition.values;
|
|
849
|
+
break;
|
|
806
850
|
case "absent": return {
|
|
807
851
|
sql: column + " IS NULL",
|
|
808
852
|
params: []
|
|
@@ -812,6 +856,10 @@ function fragment(condition, schema) {
|
|
|
812
856
|
params: []
|
|
813
857
|
};
|
|
814
858
|
}
|
|
859
|
+
return {
|
|
860
|
+
sql,
|
|
861
|
+
params: values.map((value) => encodeValue(value, nested ? valueType(value) : declared ?? "json"))
|
|
862
|
+
};
|
|
815
863
|
}
|
|
816
864
|
/**
|
|
817
865
|
* Fold the conditions into one WHERE clause, parenthesizing progressively
|
|
@@ -835,16 +883,17 @@ function fragment(condition, schema) {
|
|
|
835
883
|
* ```
|
|
836
884
|
*/
|
|
837
885
|
function compileWhere(conditions, schema) {
|
|
838
|
-
|
|
886
|
+
const [first, ...remaining] = conditions;
|
|
887
|
+
if (first === void 0) return {
|
|
839
888
|
sql: "",
|
|
840
889
|
params: []
|
|
841
890
|
};
|
|
842
|
-
const head = fragment(
|
|
891
|
+
const head = fragment(first, schema);
|
|
843
892
|
let clause = head.sql;
|
|
844
893
|
const params = [...head.params];
|
|
845
|
-
for (
|
|
846
|
-
const next = fragment(
|
|
847
|
-
const operator =
|
|
894
|
+
for (const condition of remaining) {
|
|
895
|
+
const next = fragment(condition, schema);
|
|
896
|
+
const operator = condition.connector === "or" ? "OR" : "AND";
|
|
848
897
|
clause = "(" + clause + " " + operator + " " + next.sql + ")";
|
|
849
898
|
params.push(...next.params);
|
|
850
899
|
}
|
|
@@ -961,18 +1010,6 @@ function compileCriteria(criteria, schema) {
|
|
|
961
1010
|
};
|
|
962
1011
|
}
|
|
963
1012
|
//#endregion
|
|
964
|
-
//#region src/server/constants.ts
|
|
965
|
-
/**
|
|
966
|
-
* The reserved metadata table the {@link SQLiteDriver} creates on `open` to
|
|
967
|
-
* persist its stamped `DriverMeta` (`version` + declared schema JSON) — the
|
|
968
|
-
* SQLite realization of the `meta` / `stamp` driver hooks.
|
|
969
|
-
*
|
|
970
|
-
* @remarks
|
|
971
|
-
* A single-row table (`id = 1`). A user table named `_meta` collides with the
|
|
972
|
-
* reservation — the caller's concern to avoid, documented on the driver class.
|
|
973
|
-
*/
|
|
974
|
-
var META_TABLE = "_meta";
|
|
975
|
-
//#endregion
|
|
976
1013
|
//#region src/server/drivers/JSONDriver.ts
|
|
977
1014
|
/**
|
|
978
1015
|
* A persistent {@link DriverInterface} backed by a single JSON file — the
|
|
@@ -1012,6 +1049,7 @@ var JSONDriver = class {
|
|
|
1012
1049
|
#flushCount = 0;
|
|
1013
1050
|
#chain = Promise.resolve();
|
|
1014
1051
|
#deferring = false;
|
|
1052
|
+
#transaction;
|
|
1015
1053
|
constructor(path) {
|
|
1016
1054
|
this.#path = path;
|
|
1017
1055
|
}
|
|
@@ -1080,22 +1118,12 @@ var JSONDriver = class {
|
|
|
1080
1118
|
async transaction() {
|
|
1081
1119
|
if (this.#deferring) throw new DatabaseError("CONFLICT", "A transaction is already active on this driver", {});
|
|
1082
1120
|
const rollback = await this.#memory.snapshot();
|
|
1121
|
+
const token = {};
|
|
1083
1122
|
this.#deferring = true;
|
|
1084
|
-
|
|
1123
|
+
this.#transaction = token;
|
|
1085
1124
|
return {
|
|
1086
|
-
commit:
|
|
1087
|
-
|
|
1088
|
-
settled = true;
|
|
1089
|
-
this.#deferring = false;
|
|
1090
|
-
await this.#flush();
|
|
1091
|
-
},
|
|
1092
|
-
rollback: async () => {
|
|
1093
|
-
if (settled) throw new DatabaseError("CONFLICT", "Transaction already settled", {});
|
|
1094
|
-
settled = true;
|
|
1095
|
-
await rollback();
|
|
1096
|
-
this.#deferring = false;
|
|
1097
|
-
await this.#flush();
|
|
1098
|
-
}
|
|
1125
|
+
commit: this.#commit.bind(this, token),
|
|
1126
|
+
rollback: this.#rollback.bind(this, token, rollback)
|
|
1099
1127
|
};
|
|
1100
1128
|
}
|
|
1101
1129
|
async snapshot(tables) {
|
|
@@ -1148,6 +1176,19 @@ var JSONDriver = class {
|
|
|
1148
1176
|
this.#schema = schema;
|
|
1149
1177
|
await this.#flush();
|
|
1150
1178
|
}
|
|
1179
|
+
async #commit(token) {
|
|
1180
|
+
if (this.#transaction !== token) throw new DatabaseError("CONFLICT", "Transaction already settled", {});
|
|
1181
|
+
this.#transaction = void 0;
|
|
1182
|
+
this.#deferring = false;
|
|
1183
|
+
await this.#flush();
|
|
1184
|
+
}
|
|
1185
|
+
async #rollback(token, rollback) {
|
|
1186
|
+
if (this.#transaction !== token) throw new DatabaseError("CONFLICT", "Transaction already settled", {});
|
|
1187
|
+
this.#transaction = void 0;
|
|
1188
|
+
await rollback();
|
|
1189
|
+
this.#deferring = false;
|
|
1190
|
+
await this.#flush();
|
|
1191
|
+
}
|
|
1151
1192
|
async #load() {
|
|
1152
1193
|
let raw;
|
|
1153
1194
|
try {
|
|
@@ -1260,7 +1301,7 @@ var SQLiteDriver = class {
|
|
|
1260
1301
|
#options;
|
|
1261
1302
|
#database;
|
|
1262
1303
|
#schema = /* @__PURE__ */ new Map();
|
|
1263
|
-
#
|
|
1304
|
+
#transaction;
|
|
1264
1305
|
constructor(path, options) {
|
|
1265
1306
|
this.#path = path;
|
|
1266
1307
|
this.#options = options ?? {};
|
|
@@ -1271,9 +1312,9 @@ var SQLiteDriver = class {
|
|
|
1271
1312
|
this.#database?.close();
|
|
1272
1313
|
const database = createSQLiteDatabase({
|
|
1273
1314
|
path: this.#path,
|
|
1274
|
-
readonly: this.#options.readonly,
|
|
1275
|
-
timeout: this.#options.timeout,
|
|
1276
|
-
foreignKeys: this.#options.foreignKeys
|
|
1315
|
+
...this.#options.readonly !== void 0 ? { readonly: this.#options.readonly } : {},
|
|
1316
|
+
...this.#options.timeout !== void 0 ? { timeout: this.#options.timeout } : {},
|
|
1317
|
+
...this.#options.foreignKeys !== void 0 ? { foreignKeys: this.#options.foreignKeys } : {}
|
|
1277
1318
|
});
|
|
1278
1319
|
database.connect();
|
|
1279
1320
|
for (const [name, value] of Object.entries(this.#options.pragmas ?? {})) database.pragma(name, value);
|
|
@@ -1307,7 +1348,7 @@ var SQLiteDriver = class {
|
|
|
1307
1348
|
[schema.primary]: key
|
|
1308
1349
|
}, schema);
|
|
1309
1350
|
const names = schema.columns.map((column) => column.name);
|
|
1310
|
-
const values =
|
|
1351
|
+
const values = extractValues(encoded, names, table);
|
|
1311
1352
|
this.#require().prepare("INSERT OR REPLACE INTO " + quote(table) + " (" + names.map(quote).join(", ") + ") VALUES (" + names.map(() => "?").join(", ") + ")").run(values);
|
|
1312
1353
|
});
|
|
1313
1354
|
}
|
|
@@ -1387,8 +1428,8 @@ var SQLiteDriver = class {
|
|
|
1387
1428
|
if (conditions.every((condition) => isExactCondition(condition, schema))) {
|
|
1388
1429
|
const compiled = compileCriteria({
|
|
1389
1430
|
conditions,
|
|
1390
|
-
limit: criteria.limit,
|
|
1391
|
-
offset: criteria.offset
|
|
1431
|
+
...criteria.limit !== void 0 ? { limit: criteria.limit } : {},
|
|
1432
|
+
...criteria.offset !== void 0 ? { offset: criteria.offset } : {}
|
|
1392
1433
|
}, schema);
|
|
1393
1434
|
for (const row of this.#require().prepare("SELECT * FROM " + quote(table) + (compiled.sql === "" ? "" : " " + compiled.sql)).iterate(compiled.params)) yield decodeRow(row, schema);
|
|
1394
1435
|
return;
|
|
@@ -1420,21 +1461,11 @@ var SQLiteDriver = class {
|
|
|
1420
1461
|
async transaction() {
|
|
1421
1462
|
const database = this.#require();
|
|
1422
1463
|
this.#guard(() => database.exec("BEGIN"));
|
|
1423
|
-
|
|
1424
|
-
this.#
|
|
1464
|
+
const token = {};
|
|
1465
|
+
this.#transaction = token;
|
|
1425
1466
|
return {
|
|
1426
|
-
commit:
|
|
1427
|
-
|
|
1428
|
-
settled = true;
|
|
1429
|
-
this.#transacting = false;
|
|
1430
|
-
this.#guard(() => database.exec("COMMIT"));
|
|
1431
|
-
},
|
|
1432
|
-
rollback: async () => {
|
|
1433
|
-
if (settled) throw new DatabaseError("CONFLICT", "Transaction already settled", {});
|
|
1434
|
-
settled = true;
|
|
1435
|
-
this.#transacting = false;
|
|
1436
|
-
this.#guard(() => database.exec("ROLLBACK"));
|
|
1437
|
-
}
|
|
1467
|
+
commit: this.#commit.bind(this, token, database),
|
|
1468
|
+
rollback: this.#rollback.bind(this, token, database)
|
|
1438
1469
|
};
|
|
1439
1470
|
}
|
|
1440
1471
|
/**
|
|
@@ -1464,7 +1495,7 @@ var SQLiteDriver = class {
|
|
|
1464
1495
|
const database = this.#require();
|
|
1465
1496
|
const schema = new Map(this.#schema);
|
|
1466
1497
|
this.#guard(() => {
|
|
1467
|
-
if (this.#
|
|
1498
|
+
if (this.#transaction !== void 0) this.#applyPlan(database, plan, schema);
|
|
1468
1499
|
else database.transaction(() => this.#applyPlan(database, plan, schema));
|
|
1469
1500
|
});
|
|
1470
1501
|
this.#schema = schema;
|
|
@@ -1524,11 +1555,21 @@ var SQLiteDriver = class {
|
|
|
1524
1555
|
for (const [name, snapshot] of captured) {
|
|
1525
1556
|
current.exec("DELETE FROM " + quote(name));
|
|
1526
1557
|
const statement = current.prepare("INSERT OR REPLACE INTO " + quote(name) + " (" + snapshot.names.map(quote).join(", ") + ") VALUES (" + snapshot.names.map(() => "?").join(", ") + ")");
|
|
1527
|
-
for (const row of snapshot.rows) statement.run(snapshot.names
|
|
1558
|
+
for (const row of snapshot.rows) statement.run(extractValues(row, snapshot.names, name));
|
|
1528
1559
|
}
|
|
1529
1560
|
});
|
|
1530
1561
|
};
|
|
1531
1562
|
}
|
|
1563
|
+
async #commit(token, database) {
|
|
1564
|
+
if (this.#transaction !== token) throw new DatabaseError("CONFLICT", "Transaction already settled", {});
|
|
1565
|
+
this.#transaction = void 0;
|
|
1566
|
+
this.#guard(() => database.exec("COMMIT"));
|
|
1567
|
+
}
|
|
1568
|
+
async #rollback(token, database) {
|
|
1569
|
+
if (this.#transaction !== token) throw new DatabaseError("CONFLICT", "Transaction already settled", {});
|
|
1570
|
+
this.#transaction = void 0;
|
|
1571
|
+
this.#guard(() => database.exec("ROLLBACK"));
|
|
1572
|
+
}
|
|
1532
1573
|
#guard(run) {
|
|
1533
1574
|
try {
|
|
1534
1575
|
return run();
|
|
@@ -1658,6 +1699,6 @@ function createSQLiteDriver(options = ":memory:") {
|
|
|
1658
1699
|
return new SQLiteDriver(resolved.path ?? ":memory:", resolved);
|
|
1659
1700
|
}
|
|
1660
1701
|
//#endregion
|
|
1661
|
-
export { EXACT_COLUMN_TYPES, EXACT_RANGE_COLUMN_TYPES, JSONDriver, META_TABLE, SQLiteDriver, aggregateSQL, columnSQL, compileCriteria, compileOrder, compilePage, compileWhere, createJSONDriver, createSQLiteDriver, declaredType, decodeRow, decodeValue, encodeRow, encodeValue, escapeLike, fieldColumn, fragment, generateKey, indexName, isExactCondition, isExactCriteria, isExactOrder, jsonTypeColumn, matchesDeclaredType, quote, schemaToIndexes, schemaToTable, stepToSQL, stepToSchema, valueType };
|
|
1702
|
+
export { EXACT_COLUMN_TYPES, EXACT_RANGE_COLUMN_TYPES, JSONDriver, META_TABLE, SQLiteDriver, aggregateSQL, columnSQL, compileCriteria, compileOrder, compilePage, compileWhere, createJSONDriver, createSQLiteDriver, declaredType, decodeRow, decodeValue, encodeRow, encodeValue, escapeLike, extractValues, fieldColumn, fragment, generateKey, indexName, isExactCondition, isExactCriteria, isExactOrder, jsonTypeColumn, matchesDeclaredType, quote, schemaToIndexes, schemaToTable, stepToSQL, stepToSchema, valueType };
|
|
1662
1703
|
|
|
1663
1704
|
//# sourceMappingURL=index.js.map
|