db-crud-api 0.3.25 → 0.3.26

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/lib/mssql.js CHANGED
@@ -40,7 +40,7 @@ function stringifyValue(fieldName, value, tSchema) {
40
40
  // if string or uuid
41
41
  if (_fieldType == 'string' || _fieldType == 'uuid') {
42
42
  if (value.trimStart().charAt(0) !== '\'' && value.trimStart().charAt(0) !== '\"') {
43
- return `\'${value}\'`;
43
+ return `\'${value.replace(/'/g, "''")}\'`;
44
44
  }
45
45
  }
46
46
 
@@ -51,7 +51,7 @@ function stringifyValue(fieldName, value, tSchema) {
51
51
  if (typeof value == 'boolean')
52
52
  return `\'${value}\'`;
53
53
  if (typeof value == 'string' && value.trimStart().charAt(0) !== '\'' && value.trimStart().charAt(0) !== '\"')
54
- return `\'${value}\'`;
54
+ return `\'${value.replace(/'/g, "''")}\'`;
55
55
  }
56
56
 
57
57
  return value;
package/lib/mysql.js CHANGED
@@ -42,7 +42,8 @@ function stringifyValue(fieldName, value, tSchema) {
42
42
  // if string or uuid
43
43
  if (_fieldType == 'string' || _fieldType == 'uuid') {
44
44
  if (value.trimStart().charAt(0) !== '\'' && value.trimStart().charAt(0) !== '\"') {
45
- return `\'${value}\'`;
45
+ // return `\'${value}\'`;
46
+ return sql.escape(`${value}`);
46
47
  }
47
48
  }
48
49
 
@@ -53,7 +54,7 @@ function stringifyValue(fieldName, value, tSchema) {
53
54
  if (typeof value == 'boolean')
54
55
  return `\'${value}\'`;
55
56
  if (typeof value == 'string' && value.trimStart().charAt(0) !== '\'' && value.trimStart().charAt(0) !== '\"')
56
- return `\'${value}\'`;
57
+ return sql.escape(`${value}`);
57
58
  }
58
59
 
59
60
  return value;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "db-crud-api",
3
- "version": "0.3.25",
3
+ "version": "0.3.26",
4
4
  "type": "module",
5
5
  "description": "CRUD api for database tables",
6
6
  "main": "index.js",
@@ -1,486 +0,0 @@
1
- 'use strict';
2
-
3
- // import modules
4
- import schema from './schema.js'
5
- import * as mssql from './mssql.js';
6
- import * as mysql from './mysql.js';
7
-
8
- // Common
9
- const defautlFields = ['*'];
10
- export const serverType = Object.freeze({ mssql: 'ms-sql', mysql: 'my-sql', mongodb: 'mongo-db' });
11
- export const objectType = Object.freeze({ table: 'T', procedure: 'P' });
12
-
13
- // Exported functions
14
- export function idField(tSchema) {
15
- return tSchema.table?.idField ?? 'id';
16
- }
17
-
18
- export function autoId(tSchema) {
19
- return tSchema.table?.autoId;
20
- }
21
-
22
- export function getProperty(obj, keyToFind) {
23
- if (typeof obj !== 'object' || obj === null || !keyToFind) {
24
- return undefined;
25
- }
26
-
27
- const lowerKeyToFind = keyToFind.toLowerCase();
28
-
29
- for (const key in obj) {
30
- // Usa hasOwnProperty per escludere le proprietà ereditate
31
- if (Object.prototype.hasOwnProperty.call(obj, key)) {
32
-
33
- if (key.toLowerCase() === lowerKeyToFind) {
34
- return obj[key];
35
- }
36
- }
37
- }
38
-
39
- return undefined;
40
- }
41
-
42
- export function upsertProperty(obj, keyToUpdate, newValue) {
43
- if (typeof obj !== 'object' || obj === null) {
44
- // Non è un oggetto valido
45
- return false;
46
- }
47
-
48
- const lowerKeyToUpdate = keyToUpdate.toLowerCase();
49
- let propertyFound = false;
50
-
51
- for (const key in obj) {
52
- if (Object.prototype.hasOwnProperty.call(obj, key)) {
53
- if (key.toLowerCase() === lowerKeyToUpdate) {
54
- obj[key] = newValue;
55
- propertyFound = true;
56
- break;
57
- }
58
- }
59
- }
60
-
61
- if (!propertyFound) {
62
- obj[keyToUpdate] = newValue;
63
- }
64
-
65
- return true;
66
- }
67
-
68
- export async function runQuery(dbOpes) {
69
-
70
- // all connections must have same id
71
- const _connection = Array.isArray(dbOpes) ? dbOpes[0].connection : dbOpes.connection;
72
- if (Array.isArray(dbOpes)) {
73
- for (let i = 1; i < dbOpes.length; i++) {
74
- if (dbOpes[i].connection?.id !== _connection.id) throw new TypeError('runQuery: for multiple operations, connection must be the same');
75
- }
76
- }
77
-
78
- // MSSQL
79
- if (_connection.serverType === serverType.mssql) {
80
- return await mssql.query(_connection, dbOpes);
81
- }
82
-
83
- // MySQL
84
- else if (_connection.serverType === serverType.mysql) {
85
- return await mysql.query(_connection, dbOpes);
86
- }
87
-
88
- // server type not supported
89
- else throw new TypeError('server type not supported');
90
-
91
- }
92
-
93
- export function prepareConnection(schema) {
94
- // MySQL
95
- if (schema.server.type === serverType.mysql) {
96
- const _return = mysql.prepareConnection(schema);
97
- _return.serverType = serverType.mysql; // append 'serverType' to connection
98
- return _return;
99
- }
100
- // MSSQL is also the default
101
- if (!schema.server.type || schema.server.type === serverType.mssql) {
102
- const _return = mssql.prepareConnection(schema);
103
- _return.serverType = serverType.mssql; // append 'serverType' to connection
104
- return _return;
105
- }
106
- throw new TypeError('server type not supported');
107
- }
108
-
109
- export function closeConnection(connection) {
110
- // MSSQL
111
- if (connection.serverType === serverType.mssql) { return mssql.closeConnection(connection); }
112
- // MySQL
113
- if (connection.serverType === serverType.mysql) { return mysql.closeConnection(connection); }
114
- }
115
-
116
- export function closeAllConnections() {
117
- // MSSQL
118
- mssql.closeAllConnections();
119
- // MySQL
120
- mysql.closeAllConnections();
121
-
122
- return;
123
- }
124
-
125
- export function testConnection() {
126
- const _connection = prepareConnection(prepareSchema("test", objectType.procedure));
127
- // MSSQL
128
- if (_connection.serverType === serverType.mssql) { return mssql.testConnection(_connection); }
129
- // MySQL
130
- if (_connection.serverType === serverType.mysql) { return mysql.testConnection(_connection); }
131
- // server type not supported
132
- throw new TypeError('server type not supported');
133
- }
134
-
135
- export function toStringValue(value) {
136
- if (!value) return 'null';
137
- if (value.trimStart().charAt(0) === '\'') return value;
138
- return `\'${value}\'`;
139
- }
140
-
141
- export function prepareSchema(obj, objType) {
142
- // objType = 'objectType.' (Table or StoreProcedure)
143
- // obj = 'systemName.dbName.objName' or 'dbName.objName' or 'objName' or 'systemNme..objName'
144
-
145
- if (obj == undefined || typeof obj !== 'string') throw new TypeError('prepareSchema: wrong obj');
146
- if (objType !== undefined && objType !== objectType.table && objType !== objectType.procedure) throw new TypeError(`prepareSchema: wrong objType, must be ${objectType.join(', ')}`);
147
- const objPath = obj.trimStart().split(' ')[0];
148
-
149
- // split objPath to serverName,dbName,objName
150
- let serverName = undefined;
151
- let dbName = undefined;
152
- let objName = undefined;
153
- const objPathArray = objPath.split('.');
154
- if (objPathArray.length > 2) {
155
- serverName = objPathArray[0]
156
- dbName = objPathArray[1]
157
- objName = objPathArray[2]
158
- }
159
- else if (objPathArray.length > 1) {
160
- dbName = objPathArray[0]
161
- objName = objPathArray[1]
162
- }
163
- else if (objPathArray.length > 0) {
164
- objName = objPathArray[0]
165
- }
166
-
167
- // server
168
- if (!serverName || serverName.length == 0) {
169
- if (!schema.servers || !Object.keys(schema.servers)[0]) throw new TypeError('missing default server in dbSchema');
170
- serverName = Object.keys(schema.servers)[0];
171
- }
172
- else { // add server to schema
173
- if (!schema.servers) { schema.servers = {} };
174
- if (!schema.servers[serverName]) { schema.servers[serverName] = {} };
175
- }
176
- if (!schema.servers[serverName].realName) { schema.servers[serverName].realName = serverName } // add realName
177
-
178
- // database
179
- if (!dbName || dbName.length == 0) {
180
- if (!schema.servers[serverName].databases || !Object.keys(schema.servers[serverName].databases)[0]) throw new TypeError('missing default database in dbSchema');
181
- dbName = Object.keys(schema.servers[serverName].databases)[0];
182
- }
183
- else { // add db to schema
184
- if (!schema.servers[serverName].databases) { schema.servers[serverName].databases = {} };
185
- if (!schema.servers[serverName].databases[dbName]) { schema.servers[serverName].databases[dbName] = {} };
186
- }
187
- if (!schema.servers[serverName].databases[dbName].realName) { schema.servers[serverName].databases[dbName].realName = dbName } // add realName
188
-
189
- // table
190
- if (objType === objectType.table || objType == undefined) {
191
- if (!objName || objName.length == 0) {
192
- if (!schema.servers[serverName].databases[dbName] || !Object.keys(schema.servers[serverName].databases[dbName].tables)[0]) throw new TypeError('missing default table in dbSchema');
193
- objName = Object.keys(schema.servers[serverName].databases[dbName].tables)[0];
194
- }
195
- else { // add table to schema
196
- if (!schema.servers[serverName].databases[dbName].tables) { schema.servers[serverName].databases[dbName].tables = {} };
197
- if (!schema.servers[serverName].databases[dbName].tables[objName]) { schema.servers[serverName].databases[dbName].tables[objName] = {} }
198
- }
199
- if (!schema.servers[serverName].databases[dbName].tables[objName].realName) { schema.servers[serverName].databases[dbName].tables[objName].realName = objName } // add realName
200
- }
201
-
202
- // store procedure
203
- if (objType === objectType.procedure) {
204
- if (!objName || objName.length == 0) {
205
- if (!schema.servers[serverName].databases[dbName] || !Object.keys(schema.servers[serverName].databases[dbName].procedures)[0]) throw new TypeError('missing default procedure in dbSchema');
206
- objName = Object.keys(schema.servers[serverName].databases[dbName].procedures)[0];
207
- }
208
- else { // add storeprocedure to schema
209
- if (!schema.servers[serverName].databases[dbName].procedures) { schema.servers[serverName].databases[dbName].procedures = {} };
210
- if (!schema.servers[serverName].databases[dbName].procedures[objName]) { schema.servers[serverName].databases[dbName].procedures[objName] = {command: obj} }
211
- }
212
- if (!schema.servers[serverName].databases[dbName].procedures[objName].realName) { schema.servers[serverName].databases[dbName].procedures[objName].realName = objName } // add realName
213
- }
214
-
215
- // return Schema
216
- return {
217
- table: (objType == undefined || objType === objectType.table) ? schema.servers[serverName].databases[dbName].tables[objName] : undefined,
218
- procedure: (objType === objectType.procedure) ? schema.servers[serverName].databases[dbName].procedures[objName] : undefined,
219
- database: schema.servers[serverName].databases[dbName],
220
- server: schema.servers[serverName]
221
- }
222
-
223
- }
224
-
225
- export function prepareRun(tSchema, connection, reqOpe) {
226
- const _reqOpe = [];
227
- const _result = [];
228
- if (Array.isArray(reqOpe)) _reqOpe.push(...reqOpe);
229
- else _reqOpe.push(reqOpe);
230
- _reqOpe.forEach(function (_ope) {
231
- if (_ope?.get) _result.push(prepareGet(tSchema, connection, _ope));
232
- else if (_ope?.patch) _result.push(preparePatch(tSchema, connection, _ope));
233
- else if (_ope?.put) _result.push(preparePut(tSchema, connection, _ope));
234
- else if (_ope?.delete) _result.push(prepareDelete(tSchema, connection, _ope));
235
- else if (_ope?.execute) _result.push(prepareExecute(connection, _ope));
236
- else if (_ope?.begin) _result.push(prepareBegin(connection, _ope));
237
- else if (_ope?.commit) _result.push(prepareCommit(connection, _ope));
238
- else if (_ope?.rollback) _result.push(prepareRollback(connection, _ope));
239
- else if (_ope?.passthrough) _result.push(preparePassthrough(connection, _ope));
240
- else throw new Error('Request sintax error, missing property get/patch/put/delete/...');
241
- });
242
- if (_result.length > 1) return _result;
243
- if (_result.length = 1) return _result[0];
244
- return undefined;
245
- }
246
-
247
- export function prepareRunById(tSchema, connection, reqOpe, idValue) {
248
- if (reqOpe?.get) return prepareGetById(tSchema, connection, reqOpe, idValue);
249
- if (reqOpe?.patch) return preparePatchById(tSchema, connection, reqOpe, idValue);
250
- if (reqOpe?.put) return preparePutById(tSchema, connection, reqOpe, idValue);
251
- if (reqOpe?.delete) return prepareDeleteById(tSchema, connection, reqOpe, idValue);
252
- else throw new Error('Request sintax error, missing property get/patch/put/delete...');
253
- }
254
-
255
- export function prepareGet(tSchema, connection, reqOpe) {
256
- const _reqOpe = [];
257
- const _result = [];
258
- if (Array.isArray(reqOpe)) _reqOpe.push(...reqOpe);
259
- else _reqOpe.push(reqOpe);
260
- _reqOpe.forEach(function (_ope) {
261
- _result.push({
262
- get: {
263
- schema: tSchema,
264
- options: _ope?.get?.options,
265
- fields: _ope?.get?.fields ?? defautlFields,
266
- filters: _ope?.get?.filters,
267
- groups: _ope?.get?.groups,
268
- groupsFilters: _ope?.get?.groupsFilters,
269
- orderBy: _ope?.get?.orderBy,
270
- params: _ope?.get?.params
271
- },
272
- connection: connection,
273
- appLog: _ope?.hasOwnProperty('appLog') ? _ope.appLog : undefined
274
- });
275
- });
276
- if (_result.length > 1) return _result;
277
- if (_result.length = 1) return _result[0];
278
- return undefined;
279
- };
280
-
281
- export function prepareGetById(tSchema, connection, reqOpe, idValue) {
282
- const _filters = [idField(tSchema) + ' = ' + toStringValue(idValue)];
283
- if (reqOpe?.get?.filters && reqOpe?.get?.filters.length > 0) {
284
- _filters.push('and');
285
- Array.isArray(reqOpe.get.filters) ? _filters.push(...reqOpe.get.filters) : _filters.push(reqOpe.get.filters);
286
- }
287
- return {
288
- get: {
289
- schema: tSchema,
290
- options: reqOpe?.get?.options,
291
- fields: reqOpe?.get?.fields ?? defautlFields,
292
- filters: _filters
293
- },
294
- connection: connection,
295
- appLog: reqOpe?.hasOwnProperty('appLog') ? reqOpe.appLog : undefined
296
- }
297
- };
298
-
299
- export function preparePatch(tSchema, connection, reqOpe) {
300
- const _reqOpe = [];
301
- const _result = [];
302
- if (Array.isArray(reqOpe)) _reqOpe.push(...reqOpe);
303
- else _reqOpe.push(reqOpe);
304
- _reqOpe.forEach(function (_ope) {
305
- if (_ope?.patch) {
306
- if (!_ope.patch.sets) throw new Error('Request sintax error, missing "patch.sets" property.')
307
- _result.push({
308
- patch: {
309
- schema: tSchema,
310
- sets: _ope.patch.sets,
311
- filters: _ope.patch.filters,
312
- params: _ope.patch.params
313
- },
314
- connection: connection,
315
- appLog: _ope.hasOwnProperty('appLog') ? _ope.appLog : undefined
316
- });
317
- }
318
- else throw new Error('Request sintax error, missing "patch" property.');
319
- });
320
- if (_result.length > 1) return _result;
321
- if (_result.length = 1) return _result[0];
322
- return undefined;
323
- };
324
-
325
- export function preparePatchById(tSchema, connection, reqOpe, idValue) {
326
- if (!reqOpe?.patch) throw new Error('Request sintax error, missing "patch" property.')
327
- if (!reqOpe.patch.sets) throw new Error('Missing "patch.sets" in operation.')
328
- const _filters = [idField(tSchema) + ' = ' + toStringValue(idValue)];
329
- if (reqOpe?.patch?.filters && reqOpe?.patch?.filters.length > 0) {
330
- _filters.push('and');
331
- Array.isArray(reqOpe.patch.filters) ? _filters.push(...reqOpe.patch.filters) : _filters.push(reqOpe.patch.filters);
332
- }
333
- return {
334
- patch: {
335
- schema: tSchema,
336
- sets: reqOpe.patch.sets,
337
- filters: _filters
338
- },
339
- connection: connection,
340
- appLog: reqOpe.hasOwnProperty('appLog') ? reqOpe.appLog : undefined
341
- }
342
- };
343
-
344
- export function preparePut(tSchema, connection, reqOpe) {
345
- const _reqOpe = [];
346
- const _result = [];
347
- if (Array.isArray(reqOpe)) _reqOpe.push(...reqOpe);
348
- else _reqOpe.push(reqOpe);
349
- _reqOpe.forEach(function (_ope) {
350
- if (_ope?.put) {
351
- if (!_ope.put.sets) throw new Error('Request sintax error, missing "put.sets" property.')
352
- _result.push({
353
- put: {
354
- schema: tSchema,
355
- sets: _ope.put.sets,
356
- params: _ope.put.params
357
- },
358
- connection: connection,
359
- appLog: _ope.hasOwnProperty('appLog') ? _ope.appLog : undefined
360
- });
361
- }
362
- else throw new Error('Request sintax error, missing "put" property.');
363
- });
364
- if (_result.length > 1) return _result;
365
- if (_result.length = 1) return _result[0];
366
- return undefined;
367
- };
368
-
369
- export function preparePutById(tSchema, connection, reqOpe, idValue) {
370
- if (!reqOpe?.put) throw new Error('Request sintax error, missing "put" property.')
371
- if (!reqOpe.put.sets) throw new Error('Missing "put.sets" in operation.')
372
- upsertProperty(reqOpe.put.sets, idField(tSchema), idValue);
373
- return {
374
- put: {
375
- schema: tSchema,
376
- sets: reqOpe.put.sets,
377
- params: reqOpe.put.params
378
- },
379
- connection: connection,
380
- appLog: reqOpe.hasOwnProperty('appLog') ? reqOpe.appLog : undefined
381
- }
382
- };
383
-
384
- export function prepareDelete(tSchema, connection, reqOpe) {
385
- const _reqOpe = [];
386
- const _result = [];
387
- if (Array.isArray(reqOpe)) _reqOpe.push(...reqOpe);
388
- else _reqOpe.push(reqOpe);
389
- _reqOpe.forEach(function (_ope) {
390
- if (_ope?.delete) {
391
- _result.push({
392
- delete: {
393
- schema: tSchema,
394
- filters: _ope.delete.filters,
395
- params: _ope.delete.params
396
- },
397
- connection: connection,
398
- appLog: _ope.hasOwnProperty('appLog') ? _ope.appLog : undefined
399
- });
400
- }
401
- else throw new Error('Request sintax error, missing "delete" property.');
402
- });
403
- if (_result.length > 1) return _result;
404
- if (_result.length = 1) return _result[0];
405
- return undefined;
406
- };
407
-
408
- export function prepareDeleteById(tSchema, connection, reqOpe, idValue) {
409
- return {
410
- delete: {
411
- schema: tSchema,
412
- filters: [idField(tSchema) + ' = ' + toStringValue(idValue)]
413
- },
414
- connection: connection,
415
- appLog: reqOpe.hasOwnProperty('appLog') ? reqOpe.appLog : undefined
416
- }
417
- };
418
-
419
- export function prepareExecute(pSchema, connection, reqOpe) {
420
- const _reqOpe = [];
421
- const _result = [];
422
- if (Array.isArray(reqOpe)) _reqOpe.push(...reqOpe);
423
- else _reqOpe.push(reqOpe);
424
- _reqOpe.forEach(function (_ope) {
425
- _result.push({
426
- execute: {
427
- schema: pSchema,
428
- arguments: _ope.execute?.arguments,
429
- params: _ope.execute?.params
430
- },
431
- connection: connection,
432
- appLog: _ope.hasOwnProperty('appLog') ? _ope.appLog : undefined
433
- });
434
- });
435
- if (_result.length > 1) return _result;
436
- if (_result.length = 1) return _result[0];
437
- return undefined;
438
- };
439
-
440
- export function preparePassthrough(connection, reqOpe) {
441
- const _reqOpe = [];
442
- const _result = [];
443
- if (Array.isArray(reqOpe)) _reqOpe.push(...reqOpe);
444
- else _reqOpe.push(reqOpe);
445
- _reqOpe.forEach(function (_ope) {
446
- if (_ope?.passthrough) {
447
- if (!_ope.passthrough.command) throw new Error('Request sintax error, missing "passthrough.command" property.')
448
- _result.push({
449
- passthrough: {
450
- command: _ope.passthrough.command,
451
- params: _ope.passthrough.params
452
- },
453
- connection: connection,
454
- appLog: _ope.hasOwnProperty('appLog') ? _ope.appLog : undefined
455
- });
456
- }
457
- else throw new Error('Request sintax error, missing "passthrough" property.');
458
- });
459
- if (_result.length > 1) return _result;
460
- if (_result.length = 1) return _result[0];
461
- return undefined;
462
- };
463
-
464
- export function prepareBegin(connection, reqOpe) {
465
- return {
466
- begin: {},
467
- connection: connection,
468
- appLog: reqOpe.hasOwnProperty('appLog') ? reqOpe.appLog : undefined
469
- }
470
- };
471
-
472
- export function prepareCommit(connection, reqOpe) {
473
- return {
474
- commit: {},
475
- connection: connection,
476
- appLog: reqOpe.hasOwnProperty('appLog') ? reqOpe.appLog : undefined
477
- }
478
- };
479
-
480
- export function prepareRollback(connection, reqOpe) {
481
- return {
482
- rollback: {},
483
- connection: connection,
484
- appLog: reqOpe.hasOwnProperty('appLog') ? reqOpe.appLog : undefined
485
- }
486
- };
package/lib/mysql.js.bak DELETED
@@ -1,404 +0,0 @@
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 stringifyValue(fieldName, value, tSchema) {
15
-
16
- // null or undefined
17
- if (value == undefined)
18
- return 'null';
19
-
20
- // detect field type
21
- let _fieldType = undefined;
22
- if (tSchema.table.fields && tSchema.table.fields[fieldName] && tSchema.table.fields[fieldName].type) {
23
- _fieldType = tSchema.table.fields[fieldName].type;
24
- }
25
-
26
- // if datetime
27
- if (_fieldType == 'datetime') {
28
- // my-sql not accepts 'Z' at end of ISO string
29
- if (value instanceof Date)
30
- return `\'${value.toISOString().slice(0, -1)}\'`;
31
- if (typeof value == 'string') {
32
- const valueDate = new Date(Date.parse(value));
33
- return `\'${valueDate.toISOString().slice(0, -1)}\'`;
34
- }
35
- return value;
36
- }
37
-
38
- // if boolean
39
- if (_fieldType == 'boolean' && typeof value == 'boolean')
40
- return `\'${value}\'`;
41
-
42
- // if string or uuid
43
- if (_fieldType == 'string' || _fieldType == 'uuid') {
44
- if (value.trimStart().charAt(0) !== '\'' && value.trimStart().charAt(0) !== '\"') {
45
- return `\'${value}\'`;
46
- }
47
- }
48
-
49
- // field not in schema
50
- if (_fieldType == undefined) {
51
- if (value instanceof Date)
52
- return `\'${value.toISOString().slice(0, -1)}\'`;
53
- if (typeof value == 'boolean')
54
- return `\'${value}\'`;
55
- if (typeof value == 'string' && value.trimStart().charAt(0) !== '\'' && value.trimStart().charAt(0) !== '\"')
56
- return `\'${value}\'`;
57
- }
58
-
59
- return value;
60
- }
61
-
62
-
63
-
64
- // Create config object for pool
65
- export function prepareConnection(tSchema) {
66
- return {
67
- id: `${tSchema.server.realName}-${tSchema.database.realName}-${tSchema.server.user}`,
68
- host: ((tSchema.server.instance && tSchema.server.instance != 'DEFAULT') ? (tSchema.server.realName + '\\' + tSchema.server.instance) : tSchema.server.realName) ?? 'localhost',
69
- port: tSchema.server.port,
70
- user: tSchema.server.user,
71
- password: tSchema.server.password,
72
- database: tSchema.database.realName,
73
- ssl: {
74
- rejectUnauthorized: false
75
- },
76
- multipleStatements: true,
77
- connectionLimit: tSchema.server.connectionLimit
78
- };
79
- };
80
-
81
- // Close connection
82
- export async function closeConnection(connection) {
83
- let pool = pools[connection.id];
84
- if (pool) {
85
- pool.releaseConnection();
86
- connection.end();
87
- pools[connection.id] = undefined; // remove pool from pools
88
- }
89
- }
90
-
91
- // Close all connections
92
- export async function closeAllConnections() {
93
- for (let poolId in pools) {
94
- if (!pools.hasOwnProperty(poolId)) continue;
95
- let pool = pools[poolId];
96
- if (pool) {
97
- pool.end();
98
- pool = undefined; // remove pool from pools
99
- }
100
- }
101
- }
102
-
103
- // Test connection
104
- export async function testConnection(connection) {
105
- try {
106
- const _connection = await sql.createConnection(connection);
107
- await _connection.end();
108
- return true;
109
- }
110
- catch (error)
111
- {
112
- throw (error);
113
- }
114
- }
115
-
116
- // Query
117
- export async function query(connection, dbOpes) {
118
-
119
- // Prepare pool
120
- let pool = pools[connection.id]; // Try to get an existing pool
121
- if (!pool) {
122
- pool = new sql.createPool(connection); // Create new pool
123
- pools[connection.id] = pool; // add new pool to pools
124
- }
125
-
126
- // Prepare sql statement
127
- let sqlString = '';
128
- let appLog = true;
129
- // if exists, input params will be added to request
130
- if (Array.isArray(dbOpes)) {
131
- dbOpes.forEach((dbOpe, index) => {
132
- sqlString += ToSql(dbOpe, pool);
133
- if (dbOpe?.hasOwnProperty('appLog') && dbOpe.appLog === false) appLog = false;
134
- });
135
- }
136
- else {
137
- sqlString += ToSql(dbOpes, pool);
138
- if (dbOpes?.hasOwnProperty('appLog') && dbOpes.appLog === false) appLog = false;
139
- }
140
-
141
- sqlString = normalizeSpecialName(sqlString);
142
-
143
- // Log
144
- if (appLog) {
145
- log(JSON.stringify(dbOpes), 60);
146
- log(sqlString, 50);
147
- }
148
-
149
- // Run query
150
- let sqlresult = undefined;
151
- let sqlconn = undefined;
152
- try {
153
- sqlconn = await pool.getConnection();
154
- sqlresult = await sqlconn.query(sqlString);
155
- }
156
- catch (err) { throw (err); } // using original error
157
- finally { if (sqlconn) sqlconn.release(); }
158
-
159
- // Log
160
- if (appLog) {
161
- log(`Query result: ${(sqlresult && sqlresult.length > 0) ? sqlresult[0].length : 0} rows.`, 50);
162
- }
163
-
164
- // normalize return object
165
- if (sqlresult == undefined) return;
166
- if (sqlresult.length === 0) return;
167
- if (sqlresult[0].length === 0) return;
168
-
169
- return sqlresult[0];
170
- }
171
-
172
- // Normalize special name to replace square brackets with backticks, considering quoted strings
173
- function normalizeSpecialName(sql) {
174
- let result = "";
175
- let inSingleQuote = false;
176
- let inDoubleQuote = false;
177
-
178
- for (let i = 0; i < sql.length; i++) {
179
- const char = sql[i];
180
-
181
- // Gestione delle virgolette singole '
182
- if (char === "'" && !inDoubleQuote) {
183
- inSingleQuote = !inSingleQuote;
184
- }
185
- // Gestione delle virgolette doppie "
186
- else if (char === '"' && !inSingleQuote) {
187
- inDoubleQuote = !inDoubleQuote;
188
- }
189
-
190
- // Se non siamo all'interno di una stringa, sostituiamo le quadre
191
- if (!inSingleQuote && !inDoubleQuote) {
192
- if (char === '[' || char === ']') {
193
- result += '`';
194
- continue;
195
- }
196
- }
197
-
198
- result += char;
199
- }
200
-
201
- return result;
202
- }
203
-
204
- // Compose fully qualified table name
205
- function fullyQualifiedTableName(tSchema) {
206
- return (tSchema.database.realName + '.' + tSchema.table.realName);
207
- }
208
-
209
- function containLIMIT(s) {
210
- const _return = s?.match(_match_LIMIT_n);
211
- if (_return) return _return[0];
212
- else return undefined;
213
- };
214
-
215
- function containTOP(s) {
216
- const _return = s?.match(_match_TOP_n);
217
- if (_return) return _return[0];
218
- else return undefined;
219
- };
220
-
221
- function replaceTOPToLIMIT(s) {
222
- const _replace = containTOP(s);
223
- if (_replace) { return s.replace(_match_TOP_n, _replace.replace(_match_TOP, 'LIMIT')); }
224
- else return s;
225
- }
226
-
227
- // Parse oprations object to sql string
228
- function ToSql(dbOpe, sqlRequest) {
229
- if (dbOpe.get) return getToSql(dbOpe, sqlRequest);
230
- if (dbOpe.patch) return patchToSql(dbOpe, sqlRequest);
231
- if (dbOpe.put) return putToSql(dbOpe, sqlRequest);
232
- if (dbOpe.delete) return deleteToSql(dbOpe, sqlRequest);
233
- if (dbOpe.execute) return executeToSql(dbOpe, sqlRequest);
234
- if (dbOpe.begin) return beginToSql(dbOpe, sqlRequest);
235
- if (dbOpe.commit) return commitToSql(dbOpe, sqlRequest);
236
- if (dbOpe.passthrough) return passthroughToSql(dbOpe, sqlRequest);
237
- }
238
-
239
- // Parse operation object to sql string without any trasformation.
240
- function passthroughToSql(dbOpe, sqlRequest) {
241
-
242
- let result = "";
243
-
244
- if (dbOpe.passthrough.command) {
245
- result += dbOpe.passthrough.command;
246
- }
247
- else { throw new Error('command is missing.'); }
248
-
249
- if (dbOpe.passthrough.params) addParams(dbOpe.passthrough.params, sqlRequest);
250
-
251
- return result;
252
- }
253
-
254
- // Parse get operation object to sql string
255
- function getToSql(dbOpe, sqlRequest) {
256
- let _first = true;
257
-
258
- let result = 'select'
259
-
260
- // omit 'limit' or 'top'
261
- if (dbOpe.get.options && dbOpe.get.options.length > 0) {
262
- if (Array.isArray(dbOpe.get.options)) {
263
- for (const s of dbOpe.get.options) { if (!containLIMIT(s) && !containTOP(s)) result += ' ' + s; }
264
- }
265
- else if (!containLIMIT(dbOpe.get.options) && !containTOP(dbOpe.get.options)) result += ' ' + dbOpe.get.options;
266
- }
267
-
268
- if (dbOpe.get.fields && dbOpe.get.fields.length > 0) {
269
- if (Array.isArray(dbOpe.get.fields)) result += ' ' + dbOpe.get.fields.join(',')
270
- else result += ' ' + dbOpe.get.fields;
271
- }
272
- else { throw new Error('fields is missing.'); }
273
-
274
- result += ' from ' + fullyQualifiedTableName(dbOpe.get.schema);
275
-
276
- if (dbOpe.get.filters && dbOpe.get.filters.length > 0) {
277
- if (Array.isArray(dbOpe.get.filters)) result += ' where ' + dbOpe.get.filters.join(' ');
278
- else result += ' where ' + dbOpe.get.filters;
279
- }
280
-
281
- if (dbOpe.get.groups && dbOpe.get.groups.length > 0) {
282
- if (Array.isArray(dbOpe.get.groups)) result += ' group by ' + dbOpe.get.groups.join(', ');
283
- else result += ' group by ' + dbOpe.get.groups;
284
- }
285
-
286
- if (dbOpe.get.groupsFilters && dbOpe.get.groupsFilters.length > 0) {
287
- if (Array.isArray(dbOpe.get.groupsFilters)) result += ' having ' + dbOpe.get.groupsFilters.join(' ');
288
- else result += ' having ' + dbOpe.get.groupsFilters;
289
- }
290
-
291
- if (dbOpe.get.orderBy && dbOpe.get.orderBy.length > 0) {
292
- if (Array.isArray(dbOpe.get.orderBy)) result += ' order by ' + dbOpe.get.orderBy.join(', ');
293
- else result += ' order by ' + dbOpe.get.orderBy;
294
- }
295
-
296
- // search if 'limit' or 'top'
297
- if (dbOpe.get.options && dbOpe.get.options.length > 0) {
298
- if (Array.isArray(dbOpe.get.options)) {
299
- for (const s of dbOpe.get.options) { if (containLIMIT(s) || containTOP(s)) result += ' ' + replaceTOPToLIMIT(s); }
300
- }
301
- else if (containLIMIT(dbOpe.get.options) || containTOP(dbOpe.get.options)) result += ' ' + replaceTOPToLIMIT(dbOpe.get.options);
302
- }
303
-
304
- if (dbOpe.get.params) addParams(dbOpe.get.params, sqlRequest);
305
-
306
- result += ';'
307
-
308
- return result;
309
- }
310
-
311
- // Parse patch operation object to sql string
312
- function patchToSql(dbOpe, sqlRequest) {
313
- let result = 'update ' + fullyQualifiedTableName(dbOpe.patch.schema);
314
-
315
- if (dbOpe.patch.sets) { result += ' set ' + Object.entries(dbOpe.patch.sets).map(e => { return e[0] + '=' + stringifyValue(e[0], e[1], dbOpe.patch.schema) }).join(', '); }
316
- else { throw new Error('sets is missing.'); }
317
-
318
- if (dbOpe.patch.filters && dbOpe.patch.filters.length > 0) {
319
- if (Array.isArray(dbOpe.patch.filters)) result += ' where ' + dbOpe.patch.filters.join(' ');
320
- else result += ' where ' + dbOpe.patch.filters;
321
- }
322
-
323
- if (dbOpe.patch.params) addParams(dbOpe.patch.params, sqlRequest);
324
-
325
- result += ';'
326
-
327
- return result;
328
- }
329
-
330
- // Parse put (add) operation object to sql string
331
- function putToSql(dbOpe, sqlRequest) {
332
- let result = 'insert into ' + fullyQualifiedTableName(dbOpe.put.schema);
333
-
334
- if ((dbOpe.put.sets) && (Object.keys(dbOpe.put.sets).length > 0)) {
335
- let result_f = ' ('; let result_v = ' values (';
336
- let _first = true;
337
- for (const [key, value] of Object.entries(dbOpe.put.sets)) {
338
- if (!_first) { result_f += ', '; result_v += ', '; } else { _first = false }
339
- if (key || value) { result_f += key; result_v += stringifyValue(key, value, dbOpe.put.schema); }
340
- }
341
- result_f += ')'; result_v += ')';
342
- result += result_f + result_v;
343
- }
344
- else { throw new Error('sets is missing.'); }
345
-
346
- if (dbOpe.put.params) addParams(dbOpe.put.params, sqlRequest);
347
-
348
- result += ';'
349
-
350
- return result;
351
- }
352
-
353
- // Parse delete operation object to sql string
354
- function deleteToSql(dbOpe, sqlRequest) {
355
- let result = 'delete from ' + fullyQualifiedTableName(dbOpe.delete.schema);
356
-
357
- if (dbOpe.delete.filters && dbOpe.delete.filters.length > 0) {
358
- if (Array.isArray(dbOpe.delete.filters)) result += ' where ' + dbOpe.delete.filters.join(' ');
359
- else result += ' where ' + dbOpe.delete.filters;
360
- }
361
-
362
- if (dbOpe.delete.params) addParams(dbOpe.delete.params, sqlRequest);
363
-
364
- result += ';'
365
-
366
- return result;
367
- }
368
-
369
- // Parse execute operation object to sql string
370
- function executeToSql(dbOpe, sqlRequest) {
371
- let result = "CALL ";
372
-
373
- if (dbOpe.execute.schema.procedure) {
374
- result += dbOpe.execute.schema.procedure.command;
375
- if (dbOpe.execute.arguments) { result += ('(' + dbOpe.execute.arguments) + ')'; }
376
- }
377
- else { throw new Error('missing procedure/function name.'); }
378
-
379
- if (dbOpe.execute.params) addParams(dbOpe.execute.params, sqlRequest);
380
-
381
- result += ';'
382
-
383
- return result;
384
- }
385
-
386
- // Parse begin operation object to sql string
387
- function beginToSql(dbOpe, sqlRequest) {
388
- return "START TRANSACTION; ";
389
- }
390
-
391
- // Parse commit operation object to sql string
392
- function commitToSql(dbOpe, sqlRequest) {
393
- return " COMMIT;";
394
- }
395
-
396
- // Add input parameters to pool.request
397
- function addParams(params, sqlRequest) {
398
- if (params) {
399
- for (const [key, value] of Object.entries(params)) {
400
- sqlRequest.input(key, value)
401
- }
402
- }
403
- return;
404
- }