@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.
@@ -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 MariaDb.
13
+ * Implmentation of OINODbDataSet for MsSql.
13
14
  *
14
15
  */
15
16
  class OINOMsSqlData extends db_1.OINODbDataSet {
16
- _recordsets = [db_1.OINODB_EMPTY_ROWS];
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(db_1.OINO_INFO_PREFIX + "SQL result is empty");
29
+ this.messages.push(common_1.OINO_INFO_PREFIX + "SQL result is empty");
29
30
  }
30
- else if (!(Array.isArray(data) && (data.length > 0) && Array.isArray(data[0]))) {
31
- throw new Error(db_1.OINO_ERROR_PREFIX + ": OINOMsSqlData constructor: invalid data!");
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 MariaDb/MySql-database.
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(db_1.OINO_ERROR_PREFIX + ": Not OINODbMsSql-type: " + this._params.type);
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
- db_1.OINOLog.error("@oino-ts/db-mssql", "OINODbMsSql", "constructor", "OINODbMsSql error event", conn);
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
- const request = this._pool.request(); // this does not need to be released but the pool will handle it
136
- const sql_res = await request.query(sql);
137
- const result = new OINOMsSqlData(sql_res.recordsets);
138
- return result;
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
- const sql_res = await this._pool.request().query(sql);
142
- return new OINOMsSqlData(db_1.OINODB_EMPTY_ROWS);
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
- db_1.OINOLog.error("@oino-ts/db-mssql", "OINODbMsSql", "printSqlSelect", "LIMIT without ORDER BY is not supported in MS SQL Server");
262
- throw new Error(db_1.OINO_ERROR_PREFIX + ": LIMIT without ORDER BY is not supported in MS SQL Server");
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
- db_1.OINOLog.debug("@oino-ts/db-mssql", "OINODbMsSql", "printSqlSelect", "Result", { sql: result });
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 db_1.OINOResult();
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
- db_1.OINOLog.exception("@oino-ts/db-mssql", "OINODbMsSql", "connect", "exception in connect", { message: e.message, stack: e.stack });
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 db_1.OINOResult();
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
- db_1.OINOBenchmark.startMetric("OINODb", "validate");
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.sqlSelect(sql);
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
- db_1.OINOLog.exception("@oino-ts/db-mssql", "OINODbMsSql", "validate", "exception in validate", { message: e.message, stack: e.stack });
355
+ common_1.OINOLog.exception("@oino-ts/db-mssql", "OINODbMsSql", "validate", "exception in validate", { message: e.message, stack: e.stack });
321
356
  }
322
- db_1.OINOBenchmark.endMetric("OINODb", "validate");
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
- db_1.OINOBenchmark.startMetric("OINODb", "sqlSelect");
333
- let result;
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
- db_1.OINOBenchmark.endMetric("OINODb", "sqlSelect");
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
- db_1.OINOBenchmark.startMetric("OINODb", "sqlExec");
352
- let result;
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
- db_1.OINOBenchmark.endMetric("OINODb", "sqlExec");
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
- db_1.OINOLog.info("@oino-ts/db-mssql", "OINODbMsSql", "initializeApiDatamodel", "Field excluded in API parameters.", { field: field_name });
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(db_1.OINO_ERROR_PREFIX + "Primary key field excluded in API parameters: " + field_name);
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
- db_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 });
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
- db_1.OINOLog.info("@oino-ts/db-mssql", "OINODbMsSql", "initializeApiDatamodel", "\n" + api.datamodel.printDebug("\n"));
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
  }
@@ -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 { OINODb, OINODbDataSet, OINOBooleanDataField, OINONumberDataField, OINOStringDataField, OINO_ERROR_PREFIX, OINOBenchmark, OINODatetimeDataField, OINOBlobDataField, OINO_INFO_PREFIX, OINODB_EMPTY_ROW, OINODB_EMPTY_ROWS, OINOLog, OINOResult } from "@oino-ts/db";
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 MariaDb.
10
+ * Implmentation of OINODbDataSet for MsSql.
10
11
  *
11
12
  */
12
13
  class OINOMsSqlData extends OINODbDataSet {
13
- _recordsets = [OINODB_EMPTY_ROWS];
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) && Array.isArray(data[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 MariaDb/MySql-database.
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
- const request = this._pool.request(); // this does not need to be released but the pool will handle it
133
- const sql_res = await request.query(sql);
134
- const result = new OINOMsSqlData(sql_res.recordsets);
135
- return result;
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
- const sql_res = await this._pool.request().query(sql);
139
- return new OINOMsSqlData(OINODB_EMPTY_ROWS);
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.sqlSelect(sql);
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
- OINOBenchmark.startMetric("OINODb", "sqlSelect");
330
- let result;
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
- OINOBenchmark.startMetric("OINODb", "sqlExec");
349
- let result;
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 { OINODb, OINODbParams, OINODbDataSet, OINODbApi, OINODataCell, OINOResult } from "@oino-ts/db";
1
+ import { OINOResult } from "@oino-ts/common";
2
+ import { OINODb, OINODbParams, OINODbDataSet, OINODbApi, OINODataCell } from "@oino-ts/db";
2
3
  /**
3
- * Implementation of MariaDb/MySql-database.
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.18.1",
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.18.1",
25
+ "@oino-ts/db": "0.20.0",
26
26
  "mssql": "^11.0.1"
27
27
  },
28
28
  "devDependencies": {
@@ -4,16 +4,17 @@
4
4
  * file, You can obtain one at https://mozilla.org/MPL/2.0/.
5
5
  */
6
6
 
7
- import { OINODb, OINODbParams, OINODbDataSet, OINODbApi, OINOBooleanDataField, OINONumberDataField, OINOStringDataField, OINODbDataFieldParams, OINO_ERROR_PREFIX, OINODataRow, OINODataCell, OINOBenchmark, OINODatetimeDataField, OINOBlobDataField, OINO_INFO_PREFIX, OINODB_EMPTY_ROW, OINODB_EMPTY_ROWS, OINOLog, OINOResult } from "@oino-ts/db";
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 MariaDb.
13
+ * Implmentation of OINODbDataSet for MsSql.
13
14
  *
14
15
  */
15
16
  class OINOMsSqlData extends OINODbDataSet {
16
- private _recordsets:OINODataRow[][] = [OINODB_EMPTY_ROWS]
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>0) && Array.isArray(data[0]))) {
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 as OINODataRow[][]
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 MariaDb/MySql-database.
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
- const request = this._pool.request() // this does not need to be released but the pool will handle it
148
- const sql_res = await request.query(sql)
149
- const result:OINOMsSqlData = new OINOMsSqlData(sql_res.recordsets)
150
- return result
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
- const sql_res = await this._pool.request().query(sql);
155
- return new OINOMsSqlData(OINODB_EMPTY_ROWS)
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.sqlSelect(sql)
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
- OINOBenchmark.startMetric("OINODb", "sqlSelect")
353
- let result:OINODbDataSet
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
- OINOBenchmark.startMetric("OINODb", "sqlExec")
373
- let result:OINODbDataSet
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
  }