@oino-ts/db 0.19.0 → 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.
@@ -55,6 +55,23 @@ class OINODb {
55
55
  result += ";";
56
56
  return result;
57
57
  }
58
+ /**
59
+ * Print SQL select statement with DB specific formatting.
60
+ *
61
+ * @param tableName - The name of the table to select from.
62
+ * @param columns - The columns to be selected.
63
+ * @param values - The values to be inserted.
64
+ * @param returnIdFields - the id fields to return if returnIds is true (if supported by the database)
65
+ *
66
+ */
67
+ printSqlInsert(tableName, columns, values, returnIdFields) {
68
+ let result = "INSERT INTO " + tableName + " (" + columns + ") VALUES (" + values + ")";
69
+ if (returnIdFields) {
70
+ result += " RETURNING " + returnIdFields.join(",");
71
+ }
72
+ result += ";";
73
+ return result;
74
+ }
58
75
  }
59
76
  exports.OINODb = OINODb;
60
77
  /**
@@ -65,7 +82,7 @@ exports.OINODb = OINODb;
65
82
  * `OINODbDataSet` will serve it out consistently.
66
83
  *
67
84
  */
68
- class OINODbDataSet {
85
+ class OINODbDataSet extends common_1.OINOResult {
69
86
  _data;
70
87
  /** Error messages */
71
88
  messages;
@@ -77,6 +94,7 @@ class OINODbDataSet {
77
94
  *
78
95
  */
79
96
  constructor(data, messages = []) {
97
+ super();
80
98
  this._data = data;
81
99
  this.messages = messages;
82
100
  }
@@ -17,7 +17,7 @@ class OINODbApiRequest extends common_1.OINOHttpRequest {
17
17
  constructor(init) {
18
18
  super(init);
19
19
  this.rowId = init?.rowId || "";
20
- this.rowData = init?.rowData || null;
20
+ this.rowData = init?.rowData || null; // rowData is not compatible with OINOHttpRequest body so it's not automatically set, caller can set both if needed
21
21
  this.sqlParams = init?.sqlParams || {};
22
22
  if (init?.filter) {
23
23
  if (init.filter instanceof index_js_1.OINODbSqlFilter) {
@@ -348,8 +348,8 @@ class OINODbApi {
348
348
  sql = this.datamodel.printSqlSelect(rowId, request.sqlParams || {});
349
349
  common_1.OINOLog.debug("@oino-ts/db", "OINODbApi", "_doGet", "Print SQL", { sql: sql });
350
350
  const sql_res = await this.db.sqlSelect(sql);
351
- if (sql_res.hasErrors()) {
352
- result.setError(500, sql_res.getFirstError(), "DoGet");
351
+ if (sql_res.success == false) {
352
+ result.setError(500, sql_res.statusText, "DoGet");
353
353
  if (this._debugOnError) {
354
354
  result.addDebug("OINO GET SQL [" + sql + "]", "DoPut");
355
355
  }
@@ -366,7 +366,7 @@ class OINODbApi {
366
366
  }
367
367
  }
368
368
  }
369
- async _doPost(result, rows) {
369
+ async _doPost(result, rows, request) {
370
370
  let sql = "";
371
371
  try {
372
372
  for (let i = 0; i < rows.length; i++) {
@@ -384,13 +384,16 @@ class OINODbApi {
384
384
  else if (result.success) {
385
385
  common_1.OINOLog.debug("@oino-ts/db", "OINODbApi", "_doPost", "Print SQL", { sql: sql });
386
386
  const sql_res = await this.db.sqlExec(sql);
387
- if (sql_res.hasErrors()) {
388
- result.setError(500, sql_res.getFirstError(), "DoPost");
387
+ if (sql_res.success == false) {
388
+ result.setError(500, sql_res.statusText, "DoPost");
389
389
  if (this._debugOnError) {
390
- result.addDebug("OINO POST MESSAGES [" + sql_res.messages.join('|') + "]", "DoPost");
390
+ result.addDebug("OINO POST MESSAGES [" + sql_res.statusText + "]", "DoPost");
391
391
  result.addDebug("OINO POST SQL [" + sql + "]", "DoPost");
392
392
  }
393
393
  }
394
+ else if (this.params.returnInsertedIds) {
395
+ result.data = new index_js_1.OINODbModelSet(this.datamodel, sql_res, request.sqlParams); // return the inserted ids as data
396
+ }
394
397
  }
395
398
  }
396
399
  catch (e) {
@@ -421,10 +424,10 @@ class OINODbApi {
421
424
  else if (result.success) {
422
425
  common_1.OINOLog.debug("@oino-ts/db", "OINODbApi", "_doPut", "Print SQL", { sql: sql });
423
426
  const sql_res = await this.db.sqlExec(sql);
424
- if (sql_res.hasErrors()) {
425
- result.setError(500, sql_res.getFirstError(), "DoPut");
427
+ if (sql_res.success == false) {
428
+ result.setError(500, sql_res.statusText, "DoPut");
426
429
  if (this._debugOnError) {
427
- result.addDebug("OINO PUT MESSAGES [" + sql_res.messages.join('|') + "]", "DoPut");
430
+ result.addDebug("OINO PUT MESSAGES [" + sql_res.statusText + "]", "DoPut");
428
431
  result.addDebug("OINO PUT SQL [" + sql + "]", "DoPut");
429
432
  }
430
433
  }
@@ -434,7 +437,7 @@ class OINODbApi {
434
437
  result.setError(500, "Unhandled exception: " + e.message, "DoPut");
435
438
  common_1.OINOLog.exception("@oino-ts/db", "OINODbApi", "_doPut", "exception in put request", { message: e.message, stack: e.stack });
436
439
  if (this._debugOnError) {
437
- result.addDebug("OINO POST SQL [" + sql + "]", "DoPut");
440
+ result.addDebug("OINO PUT SQL [" + sql + "]", "DoPut");
438
441
  }
439
442
  }
440
443
  }
@@ -461,10 +464,10 @@ class OINODbApi {
461
464
  else if (result.success) {
462
465
  common_1.OINOLog.debug("@oino-ts/db", "OINODbApi", "_doDelete", "Print SQL", { sql: sql });
463
466
  const sql_res = await this.db.sqlExec(sql);
464
- if (sql_res.hasErrors()) {
465
- result.setError(500, sql_res.getFirstError(), "DoDelete");
467
+ if (sql_res.success == false) {
468
+ result.setError(500, sql_res.statusText, "DoDelete");
466
469
  if (this._debugOnError) {
467
- result.addDebug("OINO DELETE MESSAGES [" + sql_res.messages.join('|') + "]", "DoDelete");
470
+ result.addDebug("OINO DELETE MESSAGES [" + sql_res.statusText + "]", "DoDelete");
468
471
  result.addDebug("OINO DELETE SQL [" + sql + "]", "DoDelete");
469
472
  }
470
473
  }
@@ -550,7 +553,7 @@ class OINODbApi {
550
553
  }
551
554
  else {
552
555
  try {
553
- await this._doPost(result, rows);
556
+ await this._doPost(result, rows, request);
554
557
  }
555
558
  catch (e) {
556
559
  result.setError(500, "Unhandled exception in HTTP POST doRequest: " + e.message, "DoRequest");
@@ -67,7 +67,7 @@ class OINODbDataModel {
67
67
  }
68
68
  }
69
69
  // console.log("_printSqlInsertColumnsAndValues: columns=" + columns + ", values=" + values)
70
- return "(" + columns + ") VALUES (" + values + ")";
70
+ return [columns, values];
71
71
  }
72
72
  _printSqlUpdateValues(row) {
73
73
  let result = "";
@@ -109,6 +109,15 @@ class OINODbDataModel {
109
109
  }
110
110
  return "(" + result + ")";
111
111
  }
112
+ _printSqlPrimaryKeyColumns() {
113
+ let result = [];
114
+ for (let f of this.fields) {
115
+ if (f.fieldParams.isPrimaryKey) {
116
+ result.push(this.api.db.printSqlColumnname(f.name));
117
+ }
118
+ }
119
+ return result;
120
+ }
112
121
  /**
113
122
  * Add a field to the datamodel.
114
123
  *
@@ -255,8 +264,10 @@ class OINODbDataModel {
255
264
  *
256
265
  */
257
266
  printSqlInsert(row) {
258
- let result = "INSERT INTO " + this.api.db.printSqlTablename(this.api.params.tableName) + " " + this._printSqlInsertColumnsAndValues(row) + ";";
259
- return result;
267
+ const table_name = this.api.db.printSqlTablename(this.api.params.tableName);
268
+ const [columns, values] = this._printSqlInsertColumnsAndValues(row);
269
+ const return_fields = this.api.params.returnInsertedIds ? this._printSqlPrimaryKeyColumns() : undefined;
270
+ return this.api.db.printSqlInsert(table_name, columns, values, return_fields);
260
271
  }
261
272
  /**
262
273
  * Print SQL insert statement from one data row.
package/dist/cjs/index.js CHANGED
@@ -42,6 +42,6 @@ Object.defineProperty(exports, "OINODbParser", { enumerable: true, get: function
42
42
  /** Empty row instance */
43
43
  exports.OINODB_EMPTY_ROW = [];
44
44
  /** Empty row array instance */
45
- exports.OINODB_EMPTY_ROWS = [exports.OINODB_EMPTY_ROW];
45
+ exports.OINODB_EMPTY_ROWS = [];
46
46
  /** Constant for undefined values */
47
47
  exports.OINODB_UNDEFINED = ""; // original idea was to have a defined literal that get's swapped back to undefined, but current implementation just leaves it out at serialization (so value does not matter)
@@ -3,7 +3,7 @@
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 { OINO_ERROR_PREFIX } from "@oino-ts/common";
6
+ import { OINO_ERROR_PREFIX, OINOResult } from "@oino-ts/common";
7
7
  import { OINODB_EMPTY_ROW } from "./index.js";
8
8
  /**
9
9
  * Base class for database abstraction, implementing methods for connecting, making queries and parsing/formatting data
@@ -52,6 +52,23 @@ export class OINODb {
52
52
  result += ";";
53
53
  return result;
54
54
  }
55
+ /**
56
+ * Print SQL select statement with DB specific formatting.
57
+ *
58
+ * @param tableName - The name of the table to select from.
59
+ * @param columns - The columns to be selected.
60
+ * @param values - The values to be inserted.
61
+ * @param returnIdFields - the id fields to return if returnIds is true (if supported by the database)
62
+ *
63
+ */
64
+ printSqlInsert(tableName, columns, values, returnIdFields) {
65
+ let result = "INSERT INTO " + tableName + " (" + columns + ") VALUES (" + values + ")";
66
+ if (returnIdFields) {
67
+ result += " RETURNING " + returnIdFields.join(",");
68
+ }
69
+ result += ";";
70
+ return result;
71
+ }
55
72
  }
56
73
  /**
57
74
  * Base class for SQL results that can be asynchronously iterated (but
@@ -61,7 +78,7 @@ export class OINODb {
61
78
  * `OINODbDataSet` will serve it out consistently.
62
79
  *
63
80
  */
64
- export class OINODbDataSet {
81
+ export class OINODbDataSet extends OINOResult {
65
82
  _data;
66
83
  /** Error messages */
67
84
  messages;
@@ -73,6 +90,7 @@ export class OINODbDataSet {
73
90
  *
74
91
  */
75
92
  constructor(data, messages = []) {
93
+ super();
76
94
  this._data = data;
77
95
  this.messages = messages;
78
96
  }
@@ -14,7 +14,7 @@ export class OINODbApiRequest extends OINOHttpRequest {
14
14
  constructor(init) {
15
15
  super(init);
16
16
  this.rowId = init?.rowId || "";
17
- this.rowData = init?.rowData || null;
17
+ this.rowData = init?.rowData || null; // rowData is not compatible with OINOHttpRequest body so it's not automatically set, caller can set both if needed
18
18
  this.sqlParams = init?.sqlParams || {};
19
19
  if (init?.filter) {
20
20
  if (init.filter instanceof OINODbSqlFilter) {
@@ -342,8 +342,8 @@ export class OINODbApi {
342
342
  sql = this.datamodel.printSqlSelect(rowId, request.sqlParams || {});
343
343
  OINOLog.debug("@oino-ts/db", "OINODbApi", "_doGet", "Print SQL", { sql: sql });
344
344
  const sql_res = await this.db.sqlSelect(sql);
345
- if (sql_res.hasErrors()) {
346
- result.setError(500, sql_res.getFirstError(), "DoGet");
345
+ if (sql_res.success == false) {
346
+ result.setError(500, sql_res.statusText, "DoGet");
347
347
  if (this._debugOnError) {
348
348
  result.addDebug("OINO GET SQL [" + sql + "]", "DoPut");
349
349
  }
@@ -360,7 +360,7 @@ export class OINODbApi {
360
360
  }
361
361
  }
362
362
  }
363
- async _doPost(result, rows) {
363
+ async _doPost(result, rows, request) {
364
364
  let sql = "";
365
365
  try {
366
366
  for (let i = 0; i < rows.length; i++) {
@@ -378,13 +378,16 @@ export class OINODbApi {
378
378
  else if (result.success) {
379
379
  OINOLog.debug("@oino-ts/db", "OINODbApi", "_doPost", "Print SQL", { sql: sql });
380
380
  const sql_res = await this.db.sqlExec(sql);
381
- if (sql_res.hasErrors()) {
382
- result.setError(500, sql_res.getFirstError(), "DoPost");
381
+ if (sql_res.success == false) {
382
+ result.setError(500, sql_res.statusText, "DoPost");
383
383
  if (this._debugOnError) {
384
- result.addDebug("OINO POST MESSAGES [" + sql_res.messages.join('|') + "]", "DoPost");
384
+ result.addDebug("OINO POST MESSAGES [" + sql_res.statusText + "]", "DoPost");
385
385
  result.addDebug("OINO POST SQL [" + sql + "]", "DoPost");
386
386
  }
387
387
  }
388
+ else if (this.params.returnInsertedIds) {
389
+ result.data = new OINODbModelSet(this.datamodel, sql_res, request.sqlParams); // return the inserted ids as data
390
+ }
388
391
  }
389
392
  }
390
393
  catch (e) {
@@ -415,10 +418,10 @@ export class OINODbApi {
415
418
  else if (result.success) {
416
419
  OINOLog.debug("@oino-ts/db", "OINODbApi", "_doPut", "Print SQL", { sql: sql });
417
420
  const sql_res = await this.db.sqlExec(sql);
418
- if (sql_res.hasErrors()) {
419
- result.setError(500, sql_res.getFirstError(), "DoPut");
421
+ if (sql_res.success == false) {
422
+ result.setError(500, sql_res.statusText, "DoPut");
420
423
  if (this._debugOnError) {
421
- result.addDebug("OINO PUT MESSAGES [" + sql_res.messages.join('|') + "]", "DoPut");
424
+ result.addDebug("OINO PUT MESSAGES [" + sql_res.statusText + "]", "DoPut");
422
425
  result.addDebug("OINO PUT SQL [" + sql + "]", "DoPut");
423
426
  }
424
427
  }
@@ -428,7 +431,7 @@ export class OINODbApi {
428
431
  result.setError(500, "Unhandled exception: " + e.message, "DoPut");
429
432
  OINOLog.exception("@oino-ts/db", "OINODbApi", "_doPut", "exception in put request", { message: e.message, stack: e.stack });
430
433
  if (this._debugOnError) {
431
- result.addDebug("OINO POST SQL [" + sql + "]", "DoPut");
434
+ result.addDebug("OINO PUT SQL [" + sql + "]", "DoPut");
432
435
  }
433
436
  }
434
437
  }
@@ -455,10 +458,10 @@ export class OINODbApi {
455
458
  else if (result.success) {
456
459
  OINOLog.debug("@oino-ts/db", "OINODbApi", "_doDelete", "Print SQL", { sql: sql });
457
460
  const sql_res = await this.db.sqlExec(sql);
458
- if (sql_res.hasErrors()) {
459
- result.setError(500, sql_res.getFirstError(), "DoDelete");
461
+ if (sql_res.success == false) {
462
+ result.setError(500, sql_res.statusText, "DoDelete");
460
463
  if (this._debugOnError) {
461
- result.addDebug("OINO DELETE MESSAGES [" + sql_res.messages.join('|') + "]", "DoDelete");
464
+ result.addDebug("OINO DELETE MESSAGES [" + sql_res.statusText + "]", "DoDelete");
462
465
  result.addDebug("OINO DELETE SQL [" + sql + "]", "DoDelete");
463
466
  }
464
467
  }
@@ -544,7 +547,7 @@ export class OINODbApi {
544
547
  }
545
548
  else {
546
549
  try {
547
- await this._doPost(result, rows);
550
+ await this._doPost(result, rows, request);
548
551
  }
549
552
  catch (e) {
550
553
  result.setError(500, "Unhandled exception in HTTP POST doRequest: " + e.message, "DoRequest");
@@ -64,7 +64,7 @@ export class OINODbDataModel {
64
64
  }
65
65
  }
66
66
  // console.log("_printSqlInsertColumnsAndValues: columns=" + columns + ", values=" + values)
67
- return "(" + columns + ") VALUES (" + values + ")";
67
+ return [columns, values];
68
68
  }
69
69
  _printSqlUpdateValues(row) {
70
70
  let result = "";
@@ -106,6 +106,15 @@ export class OINODbDataModel {
106
106
  }
107
107
  return "(" + result + ")";
108
108
  }
109
+ _printSqlPrimaryKeyColumns() {
110
+ let result = [];
111
+ for (let f of this.fields) {
112
+ if (f.fieldParams.isPrimaryKey) {
113
+ result.push(this.api.db.printSqlColumnname(f.name));
114
+ }
115
+ }
116
+ return result;
117
+ }
109
118
  /**
110
119
  * Add a field to the datamodel.
111
120
  *
@@ -252,8 +261,10 @@ export class OINODbDataModel {
252
261
  *
253
262
  */
254
263
  printSqlInsert(row) {
255
- let result = "INSERT INTO " + this.api.db.printSqlTablename(this.api.params.tableName) + " " + this._printSqlInsertColumnsAndValues(row) + ";";
256
- return result;
264
+ const table_name = this.api.db.printSqlTablename(this.api.params.tableName);
265
+ const [columns, values] = this._printSqlInsertColumnsAndValues(row);
266
+ const return_fields = this.api.params.returnInsertedIds ? this._printSqlPrimaryKeyColumns() : undefined;
267
+ return this.api.db.printSqlInsert(table_name, columns, values, return_fields);
257
268
  }
258
269
  /**
259
270
  * Print SQL insert statement from one data row.
package/dist/esm/index.js CHANGED
@@ -11,6 +11,6 @@ export { OINODbParser } from "./OINODbParser.js";
11
11
  /** Empty row instance */
12
12
  export const OINODB_EMPTY_ROW = [];
13
13
  /** Empty row array instance */
14
- export const OINODB_EMPTY_ROWS = [OINODB_EMPTY_ROW];
14
+ export const OINODB_EMPTY_ROWS = [];
15
15
  /** Constant for undefined values */
16
16
  export const OINODB_UNDEFINED = ""; // original idea was to have a defined literal that get's swapped back to undefined, but current implementation just leaves it out at serialization (so value does not matter)
@@ -26,6 +26,11 @@ export declare abstract class OINODb {
26
26
  *
27
27
  */
28
28
  abstract validate(): Promise<OINOResult>;
29
+ /**
30
+ * Disconnect from database.
31
+ *
32
+ */
33
+ abstract disconnect(): Promise<void>;
29
34
  /**
30
35
  * Print a table name using database specific SQL escaping.
31
36
  *
@@ -99,6 +104,16 @@ export declare abstract class OINODb {
99
104
  *
100
105
  */
101
106
  printSqlSelect(tableName: string, columnNames: string, whereCondition: string, orderCondition: string, limitCondition: string, groupByCondition: string): string;
107
+ /**
108
+ * Print SQL select statement with DB specific formatting.
109
+ *
110
+ * @param tableName - The name of the table to select from.
111
+ * @param columns - The columns to be selected.
112
+ * @param values - The values to be inserted.
113
+ * @param returnIdFields - the id fields to return if returnIds is true (if supported by the database)
114
+ *
115
+ */
116
+ printSqlInsert(tableName: string, columns: string, values: string, returnIdFields?: string[]): string;
102
117
  }
103
118
  /**
104
119
  * Base class for SQL results that can be asynchronously iterated (but
@@ -108,7 +123,7 @@ export declare abstract class OINODb {
108
123
  * `OINODbDataSet` will serve it out consistently.
109
124
  *
110
125
  */
111
- export declare abstract class OINODbDataSet {
126
+ export declare abstract class OINODbDataSet extends OINOResult {
112
127
  private _data;
113
128
  /** Error messages */
114
129
  readonly messages: string[];
@@ -26,6 +26,7 @@ export declare class OINODbDataModel {
26
26
  private _printSqlInsertColumnsAndValues;
27
27
  private _printSqlUpdateValues;
28
28
  private _printSqlPrimaryKeyCondition;
29
+ private _printSqlPrimaryKeyColumns;
29
30
  /**
30
31
  * Add a field to the datamodel.
31
32
  *
@@ -44,6 +44,8 @@ export type OINODbApiParams = {
44
44
  hashidStaticIds?: boolean;
45
45
  /** Name of field that has the modified field */
46
46
  cacheModifiedField?: string;
47
+ /** Return inserted id values */
48
+ returnInsertedIds?: boolean;
47
49
  };
48
50
  /**
49
51
  * Database class (constructor) type
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@oino-ts/db",
3
- "version": "0.19.0",
3
+ "version": "0.20.0",
4
4
  "description": "OINO TS library package for publishing an SQL database tables as a REST API.",
5
5
  "author": "Matias Kiviniemi (pragmatta)",
6
6
  "license": "MPL-2.0",
@@ -19,13 +19,13 @@
19
19
  "module": "./dist/esm/index.js",
20
20
  "types": "./dist/types/index.d.ts",
21
21
  "dependencies": {
22
- "@oino-ts/common": "0.19.0",
22
+ "@oino-ts/common": "0.20.0",
23
23
  "oino-ts": "file:.."
24
24
  },
25
25
  "devDependencies": {
26
- "@oino-ts/types": "0.19.0",
26
+ "@oino-ts/types": "0.20.0",
27
27
  "@types/bun": "^1.1.14",
28
- "@types/node": "^20.19.00",
28
+ "@types/node": "^20.20.00",
29
29
  "typescript": "~5.9.0"
30
30
  },
31
31
  "files": [
package/src/OINODb.ts CHANGED
@@ -43,6 +43,12 @@ export abstract class OINODb {
43
43
  */
44
44
  abstract validate(): Promise<OINOResult>
45
45
 
46
+ /**
47
+ * Disconnect from database.
48
+ *
49
+ */
50
+ abstract disconnect(): Promise<void>
51
+
46
52
  /**
47
53
  * Print a table name using database specific SQL escaping.
48
54
  *
@@ -140,6 +146,25 @@ export abstract class OINODb {
140
146
  result += ";"
141
147
  return result;
142
148
  }
149
+
150
+ /**
151
+ * Print SQL select statement with DB specific formatting.
152
+ *
153
+ * @param tableName - The name of the table to select from.
154
+ * @param columns - The columns to be selected.
155
+ * @param values - The values to be inserted.
156
+ * @param returnIdFields - the id fields to return if returnIds is true (if supported by the database)
157
+ *
158
+ */
159
+ printSqlInsert(tableName:string, columns:string, values:string, returnIdFields?:string[]): string {
160
+ let result = "INSERT INTO " + tableName + " (" + columns + ") VALUES (" + values + ")"
161
+ if (returnIdFields) {
162
+ result += " RETURNING " + returnIdFields.join(",")
163
+ }
164
+ result += ";"
165
+ return result;
166
+ }
167
+
143
168
  }
144
169
 
145
170
  /**
@@ -151,7 +176,7 @@ export abstract class OINODb {
151
176
  *
152
177
  */
153
178
 
154
- export abstract class OINODbDataSet {
179
+ export abstract class OINODbDataSet extends OINOResult {
155
180
  private _data: unknown;
156
181
 
157
182
  /** Error messages */
@@ -165,6 +190,7 @@ export abstract class OINODbDataSet {
165
190
  *
166
191
  */
167
192
  constructor(data: unknown, messages: string[] = []) {
193
+ super();
168
194
  this._data = data;
169
195
  this.messages = messages;
170
196
  }
@@ -65,7 +65,7 @@ const API_TESTS:OINOTestParams[] = [
65
65
  },
66
66
  {
67
67
  name: "API 3",
68
- apiParams: { apiName: "Employees", tableName: "Employees", hashidKey: "12345678901234567890123456789012", hashidStaticIds:true },
68
+ apiParams: { apiName: "Employees", tableName: "Employees", hashidKey: "12345678901234567890123456789012", hashidStaticIds:true, returnInsertedIds:true },
69
69
  sqlParams: { filter: OINODbSqlFilter.parse("(TitleOfCourtesy)-eq(Ms.)"), order: OINODbSqlOrder.parse("LastName asc"), limit: OINODbSqlLimit.parse("5") },
70
70
  postRow: [99, "LastName", "FirstName", "Title", "TitleOfCourtesy", new Date("2024-04-06"), new Date("2024-04-07"), "Address", "City", "Region", 12345, "EU", "123 456 7890", "9876", Buffer.from("0001020304", "hex"), "Line1\nLine2", 1, "http://accweb/emmployees/lastnamefirstname.bmp"],
71
71
  putRow: [99, "LastName2", "FirstName2", null, "TitleOfCourtesy2", new Date("2023-04-06"), new Date("2023-04-07"), "Address2", "City2", "Region2", 54321, "EU2", "234 567 8901", "8765", Buffer.from("0506070809", "hex"), "Line3\nLine4", 1, "http://accweb/emmployees/lastnamefirstname.bmp"],
@@ -260,7 +260,12 @@ export async function OINOTestApi(dbParams:OINODbParams, testParams: OINOTestPar
260
260
  expect(encodeResult((await api.doApiRequest(post_request_with_id)))).toMatchSnapshot("POST")
261
261
  })
262
262
  await test(target_name + target_db + target_table + target_group + " insert", async () => {
263
- expect(encodeResult((await api.doApiRequest(post_request)))).toMatchSnapshot("POST")
263
+ const post_res = await api.doApiRequest(post_request)
264
+ if (testParams.apiParams.returnInsertedIds) {
265
+ expect(encodeData(await post_res.data?.writeString())).toMatchSnapshot("POST RETURN ID")
266
+ } else {
267
+ expect(encodeResult(post_res)).toMatchSnapshot("POST")
268
+ }
264
269
  expect(encodeData(await (await api.doApiRequest(get_request_with_rowid)).data?.writeString())).toMatchSnapshot("GET JSON")
265
270
  expect(encodeData(await (await api.doApiRequest(get_request_with_rowid)).data?.writeString(OINOContentType.csv))).toMatchSnapshot("GET CSV")
266
271
  })
package/src/OINODbApi.ts CHANGED
@@ -30,7 +30,7 @@ export class OINODbApiRequest extends OINOHttpRequest {
30
30
  constructor (init: OINODbApiRequestInit) {
31
31
  super(init)
32
32
  this.rowId = init?.rowId || ""
33
- this.rowData = init?.rowData || null
33
+ this.rowData = init?.rowData || null // rowData is not compatible with OINOHttpRequest body so it's not automatically set, caller can set both if needed
34
34
  this.sqlParams = init?.sqlParams || {}
35
35
 
36
36
  if (init?.filter) {
@@ -369,8 +369,8 @@ export class OINODbApi {
369
369
  sql = this.datamodel.printSqlSelect(rowId, request.sqlParams || {})
370
370
  OINOLog.debug("@oino-ts/db", "OINODbApi", "_doGet", "Print SQL", {sql:sql})
371
371
  const sql_res:OINODbDataSet = await this.db.sqlSelect(sql)
372
- if (sql_res.hasErrors()) {
373
- result.setError(500, sql_res.getFirstError(), "DoGet")
372
+ if (sql_res.success == false) {
373
+ result.setError(500, sql_res.statusText, "DoGet")
374
374
  if (this._debugOnError) {
375
375
  result.addDebug("OINO GET SQL [" + sql + "]", "DoPut")
376
376
  }
@@ -386,7 +386,7 @@ export class OINODbApi {
386
386
  }
387
387
  }
388
388
 
389
- private async _doPost(result:OINODbApiResult, rows:OINODataRow[]):Promise<void> {
389
+ private async _doPost(result:OINODbApiResult, rows:OINODataRow[], request:OINODbApiRequest):Promise<void> {
390
390
  let sql:string = ""
391
391
  try {
392
392
  for (let i=0; i<rows.length; i++) {
@@ -404,12 +404,14 @@ export class OINODbApi {
404
404
  } else if (result.success) {
405
405
  OINOLog.debug("@oino-ts/db", "OINODbApi", "_doPost", "Print SQL", {sql:sql})
406
406
  const sql_res:OINODbDataSet = await this.db.sqlExec(sql)
407
- if (sql_res.hasErrors()) {
408
- result.setError(500, sql_res.getFirstError(), "DoPost")
407
+ if (sql_res.success == false) {
408
+ result.setError(500, sql_res.statusText, "DoPost")
409
409
  if (this._debugOnError) {
410
- result.addDebug("OINO POST MESSAGES [" + sql_res.messages.join('|') + "]", "DoPost")
410
+ result.addDebug("OINO POST MESSAGES [" + sql_res.statusText + "]", "DoPost")
411
411
  result.addDebug("OINO POST SQL [" + sql + "]", "DoPost")
412
412
  }
413
+ } else if (this.params.returnInsertedIds) {
414
+ result.data = new OINODbModelSet(this.datamodel, sql_res, request.sqlParams) // return the inserted ids as data
413
415
  }
414
416
  }
415
417
  } catch (e:any) {
@@ -441,10 +443,10 @@ export class OINODbApi {
441
443
  } else if (result.success) {
442
444
  OINOLog.debug("@oino-ts/db", "OINODbApi", "_doPut", "Print SQL", {sql:sql})
443
445
  const sql_res:OINODbDataSet = await this.db.sqlExec(sql)
444
- if (sql_res.hasErrors()) {
445
- result.setError(500, sql_res.getFirstError(), "DoPut")
446
+ if (sql_res.success == false) {
447
+ result.setError(500, sql_res.statusText, "DoPut")
446
448
  if (this._debugOnError) {
447
- result.addDebug("OINO PUT MESSAGES [" + sql_res.messages.join('|') + "]", "DoPut")
449
+ result.addDebug("OINO PUT MESSAGES [" + sql_res.statusText + "]", "DoPut")
448
450
  result.addDebug("OINO PUT SQL [" + sql + "]", "DoPut")
449
451
  }
450
452
  }
@@ -453,7 +455,7 @@ export class OINODbApi {
453
455
  result.setError(500, "Unhandled exception: " + e.message, "DoPut")
454
456
  OINOLog.exception("@oino-ts/db", "OINODbApi", "_doPut", "exception in put request", {message:e.message, stack:e.stack})
455
457
  if (this._debugOnError) {
456
- result.addDebug("OINO POST SQL [" + sql + "]", "DoPut")
458
+ result.addDebug("OINO PUT SQL [" + sql + "]", "DoPut")
457
459
  }
458
460
  }
459
461
  }
@@ -480,10 +482,10 @@ export class OINODbApi {
480
482
 
481
483
  OINOLog.debug("@oino-ts/db", "OINODbApi", "_doDelete", "Print SQL", {sql:sql})
482
484
  const sql_res:OINODbDataSet = await this.db.sqlExec(sql)
483
- if (sql_res.hasErrors()) {
484
- result.setError(500, sql_res.getFirstError(), "DoDelete")
485
+ if (sql_res.success == false) {
486
+ result.setError(500, sql_res.statusText, "DoDelete")
485
487
  if (this._debugOnError) {
486
- result.addDebug("OINO DELETE MESSAGES [" + sql_res.messages.join('|') + "]", "DoDelete")
488
+ result.addDebug("OINO DELETE MESSAGES [" + sql_res.statusText + "]", "DoDelete")
487
489
  result.addDebug("OINO DELETE SQL [" + sql + "]", "DoDelete")
488
490
  }
489
491
  }
@@ -570,7 +572,7 @@ export class OINODbApi {
570
572
 
571
573
  } else {
572
574
  try {
573
- await this._doPost(result, rows)
575
+ await this._doPost(result, rows, request)
574
576
 
575
577
  } catch (e:any) {
576
578
  result.setError(500, "Unhandled exception in HTTP POST doRequest: " + e.message, "DoRequest")
@@ -53,7 +53,7 @@ export class OINODbDataModel {
53
53
  return result.substring(0, result.length-1)
54
54
  }
55
55
 
56
- private _printSqlInsertColumnsAndValues(row: OINODataRow): string {
56
+ private _printSqlInsertColumnsAndValues(row: OINODataRow): [string, string] {
57
57
  let columns: string = "";
58
58
  let values: string = "";
59
59
  for (let i=0; i< this.fields.length; i++) {
@@ -70,7 +70,7 @@ export class OINODbDataModel {
70
70
  }
71
71
  }
72
72
  // console.log("_printSqlInsertColumnsAndValues: columns=" + columns + ", values=" + values)
73
- return "(" + columns + ") VALUES (" + values + ")";
73
+ return [ columns, values ]
74
74
  }
75
75
 
76
76
  private _printSqlUpdateValues(row: OINODataRow): string {
@@ -115,6 +115,16 @@ export class OINODbDataModel {
115
115
  return "(" + result + ")";
116
116
  }
117
117
 
118
+ private _printSqlPrimaryKeyColumns(): string[] {
119
+ let result: string[] = []
120
+ for (let f of this.fields) {
121
+ if (f.fieldParams.isPrimaryKey) {
122
+ result.push(this.api.db.printSqlColumnname(f.name))
123
+ }
124
+ }
125
+ return result
126
+ }
127
+
118
128
  /**
119
129
  * Add a field to the datamodel.
120
130
  *
@@ -263,8 +273,10 @@ export class OINODbDataModel {
263
273
  *
264
274
  */
265
275
  printSqlInsert(row: OINODataRow): string {
266
- let result: string = "INSERT INTO " + this.api.db.printSqlTablename(this.api.params.tableName) + " " + this._printSqlInsertColumnsAndValues(row) + ";";
267
- return result;
276
+ const table_name = this.api.db.printSqlTablename(this.api.params.tableName)
277
+ const [columns, values] = this._printSqlInsertColumnsAndValues(row)
278
+ const return_fields = this.api.params.returnInsertedIds ? this._printSqlPrimaryKeyColumns() : undefined
279
+ return this.api.db.printSqlInsert(table_name, columns, values, return_fields);
268
280
  }
269
281
 
270
282
  /**
package/src/index.ts CHANGED
@@ -43,7 +43,9 @@ export type OINODbApiParams = {
43
43
  /** Make hashids static per row/table */
44
44
  hashidStaticIds?: boolean,
45
45
  /** Name of field that has the modified field */
46
- cacheModifiedField?:string
46
+ cacheModifiedField?:string,
47
+ /** Return inserted id values */
48
+ returnInsertedIds?: boolean
47
49
  }
48
50
 
49
51
  /**
@@ -107,7 +109,7 @@ export type OINODataRow = Array<OINODataCell>
107
109
  /** Empty row instance */
108
110
  export const OINODB_EMPTY_ROW:OINODataRow = []
109
111
  /** Empty row array instance */
110
- export const OINODB_EMPTY_ROWS:OINODataRow[] = [OINODB_EMPTY_ROW]
112
+ export const OINODB_EMPTY_ROWS:OINODataRow[] = []
111
113
  /** Constant for undefined values */
112
114
  export const OINODB_UNDEFINED = "" // original idea was to have a defined literal that get's swapped back to undefined, but current implementation just leaves it out at serialization (so value does not matter)
113
115