@b9g/zen 0.1.0 → 0.1.1
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/CHANGELOG.md +23 -0
- package/README.md +32 -12
- package/{chunk-QXGEP5PB.js → chunk-CHF7L5PC.js} +27 -2
- package/chunk-W7JTNEM4.js +63 -0
- package/{chunk-56M5Z3A6.js → chunk-XHXMCOSW.js} +176 -4
- package/ddl-2A2UFUR3.js +11 -0
- package/package.json +1 -1
- package/src/bun.d.ts +12 -1
- package/src/bun.js +137 -5
- package/src/mysql.d.ts +12 -0
- package/src/mysql.js +121 -4
- package/src/postgres.d.ts +12 -0
- package/src/postgres.js +101 -4
- package/src/sqlite.d.ts +12 -1
- package/src/sqlite.js +113 -4
- package/src/zen.d.ts +1 -1
- package/src/zen.js +190 -49
- package/chunk-2IEEEMRN.js +0 -38
- package/ddl-NAJM37GQ.js +0 -9
package/src/zen.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/// <reference types="./zen.d.ts" />
|
|
2
|
-
import "../chunk-
|
|
2
|
+
import "../chunk-W7JTNEM4.js";
|
|
3
3
|
import {
|
|
4
4
|
AlreadyExistsError,
|
|
5
5
|
CURRENT_DATE,
|
|
@@ -20,19 +20,25 @@ import {
|
|
|
20
20
|
TableDefinitionError,
|
|
21
21
|
TransactionError,
|
|
22
22
|
ValidationError,
|
|
23
|
+
createTemplate,
|
|
23
24
|
decodeData,
|
|
24
25
|
extendZod,
|
|
26
|
+
getTableMeta,
|
|
27
|
+
getViewMeta,
|
|
25
28
|
hasErrorCode,
|
|
26
29
|
ident,
|
|
30
|
+
inferFieldType,
|
|
27
31
|
isDatabaseError,
|
|
28
32
|
isSQLBuiltin,
|
|
29
33
|
isSQLIdentifier,
|
|
30
34
|
isSQLTemplate,
|
|
35
|
+
isView,
|
|
31
36
|
makeTemplate,
|
|
32
37
|
resolveSQLBuiltin,
|
|
33
38
|
table,
|
|
34
|
-
validateWithStandardSchema
|
|
35
|
-
|
|
39
|
+
validateWithStandardSchema,
|
|
40
|
+
view
|
|
41
|
+
} from "../chunk-XHXMCOSW.js";
|
|
36
42
|
|
|
37
43
|
// src/zen.ts
|
|
38
44
|
import { z as zod } from "zod";
|
|
@@ -67,7 +73,7 @@ function getPrimaryKeyValue(entity, table2) {
|
|
|
67
73
|
function entityKey(tableName, primaryKey) {
|
|
68
74
|
return `${tableName}:${primaryKey}`;
|
|
69
75
|
}
|
|
70
|
-
function buildEntityMap(rows, tables) {
|
|
76
|
+
function buildEntityMap(rows, tables, driver) {
|
|
71
77
|
const entities = /* @__PURE__ */ new Map();
|
|
72
78
|
for (const row of rows) {
|
|
73
79
|
for (const table2 of tables) {
|
|
@@ -79,7 +85,7 @@ function buildEntityMap(rows, tables) {
|
|
|
79
85
|
continue;
|
|
80
86
|
const key = entityKey(table2.name, pk);
|
|
81
87
|
if (!entities.has(key)) {
|
|
82
|
-
const decoded = decodeData(table2, data);
|
|
88
|
+
const decoded = decodeData(table2, data, driver);
|
|
83
89
|
const parsed = validateWithStandardSchema(
|
|
84
90
|
table2.schema,
|
|
85
91
|
decoded
|
|
@@ -235,7 +241,7 @@ function validateRegisteredTables(rows, tables) {
|
|
|
235
241
|
);
|
|
236
242
|
}
|
|
237
243
|
}
|
|
238
|
-
function normalize(rows, tables) {
|
|
244
|
+
function normalize(rows, tables, driver) {
|
|
239
245
|
if (tables.length === 0) {
|
|
240
246
|
throw new Error("At least one table is required");
|
|
241
247
|
}
|
|
@@ -243,16 +249,16 @@ function normalize(rows, tables) {
|
|
|
243
249
|
return [];
|
|
244
250
|
}
|
|
245
251
|
validateRegisteredTables(rows, tables);
|
|
246
|
-
const entities = buildEntityMap(rows, tables);
|
|
252
|
+
const entities = buildEntityMap(rows, tables, driver);
|
|
247
253
|
resolveReferences(entities, tables);
|
|
248
254
|
applyDerivedProperties(entities, tables);
|
|
249
255
|
const mainTable = tables[0];
|
|
250
256
|
return extractMainEntities(rows, mainTable, entities);
|
|
251
257
|
}
|
|
252
|
-
function normalizeOne(row, tables) {
|
|
258
|
+
function normalizeOne(row, tables, driver) {
|
|
253
259
|
if (!row)
|
|
254
260
|
return null;
|
|
255
|
-
const results = normalize([row], tables);
|
|
261
|
+
const results = normalize([row], tables, driver);
|
|
256
262
|
return results[0] ?? null;
|
|
257
263
|
}
|
|
258
264
|
|
|
@@ -318,7 +324,7 @@ function injectSchemaExpressions(table2, data, operation) {
|
|
|
318
324
|
}
|
|
319
325
|
return result;
|
|
320
326
|
}
|
|
321
|
-
function encodeData(table2, data) {
|
|
327
|
+
function encodeData(table2, data, driver) {
|
|
322
328
|
const encoded = {};
|
|
323
329
|
const shape = table2.schema.shape;
|
|
324
330
|
for (const [key, value] of Object.entries(data)) {
|
|
@@ -326,16 +332,21 @@ function encodeData(table2, data) {
|
|
|
326
332
|
const fieldSchema = shape?.[key];
|
|
327
333
|
if (fieldMeta?.encode && typeof fieldMeta.encode === "function") {
|
|
328
334
|
encoded[key] = fieldMeta.encode(value);
|
|
335
|
+
} else if (driver?.encodeValue && fieldSchema) {
|
|
336
|
+
const fieldType = inferFieldType(fieldSchema);
|
|
337
|
+
encoded[key] = driver.encodeValue(value, fieldType);
|
|
329
338
|
} else if (fieldSchema) {
|
|
330
339
|
let core = fieldSchema;
|
|
331
340
|
while (typeof core.unwrap === "function") {
|
|
332
|
-
if (core instanceof z.ZodArray || core instanceof z.ZodObject) {
|
|
341
|
+
if (core instanceof z.ZodArray || core instanceof z.ZodObject || core instanceof z.ZodDate) {
|
|
333
342
|
break;
|
|
334
343
|
}
|
|
335
344
|
core = core.unwrap();
|
|
336
345
|
}
|
|
337
346
|
if ((core instanceof z.ZodObject || core instanceof z.ZodArray) && value !== null && value !== void 0) {
|
|
338
347
|
encoded[key] = JSON.stringify(value);
|
|
348
|
+
} else if (core instanceof z.ZodDate && value instanceof Date && !isNaN(value.getTime())) {
|
|
349
|
+
encoded[key] = value.toISOString().replace("T", " ").replace("Z", "");
|
|
339
350
|
} else {
|
|
340
351
|
encoded[key] = value;
|
|
341
352
|
}
|
|
@@ -345,6 +356,14 @@ function encodeData(table2, data) {
|
|
|
345
356
|
}
|
|
346
357
|
return encoded;
|
|
347
358
|
}
|
|
359
|
+
function assertNotView(table2, operation) {
|
|
360
|
+
const meta = getTableMeta(table2);
|
|
361
|
+
if (meta.isView) {
|
|
362
|
+
throw new Error(
|
|
363
|
+
`Cannot ${operation} on view "${table2.name}". Views are read-only. Use the base table "${meta.viewOf}" for mutations.`
|
|
364
|
+
);
|
|
365
|
+
}
|
|
366
|
+
}
|
|
348
367
|
function mergeExpression(baseStrings, baseValues, expr) {
|
|
349
368
|
baseStrings[baseStrings.length - 1] += expr.strings[0];
|
|
350
369
|
for (let i = 1; i < expr.strings.length; i++) {
|
|
@@ -600,6 +619,7 @@ var Transaction = class {
|
|
|
600
619
|
}
|
|
601
620
|
all(tables) {
|
|
602
621
|
const tableArray = Array.isArray(tables) ? tables : [tables];
|
|
622
|
+
const primaryTable = tableArray[0];
|
|
603
623
|
return async (strings, ...values) => {
|
|
604
624
|
const { strings: colStrings, values: colValues } = buildSelectCols(tableArray);
|
|
605
625
|
const { strings: expandedStrings, values: expandedValues } = expandFragments(strings, values);
|
|
@@ -611,7 +631,7 @@ var Transaction = class {
|
|
|
611
631
|
}
|
|
612
632
|
queryValues.push(...colValues);
|
|
613
633
|
queryStrings[queryStrings.length - 1] += " FROM ";
|
|
614
|
-
queryValues.push(ident(
|
|
634
|
+
queryValues.push(ident(primaryTable.name));
|
|
615
635
|
queryStrings.push(" ");
|
|
616
636
|
queryStrings[queryStrings.length - 1] += expandedStrings[0];
|
|
617
637
|
for (let i = 1; i < expandedStrings.length; i++) {
|
|
@@ -622,7 +642,7 @@ var Transaction = class {
|
|
|
622
642
|
makeTemplate(queryStrings),
|
|
623
643
|
queryValues
|
|
624
644
|
);
|
|
625
|
-
return normalize(rows, tableArray);
|
|
645
|
+
return normalize(rows, tableArray, this.#driver);
|
|
626
646
|
};
|
|
627
647
|
}
|
|
628
648
|
get(tables, id) {
|
|
@@ -638,10 +658,11 @@ var Transaction = class {
|
|
|
638
658
|
return this.#driver.get(strings, values).then((row) => {
|
|
639
659
|
if (!row)
|
|
640
660
|
return null;
|
|
641
|
-
return decodeData(table2, row);
|
|
661
|
+
return decodeData(table2, row, this.#driver);
|
|
642
662
|
});
|
|
643
663
|
}
|
|
644
664
|
const tableArray = Array.isArray(tables) ? tables : [tables];
|
|
665
|
+
const primaryTable = tableArray[0];
|
|
645
666
|
return async (strings, ...values) => {
|
|
646
667
|
const { strings: colStrings, values: colValues } = buildSelectCols(tableArray);
|
|
647
668
|
const { strings: expandedStrings, values: expandedValues } = expandFragments(strings, values);
|
|
@@ -653,7 +674,7 @@ var Transaction = class {
|
|
|
653
674
|
}
|
|
654
675
|
queryValues.push(...colValues);
|
|
655
676
|
queryStrings[queryStrings.length - 1] += " FROM ";
|
|
656
|
-
queryValues.push(ident(
|
|
677
|
+
queryValues.push(ident(primaryTable.name));
|
|
657
678
|
queryStrings.push(" ");
|
|
658
679
|
queryStrings[queryStrings.length - 1] += expandedStrings[0];
|
|
659
680
|
for (let i = 1; i < expandedStrings.length; i++) {
|
|
@@ -664,10 +685,15 @@ var Transaction = class {
|
|
|
664
685
|
makeTemplate(queryStrings),
|
|
665
686
|
queryValues
|
|
666
687
|
);
|
|
667
|
-
return normalizeOne(
|
|
688
|
+
return normalizeOne(
|
|
689
|
+
row,
|
|
690
|
+
tableArray,
|
|
691
|
+
this.#driver
|
|
692
|
+
);
|
|
668
693
|
};
|
|
669
694
|
}
|
|
670
695
|
async insert(table2, data) {
|
|
696
|
+
assertNotView(table2, "insert");
|
|
671
697
|
if (Array.isArray(data)) {
|
|
672
698
|
if (data.length === 0) {
|
|
673
699
|
return [];
|
|
@@ -716,7 +742,7 @@ var Transaction = class {
|
|
|
716
742
|
schema,
|
|
717
743
|
regularData
|
|
718
744
|
);
|
|
719
|
-
const encoded = encodeData(table2, validated);
|
|
745
|
+
const encoded = encodeData(table2, validated, this.#driver);
|
|
720
746
|
const insertParts = buildInsertParts(
|
|
721
747
|
table2.name,
|
|
722
748
|
encoded,
|
|
@@ -729,7 +755,7 @@ var Transaction = class {
|
|
|
729
755
|
strings,
|
|
730
756
|
values
|
|
731
757
|
);
|
|
732
|
-
return decodeData(table2, row);
|
|
758
|
+
return decodeData(table2, row, this.#driver);
|
|
733
759
|
}
|
|
734
760
|
await this.#driver.run(insertParts.strings, insertParts.values);
|
|
735
761
|
const pk = table2.meta.primary;
|
|
@@ -741,12 +767,13 @@ var Transaction = class {
|
|
|
741
767
|
values
|
|
742
768
|
);
|
|
743
769
|
if (row) {
|
|
744
|
-
return decodeData(table2, row);
|
|
770
|
+
return decodeData(table2, row, this.#driver);
|
|
745
771
|
}
|
|
746
772
|
}
|
|
747
773
|
return validated;
|
|
748
774
|
}
|
|
749
775
|
update(table2, data, idOrIds) {
|
|
776
|
+
assertNotView(table2, "update");
|
|
750
777
|
if (idOrIds === void 0) {
|
|
751
778
|
return async (strings, ...values) => {
|
|
752
779
|
return this.#updateWithWhere(table2, data, strings, values);
|
|
@@ -789,7 +816,7 @@ var Transaction = class {
|
|
|
789
816
|
if (allColumns.length === 0) {
|
|
790
817
|
throw new Error("No fields to update");
|
|
791
818
|
}
|
|
792
|
-
const encoded = encodeData(table2, validated);
|
|
819
|
+
const encoded = encodeData(table2, validated, this.#driver);
|
|
793
820
|
const updateParts = buildUpdateByIdParts(
|
|
794
821
|
table2.name,
|
|
795
822
|
pk,
|
|
@@ -806,7 +833,7 @@ var Transaction = class {
|
|
|
806
833
|
);
|
|
807
834
|
if (!row2)
|
|
808
835
|
return null;
|
|
809
|
-
return decodeData(table2, row2);
|
|
836
|
+
return decodeData(table2, row2, this.#driver);
|
|
810
837
|
}
|
|
811
838
|
await this.#driver.run(updateParts.strings, updateParts.values);
|
|
812
839
|
const { strings: selectStrings, values: selectValues } = buildSelectByPkParts(
|
|
@@ -820,7 +847,7 @@ var Transaction = class {
|
|
|
820
847
|
);
|
|
821
848
|
if (!row)
|
|
822
849
|
return null;
|
|
823
|
-
return decodeData(table2, row);
|
|
850
|
+
return decodeData(table2, row, this.#driver);
|
|
824
851
|
}
|
|
825
852
|
async #updateByIds(table2, data, ids) {
|
|
826
853
|
if (ids.length === 0) {
|
|
@@ -857,7 +884,7 @@ var Transaction = class {
|
|
|
857
884
|
if (allColumns.length === 0) {
|
|
858
885
|
throw new Error("No fields to update");
|
|
859
886
|
}
|
|
860
|
-
const encoded = encodeData(table2, validated);
|
|
887
|
+
const encoded = encodeData(table2, validated, this.#driver);
|
|
861
888
|
const updateParts = buildUpdateByIdsParts(
|
|
862
889
|
table2.name,
|
|
863
890
|
pk,
|
|
@@ -874,7 +901,7 @@ var Transaction = class {
|
|
|
874
901
|
);
|
|
875
902
|
const resultMap2 = /* @__PURE__ */ new Map();
|
|
876
903
|
for (const row of rows2) {
|
|
877
|
-
const entity = decodeData(table2, row);
|
|
904
|
+
const entity = decodeData(table2, row, this.#driver);
|
|
878
905
|
resultMap2.set(row[pk], entity);
|
|
879
906
|
}
|
|
880
907
|
return ids.map((id) => resultMap2.get(id) ?? null);
|
|
@@ -887,7 +914,7 @@ var Transaction = class {
|
|
|
887
914
|
);
|
|
888
915
|
const resultMap = /* @__PURE__ */ new Map();
|
|
889
916
|
for (const row of rows) {
|
|
890
|
-
const entity = decodeData(table2, row);
|
|
917
|
+
const entity = decodeData(table2, row, this.#driver);
|
|
891
918
|
resultMap.set(row[pk], entity);
|
|
892
919
|
}
|
|
893
920
|
return ids.map((id) => resultMap.get(id) ?? null);
|
|
@@ -920,7 +947,7 @@ var Transaction = class {
|
|
|
920
947
|
if (allColumns.length === 0) {
|
|
921
948
|
throw new Error("No fields to update");
|
|
922
949
|
}
|
|
923
|
-
const encoded = encodeData(table2, validated);
|
|
950
|
+
const encoded = encodeData(table2, validated, this.#driver);
|
|
924
951
|
const { strings: whereStrings, values: whereValues } = expandFragments(
|
|
925
952
|
strings,
|
|
926
953
|
templateValues
|
|
@@ -957,7 +984,7 @@ var Transaction = class {
|
|
|
957
984
|
makeTemplate(queryStrings),
|
|
958
985
|
queryValues
|
|
959
986
|
);
|
|
960
|
-
return rows2.map((row) => decodeData(table2, row));
|
|
987
|
+
return rows2.map((row) => decodeData(table2, row, this.#driver));
|
|
961
988
|
}
|
|
962
989
|
const selectIdStrings = ["SELECT "];
|
|
963
990
|
const selectIdValues = [];
|
|
@@ -987,9 +1014,10 @@ var Transaction = class {
|
|
|
987
1014
|
selectStrings,
|
|
988
1015
|
selectVals
|
|
989
1016
|
);
|
|
990
|
-
return rows.map((row) => decodeData(table2, row));
|
|
1017
|
+
return rows.map((row) => decodeData(table2, row, this.#driver));
|
|
991
1018
|
}
|
|
992
1019
|
delete(table2, idOrIds) {
|
|
1020
|
+
assertNotView(table2, "delete");
|
|
993
1021
|
if (idOrIds === void 0) {
|
|
994
1022
|
return async (strings, ...values) => {
|
|
995
1023
|
const { strings: expandedStrings, values: expandedValues } = expandFragments(strings, values);
|
|
@@ -1028,6 +1056,7 @@ var Transaction = class {
|
|
|
1028
1056
|
return this.#driver.run(strings, values);
|
|
1029
1057
|
}
|
|
1030
1058
|
softDelete(table2, idOrIds) {
|
|
1059
|
+
assertNotView(table2, "softDelete");
|
|
1031
1060
|
const softDeleteField = table2.meta.softDeleteField;
|
|
1032
1061
|
if (!softDeleteField) {
|
|
1033
1062
|
throw new Error(
|
|
@@ -1205,9 +1234,11 @@ var Database = class extends EventTarget {
|
|
|
1205
1234
|
#driver;
|
|
1206
1235
|
#version = 0;
|
|
1207
1236
|
#opened = false;
|
|
1208
|
-
|
|
1237
|
+
#tables = [];
|
|
1238
|
+
constructor(driver, options) {
|
|
1209
1239
|
super();
|
|
1210
1240
|
this.#driver = driver;
|
|
1241
|
+
this.#tables = options?.tables ?? [];
|
|
1211
1242
|
}
|
|
1212
1243
|
/**
|
|
1213
1244
|
* Current database schema version.
|
|
@@ -1284,6 +1315,7 @@ var Database = class extends EventTarget {
|
|
|
1284
1315
|
}
|
|
1285
1316
|
all(tables) {
|
|
1286
1317
|
const tableArray = Array.isArray(tables) ? tables : [tables];
|
|
1318
|
+
const primaryTable = tableArray[0];
|
|
1287
1319
|
return async (strings, ...values) => {
|
|
1288
1320
|
const { strings: colStrings, values: colValues } = buildSelectCols(tableArray);
|
|
1289
1321
|
const { strings: expandedStrings, values: expandedValues } = expandFragments(strings, values);
|
|
@@ -1295,7 +1327,7 @@ var Database = class extends EventTarget {
|
|
|
1295
1327
|
}
|
|
1296
1328
|
queryValues.push(...colValues);
|
|
1297
1329
|
queryStrings[queryStrings.length - 1] += " FROM ";
|
|
1298
|
-
queryValues.push(ident(
|
|
1330
|
+
queryValues.push(ident(primaryTable.name));
|
|
1299
1331
|
queryStrings.push(" ");
|
|
1300
1332
|
queryStrings[queryStrings.length - 1] += expandedStrings[0];
|
|
1301
1333
|
for (let i = 1; i < expandedStrings.length; i++) {
|
|
@@ -1306,7 +1338,7 @@ var Database = class extends EventTarget {
|
|
|
1306
1338
|
makeTemplate(queryStrings),
|
|
1307
1339
|
queryValues
|
|
1308
1340
|
);
|
|
1309
|
-
return normalize(rows, tableArray);
|
|
1341
|
+
return normalize(rows, tableArray, this.#driver);
|
|
1310
1342
|
};
|
|
1311
1343
|
}
|
|
1312
1344
|
get(tables, id) {
|
|
@@ -1322,10 +1354,11 @@ var Database = class extends EventTarget {
|
|
|
1322
1354
|
return this.#driver.get(strings, values).then((row) => {
|
|
1323
1355
|
if (!row)
|
|
1324
1356
|
return null;
|
|
1325
|
-
return decodeData(table2, row);
|
|
1357
|
+
return decodeData(table2, row, this.#driver);
|
|
1326
1358
|
});
|
|
1327
1359
|
}
|
|
1328
1360
|
const tableArray = Array.isArray(tables) ? tables : [tables];
|
|
1361
|
+
const primaryTable = tableArray[0];
|
|
1329
1362
|
return async (strings, ...values) => {
|
|
1330
1363
|
const { strings: colStrings, values: colValues } = buildSelectCols(tableArray);
|
|
1331
1364
|
const { strings: expandedStrings, values: expandedValues } = expandFragments(strings, values);
|
|
@@ -1337,7 +1370,7 @@ var Database = class extends EventTarget {
|
|
|
1337
1370
|
}
|
|
1338
1371
|
queryValues.push(...colValues);
|
|
1339
1372
|
queryStrings[queryStrings.length - 1] += " FROM ";
|
|
1340
|
-
queryValues.push(ident(
|
|
1373
|
+
queryValues.push(ident(primaryTable.name));
|
|
1341
1374
|
queryStrings.push(" ");
|
|
1342
1375
|
queryStrings[queryStrings.length - 1] += expandedStrings[0];
|
|
1343
1376
|
for (let i = 1; i < expandedStrings.length; i++) {
|
|
@@ -1348,10 +1381,15 @@ var Database = class extends EventTarget {
|
|
|
1348
1381
|
makeTemplate(queryStrings),
|
|
1349
1382
|
queryValues
|
|
1350
1383
|
);
|
|
1351
|
-
return normalizeOne(
|
|
1384
|
+
return normalizeOne(
|
|
1385
|
+
row,
|
|
1386
|
+
tableArray,
|
|
1387
|
+
this.#driver
|
|
1388
|
+
);
|
|
1352
1389
|
};
|
|
1353
1390
|
}
|
|
1354
1391
|
async insert(table2, data) {
|
|
1392
|
+
assertNotView(table2, "insert");
|
|
1355
1393
|
if (Array.isArray(data)) {
|
|
1356
1394
|
if (data.length === 0) {
|
|
1357
1395
|
return [];
|
|
@@ -1400,7 +1438,7 @@ var Database = class extends EventTarget {
|
|
|
1400
1438
|
schema,
|
|
1401
1439
|
regularData
|
|
1402
1440
|
);
|
|
1403
|
-
const encoded = encodeData(table2, validated);
|
|
1441
|
+
const encoded = encodeData(table2, validated, this.#driver);
|
|
1404
1442
|
const insertParts = buildInsertParts(
|
|
1405
1443
|
table2.name,
|
|
1406
1444
|
encoded,
|
|
@@ -1413,7 +1451,7 @@ var Database = class extends EventTarget {
|
|
|
1413
1451
|
strings,
|
|
1414
1452
|
values
|
|
1415
1453
|
);
|
|
1416
|
-
return decodeData(table2, row);
|
|
1454
|
+
return decodeData(table2, row, this.#driver);
|
|
1417
1455
|
}
|
|
1418
1456
|
await this.#driver.run(insertParts.strings, insertParts.values);
|
|
1419
1457
|
const pk = table2.meta.primary;
|
|
@@ -1425,12 +1463,13 @@ var Database = class extends EventTarget {
|
|
|
1425
1463
|
values
|
|
1426
1464
|
);
|
|
1427
1465
|
if (row) {
|
|
1428
|
-
return decodeData(table2, row);
|
|
1466
|
+
return decodeData(table2, row, this.#driver);
|
|
1429
1467
|
}
|
|
1430
1468
|
}
|
|
1431
1469
|
return validated;
|
|
1432
1470
|
}
|
|
1433
1471
|
update(table2, data, idOrIds) {
|
|
1472
|
+
assertNotView(table2, "update");
|
|
1434
1473
|
if (idOrIds === void 0) {
|
|
1435
1474
|
return async (strings, ...values) => {
|
|
1436
1475
|
return this.#updateWithWhere(table2, data, strings, values);
|
|
@@ -1473,7 +1512,7 @@ var Database = class extends EventTarget {
|
|
|
1473
1512
|
if (allColumns.length === 0) {
|
|
1474
1513
|
throw new Error("No fields to update");
|
|
1475
1514
|
}
|
|
1476
|
-
const encoded = encodeData(table2, validated);
|
|
1515
|
+
const encoded = encodeData(table2, validated, this.#driver);
|
|
1477
1516
|
const updateParts = buildUpdateByIdParts(
|
|
1478
1517
|
table2.name,
|
|
1479
1518
|
pk,
|
|
@@ -1490,7 +1529,7 @@ var Database = class extends EventTarget {
|
|
|
1490
1529
|
);
|
|
1491
1530
|
if (!row2)
|
|
1492
1531
|
return null;
|
|
1493
|
-
return decodeData(table2, row2);
|
|
1532
|
+
return decodeData(table2, row2, this.#driver);
|
|
1494
1533
|
}
|
|
1495
1534
|
await this.#driver.run(updateParts.strings, updateParts.values);
|
|
1496
1535
|
const { strings: selectStrings, values: selectValues } = buildSelectByPkParts(
|
|
@@ -1504,7 +1543,7 @@ var Database = class extends EventTarget {
|
|
|
1504
1543
|
);
|
|
1505
1544
|
if (!row)
|
|
1506
1545
|
return null;
|
|
1507
|
-
return decodeData(table2, row);
|
|
1546
|
+
return decodeData(table2, row, this.#driver);
|
|
1508
1547
|
}
|
|
1509
1548
|
async #updateByIds(table2, data, ids) {
|
|
1510
1549
|
if (ids.length === 0) {
|
|
@@ -1541,7 +1580,7 @@ var Database = class extends EventTarget {
|
|
|
1541
1580
|
if (allColumns.length === 0) {
|
|
1542
1581
|
throw new Error("No fields to update");
|
|
1543
1582
|
}
|
|
1544
|
-
const encoded = encodeData(table2, validated);
|
|
1583
|
+
const encoded = encodeData(table2, validated, this.#driver);
|
|
1545
1584
|
const updateParts = buildUpdateByIdsParts(
|
|
1546
1585
|
table2.name,
|
|
1547
1586
|
pk,
|
|
@@ -1558,7 +1597,7 @@ var Database = class extends EventTarget {
|
|
|
1558
1597
|
);
|
|
1559
1598
|
const resultMap2 = /* @__PURE__ */ new Map();
|
|
1560
1599
|
for (const row of rows2) {
|
|
1561
|
-
const entity = decodeData(table2, row);
|
|
1600
|
+
const entity = decodeData(table2, row, this.#driver);
|
|
1562
1601
|
resultMap2.set(row[pk], entity);
|
|
1563
1602
|
}
|
|
1564
1603
|
return ids.map((id) => resultMap2.get(id) ?? null);
|
|
@@ -1571,7 +1610,7 @@ var Database = class extends EventTarget {
|
|
|
1571
1610
|
);
|
|
1572
1611
|
const resultMap = /* @__PURE__ */ new Map();
|
|
1573
1612
|
for (const row of rows) {
|
|
1574
|
-
const entity = decodeData(table2, row);
|
|
1613
|
+
const entity = decodeData(table2, row, this.#driver);
|
|
1575
1614
|
resultMap.set(row[pk], entity);
|
|
1576
1615
|
}
|
|
1577
1616
|
return ids.map((id) => resultMap.get(id) ?? null);
|
|
@@ -1604,7 +1643,7 @@ var Database = class extends EventTarget {
|
|
|
1604
1643
|
if (allColumns.length === 0) {
|
|
1605
1644
|
throw new Error("No fields to update");
|
|
1606
1645
|
}
|
|
1607
|
-
const encoded = encodeData(table2, validated);
|
|
1646
|
+
const encoded = encodeData(table2, validated, this.#driver);
|
|
1608
1647
|
const { strings: whereStrings, values: whereValues } = expandFragments(
|
|
1609
1648
|
strings,
|
|
1610
1649
|
templateValues
|
|
@@ -1641,7 +1680,7 @@ var Database = class extends EventTarget {
|
|
|
1641
1680
|
makeTemplate(queryStrings),
|
|
1642
1681
|
queryValues
|
|
1643
1682
|
);
|
|
1644
|
-
return rows2.map((row) => decodeData(table2, row));
|
|
1683
|
+
return rows2.map((row) => decodeData(table2, row, this.#driver));
|
|
1645
1684
|
}
|
|
1646
1685
|
const selectIdStrings = ["SELECT "];
|
|
1647
1686
|
const selectIdValues = [];
|
|
@@ -1671,9 +1710,10 @@ var Database = class extends EventTarget {
|
|
|
1671
1710
|
selectStrings,
|
|
1672
1711
|
selectVals
|
|
1673
1712
|
);
|
|
1674
|
-
return rows.map((row) => decodeData(table2, row));
|
|
1713
|
+
return rows.map((row) => decodeData(table2, row, this.#driver));
|
|
1675
1714
|
}
|
|
1676
1715
|
delete(table2, idOrIds) {
|
|
1716
|
+
assertNotView(table2, "delete");
|
|
1677
1717
|
if (idOrIds === void 0) {
|
|
1678
1718
|
return async (strings, ...values) => {
|
|
1679
1719
|
const { strings: expandedStrings, values: expandedValues } = expandFragments(strings, values);
|
|
@@ -1712,6 +1752,7 @@ var Database = class extends EventTarget {
|
|
|
1712
1752
|
return this.#driver.run(strings, values);
|
|
1713
1753
|
}
|
|
1714
1754
|
softDelete(table2, idOrIds) {
|
|
1755
|
+
assertNotView(table2, "softDelete");
|
|
1715
1756
|
const softDeleteField = table2.meta.softDeleteField;
|
|
1716
1757
|
if (!softDeleteField) {
|
|
1717
1758
|
throw new Error(
|
|
@@ -1762,7 +1803,49 @@ var Database = class extends EventTarget {
|
|
|
1762
1803
|
queryStrings.push(" = ");
|
|
1763
1804
|
queryValues.push(id);
|
|
1764
1805
|
queryStrings.push("");
|
|
1765
|
-
|
|
1806
|
+
const count = await this.#driver.run(
|
|
1807
|
+
makeTemplate(queryStrings),
|
|
1808
|
+
queryValues
|
|
1809
|
+
);
|
|
1810
|
+
if (count > 0) {
|
|
1811
|
+
await this.#cascadeSoftDelete(table2, [id]);
|
|
1812
|
+
}
|
|
1813
|
+
return count;
|
|
1814
|
+
}
|
|
1815
|
+
/**
|
|
1816
|
+
* Cascade soft delete to tables that reference the given table with onDelete: "cascade".
|
|
1817
|
+
* Only cascades to tables that have a soft delete field.
|
|
1818
|
+
*/
|
|
1819
|
+
async #cascadeSoftDelete(table2, ids) {
|
|
1820
|
+
if (ids.length === 0 || this.#tables.length === 0)
|
|
1821
|
+
return;
|
|
1822
|
+
for (const refTable of this.#tables) {
|
|
1823
|
+
const refs = refTable.references();
|
|
1824
|
+
for (const ref of refs) {
|
|
1825
|
+
if (ref.table.name === table2.name && ref.onDelete === "cascade") {
|
|
1826
|
+
if (!refTable.meta.softDeleteField)
|
|
1827
|
+
continue;
|
|
1828
|
+
const fkField = ref.fieldName;
|
|
1829
|
+
const refPk = refTable.meta.primary;
|
|
1830
|
+
if (!refPk)
|
|
1831
|
+
continue;
|
|
1832
|
+
const whereIn = refTable.in(fkField, ids);
|
|
1833
|
+
const selectTemplate = createTemplate(
|
|
1834
|
+
makeTemplate(["SELECT ", " FROM ", " WHERE ", ""]),
|
|
1835
|
+
[ident(refPk), ident(refTable.name), whereIn]
|
|
1836
|
+
);
|
|
1837
|
+
const { strings: selectStrings, values: selectValues } = expandFragments(selectTemplate[0], selectTemplate.slice(1));
|
|
1838
|
+
const rows = await this.#driver.all(
|
|
1839
|
+
selectStrings,
|
|
1840
|
+
selectValues
|
|
1841
|
+
);
|
|
1842
|
+
if (rows.length > 0) {
|
|
1843
|
+
const cascadeIds = rows.map((row) => row[refPk]);
|
|
1844
|
+
await this.#softDeleteByIds(refTable, cascadeIds);
|
|
1845
|
+
}
|
|
1846
|
+
}
|
|
1847
|
+
}
|
|
1848
|
+
}
|
|
1766
1849
|
}
|
|
1767
1850
|
async #softDeleteByIds(table2, ids) {
|
|
1768
1851
|
if (ids.length === 0) {
|
|
@@ -1803,16 +1886,39 @@ var Database = class extends EventTarget {
|
|
|
1803
1886
|
queryValues.push(ids[i]);
|
|
1804
1887
|
queryStrings.push(i < ids.length - 1 ? ", " : ")");
|
|
1805
1888
|
}
|
|
1806
|
-
|
|
1889
|
+
const count = await this.#driver.run(
|
|
1890
|
+
makeTemplate(queryStrings),
|
|
1891
|
+
queryValues
|
|
1892
|
+
);
|
|
1893
|
+
if (count > 0) {
|
|
1894
|
+
await this.#cascadeSoftDelete(table2, ids);
|
|
1895
|
+
}
|
|
1896
|
+
return count;
|
|
1807
1897
|
}
|
|
1808
1898
|
async #softDeleteWithWhere(table2, strings, templateValues) {
|
|
1809
1899
|
const softDeleteField = table2.meta.softDeleteField;
|
|
1900
|
+
const pk = table2.meta.primary;
|
|
1810
1901
|
const schemaExprs = injectSchemaExpressions(table2, {}, "update");
|
|
1811
1902
|
const { expressions, symbols } = extractDBExpressions(schemaExprs);
|
|
1812
1903
|
const { strings: expandedStrings, values: expandedValues } = expandFragments(
|
|
1813
1904
|
strings,
|
|
1814
1905
|
templateValues
|
|
1815
1906
|
);
|
|
1907
|
+
let affectedIds = [];
|
|
1908
|
+
if (this.#tables.length > 0 && pk) {
|
|
1909
|
+
const selectStrings = ["SELECT ", " FROM ", " "];
|
|
1910
|
+
const selectValues = [ident(pk), ident(table2.name)];
|
|
1911
|
+
selectStrings[selectStrings.length - 1] += expandedStrings[0];
|
|
1912
|
+
for (let i = 1; i < expandedStrings.length; i++) {
|
|
1913
|
+
selectStrings.push(expandedStrings[i]);
|
|
1914
|
+
}
|
|
1915
|
+
selectValues.push(...expandedValues);
|
|
1916
|
+
const rows = await this.#driver.all(
|
|
1917
|
+
makeTemplate(selectStrings),
|
|
1918
|
+
selectValues
|
|
1919
|
+
);
|
|
1920
|
+
affectedIds = rows.map((row) => row[pk]);
|
|
1921
|
+
}
|
|
1816
1922
|
const queryStrings = ["UPDATE "];
|
|
1817
1923
|
const queryValues = [];
|
|
1818
1924
|
queryValues.push(ident(table2.name));
|
|
@@ -1839,7 +1945,14 @@ var Database = class extends EventTarget {
|
|
|
1839
1945
|
queryStrings.push(expandedStrings[i]);
|
|
1840
1946
|
}
|
|
1841
1947
|
queryValues.push(...expandedValues);
|
|
1842
|
-
|
|
1948
|
+
const count = await this.#driver.run(
|
|
1949
|
+
makeTemplate(queryStrings),
|
|
1950
|
+
queryValues
|
|
1951
|
+
);
|
|
1952
|
+
if (count > 0 && affectedIds.length > 0) {
|
|
1953
|
+
await this.#cascadeSoftDelete(table2, affectedIds);
|
|
1954
|
+
}
|
|
1955
|
+
return count;
|
|
1843
1956
|
}
|
|
1844
1957
|
// ==========================================================================
|
|
1845
1958
|
// Raw - No Normalization
|
|
@@ -1930,6 +2043,7 @@ var Database = class extends EventTarget {
|
|
|
1930
2043
|
* await db.ensureTable(Posts); // FK to Users - ensure Users first
|
|
1931
2044
|
*/
|
|
1932
2045
|
async ensureTable(table2) {
|
|
2046
|
+
assertNotView(table2, "ensureTable");
|
|
1933
2047
|
if (!this.#driver.ensureTable) {
|
|
1934
2048
|
throw new Error(
|
|
1935
2049
|
"Driver does not implement ensureTable(). Schema ensure methods require a driver with schema management support."
|
|
@@ -1941,6 +2055,29 @@ var Database = class extends EventTarget {
|
|
|
1941
2055
|
}
|
|
1942
2056
|
return await doEnsure();
|
|
1943
2057
|
}
|
|
2058
|
+
/**
|
|
2059
|
+
* Ensure a view exists in the database.
|
|
2060
|
+
*
|
|
2061
|
+
* Creates the view if it doesn't exist, or replaces it if it does.
|
|
2062
|
+
* The base table must already exist.
|
|
2063
|
+
*
|
|
2064
|
+
* @example
|
|
2065
|
+
* const ActiveUsers = view("active_users", Users)`WHERE ${Users.cols.deletedAt} IS NULL`;
|
|
2066
|
+
* await db.ensureTable(Users);
|
|
2067
|
+
* await db.ensureView(ActiveUsers);
|
|
2068
|
+
*/
|
|
2069
|
+
async ensureView(viewObj) {
|
|
2070
|
+
if (!this.#driver.ensureView) {
|
|
2071
|
+
throw new Error(
|
|
2072
|
+
"Driver does not implement ensureView(). Schema ensure methods require a driver with schema management support."
|
|
2073
|
+
);
|
|
2074
|
+
}
|
|
2075
|
+
const doEnsure = () => this.#driver.ensureView(viewObj);
|
|
2076
|
+
if (this.#driver.withMigrationLock) {
|
|
2077
|
+
return await this.#driver.withMigrationLock(doEnsure);
|
|
2078
|
+
}
|
|
2079
|
+
return await doEnsure();
|
|
2080
|
+
}
|
|
1944
2081
|
/**
|
|
1945
2082
|
* Ensure constraints (unique, foreign key) are applied to an existing table.
|
|
1946
2083
|
*
|
|
@@ -1963,6 +2100,7 @@ var Database = class extends EventTarget {
|
|
|
1963
2100
|
* await db.ensureConstraints(Users);
|
|
1964
2101
|
*/
|
|
1965
2102
|
async ensureConstraints(table2) {
|
|
2103
|
+
assertNotView(table2, "ensureConstraints");
|
|
1966
2104
|
if (!this.#driver.ensureConstraints) {
|
|
1967
2105
|
throw new Error(
|
|
1968
2106
|
"Driver does not implement ensureConstraints(). Schema ensure methods require a driver with schema management support."
|
|
@@ -2132,12 +2270,15 @@ export {
|
|
|
2132
2270
|
Transaction,
|
|
2133
2271
|
TransactionError,
|
|
2134
2272
|
ValidationError,
|
|
2273
|
+
getViewMeta,
|
|
2135
2274
|
hasErrorCode,
|
|
2136
2275
|
ident,
|
|
2137
2276
|
isDatabaseError,
|
|
2138
2277
|
isSQLBuiltin,
|
|
2139
2278
|
isSQLIdentifier,
|
|
2140
2279
|
isSQLTemplate,
|
|
2280
|
+
isView,
|
|
2141
2281
|
table,
|
|
2282
|
+
view,
|
|
2142
2283
|
zod as z
|
|
2143
2284
|
};
|