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