db-crud-wrapper 1.0.1
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/CHANGELOG.md +81 -0
- package/README.md +96 -0
- package/index.js +5 -0
- package/lib/builder.js +404 -0
- package/lib/config.js +287 -0
- package/lib/db-operations.js +426 -0
- package/lib/f.js +45 -0
- package/lib/factory.js +89 -0
- package/lib/log.js +21 -0
- package/lib/mssql.js +483 -0
- package/lib/mysql.js +532 -0
- package/lib/session-store.js +196 -0
- package/package.json +31 -0
package/lib/mysql.js
ADDED
|
@@ -0,0 +1,532 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
import sql from 'mysql2/promise';
|
|
4
|
+
import log from './log.js'
|
|
5
|
+
|
|
6
|
+
// Regex
|
|
7
|
+
const _match_LIMIT_n = /\bLIMIT\b +\d+/ig
|
|
8
|
+
const _match_TOP_n = /\bTOP\b +\d+/ig
|
|
9
|
+
const _match_TOP = /\bTOP\b/ig
|
|
10
|
+
|
|
11
|
+
const pools = {};
|
|
12
|
+
|
|
13
|
+
// Common
|
|
14
|
+
function isExpression(str) {
|
|
15
|
+
if (typeof str !== 'string') return false;
|
|
16
|
+
const trimmed = str.trim();
|
|
17
|
+
return (trimmed.startsWith('[') && trimmed.endsWith(']')) ||
|
|
18
|
+
(trimmed.startsWith('`') && trimmed.endsWith('`'));
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function removeExpressionDelimiters(str) {
|
|
22
|
+
if (typeof str !== 'string') return str;
|
|
23
|
+
const trimmed = str.trim();
|
|
24
|
+
if ((trimmed.startsWith('[') && trimmed.endsWith(']')) ||
|
|
25
|
+
(trimmed.startsWith('`') && trimmed.endsWith('`'))) {
|
|
26
|
+
return trimmed.slice(1, -1);
|
|
27
|
+
}
|
|
28
|
+
return str;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function stringifyValue(fieldName, value, tSchema) {
|
|
32
|
+
|
|
33
|
+
// null or undefined
|
|
34
|
+
if (value == undefined)
|
|
35
|
+
return 'null';
|
|
36
|
+
|
|
37
|
+
// if values is an expression than remove delimiters
|
|
38
|
+
if (isExpression(value)) {
|
|
39
|
+
return removeExpressionDelimiters(value);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// detect field type
|
|
43
|
+
let _fieldType = undefined;
|
|
44
|
+
if (tSchema.table.fields && tSchema.table.fields[fieldName] && tSchema.table.fields[fieldName].type) {
|
|
45
|
+
_fieldType = tSchema.table.fields[fieldName].type;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// if datetime
|
|
49
|
+
if (_fieldType == 'datetime') {
|
|
50
|
+
// my-sql not accepts 'Z' at end of ISO string
|
|
51
|
+
if (value instanceof Date)
|
|
52
|
+
return `\'${value.toISOString().slice(0, -1)}\'`;
|
|
53
|
+
if (typeof value == 'string') {
|
|
54
|
+
const valueDate = new Date(Date.parse(value));
|
|
55
|
+
return `\'${valueDate.toISOString().slice(0, -1)}\'`;
|
|
56
|
+
}
|
|
57
|
+
return value;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// if boolean
|
|
61
|
+
if (_fieldType == 'boolean' && typeof value == 'boolean')
|
|
62
|
+
return `\'${value}\'`;
|
|
63
|
+
|
|
64
|
+
// if string or uuid
|
|
65
|
+
if (_fieldType == 'string' || _fieldType == 'uuid') {
|
|
66
|
+
return sql.escape(`${value}`);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// field not in schema
|
|
70
|
+
if (_fieldType == undefined) {
|
|
71
|
+
if (value instanceof Date)
|
|
72
|
+
return `\'${value.toISOString().slice(0, -1)}\'`;
|
|
73
|
+
if (typeof value == 'boolean')
|
|
74
|
+
return `\'${value}\'`;
|
|
75
|
+
if (typeof value == 'string')
|
|
76
|
+
return sql.escape(`${value}`);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
return value;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
// Create config object for pool
|
|
85
|
+
export function prepareConnection(tSchema) {
|
|
86
|
+
return {
|
|
87
|
+
id: `${tSchema.server.realName}-${tSchema.database.realName}-${tSchema.server.user}`,
|
|
88
|
+
host: ((tSchema.server.instance && tSchema.server.instance != 'DEFAULT') ? (tSchema.server.realName + '\\' + tSchema.server.instance) : tSchema.server.realName) ?? 'localhost',
|
|
89
|
+
port: tSchema.server.port,
|
|
90
|
+
user: tSchema.server.user,
|
|
91
|
+
password: tSchema.server.password,
|
|
92
|
+
database: tSchema.database.realName,
|
|
93
|
+
ssl: {
|
|
94
|
+
rejectUnauthorized: false
|
|
95
|
+
},
|
|
96
|
+
multipleStatements: true,
|
|
97
|
+
connectionLimit: tSchema.server.connectionLimit,
|
|
98
|
+
enableKeepAlive: true,
|
|
99
|
+
keepAliveInitialDelay: 30000,
|
|
100
|
+
timezone: 'Z' // Forza l'uso dell'UTC (Zulu time)
|
|
101
|
+
};
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
// Close connection
|
|
105
|
+
export async function closeConnection(connection) {
|
|
106
|
+
let pool = pools[connection.id];
|
|
107
|
+
if (pool) {
|
|
108
|
+
pool.releaseConnection();
|
|
109
|
+
await connection.end();
|
|
110
|
+
pools[connection.id] = undefined; // remove pool from pools
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// Close all connections
|
|
115
|
+
export async function closeAllConnections() {
|
|
116
|
+
for (let poolId in pools) {
|
|
117
|
+
if (!pools.hasOwnProperty(poolId)) continue;
|
|
118
|
+
let pool = pools[poolId];
|
|
119
|
+
if (pool) {
|
|
120
|
+
await pool.end();
|
|
121
|
+
pool = undefined; // remove pool from pools
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// Test connection
|
|
127
|
+
export async function testConnection(connection) {
|
|
128
|
+
let _pool;
|
|
129
|
+
try {
|
|
130
|
+
// const _connection = await sql.createConnection(connection);
|
|
131
|
+
// await _connection.end();
|
|
132
|
+
_pool = new sql.createPool(connection); // Create new pool
|
|
133
|
+
await _pool.query('SELECT 1');
|
|
134
|
+
return true;
|
|
135
|
+
}
|
|
136
|
+
catch (error) {
|
|
137
|
+
throw (error);
|
|
138
|
+
}
|
|
139
|
+
finally {
|
|
140
|
+
if (_pool) await _pool.end();
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// Query
|
|
145
|
+
export async function query(connection, dbOpes, rawResult = false) {
|
|
146
|
+
|
|
147
|
+
// Prepare pool
|
|
148
|
+
let pool = pools[connection.id]; // Try to get an existing pool
|
|
149
|
+
if (!pool) {
|
|
150
|
+
pool = new sql.createPool(connection); // Create new pool
|
|
151
|
+
pools[connection.id] = pool; // add new pool to pools
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// Prepare sql statement
|
|
155
|
+
let sqlString = '';
|
|
156
|
+
const paramsObject = {};
|
|
157
|
+
let appLog = true;
|
|
158
|
+
|
|
159
|
+
if (Array.isArray(dbOpes)) {
|
|
160
|
+
dbOpes.forEach((dbOpe, index) => {
|
|
161
|
+
sqlString += ToSql(dbOpe, paramsObject); // if exists, input params will be added to paramsObject
|
|
162
|
+
if (dbOpe?.hasOwnProperty('appLog') && dbOpe.appLog === false) appLog = false;
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
else {
|
|
166
|
+
sqlString += ToSql(dbOpes, paramsObject); // if exists, input params will be added to paramsObject
|
|
167
|
+
if (dbOpes?.hasOwnProperty('appLog') && dbOpes.appLog === false) appLog = false;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
sqlString = normalizeSpecialName(sqlString);
|
|
171
|
+
|
|
172
|
+
// convert @param to ? and build params array
|
|
173
|
+
const _translated = translateParamsToMysql(sqlString, paramsObject);
|
|
174
|
+
sqlString = _translated.sqlString;
|
|
175
|
+
const sqlParams = _translated.paramsArray;
|
|
176
|
+
|
|
177
|
+
// Log
|
|
178
|
+
if (appLog) {
|
|
179
|
+
log(JSON.stringify(dbOpes), 60);
|
|
180
|
+
log(sqlString, 50);
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
// Run query
|
|
184
|
+
let sqlresult = undefined;
|
|
185
|
+
//let sqlconn = undefined;
|
|
186
|
+
try {
|
|
187
|
+
// sqlconn = await pool.getConnection();
|
|
188
|
+
// sqlresult = await sqlconn.query(sqlString);
|
|
189
|
+
sqlresult = await pool.query(sqlString, sqlParams);
|
|
190
|
+
}
|
|
191
|
+
catch (err) { throw (err); } // using original error
|
|
192
|
+
// finally { if (sqlconn) sqlconn.release(); }
|
|
193
|
+
|
|
194
|
+
// normalize return object
|
|
195
|
+
const _return = normalizeQueryResults(sqlresult);
|
|
196
|
+
|
|
197
|
+
// Log
|
|
198
|
+
if (appLog) {
|
|
199
|
+
if (Array.isArray(dbOpes)) // multiple query
|
|
200
|
+
log(`Batch return ${Number.isInteger(_return) ? _return : Array.isArray(_return) ? _return.length : _return ? 1 : 0} result(s).`, 50)
|
|
201
|
+
else // single query
|
|
202
|
+
log(`Query result: ${Number.isInteger(_return) ? _return : Array.isArray(_return) ? _return.length : _return ? 1 : 0} row(s).`, 50)
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
// return
|
|
206
|
+
return rawResult ? sqlresult : _return;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
// Normalize special name to replace square brackets with backticks, considering quoted strings
|
|
210
|
+
function normalizeSpecialName(sql) {
|
|
211
|
+
let result = "";
|
|
212
|
+
let inSingleQuote = false;
|
|
213
|
+
let inDoubleQuote = false;
|
|
214
|
+
|
|
215
|
+
for (let i = 0; i < sql.length; i++) {
|
|
216
|
+
const char = sql[i];
|
|
217
|
+
|
|
218
|
+
// Gestione delle virgolette singole '
|
|
219
|
+
if (char === "'" && !inDoubleQuote) {
|
|
220
|
+
inSingleQuote = !inSingleQuote;
|
|
221
|
+
}
|
|
222
|
+
// Gestione delle virgolette doppie "
|
|
223
|
+
else if (char === '"' && !inSingleQuote) {
|
|
224
|
+
inDoubleQuote = !inDoubleQuote;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
// Se non siamo all'interno di una stringa, sostituiamo le quadre
|
|
228
|
+
if (!inSingleQuote && !inDoubleQuote) {
|
|
229
|
+
if (char === '[' || char === ']') {
|
|
230
|
+
result += '`';
|
|
231
|
+
continue;
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
result += char;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
return result;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
// Compose fully qualified table name
|
|
242
|
+
function fullyQualifiedTableName(tSchema) {
|
|
243
|
+
return (tSchema.database.realName + '.' + tSchema.table.realName);
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
function containLIMIT(s) {
|
|
247
|
+
const _return = s?.match(_match_LIMIT_n);
|
|
248
|
+
if (_return) return _return[0];
|
|
249
|
+
else return undefined;
|
|
250
|
+
};
|
|
251
|
+
|
|
252
|
+
function containTOP(s) {
|
|
253
|
+
const _return = s?.match(_match_TOP_n);
|
|
254
|
+
if (_return) return _return[0];
|
|
255
|
+
else return undefined;
|
|
256
|
+
};
|
|
257
|
+
|
|
258
|
+
function replaceTOPToLIMIT(s) {
|
|
259
|
+
const _replace = containTOP(s);
|
|
260
|
+
if (_replace) { return s.replace(_match_TOP_n, _replace.replace(_match_TOP, 'LIMIT')); }
|
|
261
|
+
else return s;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
/**
|
|
265
|
+
* Normalizza l'output di mysql2 ignorando i campi (fields).
|
|
266
|
+
* @param {Array} rawResponse - L'intero array restituito dalla query()
|
|
267
|
+
* @return {Array|number|Array<number>} - Restituisce i risultati normalizzati:
|
|
268
|
+
* - Per query SELECT singole: un array di record.
|
|
269
|
+
* - Per query di modifica singole (INSERT, UPDATE, DELETE): il numero di righe interessate.
|
|
270
|
+
* - Per batch di query (MULTIPLE STATEMENTS): un array dove ogni elemento è
|
|
271
|
+
* o un array di record (per SELECT) o un intero (per modifiche).
|
|
272
|
+
*/
|
|
273
|
+
function normalizeQueryResults(rawResponse) {
|
|
274
|
+
// 1. Prendiamo solo il primo elemento (i dati/risultati)
|
|
275
|
+
// mysql2 restituisce sempre [risultati, campi].
|
|
276
|
+
const results = rawResponse[0];
|
|
277
|
+
|
|
278
|
+
// Helper per processare ogni singola unità di risultato
|
|
279
|
+
const normalizeItem = (item) => {
|
|
280
|
+
// Se è un array, è una SELECT -> restituisco l'array di record
|
|
281
|
+
if (Array.isArray(item)) return item;
|
|
282
|
+
// Se è un oggetto (ResultSetHeader), restituisco l'intero affectedRows
|
|
283
|
+
if (item && typeof item === 'object') return item.affectedRows ?? 0;
|
|
284
|
+
return 0;
|
|
285
|
+
};
|
|
286
|
+
|
|
287
|
+
// 2. Controllo se siamo in modalità MULTIPLE STATEMENTS (Batch or stored procedure)
|
|
288
|
+
// Se è un batch, results è un array dove il primo elemento è a sua volta
|
|
289
|
+
// un array (SELECT) o un oggetto (ResultSetHeader).
|
|
290
|
+
const isBatch = Array.isArray(results) &&
|
|
291
|
+
results.length > 0 &&
|
|
292
|
+
(Array.isArray(results[0]) || results[0]?.constructor?.name === 'ResultSetHeader');
|
|
293
|
+
|
|
294
|
+
if (isBatch) {
|
|
295
|
+
// Mappiamo ogni query del batch trasformandola in [Array o Intero]
|
|
296
|
+
return results.map(normalizeItem);
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
// 3. Caso Query Singola
|
|
300
|
+
return normalizeItem(results);
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
// Parse oprations object to sql string
|
|
304
|
+
function ToSql(dbOpe, paramsObject) {
|
|
305
|
+
if (dbOpe.get) return getToSql(dbOpe, paramsObject);
|
|
306
|
+
if (dbOpe.post) return postToSql(dbOpe, paramsObject);
|
|
307
|
+
if (dbOpe.patch) return patchToSql(dbOpe, paramsObject);
|
|
308
|
+
if (dbOpe.put) return putToSql(dbOpe, paramsObject);
|
|
309
|
+
if (dbOpe.delete) return deleteToSql(dbOpe, paramsObject);
|
|
310
|
+
if (dbOpe.command) return commandToSql(dbOpe, paramsObject);
|
|
311
|
+
if (dbOpe.begin) return beginToSql(dbOpe, paramsObject);
|
|
312
|
+
if (dbOpe.commit) return commitToSql(dbOpe, paramsObject);
|
|
313
|
+
if (dbOpe.passthrough) return passthroughToSql(dbOpe, paramsObject);
|
|
314
|
+
throw new Error('Sintax error, missing property get/post/patch/put/delete/...');
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
// Parse operation object to sql string without any trasformation.
|
|
318
|
+
function passthroughToSql(dbOpe, paramsObject) {
|
|
319
|
+
let result = "";
|
|
320
|
+
|
|
321
|
+
if (dbOpe.passthrough.command) {
|
|
322
|
+
result += dbOpe.passthrough.command;
|
|
323
|
+
}
|
|
324
|
+
else { throw new Error('command is missing.'); }
|
|
325
|
+
|
|
326
|
+
if (dbOpe.passthrough.params) {
|
|
327
|
+
Object.assign(paramsObject, dbOpe.passthrough.params);
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
return result;
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
// Parse get operation object to sql string
|
|
334
|
+
function getToSql(dbOpe, paramsObject) {
|
|
335
|
+
let _first = true;
|
|
336
|
+
|
|
337
|
+
let result = 'select'
|
|
338
|
+
|
|
339
|
+
// omit 'limit' or 'top'
|
|
340
|
+
if (dbOpe.get.options && dbOpe.get.options.length > 0) {
|
|
341
|
+
if (Array.isArray(dbOpe.get.options)) {
|
|
342
|
+
for (const s of dbOpe.get.options) { if (!containLIMIT(s) && !containTOP(s)) result += ' ' + s; }
|
|
343
|
+
}
|
|
344
|
+
else if (!containLIMIT(dbOpe.get.options) && !containTOP(dbOpe.get.options)) result += ' ' + dbOpe.get.options;
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
if (dbOpe.get.fields && dbOpe.get.fields.length > 0) {
|
|
348
|
+
if (Array.isArray(dbOpe.get.fields)) result += ' ' + dbOpe.get.fields.join(',')
|
|
349
|
+
else result += ' ' + dbOpe.get.fields;
|
|
350
|
+
}
|
|
351
|
+
else { throw new Error('fields is missing.'); }
|
|
352
|
+
|
|
353
|
+
result += ' from ' + fullyQualifiedTableName(dbOpe.get.schema);
|
|
354
|
+
|
|
355
|
+
if (dbOpe.get.filters && dbOpe.get.filters.length > 0) {
|
|
356
|
+
if (Array.isArray(dbOpe.get.filters)) result += ' where ' + dbOpe.get.filters.join(' ');
|
|
357
|
+
else result += ' where ' + dbOpe.get.filters;
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
if (dbOpe.get.groupBy && dbOpe.get.groupBy.length > 0) {
|
|
361
|
+
if (Array.isArray(dbOpe.get.groupBy)) result += ' group by ' + dbOpe.get.groupBy.join(', ');
|
|
362
|
+
else result += ' group by ' + dbOpe.get.groupBy;
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
if (dbOpe.get.groupFilters && dbOpe.get.groupFilters.length > 0) {
|
|
366
|
+
if (Array.isArray(dbOpe.get.groupFilters)) result += ' having ' + dbOpe.get.groupFilters.join(' ');
|
|
367
|
+
else result += ' having ' + dbOpe.get.groupFilters;
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
if (dbOpe.get.orderBy && dbOpe.get.orderBy.length > 0) {
|
|
371
|
+
if (Array.isArray(dbOpe.get.orderBy)) result += ' order by ' + dbOpe.get.orderBy.join(', ');
|
|
372
|
+
else result += ' order by ' + dbOpe.get.orderBy;
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
// search if 'limit' or 'top'
|
|
376
|
+
if (dbOpe.get.options && dbOpe.get.options.length > 0) {
|
|
377
|
+
if (Array.isArray(dbOpe.get.options)) {
|
|
378
|
+
for (const s of dbOpe.get.options) { if (containLIMIT(s) || containTOP(s)) result += ' ' + replaceTOPToLIMIT(s); }
|
|
379
|
+
}
|
|
380
|
+
else if (containLIMIT(dbOpe.get.options) || containTOP(dbOpe.get.options)) result += ' ' + replaceTOPToLIMIT(dbOpe.get.options);
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
if (dbOpe.get.params) {
|
|
384
|
+
Object.assign(paramsObject, dbOpe.get.params);
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
return result += ';' ;
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
// Parse post operation object to sql string
|
|
391
|
+
function postToSql(dbOpe, paramsObject) {
|
|
392
|
+
let result = 'insert into ' + fullyQualifiedTableName(dbOpe.post.schema);
|
|
393
|
+
|
|
394
|
+
if ((dbOpe.post.values) && (Object.keys(dbOpe.post.values).length > 0)) {
|
|
395
|
+
let result_f = ' (';
|
|
396
|
+
let result_v = ' values (';
|
|
397
|
+
let _first = true;
|
|
398
|
+
for (const [key, value] of Object.entries(dbOpe.post.values)) {
|
|
399
|
+
if (!_first) {
|
|
400
|
+
result_f += ', ';
|
|
401
|
+
result_v += ', ';
|
|
402
|
+
} else {
|
|
403
|
+
_first = false
|
|
404
|
+
}
|
|
405
|
+
if (key || value) {
|
|
406
|
+
result_f += key;
|
|
407
|
+
result_v += stringifyValue(key, value, dbOpe.post.schema);
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
result_f += ')'; result_v += ')';
|
|
411
|
+
result += result_f + result_v;
|
|
412
|
+
}
|
|
413
|
+
else { throw new Error('values is missing.'); }
|
|
414
|
+
|
|
415
|
+
if (dbOpe.post.params) {
|
|
416
|
+
Object.assign(paramsObject, dbOpe.post.params);
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
return result += ';' ;
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
// Parse patch operation object to sql string
|
|
423
|
+
function patchToSql(dbOpe, paramsObject) {
|
|
424
|
+
let result = 'update ' + fullyQualifiedTableName(dbOpe.patch.schema);
|
|
425
|
+
|
|
426
|
+
if (dbOpe.patch.values) { result += ' set ' + Object.entries(dbOpe.patch.values).map(e => { return e[0] + '=' + stringifyValue(e[0], e[1], dbOpe.patch.schema) }).join(', '); }
|
|
427
|
+
else { throw new Error('values is missing.'); }
|
|
428
|
+
|
|
429
|
+
if (dbOpe.patch.filters && dbOpe.patch.filters.length > 0) {
|
|
430
|
+
if (Array.isArray(dbOpe.patch.filters)) result += ' where ' + dbOpe.patch.filters.join(' ');
|
|
431
|
+
else result += ' where ' + dbOpe.patch.filters;
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
if (dbOpe.patch.params) {
|
|
435
|
+
Object.assign(paramsObject, dbOpe.patch.params);
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
return result += ';' ;
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
// Parse put operation object to sql string
|
|
442
|
+
function putToSql(dbOpe, paramsObject) {
|
|
443
|
+
let result = 'update ' + fullyQualifiedTableName(dbOpe.put.schema);
|
|
444
|
+
|
|
445
|
+
if (dbOpe.put.values) { result += ' set ' + Object.entries(dbOpe.put.values).map(e => { return e[0] + '=' + stringifyValue(e[0], e[1], dbOpe.put.schema) }).join(', '); }
|
|
446
|
+
else { throw new Error('values is missing.'); }
|
|
447
|
+
|
|
448
|
+
if (dbOpe.put.filters && dbOpe.put.filters.length > 0) {
|
|
449
|
+
if (Array.isArray(dbOpe.put.filters)) result += ' where ' + dbOpe.put.filters.join(' ');
|
|
450
|
+
else result += ' where ' + dbOpe.put.filters;
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
if (dbOpe.put.params) {
|
|
454
|
+
Object.assign(paramsObject, dbOpe.put.params);
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
return result += ';' ;
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
// Parse delete operation object to sql string and consolidate params to paramsObject
|
|
461
|
+
function deleteToSql(dbOpe, paramsObject) {
|
|
462
|
+
let result = 'delete from ' + fullyQualifiedTableName(dbOpe.delete.schema);
|
|
463
|
+
|
|
464
|
+
if (dbOpe.delete.filters && dbOpe.delete.filters.length > 0) {
|
|
465
|
+
if (Array.isArray(dbOpe.delete.filters)) result += ' where ' + dbOpe.delete.filters.join(' ');
|
|
466
|
+
else result += ' where ' + dbOpe.delete.filters;
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
if (dbOpe.delete.params) {
|
|
470
|
+
Object.assign(paramsObject, dbOpe.delete.params);
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
return result += ';' ;
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
// Parse command operation object to sql string
|
|
477
|
+
function commandToSql(dbOpe, paramsObject) {
|
|
478
|
+
let result = "CALL ";
|
|
479
|
+
|
|
480
|
+
if (dbOpe.command.schema.procedure) {
|
|
481
|
+
result += dbOpe.command.schema.procedure.command;
|
|
482
|
+
if (dbOpe.command.arguments) {
|
|
483
|
+
// if argument is string but not param, will be wrap into ''
|
|
484
|
+
result += ('(' + [].concat(dbOpe.command.arguments).map(item => {
|
|
485
|
+
return (typeof item === 'string' && !item.trimStart().startsWith("@")) ? `'${item}'` : item
|
|
486
|
+
}).join(', ') + ')');
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
else { throw new Error('missing procedure/function name.'); }
|
|
490
|
+
|
|
491
|
+
if (dbOpe.command.params) {
|
|
492
|
+
Object.assign(paramsObject, dbOpe.command.params);
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
return result += ';' ;
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
// Parse begin operation object to sql string
|
|
499
|
+
function beginToSql(dbOpe, paramsObject) {
|
|
500
|
+
return "START TRANSACTION; ";
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
// Parse commit operation object to sql string
|
|
504
|
+
function commitToSql(dbOpe, paramsObject) {
|
|
505
|
+
return " COMMIT;";
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
/**
|
|
509
|
+
* Converte una query da formato MSSQL (@param) a MySQL (?)
|
|
510
|
+
* @param {string} sqlString - La stringa SQL con segnaposti in formato MSSQL
|
|
511
|
+
* @param {Object} params - Oggetto con i valori { nome: 'valore' }
|
|
512
|
+
* @returns {Object} { sqlString: string, params: Array }
|
|
513
|
+
*/
|
|
514
|
+
function translateParamsToMysql(sqlString, params) {
|
|
515
|
+
const _params = [];
|
|
516
|
+
|
|
517
|
+
// Regex per trovare i segnaposti che iniziano con @ seguiti da caratteri alfanumerici
|
|
518
|
+
// Usa un lookahead negativo per evitare di catturare @ nelle email se necessario
|
|
519
|
+
const regex = /@([a-zA-Z0-9_]+)/g;
|
|
520
|
+
|
|
521
|
+
const _sqlString = sqlString.replace(regex, (match, name) => {
|
|
522
|
+
if (Object.prototype.hasOwnProperty.call(params, name)) {
|
|
523
|
+
_params.push(params[name]);
|
|
524
|
+
return '?';
|
|
525
|
+
}
|
|
526
|
+
// Se non è nell'oggetto params, è probabilmente una variabile MySQL
|
|
527
|
+
// o parte di una stringa, quindi la lasciamo intatta
|
|
528
|
+
return match;
|
|
529
|
+
});
|
|
530
|
+
|
|
531
|
+
return { sqlString: _sqlString, paramsArray: _params };
|
|
532
|
+
}
|