@areumtecnologia/mysql-db-handler 1.0.9 → 1.0.10
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/index.js +3 -1
- package/lib/database-cache.js +2 -2
- package/lib/database.js +8 -4
- package/lib/databaseHandler.js +56 -7
- package/package.json +3 -3
- package/lib/database-singleton.js +0 -19
package/index.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
// Áreum Tecnologia - Renan Moreira - renan.moreira@areum.com.br
|
|
2
|
+
const DataBaseCache = require('./lib/database-cache');
|
|
2
3
|
const DataBase = require('./lib/database');
|
|
3
4
|
const DataBaseHandler = require('./lib/databaseHandler');
|
|
4
5
|
// We do not export the singleton by default in a library usually,
|
|
@@ -6,5 +7,6 @@ const DataBaseHandler = require('./lib/databaseHandler');
|
|
|
6
7
|
|
|
7
8
|
module.exports = {
|
|
8
9
|
DataBase,
|
|
9
|
-
DataBaseHandler
|
|
10
|
+
DataBaseHandler,
|
|
11
|
+
DataBaseCache
|
|
10
12
|
};
|
package/lib/database-cache.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
const mysql = require('mysql2/promise');
|
|
3
3
|
const NodeCache = require('node-cache');
|
|
4
4
|
|
|
5
|
-
class
|
|
5
|
+
class DataBaseCache {
|
|
6
6
|
constructor(config = {}) {
|
|
7
7
|
this.config = config;
|
|
8
8
|
this.pool = mysql.createPool(this.config); // The pool is created once when the instance is created.
|
|
@@ -74,4 +74,4 @@ class DataBase {
|
|
|
74
74
|
}
|
|
75
75
|
}
|
|
76
76
|
|
|
77
|
-
module.exports =
|
|
77
|
+
module.exports = DataBaseCache;
|
package/lib/database.js
CHANGED
|
@@ -31,8 +31,9 @@ class DataBase {
|
|
|
31
31
|
* Executes a SQL query using a pooled connection.
|
|
32
32
|
* @param {string} sql - The SQL query to execute.
|
|
33
33
|
* @param {Array} [params] - The parameters for the SQL query.
|
|
34
|
-
* @returns {Promise<Array>} The result set from the query
|
|
35
|
-
*
|
|
34
|
+
* @returns {Promise<Array|{error: Error}>} The result set from the query,
|
|
35
|
+
* or an object with an `error` property if the query fails.
|
|
36
|
+
* This prevents unhandled exceptions from crashing the application.
|
|
36
37
|
*/
|
|
37
38
|
async query(sql, params) {
|
|
38
39
|
let connection; // Mova a declaração da conexão para fora do bloco try
|
|
@@ -44,9 +45,12 @@ class DataBase {
|
|
|
44
45
|
const [rows] = await connection.query(sql, params);
|
|
45
46
|
return rows;
|
|
46
47
|
} catch (error) {
|
|
47
|
-
// Passo 3:
|
|
48
|
+
// Passo 3: Logar o erro para diagnóstico
|
|
48
49
|
console.error('Erro na execução da query:', error);
|
|
49
|
-
|
|
50
|
+
|
|
51
|
+
// Retorna o erro encapsulado em { error } para evitar crashes não tratados,
|
|
52
|
+
// mantendo o contrato documentado no README.
|
|
53
|
+
return { error };
|
|
50
54
|
} finally {
|
|
51
55
|
// Passo 4: Este bloco SEMPRE será executado, independentemente de sucesso ou falha no 'try'
|
|
52
56
|
if (connection) {
|
package/lib/databaseHandler.js
CHANGED
|
@@ -49,16 +49,37 @@ class DatabaseHandler {
|
|
|
49
49
|
const bindings = [];
|
|
50
50
|
for (const item of strictCondition) {
|
|
51
51
|
if (typeof item === 'string') {
|
|
52
|
+
// Operadores lógicos (AND / OR) são inseridos como-is, sem parênteses.
|
|
52
53
|
clauses.push(item.toUpperCase());
|
|
53
54
|
} else if (typeof item === 'object' && item !== null) {
|
|
54
55
|
const key = Object.keys(item).find(k => k !== 'operator');
|
|
55
56
|
if (!key) continue;
|
|
56
57
|
const value = item[key];
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
58
|
+
let operator = item.operator || '=';
|
|
59
|
+
let upperOp = String(operator).toUpperCase();
|
|
60
|
+
|
|
61
|
+
// Suporte a arrays => IN / NOT IN (consistente com _buildWhereClause)
|
|
62
|
+
if (Array.isArray(value) && upperOp === '=') {
|
|
63
|
+
operator = 'IN';
|
|
64
|
+
upperOp = 'IN';
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
if (Array.isArray(value) && (upperOp === 'IN' || upperOp === 'NOT IN')) {
|
|
68
|
+
if (value.length === 0) {
|
|
69
|
+
clauses.push(upperOp === 'IN' ? '1 = 0' : '1 = 1');
|
|
70
|
+
} else {
|
|
71
|
+
const placeholders = value.map(() => '?').join(', ');
|
|
72
|
+
clauses.push(`\`${key}\` ${operator} (${placeholders})`);
|
|
73
|
+
bindings.push(...value);
|
|
74
|
+
}
|
|
75
|
+
} else {
|
|
76
|
+
clauses.push(`\`${key}\` ${operator} ?`);
|
|
77
|
+
bindings.push(value);
|
|
78
|
+
}
|
|
60
79
|
}
|
|
61
80
|
}
|
|
81
|
+
// Junta com espaço para preservar operadores AND/OR intercalados.
|
|
82
|
+
// Ex: "(a = ? AND b = ?)" em vez de "(a = ? b = ?)" que era inválido.
|
|
62
83
|
return { sql: `(${clauses.join(' ')})`, bindings };
|
|
63
84
|
}
|
|
64
85
|
|
|
@@ -182,12 +203,31 @@ class DatabaseHandler {
|
|
|
182
203
|
// --- Queries ---
|
|
183
204
|
const baseWhereSql = baseWhere.sql ? `WHERE ${baseWhere.sql}` : '';
|
|
184
205
|
const totalCountSql = `SELECT COUNT(*) as total FROM ${this.table} ${baseWhereSql}`;
|
|
185
|
-
const
|
|
186
|
-
|
|
206
|
+
const totalResult = await this.executeQuery(totalCountSql, baseWhere.bindings);
|
|
207
|
+
// Contrato: executeQuery propaga { error } em caso de falha (não lança).
|
|
208
|
+
if (totalResult && totalResult.error) {
|
|
209
|
+
return {
|
|
210
|
+
draw: parseInt(draw || 0),
|
|
211
|
+
recordsTotal: 0,
|
|
212
|
+
recordsFiltered: 0,
|
|
213
|
+
data: [],
|
|
214
|
+
error: totalResult.error.message
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
const recordsTotal = (totalResult && totalResult[0] && totalResult[0].total) || 0;
|
|
187
218
|
|
|
188
219
|
const filteredCountSql = `SELECT COUNT(*) as total FROM ${this.table} ${whereSql}`;
|
|
189
|
-
const
|
|
190
|
-
|
|
220
|
+
const filteredResult = await this.executeQuery(filteredCountSql, finalBindings);
|
|
221
|
+
if (filteredResult && filteredResult.error) {
|
|
222
|
+
return {
|
|
223
|
+
draw: parseInt(draw || 0),
|
|
224
|
+
recordsTotal: parseInt(recordsTotal),
|
|
225
|
+
recordsFiltered: 0,
|
|
226
|
+
data: [],
|
|
227
|
+
error: filteredResult.error.message
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
const recordsFiltered = (filteredResult && filteredResult[0] && filteredResult[0].total) || 0;
|
|
191
231
|
|
|
192
232
|
// CORREÇÃO: Construção segura da cláusula SELECT para evitar vírgulas duplas.
|
|
193
233
|
const selectFields = ['*'];
|
|
@@ -197,6 +237,15 @@ class DatabaseHandler {
|
|
|
197
237
|
}
|
|
198
238
|
const dataSql = `SELECT ${selectFields.join(', ')} FROM ${this.table} ${whereSql} ${orderSql} ${limitSql}`;
|
|
199
239
|
const data = await this.executeQuery(dataSql, finalBindings);
|
|
240
|
+
if (data && data.error) {
|
|
241
|
+
return {
|
|
242
|
+
draw: parseInt(draw || 0),
|
|
243
|
+
recordsTotal: parseInt(recordsTotal),
|
|
244
|
+
recordsFiltered: parseInt(recordsFiltered),
|
|
245
|
+
data: [],
|
|
246
|
+
error: data.error.message
|
|
247
|
+
};
|
|
248
|
+
}
|
|
200
249
|
|
|
201
250
|
return {
|
|
202
251
|
draw: parseInt(draw || 0),
|
package/package.json
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@areumtecnologia/mysql-db-handler",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.10",
|
|
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": {
|
|
7
|
-
"test": "
|
|
7
|
+
"test": "node tests/update_operators.test.js && node tests/selectToDatatable.test.js"
|
|
8
8
|
},
|
|
9
9
|
"author": "Renan Moreira / Áreum Tecnologia",
|
|
10
10
|
"license": "MIT",
|
|
11
11
|
"dependencies": {
|
|
12
|
-
"mysql2": "^3.
|
|
12
|
+
"mysql2": "^3.23.1"
|
|
13
13
|
}
|
|
14
14
|
}
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
// Áreum Tecnologia - Renan Moreira - renan.moreira@areum.com.br
|
|
2
|
-
// src/database/database-singleton.js
|
|
3
|
-
// Exemplo Singleton para a conexão com o banco de dados
|
|
4
|
-
const { DB_HOST, DB_USER, DB_PASS } = require('../constants');
|
|
5
|
-
const DataBase = require("./database");
|
|
6
|
-
|
|
7
|
-
const dbi = new DataBase({
|
|
8
|
-
host: DB_HOST,
|
|
9
|
-
user: DB_USER,
|
|
10
|
-
password: DB_PASS,
|
|
11
|
-
database: '',
|
|
12
|
-
charset: "utf8mb4",
|
|
13
|
-
timezone: "-03:00",
|
|
14
|
-
connectionLimit: 1, // Ajustado para um limite de conexão mais comum
|
|
15
|
-
waitForConnections: true,
|
|
16
|
-
queueLimit: 0
|
|
17
|
-
});
|
|
18
|
-
// console.log("DATABASE SINGLETON CREATED", dbi.id);
|
|
19
|
-
module.exports = dbi;
|