@dbcube/query-builder 5.1.6 → 5.2.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/README.md +122 -1700
- package/dist/index.cjs +80 -22
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.mts +80 -47
- package/dist/index.d.ts +80 -47
- package/dist/index.js +80 -22
- package/dist/index.js.map +1 -1
- package/package.json +5 -2
- package/.npmignore +0 -51
- package/CONTRIBUTING.md +0 -9
- package/bun.lockb +0 -0
- package/pnpm-workspace.yaml +0 -2
- package/tsup.config.ts +0 -14
package/dist/index.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
// src/lib/Database.ts
|
|
2
2
|
import fs from "fs";
|
|
3
3
|
import path2 from "path";
|
|
4
|
+
import { randomUUID } from "crypto";
|
|
4
5
|
import { QueryEngine, ComputedFieldProcessor, TriggerProcessor } from "@dbcube/core";
|
|
5
6
|
|
|
6
7
|
// src/lib/Trigger.ts
|
|
@@ -37,11 +38,17 @@ var Trigger = class {
|
|
|
37
38
|
const pathFile = path.resolve(process.cwd(), "dbcube", "triggers", `${trigger.database_ref}_${trigger.table_ref}_${trigger.type}.js`);
|
|
38
39
|
const requireUrl = typeof __filename !== "undefined" ? __filename : process.cwd();
|
|
39
40
|
const require2 = createRequire(requireUrl);
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
41
|
+
try {
|
|
42
|
+
delete require2.cache[require2.resolve(pathFile)];
|
|
43
|
+
} catch {
|
|
44
|
+
}
|
|
45
|
+
try {
|
|
46
|
+
const triggerModule = require2(pathFile);
|
|
47
|
+
const dataProcess = triggerModule.default || triggerModule;
|
|
48
|
+
await dataProcess({ db: this.instance, oldData: row, newData: row });
|
|
49
|
+
} finally {
|
|
50
|
+
interceptor.restore();
|
|
51
|
+
}
|
|
45
52
|
return interceptor;
|
|
46
53
|
}
|
|
47
54
|
return null;
|
|
@@ -105,7 +112,10 @@ var Database = class _Database {
|
|
|
105
112
|
} catch (error) {
|
|
106
113
|
try {
|
|
107
114
|
await this.engine.rollbackTransaction(txId);
|
|
108
|
-
} catch {
|
|
115
|
+
} catch (rollbackError) {
|
|
116
|
+
console.error(
|
|
117
|
+
`[dbcube] Rollback of transaction ${txId} failed: ${rollbackError?.message ?? rollbackError}`
|
|
118
|
+
);
|
|
109
119
|
}
|
|
110
120
|
throw error;
|
|
111
121
|
}
|
|
@@ -130,10 +140,9 @@ var Database = class _Database {
|
|
|
130
140
|
if (response.status != 200) {
|
|
131
141
|
returnFormattedError(response.status, response.message);
|
|
132
142
|
}
|
|
133
|
-
return response.data;
|
|
134
143
|
}
|
|
135
144
|
async disconnect() {
|
|
136
|
-
|
|
145
|
+
await this.engine.run("query_engine", [
|
|
137
146
|
"--action",
|
|
138
147
|
"disconnect"
|
|
139
148
|
]);
|
|
@@ -194,8 +203,12 @@ var Table = class _Table {
|
|
|
194
203
|
triggers;
|
|
195
204
|
txId = null;
|
|
196
205
|
relations = [];
|
|
197
|
-
|
|
206
|
+
/** Builders de grupo mutan en sitio (ver clone()) */
|
|
207
|
+
_mutable = false;
|
|
208
|
+
instance;
|
|
209
|
+
constructor(instance, databaseName, tableName, engine, computedFields = [], triggers = [], txId = null) {
|
|
198
210
|
this.engine = engine;
|
|
211
|
+
this.instance = instance;
|
|
199
212
|
this.computedFields = computedFields;
|
|
200
213
|
this.triggers = triggers;
|
|
201
214
|
this.trigger = new Trigger(instance, databaseName, triggers);
|
|
@@ -272,7 +285,8 @@ var Table = class _Table {
|
|
|
272
285
|
*/
|
|
273
286
|
whereGroup(callback) {
|
|
274
287
|
const clone = this.clone();
|
|
275
|
-
const groupQuery = new _Table(this, clone.dml.database, clone.dml.table, clone.engine);
|
|
288
|
+
const groupQuery = new _Table(this.instance, clone.dml.database, clone.dml.table, clone.engine);
|
|
289
|
+
groupQuery._mutable = true;
|
|
276
290
|
callback(groupQuery);
|
|
277
291
|
clone.dml.where.push({
|
|
278
292
|
type: clone.nextType,
|
|
@@ -534,6 +548,7 @@ var Table = class _Table {
|
|
|
534
548
|
column,
|
|
535
549
|
alias: "count"
|
|
536
550
|
};
|
|
551
|
+
clone.dml.orderBy = [];
|
|
537
552
|
clone.dml.columns = [`COUNT(${column}) AS count`];
|
|
538
553
|
clone.dml.data = null;
|
|
539
554
|
clone.dml.limit = null;
|
|
@@ -567,6 +582,7 @@ var Table = class _Table {
|
|
|
567
582
|
column,
|
|
568
583
|
alias: "sum"
|
|
569
584
|
};
|
|
585
|
+
clone.dml.orderBy = [];
|
|
570
586
|
clone.dml.columns = [`SUM(${column}) AS sum`];
|
|
571
587
|
clone.dml.data = null;
|
|
572
588
|
clone.dml.limit = 1;
|
|
@@ -599,6 +615,7 @@ var Table = class _Table {
|
|
|
599
615
|
column,
|
|
600
616
|
alias: "avg"
|
|
601
617
|
};
|
|
618
|
+
clone.dml.orderBy = [];
|
|
602
619
|
clone.dml.columns = [`AVG(${column}) AS avg`];
|
|
603
620
|
clone.dml.data = null;
|
|
604
621
|
clone.dml.limit = 1;
|
|
@@ -631,6 +648,7 @@ var Table = class _Table {
|
|
|
631
648
|
column,
|
|
632
649
|
alias: "max"
|
|
633
650
|
};
|
|
651
|
+
clone.dml.orderBy = [];
|
|
634
652
|
clone.dml.columns = [`MAX(${column}) AS max`];
|
|
635
653
|
clone.dml.data = null;
|
|
636
654
|
clone.dml.limit = 1;
|
|
@@ -663,6 +681,7 @@ var Table = class _Table {
|
|
|
663
681
|
column,
|
|
664
682
|
alias: "min"
|
|
665
683
|
};
|
|
684
|
+
clone.dml.orderBy = [];
|
|
666
685
|
clone.dml.columns = [`MIN(${column}) AS min`];
|
|
667
686
|
clone.dml.data = null;
|
|
668
687
|
clone.dml.limit = 1;
|
|
@@ -819,11 +838,10 @@ var Table = class _Table {
|
|
|
819
838
|
* console.log(user); // { id: 1, name: 'John' }
|
|
820
839
|
*/
|
|
821
840
|
async find(value, column = "id") {
|
|
822
|
-
const clone = this.clone();
|
|
841
|
+
const clone = this.clone().where(column, "=", value);
|
|
823
842
|
clone.dml.type = "select";
|
|
824
843
|
clone.dml.data = null;
|
|
825
844
|
clone.dml.aggregation = null;
|
|
826
|
-
clone.where(column, "=", value);
|
|
827
845
|
clone.dml.limit = 1;
|
|
828
846
|
try {
|
|
829
847
|
const result = await clone.getResponse();
|
|
@@ -880,8 +898,7 @@ var Table = class _Table {
|
|
|
880
898
|
}
|
|
881
899
|
clone.dml.type = "update";
|
|
882
900
|
clone.dml.data = data;
|
|
883
|
-
|
|
884
|
-
return data;
|
|
901
|
+
return clone.getResponse(clone.dml, "Update");
|
|
885
902
|
}
|
|
886
903
|
/**
|
|
887
904
|
* Deletes rows from the table based on the defined conditions.
|
|
@@ -1101,12 +1118,37 @@ var Table = class _Table {
|
|
|
1101
1118
|
throw new Error("The upsert method requires at least one conflict key column.");
|
|
1102
1119
|
}
|
|
1103
1120
|
const motor = this.engine?.getConfig?.()?.type ?? "mysql";
|
|
1104
|
-
if (motor === "mongodb") {
|
|
1105
|
-
throw new Error("upsert() is not supported for MongoDB yet. Use update() + insert() or raw commands.");
|
|
1106
|
-
}
|
|
1107
1121
|
const table = this.dml.table;
|
|
1108
1122
|
const columns = Object.keys(data[0]);
|
|
1109
1123
|
const targets = updateColumns ?? columns.filter((c) => !conflictKeys.includes(c));
|
|
1124
|
+
assertValidIdentifier(table, "table");
|
|
1125
|
+
for (const c of columns) assertValidIdentifier(c, "column");
|
|
1126
|
+
for (const c of conflictKeys) assertValidIdentifier(c, "conflict key");
|
|
1127
|
+
for (const c of targets) assertValidIdentifier(c, "update column");
|
|
1128
|
+
if (motor === "mongodb") {
|
|
1129
|
+
const updates = data.map((row) => {
|
|
1130
|
+
const q = {};
|
|
1131
|
+
for (const k of conflictKeys) q[k] = row[k];
|
|
1132
|
+
const set = {};
|
|
1133
|
+
for (const c of targets) if (c in row) set[c] = row[c];
|
|
1134
|
+
const setOnInsert = {};
|
|
1135
|
+
for (const c of columns) {
|
|
1136
|
+
if (!targets.includes(c) && !conflictKeys.includes(c)) setOnInsert[c] = row[c];
|
|
1137
|
+
}
|
|
1138
|
+
if (!("uuid" in row)) setOnInsert["uuid"] = randomUUID();
|
|
1139
|
+
const u = {};
|
|
1140
|
+
if (Object.keys(set).length) u["$set"] = set;
|
|
1141
|
+
if (Object.keys(setOnInsert).length) u["$setOnInsert"] = setOnInsert;
|
|
1142
|
+
return { q, u, upsert: true, multi: false };
|
|
1143
|
+
});
|
|
1144
|
+
const command = JSON.stringify({ update: table, updates });
|
|
1145
|
+
const response2 = await this.engine.rawQuery(command, [], this.txId ?? void 0);
|
|
1146
|
+
if (response2.status != 200) {
|
|
1147
|
+
returnFormattedError(response2.status, response2.message);
|
|
1148
|
+
throw new Error(response2.message);
|
|
1149
|
+
}
|
|
1150
|
+
return response2.data;
|
|
1151
|
+
}
|
|
1110
1152
|
const quote = (id) => motor === "mysql" ? `\`${id}\`` : `"${id}"`;
|
|
1111
1153
|
const params = [];
|
|
1112
1154
|
const placeholder = () => motor === "postgres" || motor === "postgresql" ? `$${params.length}` : "?";
|
|
@@ -1127,6 +1169,9 @@ var Table = class _Table {
|
|
|
1127
1169
|
const updates = targets.map((c) => `${quote(c)} = excluded.${quote(c)}`).join(", ");
|
|
1128
1170
|
sql = `INSERT INTO ${quote(table)} (${colsSql}) VALUES ${rowsSql} ON CONFLICT (${conflict}) DO UPDATE SET ${updates}`;
|
|
1129
1171
|
}
|
|
1172
|
+
if (motor === "sqlite") {
|
|
1173
|
+
await this.engine.rawQuery("SELECT name FROM sqlite_master LIMIT 1", [], this.txId ?? void 0);
|
|
1174
|
+
}
|
|
1130
1175
|
const response = await this.engine.rawQuery(sql, params, this.txId ?? void 0);
|
|
1131
1176
|
if (response.status != 200) {
|
|
1132
1177
|
returnFormattedError(response.status, response.message);
|
|
@@ -1181,7 +1226,7 @@ var Table = class _Table {
|
|
|
1181
1226
|
foreignKey = foreignKey ?? `${singularize(this.dml.table)}_id`;
|
|
1182
1227
|
}
|
|
1183
1228
|
}
|
|
1184
|
-
const relatedQuery = new _Table(this, this.dml.database, relatedTable, this.engine, this.computedFields, this.triggers, this.txId);
|
|
1229
|
+
const relatedQuery = new _Table(this.instance, this.dml.database, relatedTable, this.engine, this.computedFields, this.triggers, this.txId);
|
|
1185
1230
|
if (type === "one") {
|
|
1186
1231
|
const fkValues = [...new Set(rows.map((r) => r[foreignKey]).filter((v) => v !== null && v !== void 0))];
|
|
1187
1232
|
const related = fkValues.length > 0 ? await relatedQuery.whereIn(localKey, fkValues).get() : [];
|
|
@@ -1209,6 +1254,7 @@ var Table = class _Table {
|
|
|
1209
1254
|
const localDML = dml ? dml : this.dml;
|
|
1210
1255
|
const computedFieldsNeeded = [];
|
|
1211
1256
|
let dependeciesArrray = [];
|
|
1257
|
+
const requestedColumns = new Set(localDML.columns ?? []);
|
|
1212
1258
|
if (this.computedFields.length > 0) {
|
|
1213
1259
|
let columns = localDML.columns;
|
|
1214
1260
|
for (const field of localDML.columns) {
|
|
@@ -1236,25 +1282,28 @@ var Table = class _Table {
|
|
|
1236
1282
|
const interceptor = await this.trigger.execute("before" + type, data);
|
|
1237
1283
|
const response = await this.engine.executeDml(newDML, this.txId ?? void 0);
|
|
1238
1284
|
if (response.status != 200) {
|
|
1239
|
-
interceptor
|
|
1285
|
+
interceptor?.discard();
|
|
1240
1286
|
returnFormattedError(response.status, response.message);
|
|
1287
|
+
throw new Error(String(response.message));
|
|
1241
1288
|
}
|
|
1242
|
-
await interceptor
|
|
1289
|
+
await interceptor?.commit();
|
|
1243
1290
|
arrayResult = response.data;
|
|
1244
1291
|
}
|
|
1245
1292
|
if (after) {
|
|
1246
1293
|
const response = await this.engine.executeDml(newDML, this.txId ?? void 0);
|
|
1247
1294
|
if (response.status != 200) {
|
|
1248
1295
|
returnFormattedError(response.status, response.message);
|
|
1296
|
+
throw new Error(String(response.message));
|
|
1249
1297
|
}
|
|
1250
1298
|
const interceptor = await this.trigger.execute("after" + type, data);
|
|
1251
|
-
await interceptor
|
|
1299
|
+
await interceptor?.commit();
|
|
1252
1300
|
}
|
|
1253
1301
|
}
|
|
1254
1302
|
} else {
|
|
1255
1303
|
const response = await this.engine.executeDml(localDML, this.txId ?? void 0);
|
|
1256
1304
|
if (response.status != 200) {
|
|
1257
1305
|
returnFormattedError(response.status, response.message);
|
|
1306
|
+
throw new Error(String(response.message));
|
|
1258
1307
|
}
|
|
1259
1308
|
arrayResult = response.data;
|
|
1260
1309
|
}
|
|
@@ -1262,14 +1311,16 @@ var Table = class _Table {
|
|
|
1262
1311
|
const response = await this.engine.executeDml(localDML, this.txId ?? void 0);
|
|
1263
1312
|
if (response.status != 200) {
|
|
1264
1313
|
returnFormattedError(response.status, response.message);
|
|
1314
|
+
throw new Error(String(response.message));
|
|
1265
1315
|
}
|
|
1266
1316
|
arrayResult = response.data;
|
|
1267
1317
|
}
|
|
1268
1318
|
if (computedFieldsNeeded.length > 0) {
|
|
1269
1319
|
let newDataset = ComputedFieldProcessor.computedFields(arrayResult, computedFieldsNeeded);
|
|
1320
|
+
const toRemove = dependeciesArrray.filter((key) => !requestedColumns.has(key));
|
|
1270
1321
|
const result = newDataset.map((obj) => {
|
|
1271
1322
|
const newObj = { ...obj };
|
|
1272
|
-
|
|
1323
|
+
toRemove.forEach((key) => delete newObj[key]);
|
|
1273
1324
|
return newObj;
|
|
1274
1325
|
});
|
|
1275
1326
|
return result;
|
|
@@ -1277,8 +1328,10 @@ var Table = class _Table {
|
|
|
1277
1328
|
return arrayResult;
|
|
1278
1329
|
}
|
|
1279
1330
|
clone() {
|
|
1331
|
+
if (this._mutable) return this;
|
|
1280
1332
|
const cloned = Object.create(Object.getPrototypeOf(this));
|
|
1281
1333
|
cloned.engine = this.engine;
|
|
1334
|
+
cloned.instance = this.instance;
|
|
1282
1335
|
cloned.nextType = this.nextType;
|
|
1283
1336
|
cloned.computedFields = this.computedFields;
|
|
1284
1337
|
cloned.trigger = this.trigger;
|
|
@@ -1346,6 +1399,11 @@ function loadCubeRelations() {
|
|
|
1346
1399
|
cubeRelationsCache = result;
|
|
1347
1400
|
return result;
|
|
1348
1401
|
}
|
|
1402
|
+
function assertValidIdentifier(name, kind) {
|
|
1403
|
+
if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(name)) {
|
|
1404
|
+
throw new Error(`Invalid ${kind} name: '${name}'. Only letters, numbers and underscore are allowed.`);
|
|
1405
|
+
}
|
|
1406
|
+
}
|
|
1349
1407
|
function singularize(word) {
|
|
1350
1408
|
if (word.endsWith("ies")) return word.slice(0, -3) + "y";
|
|
1351
1409
|
if (word.endsWith("ses")) return word.slice(0, -2);
|