@areumtecnologia/mysql-db-handler 1.0.8 → 1.0.9
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 +49 -1
- package/lib/databaseHandler.js +68 -58
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -224,7 +224,9 @@ console.log('Inserted ID:', result.insertId);
|
|
|
224
224
|
|
|
225
225
|
### Updating Records (`update`)
|
|
226
226
|
|
|
227
|
-
Performs selective updates by specifying both a `set` payload and a `where` filter.
|
|
227
|
+
Performs selective updates by specifying both a `set` payload and a `where` filter. The `where` filter supports both standard flat objects (where conditions are implicitly joined by `AND` using `=` or `REGEXP`) and complex array configurations (with operators, `AND`, and `OR`), sharing the same advanced querying capabilities as the `select` method.
|
|
228
|
+
|
|
229
|
+
#### 1. Simple Object Syntax (Implicit AND, = operator)
|
|
228
230
|
|
|
229
231
|
```javascript
|
|
230
232
|
const result = await usersHandler.update({
|
|
@@ -239,6 +241,52 @@ const result = await usersHandler.update({
|
|
|
239
241
|
});
|
|
240
242
|
|
|
241
243
|
console.log('Affected rows:', result.affectedRows);
|
|
244
|
+
// Executes: UPDATE users SET `status` = ?, `notes` = ? WHERE `id` = ? AND `status` = ?
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
#### 2. Advanced Array Syntax (with operators, AND/OR, and IN)
|
|
248
|
+
|
|
249
|
+
You can pass an array of condition objects interleaved with `AND` or `OR` string elements to construct complex queries:
|
|
250
|
+
|
|
251
|
+
```javascript
|
|
252
|
+
// Example updating records based on numeric thresholds and logical operators
|
|
253
|
+
const result = await usersHandler.update({
|
|
254
|
+
set: {
|
|
255
|
+
status: 'inactive'
|
|
256
|
+
},
|
|
257
|
+
where: [
|
|
258
|
+
{ age: 18, operator: '<' },
|
|
259
|
+
'AND',
|
|
260
|
+
{ status: 'active' }
|
|
261
|
+
]
|
|
262
|
+
});
|
|
263
|
+
// Executes: UPDATE users SET `status` = ? WHERE `age` < ? AND `status` = ?
|
|
264
|
+
|
|
265
|
+
// Example updating records using automatic IN operator detection
|
|
266
|
+
const result = await usersHandler.update({
|
|
267
|
+
set: {
|
|
268
|
+
role: 'archived'
|
|
269
|
+
},
|
|
270
|
+
where: [
|
|
271
|
+
{ id: [10, 20, 30] } // Automatically builds: WHERE `id` IN (?, ?, ?)
|
|
272
|
+
]
|
|
273
|
+
});
|
|
274
|
+
// Executes: UPDATE users SET `role` = ? WHERE `id` IN (?, ?, ?)
|
|
275
|
+
|
|
276
|
+
// Example combining complex logic (AND/OR)
|
|
277
|
+
const result = await usersHandler.update({
|
|
278
|
+
set: {
|
|
279
|
+
category: 'Premium'
|
|
280
|
+
},
|
|
281
|
+
where: [
|
|
282
|
+
{ total_purchases: 1000, operator: '>' },
|
|
283
|
+
'AND',
|
|
284
|
+
{ status: 'active' },
|
|
285
|
+
'OR',
|
|
286
|
+
{ is_vip: 1 }
|
|
287
|
+
]
|
|
288
|
+
});
|
|
289
|
+
// Executes: UPDATE users SET `category` = ? WHERE `total_purchases` > ? AND `status` = ? OR `is_vip` = ?
|
|
242
290
|
```
|
|
243
291
|
|
|
244
292
|
### Deleting Records (`delete`)
|
package/lib/databaseHandler.js
CHANGED
|
@@ -62,6 +62,67 @@ class DatabaseHandler {
|
|
|
62
62
|
return { sql: `(${clauses.join(' ')})`, bindings };
|
|
63
63
|
}
|
|
64
64
|
|
|
65
|
+
/**
|
|
66
|
+
* @private
|
|
67
|
+
* Constrói a cláusula WHERE (sem a palavra-chave WHERE) e seus bindings associados.
|
|
68
|
+
* @param {Object|Array} where - Condições do where.
|
|
69
|
+
* @param {boolean} useRegex - Se deve usar REGEXP por padrão (para compatibilidade com update).
|
|
70
|
+
* @returns {{ sql: string, bindings: Array }}
|
|
71
|
+
*/
|
|
72
|
+
_buildWhereClause(where, useRegex = false) {
|
|
73
|
+
if (!where) {
|
|
74
|
+
return { sql: '', bindings: [] };
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const conditions = [];
|
|
78
|
+
const bindings = [];
|
|
79
|
+
|
|
80
|
+
if (Array.isArray(where)) {
|
|
81
|
+
where.forEach((param) => {
|
|
82
|
+
if (typeof param === 'object' && param !== null && !Array.isArray(param)) {
|
|
83
|
+
const entries = Object.entries(param);
|
|
84
|
+
if (entries.length === 0) return;
|
|
85
|
+
|
|
86
|
+
const [key, value] = entries[0];
|
|
87
|
+
const [operatorKey, operatorValue] = entries[1] || [];
|
|
88
|
+
|
|
89
|
+
let op = operatorValue ?? (useRegex ? 'REGEXP' : '=');
|
|
90
|
+
let upperOp = String(op).toUpperCase();
|
|
91
|
+
|
|
92
|
+
if (Array.isArray(value) && upperOp === '=') {
|
|
93
|
+
op = 'IN';
|
|
94
|
+
upperOp = 'IN';
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
if (Array.isArray(value) && (upperOp === 'IN' || upperOp === 'NOT IN')) {
|
|
98
|
+
if (value.length === 0) {
|
|
99
|
+
conditions.push(upperOp === 'IN' ? '1 = 0' : '1 = 1');
|
|
100
|
+
} else {
|
|
101
|
+
const placeholders = value.map(() => '?').join(', ');
|
|
102
|
+
conditions.push(`\`${key}\` ${op} (${placeholders})`);
|
|
103
|
+
bindings.push(...value);
|
|
104
|
+
}
|
|
105
|
+
} else {
|
|
106
|
+
const condition = `\`${key}\` ${op} ?`;
|
|
107
|
+
conditions.push(condition);
|
|
108
|
+
bindings.push(value);
|
|
109
|
+
}
|
|
110
|
+
} else if (typeof param === 'string') {
|
|
111
|
+
conditions.push(param.toUpperCase());
|
|
112
|
+
}
|
|
113
|
+
});
|
|
114
|
+
return { sql: conditions.join(' '), bindings };
|
|
115
|
+
} else if (typeof where === 'object' && where !== null) {
|
|
116
|
+
const operator = useRegex ? 'REGEXP' : '=';
|
|
117
|
+
const keys = Object.keys(where);
|
|
118
|
+
const sql = keys.map(key => `\`${key}\` ${operator} ?`).join(' AND ');
|
|
119
|
+
const bindings = Object.values(where);
|
|
120
|
+
return { sql, bindings };
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
return { sql: '', bindings: [] };
|
|
124
|
+
}
|
|
125
|
+
|
|
65
126
|
async selectToDatatable(rawDtQuery, strictCondition = []) {
|
|
66
127
|
// NOVO: Hidrata o objeto da requisição para o formato aninhado correto.
|
|
67
128
|
const dtQuery = this._hydrateObject(rawDtQuery);
|
|
@@ -214,61 +275,8 @@ class DatabaseHandler {
|
|
|
214
275
|
return new Error('O parâmetro "params" deve ser um array');
|
|
215
276
|
}
|
|
216
277
|
|
|
217
|
-
const
|
|
218
|
-
const
|
|
219
|
-
|
|
220
|
-
if (params && params.length) {
|
|
221
|
-
// Dica: Troquei map por forEach. O map é para transformar arrays,
|
|
222
|
-
// como você só está preenchendo variáveis externas, forEach é semanticamente correto.
|
|
223
|
-
params.forEach((param) => {
|
|
224
|
-
if (typeof param === 'object' && !Array.isArray(param)) {
|
|
225
|
-
const entries = Object.entries(param);
|
|
226
|
-
const [key, value] = entries[0];
|
|
227
|
-
const [operatorKey, operatorValue] = entries[1] || [];
|
|
228
|
-
|
|
229
|
-
// --- INÍCIO DAS MODIFICAÇÕES PARA SUPORTE AO IN ---
|
|
230
|
-
|
|
231
|
-
// 1. Define o operador (padrão é '=')
|
|
232
|
-
let op = operatorValue ?? '=';
|
|
233
|
-
const upperOp = op.toUpperCase();
|
|
234
|
-
|
|
235
|
-
// 2. "Magia": Se o valor for um array e não tiver operador (ou for '='),
|
|
236
|
-
// converte automaticamente para 'IN' para facilitar sua vida.
|
|
237
|
-
if (Array.isArray(value) && upperOp === '=') {
|
|
238
|
-
op = 'IN';
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
// 3. Lógica específica para IN e NOT IN
|
|
242
|
-
if (Array.isArray(value) && (upperOp === 'IN' || upperOp === 'NOT IN')) {
|
|
243
|
-
if (value.length === 0) {
|
|
244
|
-
// O SQL não permite "IN ()".
|
|
245
|
-
// Um IN vazio nunca encontra nada (falso), um NOT IN vazio encontra tudo (verdadeiro).
|
|
246
|
-
conditions.push(upperOp === 'IN' ? '1 = 0' : '1 = 1');
|
|
247
|
-
} else {
|
|
248
|
-
// Cria a string de placeholders: "?, ?, ?" baseada no tamanho do array
|
|
249
|
-
const placeholders = value.map(() => '?').join(', ');
|
|
250
|
-
conditions.push(`\`${key}\` ${op} (${placeholders})`);
|
|
251
|
-
|
|
252
|
-
// Espalha os valores do array individualmente no array de values
|
|
253
|
-
values.push(...value);
|
|
254
|
-
}
|
|
255
|
-
} else {
|
|
256
|
-
// 4. Lógica original para valores únicos (string, number, boolean, etc)
|
|
257
|
-
// ou outros operadores (LIKE, REGEXP, >, <, etc)
|
|
258
|
-
const condition = `\`${key}\` ${op} ?`;
|
|
259
|
-
conditions.push(condition);
|
|
260
|
-
values.push(value);
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
// --- FIM DAS MODIFICAÇÕES ---
|
|
264
|
-
|
|
265
|
-
} else if (typeof param === 'string') {
|
|
266
|
-
conditions.push(param.toUpperCase());
|
|
267
|
-
}
|
|
268
|
-
});
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
const whereClause = conditions.length > 0 ? ` WHERE ${conditions.join(' ')}` : '';
|
|
278
|
+
const { sql: whereSql, bindings: values } = this._buildWhereClause(params);
|
|
279
|
+
const whereClause = whereSql ? ` WHERE ${whereSql}` : '';
|
|
272
280
|
|
|
273
281
|
// Cláusulas adicionais
|
|
274
282
|
const groupByClause = clauses['GROUPBY'] ? ` GROUP BY ${clauses['GROUPBY']}` : '';
|
|
@@ -292,14 +300,16 @@ class DatabaseHandler {
|
|
|
292
300
|
|
|
293
301
|
async update(params, options = {}) {
|
|
294
302
|
// Inicializa a string SQL para a cláusula SET
|
|
295
|
-
const operator = options.useRegex ? 'REGEXP' : '=';
|
|
296
303
|
let setClause = Object.keys(params.set).map(key => `\`${key}\` = ?`).join(', ');
|
|
304
|
+
let setValues = Object.values(params.set);
|
|
305
|
+
|
|
297
306
|
// Inicializa a string SQL para a cláusula WHERE
|
|
298
|
-
|
|
307
|
+
const { sql: whereClause, bindings: whereValues } = this._buildWhereClause(params.where, !!options.useRegex);
|
|
308
|
+
|
|
299
309
|
// Constrói a consulta SQL completa
|
|
300
310
|
const sql = `UPDATE ${this.table} SET ${setClause} WHERE ${whereClause}`;
|
|
301
311
|
// Combina os valores SET e WHERE em um único array
|
|
302
|
-
const values = [...
|
|
312
|
+
const values = [...setValues, ...whereValues];
|
|
303
313
|
// Executa a consulta
|
|
304
314
|
const result = await this.executeQuery(sql, values);
|
|
305
315
|
|
package/package.json
CHANGED