@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 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`)
@@ -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 conditions = [];
218
- const values = [];
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
- let whereClause = Object.keys(params.where).map(key => `\`${key}\` ${operator} ?`).join(' AND ');
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 = [...Object.values(params.set), ...Object.values(params.where)];
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@areumtecnologia/mysql-db-handler",
3
- "version": "1.0.8",
3
+ "version": "1.0.9",
4
4
  "description": "A powerful MySQL wrapper with connection pooling, singleton support, and advanced query handling for Node.js.",
5
5
  "main": "index.js",
6
6
  "scripts": {