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