@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.cjs
CHANGED
|
@@ -39,6 +39,7 @@ module.exports = __toCommonJS(index_exports);
|
|
|
39
39
|
// src/lib/Database.ts
|
|
40
40
|
var import_fs = __toESM(require("fs"));
|
|
41
41
|
var import_path2 = __toESM(require("path"));
|
|
42
|
+
var import_crypto = require("crypto");
|
|
42
43
|
var import_core2 = require("@dbcube/core");
|
|
43
44
|
|
|
44
45
|
// src/lib/Trigger.ts
|
|
@@ -75,11 +76,17 @@ var Trigger = class {
|
|
|
75
76
|
const pathFile = import_path.default.resolve(process.cwd(), "dbcube", "triggers", `${trigger.database_ref}_${trigger.table_ref}_${trigger.type}.js`);
|
|
76
77
|
const requireUrl = typeof __filename !== "undefined" ? __filename : process.cwd();
|
|
77
78
|
const require2 = (0, import_module.createRequire)(requireUrl);
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
79
|
+
try {
|
|
80
|
+
delete require2.cache[require2.resolve(pathFile)];
|
|
81
|
+
} catch {
|
|
82
|
+
}
|
|
83
|
+
try {
|
|
84
|
+
const triggerModule = require2(pathFile);
|
|
85
|
+
const dataProcess = triggerModule.default || triggerModule;
|
|
86
|
+
await dataProcess({ db: this.instance, oldData: row, newData: row });
|
|
87
|
+
} finally {
|
|
88
|
+
interceptor.restore();
|
|
89
|
+
}
|
|
83
90
|
return interceptor;
|
|
84
91
|
}
|
|
85
92
|
return null;
|
|
@@ -143,7 +150,10 @@ var Database = class _Database {
|
|
|
143
150
|
} catch (error) {
|
|
144
151
|
try {
|
|
145
152
|
await this.engine.rollbackTransaction(txId);
|
|
146
|
-
} catch {
|
|
153
|
+
} catch (rollbackError) {
|
|
154
|
+
console.error(
|
|
155
|
+
`[dbcube] Rollback of transaction ${txId} failed: ${rollbackError?.message ?? rollbackError}`
|
|
156
|
+
);
|
|
147
157
|
}
|
|
148
158
|
throw error;
|
|
149
159
|
}
|
|
@@ -168,10 +178,9 @@ var Database = class _Database {
|
|
|
168
178
|
if (response.status != 200) {
|
|
169
179
|
returnFormattedError(response.status, response.message);
|
|
170
180
|
}
|
|
171
|
-
return response.data;
|
|
172
181
|
}
|
|
173
182
|
async disconnect() {
|
|
174
|
-
|
|
183
|
+
await this.engine.run("query_engine", [
|
|
175
184
|
"--action",
|
|
176
185
|
"disconnect"
|
|
177
186
|
]);
|
|
@@ -232,8 +241,12 @@ var Table = class _Table {
|
|
|
232
241
|
triggers;
|
|
233
242
|
txId = null;
|
|
234
243
|
relations = [];
|
|
235
|
-
|
|
244
|
+
/** Builders de grupo mutan en sitio (ver clone()) */
|
|
245
|
+
_mutable = false;
|
|
246
|
+
instance;
|
|
247
|
+
constructor(instance, databaseName, tableName, engine, computedFields = [], triggers = [], txId = null) {
|
|
236
248
|
this.engine = engine;
|
|
249
|
+
this.instance = instance;
|
|
237
250
|
this.computedFields = computedFields;
|
|
238
251
|
this.triggers = triggers;
|
|
239
252
|
this.trigger = new Trigger(instance, databaseName, triggers);
|
|
@@ -310,7 +323,8 @@ var Table = class _Table {
|
|
|
310
323
|
*/
|
|
311
324
|
whereGroup(callback) {
|
|
312
325
|
const clone = this.clone();
|
|
313
|
-
const groupQuery = new _Table(this, clone.dml.database, clone.dml.table, clone.engine);
|
|
326
|
+
const groupQuery = new _Table(this.instance, clone.dml.database, clone.dml.table, clone.engine);
|
|
327
|
+
groupQuery._mutable = true;
|
|
314
328
|
callback(groupQuery);
|
|
315
329
|
clone.dml.where.push({
|
|
316
330
|
type: clone.nextType,
|
|
@@ -572,6 +586,7 @@ var Table = class _Table {
|
|
|
572
586
|
column,
|
|
573
587
|
alias: "count"
|
|
574
588
|
};
|
|
589
|
+
clone.dml.orderBy = [];
|
|
575
590
|
clone.dml.columns = [`COUNT(${column}) AS count`];
|
|
576
591
|
clone.dml.data = null;
|
|
577
592
|
clone.dml.limit = null;
|
|
@@ -605,6 +620,7 @@ var Table = class _Table {
|
|
|
605
620
|
column,
|
|
606
621
|
alias: "sum"
|
|
607
622
|
};
|
|
623
|
+
clone.dml.orderBy = [];
|
|
608
624
|
clone.dml.columns = [`SUM(${column}) AS sum`];
|
|
609
625
|
clone.dml.data = null;
|
|
610
626
|
clone.dml.limit = 1;
|
|
@@ -637,6 +653,7 @@ var Table = class _Table {
|
|
|
637
653
|
column,
|
|
638
654
|
alias: "avg"
|
|
639
655
|
};
|
|
656
|
+
clone.dml.orderBy = [];
|
|
640
657
|
clone.dml.columns = [`AVG(${column}) AS avg`];
|
|
641
658
|
clone.dml.data = null;
|
|
642
659
|
clone.dml.limit = 1;
|
|
@@ -669,6 +686,7 @@ var Table = class _Table {
|
|
|
669
686
|
column,
|
|
670
687
|
alias: "max"
|
|
671
688
|
};
|
|
689
|
+
clone.dml.orderBy = [];
|
|
672
690
|
clone.dml.columns = [`MAX(${column}) AS max`];
|
|
673
691
|
clone.dml.data = null;
|
|
674
692
|
clone.dml.limit = 1;
|
|
@@ -701,6 +719,7 @@ var Table = class _Table {
|
|
|
701
719
|
column,
|
|
702
720
|
alias: "min"
|
|
703
721
|
};
|
|
722
|
+
clone.dml.orderBy = [];
|
|
704
723
|
clone.dml.columns = [`MIN(${column}) AS min`];
|
|
705
724
|
clone.dml.data = null;
|
|
706
725
|
clone.dml.limit = 1;
|
|
@@ -857,11 +876,10 @@ var Table = class _Table {
|
|
|
857
876
|
* console.log(user); // { id: 1, name: 'John' }
|
|
858
877
|
*/
|
|
859
878
|
async find(value, column = "id") {
|
|
860
|
-
const clone = this.clone();
|
|
879
|
+
const clone = this.clone().where(column, "=", value);
|
|
861
880
|
clone.dml.type = "select";
|
|
862
881
|
clone.dml.data = null;
|
|
863
882
|
clone.dml.aggregation = null;
|
|
864
|
-
clone.where(column, "=", value);
|
|
865
883
|
clone.dml.limit = 1;
|
|
866
884
|
try {
|
|
867
885
|
const result = await clone.getResponse();
|
|
@@ -918,8 +936,7 @@ var Table = class _Table {
|
|
|
918
936
|
}
|
|
919
937
|
clone.dml.type = "update";
|
|
920
938
|
clone.dml.data = data;
|
|
921
|
-
|
|
922
|
-
return data;
|
|
939
|
+
return clone.getResponse(clone.dml, "Update");
|
|
923
940
|
}
|
|
924
941
|
/**
|
|
925
942
|
* Deletes rows from the table based on the defined conditions.
|
|
@@ -1139,12 +1156,37 @@ var Table = class _Table {
|
|
|
1139
1156
|
throw new Error("The upsert method requires at least one conflict key column.");
|
|
1140
1157
|
}
|
|
1141
1158
|
const motor = this.engine?.getConfig?.()?.type ?? "mysql";
|
|
1142
|
-
if (motor === "mongodb") {
|
|
1143
|
-
throw new Error("upsert() is not supported for MongoDB yet. Use update() + insert() or raw commands.");
|
|
1144
|
-
}
|
|
1145
1159
|
const table = this.dml.table;
|
|
1146
1160
|
const columns = Object.keys(data[0]);
|
|
1147
1161
|
const targets = updateColumns ?? columns.filter((c) => !conflictKeys.includes(c));
|
|
1162
|
+
assertValidIdentifier(table, "table");
|
|
1163
|
+
for (const c of columns) assertValidIdentifier(c, "column");
|
|
1164
|
+
for (const c of conflictKeys) assertValidIdentifier(c, "conflict key");
|
|
1165
|
+
for (const c of targets) assertValidIdentifier(c, "update column");
|
|
1166
|
+
if (motor === "mongodb") {
|
|
1167
|
+
const updates = data.map((row) => {
|
|
1168
|
+
const q = {};
|
|
1169
|
+
for (const k of conflictKeys) q[k] = row[k];
|
|
1170
|
+
const set = {};
|
|
1171
|
+
for (const c of targets) if (c in row) set[c] = row[c];
|
|
1172
|
+
const setOnInsert = {};
|
|
1173
|
+
for (const c of columns) {
|
|
1174
|
+
if (!targets.includes(c) && !conflictKeys.includes(c)) setOnInsert[c] = row[c];
|
|
1175
|
+
}
|
|
1176
|
+
if (!("uuid" in row)) setOnInsert["uuid"] = (0, import_crypto.randomUUID)();
|
|
1177
|
+
const u = {};
|
|
1178
|
+
if (Object.keys(set).length) u["$set"] = set;
|
|
1179
|
+
if (Object.keys(setOnInsert).length) u["$setOnInsert"] = setOnInsert;
|
|
1180
|
+
return { q, u, upsert: true, multi: false };
|
|
1181
|
+
});
|
|
1182
|
+
const command = JSON.stringify({ update: table, updates });
|
|
1183
|
+
const response2 = await this.engine.rawQuery(command, [], this.txId ?? void 0);
|
|
1184
|
+
if (response2.status != 200) {
|
|
1185
|
+
returnFormattedError(response2.status, response2.message);
|
|
1186
|
+
throw new Error(response2.message);
|
|
1187
|
+
}
|
|
1188
|
+
return response2.data;
|
|
1189
|
+
}
|
|
1148
1190
|
const quote = (id) => motor === "mysql" ? `\`${id}\`` : `"${id}"`;
|
|
1149
1191
|
const params = [];
|
|
1150
1192
|
const placeholder = () => motor === "postgres" || motor === "postgresql" ? `$${params.length}` : "?";
|
|
@@ -1165,6 +1207,9 @@ var Table = class _Table {
|
|
|
1165
1207
|
const updates = targets.map((c) => `${quote(c)} = excluded.${quote(c)}`).join(", ");
|
|
1166
1208
|
sql = `INSERT INTO ${quote(table)} (${colsSql}) VALUES ${rowsSql} ON CONFLICT (${conflict}) DO UPDATE SET ${updates}`;
|
|
1167
1209
|
}
|
|
1210
|
+
if (motor === "sqlite") {
|
|
1211
|
+
await this.engine.rawQuery("SELECT name FROM sqlite_master LIMIT 1", [], this.txId ?? void 0);
|
|
1212
|
+
}
|
|
1168
1213
|
const response = await this.engine.rawQuery(sql, params, this.txId ?? void 0);
|
|
1169
1214
|
if (response.status != 200) {
|
|
1170
1215
|
returnFormattedError(response.status, response.message);
|
|
@@ -1219,7 +1264,7 @@ var Table = class _Table {
|
|
|
1219
1264
|
foreignKey = foreignKey ?? `${singularize(this.dml.table)}_id`;
|
|
1220
1265
|
}
|
|
1221
1266
|
}
|
|
1222
|
-
const relatedQuery = new _Table(this, this.dml.database, relatedTable, this.engine, this.computedFields, this.triggers, this.txId);
|
|
1267
|
+
const relatedQuery = new _Table(this.instance, this.dml.database, relatedTable, this.engine, this.computedFields, this.triggers, this.txId);
|
|
1223
1268
|
if (type === "one") {
|
|
1224
1269
|
const fkValues = [...new Set(rows.map((r) => r[foreignKey]).filter((v) => v !== null && v !== void 0))];
|
|
1225
1270
|
const related = fkValues.length > 0 ? await relatedQuery.whereIn(localKey, fkValues).get() : [];
|
|
@@ -1247,6 +1292,7 @@ var Table = class _Table {
|
|
|
1247
1292
|
const localDML = dml ? dml : this.dml;
|
|
1248
1293
|
const computedFieldsNeeded = [];
|
|
1249
1294
|
let dependeciesArrray = [];
|
|
1295
|
+
const requestedColumns = new Set(localDML.columns ?? []);
|
|
1250
1296
|
if (this.computedFields.length > 0) {
|
|
1251
1297
|
let columns = localDML.columns;
|
|
1252
1298
|
for (const field of localDML.columns) {
|
|
@@ -1274,25 +1320,28 @@ var Table = class _Table {
|
|
|
1274
1320
|
const interceptor = await this.trigger.execute("before" + type, data);
|
|
1275
1321
|
const response = await this.engine.executeDml(newDML, this.txId ?? void 0);
|
|
1276
1322
|
if (response.status != 200) {
|
|
1277
|
-
interceptor
|
|
1323
|
+
interceptor?.discard();
|
|
1278
1324
|
returnFormattedError(response.status, response.message);
|
|
1325
|
+
throw new Error(String(response.message));
|
|
1279
1326
|
}
|
|
1280
|
-
await interceptor
|
|
1327
|
+
await interceptor?.commit();
|
|
1281
1328
|
arrayResult = response.data;
|
|
1282
1329
|
}
|
|
1283
1330
|
if (after) {
|
|
1284
1331
|
const response = await this.engine.executeDml(newDML, this.txId ?? void 0);
|
|
1285
1332
|
if (response.status != 200) {
|
|
1286
1333
|
returnFormattedError(response.status, response.message);
|
|
1334
|
+
throw new Error(String(response.message));
|
|
1287
1335
|
}
|
|
1288
1336
|
const interceptor = await this.trigger.execute("after" + type, data);
|
|
1289
|
-
await interceptor
|
|
1337
|
+
await interceptor?.commit();
|
|
1290
1338
|
}
|
|
1291
1339
|
}
|
|
1292
1340
|
} else {
|
|
1293
1341
|
const response = await this.engine.executeDml(localDML, this.txId ?? void 0);
|
|
1294
1342
|
if (response.status != 200) {
|
|
1295
1343
|
returnFormattedError(response.status, response.message);
|
|
1344
|
+
throw new Error(String(response.message));
|
|
1296
1345
|
}
|
|
1297
1346
|
arrayResult = response.data;
|
|
1298
1347
|
}
|
|
@@ -1300,14 +1349,16 @@ var Table = class _Table {
|
|
|
1300
1349
|
const response = await this.engine.executeDml(localDML, this.txId ?? void 0);
|
|
1301
1350
|
if (response.status != 200) {
|
|
1302
1351
|
returnFormattedError(response.status, response.message);
|
|
1352
|
+
throw new Error(String(response.message));
|
|
1303
1353
|
}
|
|
1304
1354
|
arrayResult = response.data;
|
|
1305
1355
|
}
|
|
1306
1356
|
if (computedFieldsNeeded.length > 0) {
|
|
1307
1357
|
let newDataset = import_core2.ComputedFieldProcessor.computedFields(arrayResult, computedFieldsNeeded);
|
|
1358
|
+
const toRemove = dependeciesArrray.filter((key) => !requestedColumns.has(key));
|
|
1308
1359
|
const result = newDataset.map((obj) => {
|
|
1309
1360
|
const newObj = { ...obj };
|
|
1310
|
-
|
|
1361
|
+
toRemove.forEach((key) => delete newObj[key]);
|
|
1311
1362
|
return newObj;
|
|
1312
1363
|
});
|
|
1313
1364
|
return result;
|
|
@@ -1315,8 +1366,10 @@ var Table = class _Table {
|
|
|
1315
1366
|
return arrayResult;
|
|
1316
1367
|
}
|
|
1317
1368
|
clone() {
|
|
1369
|
+
if (this._mutable) return this;
|
|
1318
1370
|
const cloned = Object.create(Object.getPrototypeOf(this));
|
|
1319
1371
|
cloned.engine = this.engine;
|
|
1372
|
+
cloned.instance = this.instance;
|
|
1320
1373
|
cloned.nextType = this.nextType;
|
|
1321
1374
|
cloned.computedFields = this.computedFields;
|
|
1322
1375
|
cloned.trigger = this.trigger;
|
|
@@ -1384,6 +1437,11 @@ function loadCubeRelations() {
|
|
|
1384
1437
|
cubeRelationsCache = result;
|
|
1385
1438
|
return result;
|
|
1386
1439
|
}
|
|
1440
|
+
function assertValidIdentifier(name, kind) {
|
|
1441
|
+
if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(name)) {
|
|
1442
|
+
throw new Error(`Invalid ${kind} name: '${name}'. Only letters, numbers and underscore are allowed.`);
|
|
1443
|
+
}
|
|
1444
|
+
}
|
|
1387
1445
|
function singularize(word) {
|
|
1388
1446
|
if (word.endsWith("ies")) return word.slice(0, -3) + "y";
|
|
1389
1447
|
if (word.endsWith("ses")) return word.slice(0, -2);
|