@dbcube/query-builder 5.2.2 → 5.2.4

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/index.cjs CHANGED
@@ -158,6 +158,39 @@ var Database = class _Database {
158
158
  throw error;
159
159
  }
160
160
  }
161
+ /**
162
+ * Atomic batch: every write queued in the callback runs inside ONE
163
+ * transaction with a SINGLE engine round-trip (begin/commit included).
164
+ * The callback is synchronous — writes are collected, not awaited.
165
+ * Any failure rolls back everything.
166
+ *
167
+ * This is the fastest way to run a sequence of writes atomically.
168
+ * For transactions that need to READ intermediate results, use
169
+ * `transaction()` (interactive) instead. Triggers/computed fields do
170
+ * not run in batch mode.
171
+ *
172
+ * @example
173
+ * await db.batch(b => {
174
+ * b.table('accounts').where('id', '=', 1).decrement('balance', 200);
175
+ * b.table('accounts').where('id', '=', 2).increment('balance', 200);
176
+ * });
177
+ */
178
+ async batch(builder) {
179
+ const ops = [];
180
+ const collector = new _Database(this.name);
181
+ collector.engine = this.engine;
182
+ collector.computedFields = this.computedFields;
183
+ collector.triggers = this.triggers;
184
+ collector._collectInto = ops;
185
+ builder(collector);
186
+ if (ops.length === 0) return [];
187
+ const response = await this.engine.executeBatch(ops);
188
+ if (response.status !== 200) {
189
+ returnFormattedError(response.status, response.message);
190
+ throw new Error(String(response.message));
191
+ }
192
+ return response.data;
193
+ }
161
194
  async useComputes() {
162
195
  const newDatabase = new _Database(this.name);
163
196
  const arrayComputedFields = await import_core2.ComputedFieldProcessor.getComputedFields(this.name);
@@ -223,7 +256,10 @@ var Database = class _Database {
223
256
  * const columns = await db.table('users').columns().get();
224
257
  */
225
258
  table(tableName) {
226
- return new Table(this, this.name, tableName, this.engine, this.computedFields, this.triggers, this.txId);
259
+ const t = new Table(this, this.name, tableName, this.engine, this.computedFields, this.triggers, this.txId);
260
+ const sink = this._collectInto;
261
+ if (sink) t._batchSink = sink;
262
+ return t;
227
263
  }
228
264
  setComputedFields(computedFields) {
229
265
  this.computedFields = computedFields;
@@ -243,13 +279,16 @@ var Table = class _Table {
243
279
  relations = [];
244
280
  /** Builders de grupo mutan en sitio (ver clone()) */
245
281
  _mutable = false;
282
+ /** En modo batch (db.batch) las escrituras se encolan aquí en vez de
283
+ * ejecutarse: toda la transacción viaja al engine en UN solo cruce. */
284
+ _batchSink = null;
246
285
  instance;
247
286
  constructor(instance, databaseName, tableName, engine, computedFields = [], triggers = [], txId = null) {
248
287
  this.engine = engine;
249
288
  this.instance = instance;
250
289
  this.computedFields = computedFields;
251
290
  this.triggers = triggers;
252
- this.trigger = new Trigger(instance, databaseName, triggers);
291
+ this.trigger = triggers.length > 0 ? new Trigger(instance, databaseName, triggers) : null;
253
292
  this.nextType = "AND";
254
293
  this.txId = txId;
255
294
  this.dml = {
@@ -876,6 +915,30 @@ var Table = class _Table {
876
915
  * console.log(user); // { id: 1, name: 'John' }
877
916
  */
878
917
  async find(value, column = "id") {
918
+ if (this.computedFields.length === 0 && this.relations.length === 0 && !this._mutable) {
919
+ const dml = {
920
+ type: "select",
921
+ database: this.dml.database,
922
+ table: this.dml.table,
923
+ columns: ["*"],
924
+ distinct: false,
925
+ joins: [],
926
+ where: [{ column, operator: "=", value, type: "AND", isGroup: false }],
927
+ orderBy: [],
928
+ groupBy: [],
929
+ limit: 1,
930
+ offset: null,
931
+ data: null,
932
+ aggregation: null,
933
+ having: []
934
+ };
935
+ const response = await this.engine.executeDml(dml, this.txId ?? void 0);
936
+ if (response.status != 200) {
937
+ returnFormattedError(response.status, response.message);
938
+ throw new Error(String(response.message));
939
+ }
940
+ return response.data?.[0] || null;
941
+ }
879
942
  const clone = this.clone().where(column, "=", value);
880
943
  clone.dml.type = "select";
881
944
  clone.dml.data = null;
@@ -902,13 +965,26 @@ var Table = class _Table {
902
965
  * console.log(newUsers); // [{ id: 3, name: 'Alice', age: 28 }, { id: 4, name: 'Bob', age: 32 }]
903
966
  */
904
967
  async insert(data) {
905
- const clone = this.clone();
906
968
  if (!Array.isArray(data)) {
907
969
  throw new Error("The insert method requires an array of objects with key-value pairs.");
908
970
  }
909
971
  if (!data.every((item) => typeof item === "object" && item !== null)) {
910
972
  throw new Error("The array must contain only valid objects.");
911
973
  }
974
+ if (this._batchSink) {
975
+ this._batchSink.push({ ...this.dml, type: "insert", data });
976
+ return void 0;
977
+ }
978
+ if (this.triggers.length === 0 && this.computedFields.length === 0) {
979
+ const dml = { ...this.dml, type: "insert", data };
980
+ const response = await this.engine.executeDml(dml, this.txId ?? void 0);
981
+ if (response.status != 200) {
982
+ returnFormattedError(response.status, response.message);
983
+ throw new Error(String(response.message));
984
+ }
985
+ return response.data ?? data;
986
+ }
987
+ const clone = this.clone();
912
988
  clone.dml.type = "insert";
913
989
  clone.dml.data = data;
914
990
  const result = await clone.getResponse(clone.dml, "Add");
@@ -927,13 +1003,26 @@ var Table = class _Table {
927
1003
  * console.log(result); // { affectedRows: 1 }
928
1004
  */
929
1005
  async update(data) {
930
- const clone = this.clone();
931
1006
  if (typeof data !== "object" || Array.isArray(data)) {
932
1007
  throw new Error("The update method requires an object with key-value pairs.");
933
1008
  }
934
- if (clone.dml.where.length === 0) {
1009
+ if (this.dml.where.length === 0) {
935
1010
  throw new Error("You must specify at least one WHERE condition to perform an update.");
936
1011
  }
1012
+ if (this._batchSink) {
1013
+ this._batchSink.push({ ...this.dml, type: "update", data });
1014
+ return void 0;
1015
+ }
1016
+ if (this.triggers.length === 0 && this.computedFields.length === 0) {
1017
+ const dml = { ...this.dml, type: "update", data };
1018
+ const response = await this.engine.executeDml(dml, this.txId ?? void 0);
1019
+ if (response.status != 200) {
1020
+ returnFormattedError(response.status, response.message);
1021
+ throw new Error(String(response.message));
1022
+ }
1023
+ return response.data;
1024
+ }
1025
+ const clone = this.clone();
937
1026
  clone.dml.type = "update";
938
1027
  clone.dml.data = data;
939
1028
  return clone.getResponse(clone.dml, "Update");
@@ -948,10 +1037,23 @@ var Table = class _Table {
948
1037
  * console.log(result); // { affectedRows: 1 }
949
1038
  */
950
1039
  async delete() {
951
- const clone = this.clone();
952
- if (clone.dml.where.length === 0) {
1040
+ if (this.dml.where.length === 0) {
953
1041
  throw new Error("You must specify at least one WHERE condition to perform a delete.");
954
1042
  }
1043
+ if (this._batchSink) {
1044
+ this._batchSink.push({ ...this.dml, type: "delete", data: null });
1045
+ return void 0;
1046
+ }
1047
+ if (this.triggers.length === 0 && this.computedFields.length === 0) {
1048
+ const dml = { ...this.dml, type: "delete", data: null };
1049
+ const response = await this.engine.executeDml(dml, this.txId ?? void 0);
1050
+ if (response.status != 200) {
1051
+ returnFormattedError(response.status, response.message);
1052
+ throw new Error(String(response.message));
1053
+ }
1054
+ return response.data;
1055
+ }
1056
+ const clone = this.clone();
955
1057
  clone.dml.type = "delete";
956
1058
  const deleteData = await clone.getResponse(clone.dml, "Delete");
957
1059
  return deleteData;
@@ -1104,12 +1206,26 @@ var Table = class _Table {
1104
1206
  * await db.table('posts').where('id', '=', 1).increment('views', 1, { last_viewed_at: new Date().toISOString() });
1105
1207
  */
1106
1208
  async increment(column, amount = 1, extra = {}) {
1107
- const clone = this.clone();
1108
- if (clone.dml.where.length === 0) {
1209
+ if (this.dml.where.length === 0) {
1109
1210
  throw new Error("You must specify at least one WHERE condition to perform an increment.");
1110
1211
  }
1212
+ const data = { ...extra, [column]: { $inc: Number(amount) } };
1213
+ if (this._batchSink) {
1214
+ this._batchSink.push({ ...this.dml, type: "update", data });
1215
+ return void 0;
1216
+ }
1217
+ if (this.triggers.length === 0 && this.computedFields.length === 0) {
1218
+ const dml = { ...this.dml, type: "update", data };
1219
+ const response = await this.engine.executeDml(dml, this.txId ?? void 0);
1220
+ if (response.status != 200) {
1221
+ returnFormattedError(response.status, response.message);
1222
+ throw new Error(String(response.message));
1223
+ }
1224
+ return response.data;
1225
+ }
1226
+ const clone = this.clone();
1111
1227
  clone.dml.type = "update";
1112
- clone.dml.data = { ...extra, [column]: { $inc: Number(amount) } };
1228
+ clone.dml.data = data;
1113
1229
  return clone.getResponse();
1114
1230
  }
1115
1231
  /**
@@ -1309,8 +1425,8 @@ var Table = class _Table {
1309
1425
  }
1310
1426
  let arrayResult = [];
1311
1427
  if (type) {
1312
- const beffore = this.trigger.get("before" + type);
1313
- const after = this.trigger.get("after" + type);
1428
+ const beffore = this.trigger ? this.trigger.get("before" + type) : void 0;
1429
+ const after = this.trigger ? this.trigger.get("after" + type) : void 0;
1314
1430
  if (this.triggers.length > 0 && (beffore || after)) {
1315
1431
  const dataset = localDML.data;
1316
1432
  for (let index = 0; index < dataset.length; index++) {
@@ -1370,6 +1486,7 @@ var Table = class _Table {
1370
1486
  const cloned = Object.create(Object.getPrototypeOf(this));
1371
1487
  cloned.engine = this.engine;
1372
1488
  cloned.instance = this.instance;
1489
+ cloned._batchSink = this._batchSink;
1373
1490
  cloned.nextType = this.nextType;
1374
1491
  cloned.computedFields = this.computedFields;
1375
1492
  cloned.trigger = this.trigger;
@@ -1478,7 +1595,7 @@ ${color}${BOLD}${message}${RESET}
1478
1595
  (line) => line.includes(".js:") && !line.includes("node_modules")
1479
1596
  );
1480
1597
  if (relevantStackLine) {
1481
- const match = relevantStackLine.match(/\((.*):(\d+):(\d+)\)/) || relevantStackLine.match(/at (.*):(\d+):(\d+)/);
1598
+ const match = relevantStackLine.match(/\((.*):(\d+):(\d+)\)/) || relevantStackLine.match(/at (?:async )?(.*):(\d+):(\d+)/);
1482
1599
  if (match) {
1483
1600
  const [, filePath, lineStr, columnStr] = match;
1484
1601
  const lineNum = parseInt(lineStr, 10);