@dbcube/query-builder 5.2.2 → 5.2.3
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 +129 -12
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.mts +70 -0
- package/dist/index.d.ts +70 -0
- package/dist/index.js +129 -12
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,54 @@
|
|
|
1
1
|
import { QueryEngine } from '@dbcube/core';
|
|
2
2
|
|
|
3
|
+
export interface JoinCondition {
|
|
4
|
+
column1: string;
|
|
5
|
+
operator: string;
|
|
6
|
+
column2: string;
|
|
7
|
+
}
|
|
8
|
+
export interface Join {
|
|
9
|
+
type: "INNER" | "LEFT" | "RIGHT";
|
|
10
|
+
table: string;
|
|
11
|
+
on: JoinCondition;
|
|
12
|
+
}
|
|
13
|
+
export interface WhereCondition {
|
|
14
|
+
column: string;
|
|
15
|
+
operator: string;
|
|
16
|
+
value?: any;
|
|
17
|
+
type: "AND" | "OR";
|
|
18
|
+
isGroup: boolean;
|
|
19
|
+
}
|
|
20
|
+
export interface GroupedWhereCondition {
|
|
21
|
+
type: "AND" | "OR";
|
|
22
|
+
isGroup: true;
|
|
23
|
+
conditions: WhereCondition[];
|
|
24
|
+
}
|
|
25
|
+
export interface OrderBy {
|
|
26
|
+
column: string;
|
|
27
|
+
direction: "ASC" | "DESC";
|
|
28
|
+
}
|
|
29
|
+
export interface Aggregation {
|
|
30
|
+
type: "COUNT" | "SUM" | "AVG" | "MAX" | "MIN";
|
|
31
|
+
column: string;
|
|
32
|
+
alias: string;
|
|
33
|
+
}
|
|
34
|
+
export interface DML {
|
|
35
|
+
type: "select" | "insert" | "update" | "delete" | "columns";
|
|
36
|
+
database: string;
|
|
37
|
+
table: string;
|
|
38
|
+
columns: string[];
|
|
39
|
+
requestedFields?: string[];
|
|
40
|
+
computedFieldsNeeded?: any[];
|
|
41
|
+
distinct: boolean;
|
|
42
|
+
joins: Join[];
|
|
43
|
+
where: (WhereCondition | GroupedWhereCondition)[];
|
|
44
|
+
orderBy: OrderBy[];
|
|
45
|
+
groupBy: string[];
|
|
46
|
+
limit: number | null;
|
|
47
|
+
offset: number | null;
|
|
48
|
+
data: any[] | Record<string, any> | null;
|
|
49
|
+
aggregation: Aggregation | null;
|
|
50
|
+
having?: (WhereCondition | GroupedWhereCondition)[];
|
|
51
|
+
}
|
|
3
52
|
export interface PaginatedResult<T = DatabaseRecord> {
|
|
4
53
|
items: T[];
|
|
5
54
|
page: number;
|
|
@@ -80,6 +129,24 @@ export declare class Database {
|
|
|
80
129
|
* });
|
|
81
130
|
*/
|
|
82
131
|
transaction<T>(callback: (trx: Database) => Promise<T>): Promise<T>;
|
|
132
|
+
/**
|
|
133
|
+
* Atomic batch: every write queued in the callback runs inside ONE
|
|
134
|
+
* transaction with a SINGLE engine round-trip (begin/commit included).
|
|
135
|
+
* The callback is synchronous — writes are collected, not awaited.
|
|
136
|
+
* Any failure rolls back everything.
|
|
137
|
+
*
|
|
138
|
+
* This is the fastest way to run a sequence of writes atomically.
|
|
139
|
+
* For transactions that need to READ intermediate results, use
|
|
140
|
+
* `transaction()` (interactive) instead. Triggers/computed fields do
|
|
141
|
+
* not run in batch mode.
|
|
142
|
+
*
|
|
143
|
+
* @example
|
|
144
|
+
* await db.batch(b => {
|
|
145
|
+
* b.table('accounts').where('id', '=', 1).decrement('balance', 200);
|
|
146
|
+
* b.table('accounts').where('id', '=', 2).increment('balance', 200);
|
|
147
|
+
* });
|
|
148
|
+
*/
|
|
149
|
+
batch(builder: (b: Database) => void): Promise<MutationInfo[][]>;
|
|
83
150
|
useComputes(): Promise<Database>;
|
|
84
151
|
useTriggers(): Promise<Database>;
|
|
85
152
|
connect(): Promise<void>;
|
|
@@ -143,6 +210,9 @@ export declare class Table<T extends DatabaseRecord = DatabaseRecord> {
|
|
|
143
210
|
private relations;
|
|
144
211
|
/** Builders de grupo mutan en sitio (ver clone()) */
|
|
145
212
|
private _mutable;
|
|
213
|
+
/** En modo batch (db.batch) las escrituras se encolan aquí en vez de
|
|
214
|
+
* ejecutarse: toda la transacción viaja al engine en UN solo cruce. */
|
|
215
|
+
_batchSink: DML[] | null;
|
|
146
216
|
private instance;
|
|
147
217
|
constructor(instance: Database, databaseName: string, tableName: string, engine: QueryEngine, computedFields?: ComputedFieldConfig[], triggers?: TriggerConfig[], txId?: string | null);
|
|
148
218
|
/**
|
package/dist/index.js
CHANGED
|
@@ -120,6 +120,39 @@ var Database = class _Database {
|
|
|
120
120
|
throw error;
|
|
121
121
|
}
|
|
122
122
|
}
|
|
123
|
+
/**
|
|
124
|
+
* Atomic batch: every write queued in the callback runs inside ONE
|
|
125
|
+
* transaction with a SINGLE engine round-trip (begin/commit included).
|
|
126
|
+
* The callback is synchronous — writes are collected, not awaited.
|
|
127
|
+
* Any failure rolls back everything.
|
|
128
|
+
*
|
|
129
|
+
* This is the fastest way to run a sequence of writes atomically.
|
|
130
|
+
* For transactions that need to READ intermediate results, use
|
|
131
|
+
* `transaction()` (interactive) instead. Triggers/computed fields do
|
|
132
|
+
* not run in batch mode.
|
|
133
|
+
*
|
|
134
|
+
* @example
|
|
135
|
+
* await db.batch(b => {
|
|
136
|
+
* b.table('accounts').where('id', '=', 1).decrement('balance', 200);
|
|
137
|
+
* b.table('accounts').where('id', '=', 2).increment('balance', 200);
|
|
138
|
+
* });
|
|
139
|
+
*/
|
|
140
|
+
async batch(builder) {
|
|
141
|
+
const ops = [];
|
|
142
|
+
const collector = new _Database(this.name);
|
|
143
|
+
collector.engine = this.engine;
|
|
144
|
+
collector.computedFields = this.computedFields;
|
|
145
|
+
collector.triggers = this.triggers;
|
|
146
|
+
collector._collectInto = ops;
|
|
147
|
+
builder(collector);
|
|
148
|
+
if (ops.length === 0) return [];
|
|
149
|
+
const response = await this.engine.executeBatch(ops);
|
|
150
|
+
if (response.status !== 200) {
|
|
151
|
+
returnFormattedError(response.status, response.message);
|
|
152
|
+
throw new Error(String(response.message));
|
|
153
|
+
}
|
|
154
|
+
return response.data;
|
|
155
|
+
}
|
|
123
156
|
async useComputes() {
|
|
124
157
|
const newDatabase = new _Database(this.name);
|
|
125
158
|
const arrayComputedFields = await ComputedFieldProcessor.getComputedFields(this.name);
|
|
@@ -185,7 +218,10 @@ var Database = class _Database {
|
|
|
185
218
|
* const columns = await db.table('users').columns().get();
|
|
186
219
|
*/
|
|
187
220
|
table(tableName) {
|
|
188
|
-
|
|
221
|
+
const t = new Table(this, this.name, tableName, this.engine, this.computedFields, this.triggers, this.txId);
|
|
222
|
+
const sink = this._collectInto;
|
|
223
|
+
if (sink) t._batchSink = sink;
|
|
224
|
+
return t;
|
|
189
225
|
}
|
|
190
226
|
setComputedFields(computedFields) {
|
|
191
227
|
this.computedFields = computedFields;
|
|
@@ -205,13 +241,16 @@ var Table = class _Table {
|
|
|
205
241
|
relations = [];
|
|
206
242
|
/** Builders de grupo mutan en sitio (ver clone()) */
|
|
207
243
|
_mutable = false;
|
|
244
|
+
/** En modo batch (db.batch) las escrituras se encolan aquí en vez de
|
|
245
|
+
* ejecutarse: toda la transacción viaja al engine en UN solo cruce. */
|
|
246
|
+
_batchSink = null;
|
|
208
247
|
instance;
|
|
209
248
|
constructor(instance, databaseName, tableName, engine, computedFields = [], triggers = [], txId = null) {
|
|
210
249
|
this.engine = engine;
|
|
211
250
|
this.instance = instance;
|
|
212
251
|
this.computedFields = computedFields;
|
|
213
252
|
this.triggers = triggers;
|
|
214
|
-
this.trigger = new Trigger(instance, databaseName, triggers);
|
|
253
|
+
this.trigger = triggers.length > 0 ? new Trigger(instance, databaseName, triggers) : null;
|
|
215
254
|
this.nextType = "AND";
|
|
216
255
|
this.txId = txId;
|
|
217
256
|
this.dml = {
|
|
@@ -838,6 +877,30 @@ var Table = class _Table {
|
|
|
838
877
|
* console.log(user); // { id: 1, name: 'John' }
|
|
839
878
|
*/
|
|
840
879
|
async find(value, column = "id") {
|
|
880
|
+
if (this.computedFields.length === 0 && this.relations.length === 0 && !this._mutable) {
|
|
881
|
+
const dml = {
|
|
882
|
+
type: "select",
|
|
883
|
+
database: this.dml.database,
|
|
884
|
+
table: this.dml.table,
|
|
885
|
+
columns: ["*"],
|
|
886
|
+
distinct: false,
|
|
887
|
+
joins: [],
|
|
888
|
+
where: [{ column, operator: "=", value, type: "AND", isGroup: false }],
|
|
889
|
+
orderBy: [],
|
|
890
|
+
groupBy: [],
|
|
891
|
+
limit: 1,
|
|
892
|
+
offset: null,
|
|
893
|
+
data: null,
|
|
894
|
+
aggregation: null,
|
|
895
|
+
having: []
|
|
896
|
+
};
|
|
897
|
+
const response = await this.engine.executeDml(dml, this.txId ?? void 0);
|
|
898
|
+
if (response.status != 200) {
|
|
899
|
+
returnFormattedError(response.status, response.message);
|
|
900
|
+
throw new Error(String(response.message));
|
|
901
|
+
}
|
|
902
|
+
return response.data?.[0] || null;
|
|
903
|
+
}
|
|
841
904
|
const clone = this.clone().where(column, "=", value);
|
|
842
905
|
clone.dml.type = "select";
|
|
843
906
|
clone.dml.data = null;
|
|
@@ -864,13 +927,26 @@ var Table = class _Table {
|
|
|
864
927
|
* console.log(newUsers); // [{ id: 3, name: 'Alice', age: 28 }, { id: 4, name: 'Bob', age: 32 }]
|
|
865
928
|
*/
|
|
866
929
|
async insert(data) {
|
|
867
|
-
const clone = this.clone();
|
|
868
930
|
if (!Array.isArray(data)) {
|
|
869
931
|
throw new Error("The insert method requires an array of objects with key-value pairs.");
|
|
870
932
|
}
|
|
871
933
|
if (!data.every((item) => typeof item === "object" && item !== null)) {
|
|
872
934
|
throw new Error("The array must contain only valid objects.");
|
|
873
935
|
}
|
|
936
|
+
if (this._batchSink) {
|
|
937
|
+
this._batchSink.push({ ...this.dml, type: "insert", data });
|
|
938
|
+
return void 0;
|
|
939
|
+
}
|
|
940
|
+
if (this.triggers.length === 0 && this.computedFields.length === 0) {
|
|
941
|
+
const dml = { ...this.dml, type: "insert", data };
|
|
942
|
+
const response = await this.engine.executeDml(dml, this.txId ?? void 0);
|
|
943
|
+
if (response.status != 200) {
|
|
944
|
+
returnFormattedError(response.status, response.message);
|
|
945
|
+
throw new Error(String(response.message));
|
|
946
|
+
}
|
|
947
|
+
return response.data ?? data;
|
|
948
|
+
}
|
|
949
|
+
const clone = this.clone();
|
|
874
950
|
clone.dml.type = "insert";
|
|
875
951
|
clone.dml.data = data;
|
|
876
952
|
const result = await clone.getResponse(clone.dml, "Add");
|
|
@@ -889,13 +965,26 @@ var Table = class _Table {
|
|
|
889
965
|
* console.log(result); // { affectedRows: 1 }
|
|
890
966
|
*/
|
|
891
967
|
async update(data) {
|
|
892
|
-
const clone = this.clone();
|
|
893
968
|
if (typeof data !== "object" || Array.isArray(data)) {
|
|
894
969
|
throw new Error("The update method requires an object with key-value pairs.");
|
|
895
970
|
}
|
|
896
|
-
if (
|
|
971
|
+
if (this.dml.where.length === 0) {
|
|
897
972
|
throw new Error("You must specify at least one WHERE condition to perform an update.");
|
|
898
973
|
}
|
|
974
|
+
if (this._batchSink) {
|
|
975
|
+
this._batchSink.push({ ...this.dml, type: "update", data });
|
|
976
|
+
return void 0;
|
|
977
|
+
}
|
|
978
|
+
if (this.triggers.length === 0 && this.computedFields.length === 0) {
|
|
979
|
+
const dml = { ...this.dml, type: "update", 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;
|
|
986
|
+
}
|
|
987
|
+
const clone = this.clone();
|
|
899
988
|
clone.dml.type = "update";
|
|
900
989
|
clone.dml.data = data;
|
|
901
990
|
return clone.getResponse(clone.dml, "Update");
|
|
@@ -910,10 +999,23 @@ var Table = class _Table {
|
|
|
910
999
|
* console.log(result); // { affectedRows: 1 }
|
|
911
1000
|
*/
|
|
912
1001
|
async delete() {
|
|
913
|
-
|
|
914
|
-
if (clone.dml.where.length === 0) {
|
|
1002
|
+
if (this.dml.where.length === 0) {
|
|
915
1003
|
throw new Error("You must specify at least one WHERE condition to perform a delete.");
|
|
916
1004
|
}
|
|
1005
|
+
if (this._batchSink) {
|
|
1006
|
+
this._batchSink.push({ ...this.dml, type: "delete", data: null });
|
|
1007
|
+
return void 0;
|
|
1008
|
+
}
|
|
1009
|
+
if (this.triggers.length === 0 && this.computedFields.length === 0) {
|
|
1010
|
+
const dml = { ...this.dml, type: "delete", data: null };
|
|
1011
|
+
const response = await this.engine.executeDml(dml, this.txId ?? void 0);
|
|
1012
|
+
if (response.status != 200) {
|
|
1013
|
+
returnFormattedError(response.status, response.message);
|
|
1014
|
+
throw new Error(String(response.message));
|
|
1015
|
+
}
|
|
1016
|
+
return response.data;
|
|
1017
|
+
}
|
|
1018
|
+
const clone = this.clone();
|
|
917
1019
|
clone.dml.type = "delete";
|
|
918
1020
|
const deleteData = await clone.getResponse(clone.dml, "Delete");
|
|
919
1021
|
return deleteData;
|
|
@@ -1066,12 +1168,26 @@ var Table = class _Table {
|
|
|
1066
1168
|
* await db.table('posts').where('id', '=', 1).increment('views', 1, { last_viewed_at: new Date().toISOString() });
|
|
1067
1169
|
*/
|
|
1068
1170
|
async increment(column, amount = 1, extra = {}) {
|
|
1069
|
-
|
|
1070
|
-
if (clone.dml.where.length === 0) {
|
|
1171
|
+
if (this.dml.where.length === 0) {
|
|
1071
1172
|
throw new Error("You must specify at least one WHERE condition to perform an increment.");
|
|
1072
1173
|
}
|
|
1174
|
+
const data = { ...extra, [column]: { $inc: Number(amount) } };
|
|
1175
|
+
if (this._batchSink) {
|
|
1176
|
+
this._batchSink.push({ ...this.dml, type: "update", data });
|
|
1177
|
+
return void 0;
|
|
1178
|
+
}
|
|
1179
|
+
if (this.triggers.length === 0 && this.computedFields.length === 0) {
|
|
1180
|
+
const dml = { ...this.dml, type: "update", data };
|
|
1181
|
+
const response = await this.engine.executeDml(dml, this.txId ?? void 0);
|
|
1182
|
+
if (response.status != 200) {
|
|
1183
|
+
returnFormattedError(response.status, response.message);
|
|
1184
|
+
throw new Error(String(response.message));
|
|
1185
|
+
}
|
|
1186
|
+
return response.data;
|
|
1187
|
+
}
|
|
1188
|
+
const clone = this.clone();
|
|
1073
1189
|
clone.dml.type = "update";
|
|
1074
|
-
clone.dml.data =
|
|
1190
|
+
clone.dml.data = data;
|
|
1075
1191
|
return clone.getResponse();
|
|
1076
1192
|
}
|
|
1077
1193
|
/**
|
|
@@ -1271,8 +1387,8 @@ var Table = class _Table {
|
|
|
1271
1387
|
}
|
|
1272
1388
|
let arrayResult = [];
|
|
1273
1389
|
if (type) {
|
|
1274
|
-
const beffore = this.trigger.get("before" + type);
|
|
1275
|
-
const after = this.trigger.get("after" + type);
|
|
1390
|
+
const beffore = this.trigger ? this.trigger.get("before" + type) : void 0;
|
|
1391
|
+
const after = this.trigger ? this.trigger.get("after" + type) : void 0;
|
|
1276
1392
|
if (this.triggers.length > 0 && (beffore || after)) {
|
|
1277
1393
|
const dataset = localDML.data;
|
|
1278
1394
|
for (let index = 0; index < dataset.length; index++) {
|
|
@@ -1332,6 +1448,7 @@ var Table = class _Table {
|
|
|
1332
1448
|
const cloned = Object.create(Object.getPrototypeOf(this));
|
|
1333
1449
|
cloned.engine = this.engine;
|
|
1334
1450
|
cloned.instance = this.instance;
|
|
1451
|
+
cloned._batchSink = this._batchSink;
|
|
1335
1452
|
cloned.nextType = this.nextType;
|
|
1336
1453
|
cloned.computedFields = this.computedFields;
|
|
1337
1454
|
cloned.trigger = this.trigger;
|