@oino-ts/db-mssql 0.18.1 → 0.20.0
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/dist/cjs/OINODbMsSql.js +90 -47
- package/dist/esm/OINODbMsSql.js +72 -29
- package/dist/types/OINODbMsSql.d.ts +18 -2
- package/package.json +2 -2
- package/src/OINODbMsSql.ts +74 -30
package/dist/cjs/OINODbMsSql.js
CHANGED
|
@@ -6,14 +6,15 @@
|
|
|
6
6
|
*/
|
|
7
7
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
8
|
exports.OINODbMsSql = void 0;
|
|
9
|
+
const common_1 = require("@oino-ts/common");
|
|
9
10
|
const db_1 = require("@oino-ts/db");
|
|
10
11
|
const mssql_1 = require("mssql");
|
|
11
12
|
/**
|
|
12
|
-
* Implmentation of OINODbDataSet for
|
|
13
|
+
* Implmentation of OINODbDataSet for MsSql.
|
|
13
14
|
*
|
|
14
15
|
*/
|
|
15
16
|
class OINOMsSqlData extends db_1.OINODbDataSet {
|
|
16
|
-
_recordsets
|
|
17
|
+
_recordsets;
|
|
17
18
|
_rows = db_1.OINODB_EMPTY_ROWS;
|
|
18
19
|
_currentRecordset;
|
|
19
20
|
_currentRow;
|
|
@@ -25,10 +26,10 @@ class OINOMsSqlData extends db_1.OINODbDataSet {
|
|
|
25
26
|
constructor(data, messages = []) {
|
|
26
27
|
super(data, messages);
|
|
27
28
|
if (data == null) {
|
|
28
|
-
this.messages.push(
|
|
29
|
+
this.messages.push(common_1.OINO_INFO_PREFIX + "SQL result is empty");
|
|
29
30
|
}
|
|
30
|
-
else if (!(Array.isArray(data) && (data.length > 0)
|
|
31
|
-
throw new Error(
|
|
31
|
+
else if (!(Array.isArray(data)) && (data.length > 0)) {
|
|
32
|
+
throw new Error(common_1.OINO_ERROR_PREFIX + ": OINOMsSqlData constructor: invalid data!");
|
|
32
33
|
}
|
|
33
34
|
else {
|
|
34
35
|
this._recordsets = data;
|
|
@@ -50,7 +51,7 @@ class OINOMsSqlData extends db_1.OINODbDataSet {
|
|
|
50
51
|
*
|
|
51
52
|
*/
|
|
52
53
|
isEmpty() {
|
|
53
|
-
return (this._rows.length == 0);
|
|
54
|
+
return (this._recordsets.length == 0) || (this._rows == undefined) || (this._rows.length == 0);
|
|
54
55
|
}
|
|
55
56
|
/**
|
|
56
57
|
* Is there no more content, i.e. either dataset is empty or we have moved beyond last line
|
|
@@ -98,7 +99,7 @@ class OINOMsSqlData extends db_1.OINODbDataSet {
|
|
|
98
99
|
}
|
|
99
100
|
}
|
|
100
101
|
/**
|
|
101
|
-
* Implementation of
|
|
102
|
+
* Implementation of MsSql-database.
|
|
102
103
|
*
|
|
103
104
|
*/
|
|
104
105
|
class OINODbMsSql extends db_1.OINODb {
|
|
@@ -110,7 +111,7 @@ class OINODbMsSql extends db_1.OINODb {
|
|
|
110
111
|
constructor(params) {
|
|
111
112
|
super(params);
|
|
112
113
|
if (this._params.type !== "OINODbMsSql") {
|
|
113
|
-
throw new Error(
|
|
114
|
+
throw new Error(common_1.OINO_ERROR_PREFIX + ": Not OINODbMsSql-type: " + this._params.type);
|
|
114
115
|
}
|
|
115
116
|
this._pool = new mssql_1.ConnectionPool({
|
|
116
117
|
user: this._params.user,
|
|
@@ -128,18 +129,32 @@ class OINODbMsSql extends db_1.OINODb {
|
|
|
128
129
|
});
|
|
129
130
|
delete this._params.password; // do not store password in db object
|
|
130
131
|
this._pool.on("error", (conn) => {
|
|
131
|
-
|
|
132
|
+
common_1.OINOLog.error("@oino-ts/db-mssql", "OINODbMsSql", "constructor", "OINODbMsSql error event", conn);
|
|
132
133
|
});
|
|
133
134
|
}
|
|
134
135
|
async _query(sql) {
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
136
|
+
try {
|
|
137
|
+
const request = this._pool.request(); // this does not need to be released but the pool will handle it
|
|
138
|
+
const sql_res = await request.query(sql);
|
|
139
|
+
// console.log("_query: result=", sql_res.recordsets, sql_res.recordsets?.length) // TODO: remove
|
|
140
|
+
return new OINOMsSqlData(sql_res.recordsets, []);
|
|
141
|
+
}
|
|
142
|
+
catch (e) {
|
|
143
|
+
common_1.OINOLog.exception("@oino-ts/db-mssql", "OINODbMsSql", "_query", "exception in SQL query", { message: e.message, stack: e.stack, sql: sql });
|
|
144
|
+
return new OINOMsSqlData(db_1.OINODB_EMPTY_ROWS, []).setError(500, common_1.OINO_ERROR_PREFIX + ": Exception in db query: " + e.message, "OINODbMsSql._query");
|
|
145
|
+
}
|
|
139
146
|
}
|
|
140
147
|
async _exec(sql) {
|
|
141
|
-
|
|
142
|
-
|
|
148
|
+
try {
|
|
149
|
+
const request = this._pool.request(); // this does not need to be released but the pool will handle it
|
|
150
|
+
const sql_res = await request.query(sql);
|
|
151
|
+
// console.log("_exec: result=", sql_res.recordsets, sql_res.recordsets?.length) // TODO: remove
|
|
152
|
+
return new OINOMsSqlData(sql_res.recordsets, []);
|
|
153
|
+
}
|
|
154
|
+
catch (e) {
|
|
155
|
+
common_1.OINOLog.exception("@oino-ts/db-mssql", "OINODbMsSql", "_exec", "exception in SQL exec", { message: e.message, stack: e.stack, sql: sql });
|
|
156
|
+
return new OINOMsSqlData(db_1.OINODB_EMPTY_ROWS, []).setError(500, common_1.OINO_ERROR_PREFIX + ": Exception in db exec: " + e.message, "OINODbMsSql._exec");
|
|
157
|
+
}
|
|
143
158
|
}
|
|
144
159
|
/**
|
|
145
160
|
* Print a table name using database specific SQL escaping.
|
|
@@ -258,15 +273,32 @@ class OINODbMsSql extends db_1.OINODb {
|
|
|
258
273
|
}
|
|
259
274
|
if ((limitCondition != "") && (limit_parts.length == 2)) {
|
|
260
275
|
if (orderCondition == "") {
|
|
261
|
-
|
|
262
|
-
throw new Error(
|
|
276
|
+
common_1.OINOLog.error("@oino-ts/db-mssql", "OINODbMsSql", "printSqlSelect", "LIMIT without ORDER BY is not supported in MS SQL Server");
|
|
277
|
+
throw new Error(common_1.OINO_ERROR_PREFIX + ": LIMIT without ORDER BY is not supported in MS SQL Server");
|
|
263
278
|
}
|
|
264
279
|
else {
|
|
265
280
|
result += " OFFSET " + limit_parts[1] + " ROWS FETCH NEXT " + limit_parts[0] + " ROWS ONLY";
|
|
266
281
|
}
|
|
267
282
|
}
|
|
268
283
|
result += ";";
|
|
269
|
-
|
|
284
|
+
common_1.OINOLog.debug("@oino-ts/db-mssql", "OINODbMsSql", "printSqlSelect", "Result", { sql: result });
|
|
285
|
+
return result;
|
|
286
|
+
}
|
|
287
|
+
/**
|
|
288
|
+
* Print SQL select statement with DB specific formatting.
|
|
289
|
+
*
|
|
290
|
+
* @param tableName - The name of the table to select from.
|
|
291
|
+
* @param columns - The columns to be selected.
|
|
292
|
+
* @param values - The values to be inserted.
|
|
293
|
+
* @param returnIdFields - the id fields to return if returnIds is true (if supported by the database)
|
|
294
|
+
*
|
|
295
|
+
*/
|
|
296
|
+
printSqlInsert(tableName, columns, values, returnIdFields) {
|
|
297
|
+
let result = "INSERT INTO " + tableName + " (" + columns + ")";
|
|
298
|
+
if (returnIdFields) {
|
|
299
|
+
result += " OUTPUT " + returnIdFields.map(f => "INSERTED." + f).join(", ");
|
|
300
|
+
}
|
|
301
|
+
result += " VALUES (" + values + ");";
|
|
270
302
|
return result;
|
|
271
303
|
}
|
|
272
304
|
/**
|
|
@@ -274,7 +306,10 @@ class OINODbMsSql extends db_1.OINODb {
|
|
|
274
306
|
*
|
|
275
307
|
*/
|
|
276
308
|
async connect() {
|
|
277
|
-
let result = new
|
|
309
|
+
let result = new common_1.OINOResult();
|
|
310
|
+
if (this.isConnected) {
|
|
311
|
+
return result;
|
|
312
|
+
}
|
|
278
313
|
try {
|
|
279
314
|
// make sure that any items are correctly URL encoded in the connection string
|
|
280
315
|
await this._pool.connect();
|
|
@@ -283,7 +318,7 @@ class OINODbMsSql extends db_1.OINODb {
|
|
|
283
318
|
catch (e) {
|
|
284
319
|
// ... error checks
|
|
285
320
|
result.setError(500, "Exception connecting to database: " + e.message, "OINODbMsSql.connect");
|
|
286
|
-
|
|
321
|
+
common_1.OINOLog.exception("@oino-ts/db-mssql", "OINODbMsSql", "connect", "exception in connect", { message: e.message, stack: e.stack });
|
|
287
322
|
}
|
|
288
323
|
return Promise.resolve(result);
|
|
289
324
|
}
|
|
@@ -292,15 +327,15 @@ class OINODbMsSql extends db_1.OINODb {
|
|
|
292
327
|
*
|
|
293
328
|
*/
|
|
294
329
|
async validate() {
|
|
295
|
-
let result = new
|
|
330
|
+
let result = new common_1.OINOResult();
|
|
296
331
|
if (!this.isConnected) {
|
|
297
332
|
result.setError(400, "Database is not connected!", "OINODbMsSql.validate");
|
|
298
333
|
return result;
|
|
299
334
|
}
|
|
300
|
-
|
|
335
|
+
common_1.OINOBenchmark.startMetric("OINODb", "validate");
|
|
301
336
|
try {
|
|
302
337
|
const sql = this._getValidateSql(this._params.database);
|
|
303
|
-
const sql_res = await this.
|
|
338
|
+
const sql_res = await this._query(sql);
|
|
304
339
|
if (sql_res.isEmpty()) {
|
|
305
340
|
result.setError(400, "DB returned no rows for select!", "OINODbMsSql.validate");
|
|
306
341
|
}
|
|
@@ -317,11 +352,27 @@ class OINODbMsSql extends db_1.OINODb {
|
|
|
317
352
|
}
|
|
318
353
|
catch (e) {
|
|
319
354
|
result.setError(500, "Exception in validating connection: " + e.message, "OINODbMsSql.validate");
|
|
320
|
-
|
|
355
|
+
common_1.OINOLog.exception("@oino-ts/db-mssql", "OINODbMsSql", "validate", "exception in validate", { message: e.message, stack: e.stack });
|
|
321
356
|
}
|
|
322
|
-
|
|
357
|
+
common_1.OINOBenchmark.endMetric("OINODb", "validate");
|
|
323
358
|
return result;
|
|
324
359
|
}
|
|
360
|
+
/**
|
|
361
|
+
* Disconnect from database.
|
|
362
|
+
*
|
|
363
|
+
*/
|
|
364
|
+
async disconnect() {
|
|
365
|
+
if (this._pool) {
|
|
366
|
+
try {
|
|
367
|
+
await this._pool.close();
|
|
368
|
+
}
|
|
369
|
+
catch (e) {
|
|
370
|
+
common_1.OINOLog.exception("@oino-ts/db-mssql", "OINODbMsSql", "disconnect", "exception in disconnect", { message: e.message, stack: e.stack });
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
this.isConnected = false;
|
|
374
|
+
this.isValidated = false;
|
|
375
|
+
}
|
|
325
376
|
/**
|
|
326
377
|
* Execute a select operation.
|
|
327
378
|
*
|
|
@@ -329,16 +380,12 @@ class OINODbMsSql extends db_1.OINODb {
|
|
|
329
380
|
*
|
|
330
381
|
*/
|
|
331
382
|
async sqlSelect(sql) {
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
try {
|
|
335
|
-
result = await this._query(sql);
|
|
336
|
-
}
|
|
337
|
-
catch (e) {
|
|
338
|
-
db_1.OINOLog.exception("@oino-ts/db-mssql", "OINODbMsSql", "sqlSelect", "exception in SQL select", { message: e.message, stack: e.stack });
|
|
339
|
-
result = new OINOMsSqlData(db_1.OINODB_EMPTY_ROWS, [db_1.OINO_ERROR_PREFIX + " (sqlSelect): OINODbMsSql.sqlSelect exception in _db.query: " + e.message]);
|
|
383
|
+
if (!this.isValidated) {
|
|
384
|
+
throw new Error(common_1.OINO_ERROR_PREFIX + ": Database connection not validated!");
|
|
340
385
|
}
|
|
341
|
-
|
|
386
|
+
common_1.OINOBenchmark.startMetric("OINODb", "sqlSelect");
|
|
387
|
+
let result = await this._query(sql);
|
|
388
|
+
common_1.OINOBenchmark.endMetric("OINODb", "sqlSelect");
|
|
342
389
|
return result;
|
|
343
390
|
}
|
|
344
391
|
/**
|
|
@@ -348,16 +395,12 @@ class OINODbMsSql extends db_1.OINODb {
|
|
|
348
395
|
*
|
|
349
396
|
*/
|
|
350
397
|
async sqlExec(sql) {
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
try {
|
|
354
|
-
result = await this._exec(sql);
|
|
355
|
-
}
|
|
356
|
-
catch (e) {
|
|
357
|
-
db_1.OINOLog.exception("@oino-ts/db-mssql", "OINODbMsSql", "sqlExec", "exception in SQL exec", { message: e.message, stack: e.stack });
|
|
358
|
-
result = new OINOMsSqlData(db_1.OINODB_EMPTY_ROWS, [db_1.OINO_ERROR_PREFIX + " (sqlExec): exception in _db.exec [" + e.message + "]"]);
|
|
398
|
+
if (!this.isValidated) {
|
|
399
|
+
throw new Error(common_1.OINO_ERROR_PREFIX + ": Database connection not validated!");
|
|
359
400
|
}
|
|
360
|
-
|
|
401
|
+
common_1.OINOBenchmark.startMetric("OINODb", "sqlExec");
|
|
402
|
+
let result = await this._exec(sql);
|
|
403
|
+
common_1.OINOBenchmark.endMetric("OINODb", "sqlExec");
|
|
361
404
|
return result;
|
|
362
405
|
}
|
|
363
406
|
_getSchemaSql(dbName, tableName) {
|
|
@@ -424,9 +467,9 @@ WHERE C.TABLE_CATALOG = '${dbName}';`;
|
|
|
424
467
|
isNotNull: row[1] == "NO"
|
|
425
468
|
};
|
|
426
469
|
if (api.isFieldIncluded(field_name) == false) {
|
|
427
|
-
|
|
470
|
+
common_1.OINOLog.info("@oino-ts/db-mssql", "OINODbMsSql", "initializeApiDatamodel", "Field excluded in API parameters.", { field: field_name });
|
|
428
471
|
if (field_params.isPrimaryKey) {
|
|
429
|
-
throw new Error(
|
|
472
|
+
throw new Error(common_1.OINO_ERROR_PREFIX + "Primary key field excluded in API parameters: " + field_name);
|
|
430
473
|
}
|
|
431
474
|
}
|
|
432
475
|
else {
|
|
@@ -454,13 +497,13 @@ WHERE C.TABLE_CATALOG = '${dbName}';`;
|
|
|
454
497
|
api.datamodel.addField(new db_1.OINOBooleanDataField(this, field_name, sql_type, field_params));
|
|
455
498
|
}
|
|
456
499
|
else {
|
|
457
|
-
|
|
500
|
+
common_1.OINOLog.info("@oino-ts/db-mssql", "OINODbMsSql", "initializeApiDatamodel", "Unrecognized field type treated as string", { field_name: field_name, sql_type: sql_type, char_length: char_field_length, numeric_field_length1: numeric_field_length1, numeric_field_length2: numeric_field_length2, field_params: field_params });
|
|
458
501
|
api.datamodel.addField(new db_1.OINOStringDataField(this, field_name, sql_type, field_params, 0));
|
|
459
502
|
}
|
|
460
503
|
}
|
|
461
504
|
await schema_res.next();
|
|
462
505
|
}
|
|
463
|
-
|
|
506
|
+
common_1.OINOLog.info("@oino-ts/db-mssql", "OINODbMsSql", "initializeApiDatamodel", "\n" + api.datamodel.printDebug("\n"));
|
|
464
507
|
return Promise.resolve();
|
|
465
508
|
}
|
|
466
509
|
}
|
package/dist/esm/OINODbMsSql.js
CHANGED
|
@@ -3,14 +3,15 @@
|
|
|
3
3
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
4
4
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
5
5
|
*/
|
|
6
|
-
import {
|
|
6
|
+
import { OINO_ERROR_PREFIX, OINOBenchmark, OINO_INFO_PREFIX, OINOLog, OINOResult } from "@oino-ts/common";
|
|
7
|
+
import { OINODb, OINODbDataSet, OINOBooleanDataField, OINONumberDataField, OINOStringDataField, OINODatetimeDataField, OINOBlobDataField, OINODB_EMPTY_ROW, OINODB_EMPTY_ROWS } from "@oino-ts/db";
|
|
7
8
|
import { ConnectionPool } from "mssql";
|
|
8
9
|
/**
|
|
9
|
-
* Implmentation of OINODbDataSet for
|
|
10
|
+
* Implmentation of OINODbDataSet for MsSql.
|
|
10
11
|
*
|
|
11
12
|
*/
|
|
12
13
|
class OINOMsSqlData extends OINODbDataSet {
|
|
13
|
-
_recordsets
|
|
14
|
+
_recordsets;
|
|
14
15
|
_rows = OINODB_EMPTY_ROWS;
|
|
15
16
|
_currentRecordset;
|
|
16
17
|
_currentRow;
|
|
@@ -24,7 +25,7 @@ class OINOMsSqlData extends OINODbDataSet {
|
|
|
24
25
|
if (data == null) {
|
|
25
26
|
this.messages.push(OINO_INFO_PREFIX + "SQL result is empty");
|
|
26
27
|
}
|
|
27
|
-
else if (!(Array.isArray(data) && (data.length > 0)
|
|
28
|
+
else if (!(Array.isArray(data)) && (data.length > 0)) {
|
|
28
29
|
throw new Error(OINO_ERROR_PREFIX + ": OINOMsSqlData constructor: invalid data!");
|
|
29
30
|
}
|
|
30
31
|
else {
|
|
@@ -47,7 +48,7 @@ class OINOMsSqlData extends OINODbDataSet {
|
|
|
47
48
|
*
|
|
48
49
|
*/
|
|
49
50
|
isEmpty() {
|
|
50
|
-
return (this._rows.length == 0);
|
|
51
|
+
return (this._recordsets.length == 0) || (this._rows == undefined) || (this._rows.length == 0);
|
|
51
52
|
}
|
|
52
53
|
/**
|
|
53
54
|
* Is there no more content, i.e. either dataset is empty or we have moved beyond last line
|
|
@@ -95,7 +96,7 @@ class OINOMsSqlData extends OINODbDataSet {
|
|
|
95
96
|
}
|
|
96
97
|
}
|
|
97
98
|
/**
|
|
98
|
-
* Implementation of
|
|
99
|
+
* Implementation of MsSql-database.
|
|
99
100
|
*
|
|
100
101
|
*/
|
|
101
102
|
export class OINODbMsSql extends OINODb {
|
|
@@ -129,14 +130,28 @@ export class OINODbMsSql extends OINODb {
|
|
|
129
130
|
});
|
|
130
131
|
}
|
|
131
132
|
async _query(sql) {
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
133
|
+
try {
|
|
134
|
+
const request = this._pool.request(); // this does not need to be released but the pool will handle it
|
|
135
|
+
const sql_res = await request.query(sql);
|
|
136
|
+
// console.log("_query: result=", sql_res.recordsets, sql_res.recordsets?.length) // TODO: remove
|
|
137
|
+
return new OINOMsSqlData(sql_res.recordsets, []);
|
|
138
|
+
}
|
|
139
|
+
catch (e) {
|
|
140
|
+
OINOLog.exception("@oino-ts/db-mssql", "OINODbMsSql", "_query", "exception in SQL query", { message: e.message, stack: e.stack, sql: sql });
|
|
141
|
+
return new OINOMsSqlData(OINODB_EMPTY_ROWS, []).setError(500, OINO_ERROR_PREFIX + ": Exception in db query: " + e.message, "OINODbMsSql._query");
|
|
142
|
+
}
|
|
136
143
|
}
|
|
137
144
|
async _exec(sql) {
|
|
138
|
-
|
|
139
|
-
|
|
145
|
+
try {
|
|
146
|
+
const request = this._pool.request(); // this does not need to be released but the pool will handle it
|
|
147
|
+
const sql_res = await request.query(sql);
|
|
148
|
+
// console.log("_exec: result=", sql_res.recordsets, sql_res.recordsets?.length) // TODO: remove
|
|
149
|
+
return new OINOMsSqlData(sql_res.recordsets, []);
|
|
150
|
+
}
|
|
151
|
+
catch (e) {
|
|
152
|
+
OINOLog.exception("@oino-ts/db-mssql", "OINODbMsSql", "_exec", "exception in SQL exec", { message: e.message, stack: e.stack, sql: sql });
|
|
153
|
+
return new OINOMsSqlData(OINODB_EMPTY_ROWS, []).setError(500, OINO_ERROR_PREFIX + ": Exception in db exec: " + e.message, "OINODbMsSql._exec");
|
|
154
|
+
}
|
|
140
155
|
}
|
|
141
156
|
/**
|
|
142
157
|
* Print a table name using database specific SQL escaping.
|
|
@@ -266,12 +281,32 @@ export class OINODbMsSql extends OINODb {
|
|
|
266
281
|
OINOLog.debug("@oino-ts/db-mssql", "OINODbMsSql", "printSqlSelect", "Result", { sql: result });
|
|
267
282
|
return result;
|
|
268
283
|
}
|
|
284
|
+
/**
|
|
285
|
+
* Print SQL select statement with DB specific formatting.
|
|
286
|
+
*
|
|
287
|
+
* @param tableName - The name of the table to select from.
|
|
288
|
+
* @param columns - The columns to be selected.
|
|
289
|
+
* @param values - The values to be inserted.
|
|
290
|
+
* @param returnIdFields - the id fields to return if returnIds is true (if supported by the database)
|
|
291
|
+
*
|
|
292
|
+
*/
|
|
293
|
+
printSqlInsert(tableName, columns, values, returnIdFields) {
|
|
294
|
+
let result = "INSERT INTO " + tableName + " (" + columns + ")";
|
|
295
|
+
if (returnIdFields) {
|
|
296
|
+
result += " OUTPUT " + returnIdFields.map(f => "INSERTED." + f).join(", ");
|
|
297
|
+
}
|
|
298
|
+
result += " VALUES (" + values + ");";
|
|
299
|
+
return result;
|
|
300
|
+
}
|
|
269
301
|
/**
|
|
270
302
|
* Connect to database.
|
|
271
303
|
*
|
|
272
304
|
*/
|
|
273
305
|
async connect() {
|
|
274
306
|
let result = new OINOResult();
|
|
307
|
+
if (this.isConnected) {
|
|
308
|
+
return result;
|
|
309
|
+
}
|
|
275
310
|
try {
|
|
276
311
|
// make sure that any items are correctly URL encoded in the connection string
|
|
277
312
|
await this._pool.connect();
|
|
@@ -297,7 +332,7 @@ export class OINODbMsSql extends OINODb {
|
|
|
297
332
|
OINOBenchmark.startMetric("OINODb", "validate");
|
|
298
333
|
try {
|
|
299
334
|
const sql = this._getValidateSql(this._params.database);
|
|
300
|
-
const sql_res = await this.
|
|
335
|
+
const sql_res = await this._query(sql);
|
|
301
336
|
if (sql_res.isEmpty()) {
|
|
302
337
|
result.setError(400, "DB returned no rows for select!", "OINODbMsSql.validate");
|
|
303
338
|
}
|
|
@@ -319,6 +354,22 @@ export class OINODbMsSql extends OINODb {
|
|
|
319
354
|
OINOBenchmark.endMetric("OINODb", "validate");
|
|
320
355
|
return result;
|
|
321
356
|
}
|
|
357
|
+
/**
|
|
358
|
+
* Disconnect from database.
|
|
359
|
+
*
|
|
360
|
+
*/
|
|
361
|
+
async disconnect() {
|
|
362
|
+
if (this._pool) {
|
|
363
|
+
try {
|
|
364
|
+
await this._pool.close();
|
|
365
|
+
}
|
|
366
|
+
catch (e) {
|
|
367
|
+
OINOLog.exception("@oino-ts/db-mssql", "OINODbMsSql", "disconnect", "exception in disconnect", { message: e.message, stack: e.stack });
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
this.isConnected = false;
|
|
371
|
+
this.isValidated = false;
|
|
372
|
+
}
|
|
322
373
|
/**
|
|
323
374
|
* Execute a select operation.
|
|
324
375
|
*
|
|
@@ -326,15 +377,11 @@ export class OINODbMsSql extends OINODb {
|
|
|
326
377
|
*
|
|
327
378
|
*/
|
|
328
379
|
async sqlSelect(sql) {
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
try {
|
|
332
|
-
result = await this._query(sql);
|
|
333
|
-
}
|
|
334
|
-
catch (e) {
|
|
335
|
-
OINOLog.exception("@oino-ts/db-mssql", "OINODbMsSql", "sqlSelect", "exception in SQL select", { message: e.message, stack: e.stack });
|
|
336
|
-
result = new OINOMsSqlData(OINODB_EMPTY_ROWS, [OINO_ERROR_PREFIX + " (sqlSelect): OINODbMsSql.sqlSelect exception in _db.query: " + e.message]);
|
|
380
|
+
if (!this.isValidated) {
|
|
381
|
+
throw new Error(OINO_ERROR_PREFIX + ": Database connection not validated!");
|
|
337
382
|
}
|
|
383
|
+
OINOBenchmark.startMetric("OINODb", "sqlSelect");
|
|
384
|
+
let result = await this._query(sql);
|
|
338
385
|
OINOBenchmark.endMetric("OINODb", "sqlSelect");
|
|
339
386
|
return result;
|
|
340
387
|
}
|
|
@@ -345,15 +392,11 @@ export class OINODbMsSql extends OINODb {
|
|
|
345
392
|
*
|
|
346
393
|
*/
|
|
347
394
|
async sqlExec(sql) {
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
try {
|
|
351
|
-
result = await this._exec(sql);
|
|
352
|
-
}
|
|
353
|
-
catch (e) {
|
|
354
|
-
OINOLog.exception("@oino-ts/db-mssql", "OINODbMsSql", "sqlExec", "exception in SQL exec", { message: e.message, stack: e.stack });
|
|
355
|
-
result = new OINOMsSqlData(OINODB_EMPTY_ROWS, [OINO_ERROR_PREFIX + " (sqlExec): exception in _db.exec [" + e.message + "]"]);
|
|
395
|
+
if (!this.isValidated) {
|
|
396
|
+
throw new Error(OINO_ERROR_PREFIX + ": Database connection not validated!");
|
|
356
397
|
}
|
|
398
|
+
OINOBenchmark.startMetric("OINODb", "sqlExec");
|
|
399
|
+
let result = await this._exec(sql);
|
|
357
400
|
OINOBenchmark.endMetric("OINODb", "sqlExec");
|
|
358
401
|
return result;
|
|
359
402
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { OINOResult } from "@oino-ts/common";
|
|
2
|
+
import { OINODb, OINODbParams, OINODbDataSet, OINODbApi, OINODataCell } from "@oino-ts/db";
|
|
2
3
|
/**
|
|
3
|
-
* Implementation of
|
|
4
|
+
* Implementation of MsSql-database.
|
|
4
5
|
*
|
|
5
6
|
*/
|
|
6
7
|
export declare class OINODbMsSql extends OINODb {
|
|
@@ -63,6 +64,16 @@ export declare class OINODbMsSql extends OINODb {
|
|
|
63
64
|
*
|
|
64
65
|
*/
|
|
65
66
|
printSqlSelect(tableName: string, columnNames: string, whereCondition: string, orderCondition: string, limitCondition: string, groupByCondition: string): string;
|
|
67
|
+
/**
|
|
68
|
+
* Print SQL select statement with DB specific formatting.
|
|
69
|
+
*
|
|
70
|
+
* @param tableName - The name of the table to select from.
|
|
71
|
+
* @param columns - The columns to be selected.
|
|
72
|
+
* @param values - The values to be inserted.
|
|
73
|
+
* @param returnIdFields - the id fields to return if returnIds is true (if supported by the database)
|
|
74
|
+
*
|
|
75
|
+
*/
|
|
76
|
+
printSqlInsert(tableName: string, columns: string, values: string, returnIdFields?: string[]): string;
|
|
66
77
|
/**
|
|
67
78
|
* Connect to database.
|
|
68
79
|
*
|
|
@@ -73,6 +84,11 @@ export declare class OINODbMsSql extends OINODb {
|
|
|
73
84
|
*
|
|
74
85
|
*/
|
|
75
86
|
validate(): Promise<OINOResult>;
|
|
87
|
+
/**
|
|
88
|
+
* Disconnect from database.
|
|
89
|
+
*
|
|
90
|
+
*/
|
|
91
|
+
disconnect(): Promise<void>;
|
|
76
92
|
/**
|
|
77
93
|
* Execute a select operation.
|
|
78
94
|
*
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@oino-ts/db-mssql",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.20.0",
|
|
4
4
|
"description": "OINO TS package for using Microsoft Sql databases.",
|
|
5
5
|
"author": "Matias Kiviniemi (pragmatta)",
|
|
6
6
|
"license": "MPL-2.0",
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
"module": "./dist/esm/index.js",
|
|
23
23
|
"types": "./dist/types/index.d.ts",
|
|
24
24
|
"dependencies": {
|
|
25
|
-
"@oino-ts/db": "0.
|
|
25
|
+
"@oino-ts/db": "0.20.0",
|
|
26
26
|
"mssql": "^11.0.1"
|
|
27
27
|
},
|
|
28
28
|
"devDependencies": {
|
package/src/OINODbMsSql.ts
CHANGED
|
@@ -4,16 +4,17 @@
|
|
|
4
4
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
import {
|
|
7
|
+
import { OINO_ERROR_PREFIX, OINOBenchmark, OINO_INFO_PREFIX, OINOLog, OINOResult } from "@oino-ts/common";
|
|
8
|
+
import { OINODb, OINODbParams, OINODbDataSet, OINODbApi, OINOBooleanDataField, OINONumberDataField, OINOStringDataField, OINODbDataFieldParams, OINODataRow, OINODataCell, OINODatetimeDataField, OINOBlobDataField, OINODB_EMPTY_ROW, OINODB_EMPTY_ROWS } from "@oino-ts/db";
|
|
8
9
|
|
|
9
10
|
import {ConnectionPool, config} from "mssql";
|
|
10
11
|
|
|
11
12
|
/**
|
|
12
|
-
* Implmentation of OINODbDataSet for
|
|
13
|
+
* Implmentation of OINODbDataSet for MsSql.
|
|
13
14
|
*
|
|
14
15
|
*/
|
|
15
16
|
class OINOMsSqlData extends OINODbDataSet {
|
|
16
|
-
private _recordsets:
|
|
17
|
+
private _recordsets:any
|
|
17
18
|
private _rows:OINODataRow[] = OINODB_EMPTY_ROWS
|
|
18
19
|
|
|
19
20
|
private _currentRecordset: number
|
|
@@ -29,11 +30,11 @@ class OINOMsSqlData extends OINODbDataSet {
|
|
|
29
30
|
if (data == null) {
|
|
30
31
|
this.messages.push(OINO_INFO_PREFIX + "SQL result is empty")
|
|
31
32
|
|
|
32
|
-
} else if (!(Array.isArray(data) && (data.length>
|
|
33
|
+
} else if (!(Array.isArray(data)) && (data.length > 0)) {
|
|
33
34
|
throw new Error(OINO_ERROR_PREFIX + ": OINOMsSqlData constructor: invalid data!")
|
|
34
35
|
|
|
35
36
|
} else {
|
|
36
|
-
this._recordsets = data
|
|
37
|
+
this._recordsets = data
|
|
37
38
|
this._rows = this._recordsets[0]
|
|
38
39
|
}
|
|
39
40
|
if (this.isEmpty()) {
|
|
@@ -52,7 +53,7 @@ class OINOMsSqlData extends OINODbDataSet {
|
|
|
52
53
|
*
|
|
53
54
|
*/
|
|
54
55
|
isEmpty():boolean {
|
|
55
|
-
return (this._rows.length == 0)
|
|
56
|
+
return (this._recordsets.length == 0) || (this._rows == undefined) || (this._rows.length == 0)
|
|
56
57
|
}
|
|
57
58
|
|
|
58
59
|
/**
|
|
@@ -105,7 +106,7 @@ class OINOMsSqlData extends OINODbDataSet {
|
|
|
105
106
|
}
|
|
106
107
|
|
|
107
108
|
/**
|
|
108
|
-
* Implementation of
|
|
109
|
+
* Implementation of MsSql-database.
|
|
109
110
|
*
|
|
110
111
|
*/
|
|
111
112
|
export class OINODbMsSql extends OINODb {
|
|
@@ -144,15 +145,27 @@ export class OINODbMsSql extends OINODb {
|
|
|
144
145
|
}
|
|
145
146
|
|
|
146
147
|
private async _query(sql:string):Promise<OINOMsSqlData> {
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
148
|
+
try {
|
|
149
|
+
const request = this._pool.request() // this does not need to be released but the pool will handle it
|
|
150
|
+
const sql_res = await request.query(sql)
|
|
151
|
+
// console.log("_query: result=", sql_res.recordsets, sql_res.recordsets?.length) // TODO: remove
|
|
152
|
+
return new OINOMsSqlData(sql_res.recordsets, [])
|
|
153
|
+
} catch (e:any) {
|
|
154
|
+
OINOLog.exception("@oino-ts/db-mssql", "OINODbMsSql", "_query", "exception in SQL query", {message:e.message, stack:e.stack, sql:sql})
|
|
155
|
+
return new OINOMsSqlData(OINODB_EMPTY_ROWS, []).setError(500, OINO_ERROR_PREFIX + ": Exception in db query: " + e.message, "OINODbMsSql._query") as OINOMsSqlData
|
|
156
|
+
}
|
|
151
157
|
}
|
|
152
158
|
|
|
153
159
|
private async _exec(sql:string):Promise<OINOMsSqlData> {
|
|
154
|
-
|
|
155
|
-
|
|
160
|
+
try {
|
|
161
|
+
const request = this._pool.request() // this does not need to be released but the pool will handle it
|
|
162
|
+
const sql_res = await request.query(sql)
|
|
163
|
+
// console.log("_exec: result=", sql_res.recordsets, sql_res.recordsets?.length) // TODO: remove
|
|
164
|
+
return new OINOMsSqlData(sql_res.recordsets, [])
|
|
165
|
+
} catch (e:any) {
|
|
166
|
+
OINOLog.exception("@oino-ts/db-mssql", "OINODbMsSql", "_exec", "exception in SQL exec", {message:e.message, stack:e.stack, sql:sql})
|
|
167
|
+
return new OINOMsSqlData(OINODB_EMPTY_ROWS, []).setError(500, OINO_ERROR_PREFIX + ": Exception in db exec: " + e.message, "OINODbMsSql._exec") as OINOMsSqlData
|
|
168
|
+
}
|
|
156
169
|
}
|
|
157
170
|
|
|
158
171
|
/**
|
|
@@ -288,12 +301,34 @@ export class OINODbMsSql extends OINODb {
|
|
|
288
301
|
return result;
|
|
289
302
|
}
|
|
290
303
|
|
|
304
|
+
/**
|
|
305
|
+
* Print SQL select statement with DB specific formatting.
|
|
306
|
+
*
|
|
307
|
+
* @param tableName - The name of the table to select from.
|
|
308
|
+
* @param columns - The columns to be selected.
|
|
309
|
+
* @param values - The values to be inserted.
|
|
310
|
+
* @param returnIdFields - the id fields to return if returnIds is true (if supported by the database)
|
|
311
|
+
*
|
|
312
|
+
*/
|
|
313
|
+
printSqlInsert(tableName:string, columns:string, values:string, returnIdFields?:string[]): string {
|
|
314
|
+
let result = "INSERT INTO " + tableName + " (" + columns + ")"
|
|
315
|
+
if (returnIdFields) {
|
|
316
|
+
result += " OUTPUT " + returnIdFields.map(f => "INSERTED."+f ).join(", ")
|
|
317
|
+
}
|
|
318
|
+
result += " VALUES (" + values + ");"
|
|
319
|
+
return result;
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
|
|
291
323
|
/**
|
|
292
324
|
* Connect to database.
|
|
293
325
|
*
|
|
294
326
|
*/
|
|
295
327
|
async connect(): Promise<OINOResult> {
|
|
296
328
|
let result:OINOResult = new OINOResult()
|
|
329
|
+
if (this.isConnected) {
|
|
330
|
+
return result
|
|
331
|
+
}
|
|
297
332
|
try {
|
|
298
333
|
// make sure that any items are correctly URL encoded in the connection string
|
|
299
334
|
await this._pool.connect()
|
|
@@ -320,7 +355,7 @@ export class OINODbMsSql extends OINODb {
|
|
|
320
355
|
OINOBenchmark.startMetric("OINODb", "validate")
|
|
321
356
|
try {
|
|
322
357
|
const sql = this._getValidateSql(this._params.database)
|
|
323
|
-
const sql_res:OINODbDataSet = await this.
|
|
358
|
+
const sql_res:OINODbDataSet = await this._query(sql)
|
|
324
359
|
if (sql_res.isEmpty()) {
|
|
325
360
|
result.setError(400, "DB returned no rows for select!", "OINODbMsSql.validate")
|
|
326
361
|
|
|
@@ -342,6 +377,23 @@ export class OINODbMsSql extends OINODb {
|
|
|
342
377
|
return result
|
|
343
378
|
}
|
|
344
379
|
|
|
380
|
+
/**
|
|
381
|
+
* Disconnect from database.
|
|
382
|
+
*
|
|
383
|
+
*/
|
|
384
|
+
async disconnect(): Promise<void> {
|
|
385
|
+
if (this._pool) {
|
|
386
|
+
try {
|
|
387
|
+
await this._pool.close()
|
|
388
|
+
|
|
389
|
+
} catch (e:any) {
|
|
390
|
+
OINOLog.exception("@oino-ts/db-mssql", "OINODbMsSql", "disconnect", "exception in disconnect", {message:e.message, stack:e.stack})
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
this.isConnected = false
|
|
394
|
+
this.isValidated = false
|
|
395
|
+
}
|
|
396
|
+
|
|
345
397
|
/**
|
|
346
398
|
* Execute a select operation.
|
|
347
399
|
*
|
|
@@ -349,15 +401,11 @@ export class OINODbMsSql extends OINODb {
|
|
|
349
401
|
*
|
|
350
402
|
*/
|
|
351
403
|
async sqlSelect(sql:string): Promise<OINODbDataSet> {
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
try {
|
|
355
|
-
result = await this._query(sql)
|
|
356
|
-
|
|
357
|
-
} catch (e:any) {
|
|
358
|
-
OINOLog.exception("@oino-ts/db-mssql", "OINODbMsSql", "sqlSelect", "exception in SQL select", {message:e.message, stack:e.stack})
|
|
359
|
-
result = new OINOMsSqlData(OINODB_EMPTY_ROWS, [OINO_ERROR_PREFIX + " (sqlSelect): OINODbMsSql.sqlSelect exception in _db.query: " + e.message])
|
|
404
|
+
if (!this.isValidated) {
|
|
405
|
+
throw new Error(OINO_ERROR_PREFIX + ": Database connection not validated!")
|
|
360
406
|
}
|
|
407
|
+
OINOBenchmark.startMetric("OINODb", "sqlSelect")
|
|
408
|
+
let result:OINODbDataSet = await this._query(sql)
|
|
361
409
|
OINOBenchmark.endMetric("OINODb", "sqlSelect")
|
|
362
410
|
return result
|
|
363
411
|
}
|
|
@@ -369,15 +417,11 @@ export class OINODbMsSql extends OINODb {
|
|
|
369
417
|
*
|
|
370
418
|
*/
|
|
371
419
|
async sqlExec(sql:string): Promise<OINODbDataSet> {
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
try {
|
|
375
|
-
result = await this._exec(sql)
|
|
376
|
-
|
|
377
|
-
} catch (e:any) {
|
|
378
|
-
OINOLog.exception("@oino-ts/db-mssql", "OINODbMsSql", "sqlExec", "exception in SQL exec", {message:e.message, stack:e.stack})
|
|
379
|
-
result = new OINOMsSqlData(OINODB_EMPTY_ROWS, [OINO_ERROR_PREFIX + " (sqlExec): exception in _db.exec [" + e.message + "]"])
|
|
420
|
+
if (!this.isValidated) {
|
|
421
|
+
throw new Error(OINO_ERROR_PREFIX + ": Database connection not validated!")
|
|
380
422
|
}
|
|
423
|
+
OINOBenchmark.startMetric("OINODb", "sqlExec")
|
|
424
|
+
let result:OINODbDataSet = await this._exec(sql)
|
|
381
425
|
OINOBenchmark.endMetric("OINODb", "sqlExec")
|
|
382
426
|
return result
|
|
383
427
|
}
|