@oino-ts/db 0.0.14 → 0.0.16

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/README.md CHANGED
@@ -10,15 +10,15 @@
10
10
  # GETTING STARTED
11
11
 
12
12
  ### Setup
13
- Install the `@oino-ts/core` npm package and necessary database packages and import them in your code.
13
+ Install the `@oino-ts/db` npm package and necessary database packages and import them in your code.
14
14
  ```
15
- bun install @oino-ts/core
16
- bun install @oino-ts/bunsqlite
15
+ bun install @oino-ts/db
16
+ bun install @oino-ts/db-bunsqlite
17
17
  ```
18
18
 
19
19
  ```
20
- import { OINODb, OINOApi, OINOFactory } from "@oino-ts/core";
21
- import { OINODbBunSqlite } from "@oino-ts/bunsqlite"
20
+ import { OINODb, OINOApi, OINOFactory } from "@oino-ts/db";
21
+ import { OINODbBunSqlite } from "@oino-ts/db-bunsqlite"
22
22
  ```
23
23
 
24
24
  ### Register database and logger
@@ -51,7 +51,7 @@
51
51
  ### Write results back to HTTP Response
52
52
  The results for a GET request will contain [`OINOModelSet`](https://pragmatta.github.io/oino-ts/classes/db_src.OINODbModelSet.html) data that can be written out as JSON or CSV as needed. For other requests result is just success or error with messages.
53
53
  ```
54
- return new Response(result.modelset.writeString(OINOContentType.json))
54
+ return new Response(result.data.writeString(OINOContentType.json))
55
55
  ```
56
56
 
57
57
 
@@ -129,12 +129,13 @@
129
129
  - Bun Sqlite through Bun native implementation
130
130
  - Postgresql through [pg](https://www.npmjs.com/package/pg)-package
131
131
  - Mariadb / Mysql-support through [mariadb](https://www.npmjs.com/package/mariadb)-package
132
+ - Sql Server through [mssql](https://www.npmjs.com/package/mssql)-package
132
133
 
133
134
  ## Complex Keys
134
135
  To support tables with multipart primary keys OINO generates a composite key `_OINOID_` that is included in the result and can be used as the REST ID. For example in the example above table `OrderDetails` has two primary keys `OrderID` and `ProductID` making the `_OINOID_` of form `11077:99`.
135
136
 
136
137
  ## Power Of SQL
137
- Since OINO controls the SQL, WHERE-conditions can be defined with [`OINOSqlFilter`](https://pragmatta.github.io/oino-ts/classes/db_src.OINODbSqlFilter.html) and order with [`OINOSqlOrder`](https://pragmatta.github.io/oino-ts/classes/db_src.OINODbSqlOrder.html) that are passed as HTTP request parameters. No more API development where you make unique API endpoints for each filter that fetch all data with original API and filter in backend code. Every API can be filtered when and as needed without unnessecary data tranfer and utilizing SQL indexing when available.
138
+ Since OINO is just generating SQL, WHERE-conditions can be defined with [`OINOSqlFilter`](https://pragmatta.github.io/oino-ts/classes/db_src.OINODbSqlFilter.html) and order with [`OINOSqlOrder`](https://pragmatta.github.io/oino-ts/classes/db_src.OINODbSqlOrder.html) that are passed as HTTP request parameters. No more API development where you make unique API endpoints for each filter that fetch all data with original API and filter in backend code. Every API can be filtered when and as needed without unnessecary data tranfer and utilizing SQL indexing when available.
138
139
 
139
140
  ## Swagger Support
140
141
  Swagger is great as long as the definitions are updated and with OINO you can automatically get a Swagger definition including a data model schema.
@@ -158,7 +159,7 @@
158
159
  # STATUS
159
160
  OINO is currently a hobby project which should and should considered in alpha status. That also means compatibility breaking changes can be made without prior notice when architectual issues are discovered.
160
161
 
161
- ## Beta
162
+ ## Beta
162
163
  For a beta status following milestones are planned:
163
164
 
164
165
  ### Realistic app
@@ -205,14 +206,16 @@
205
206
  # LINKS
206
207
  - [Github repository](https://github.com/pragmatta/oino-ts)
207
208
  - [NPM repository](https://www.npmjs.com/org/oino-ts)
208
-
209
+
209
210
 
210
211
  # ACKNOWLEDGEMENTS
211
212
 
212
213
  ## Libraries
213
214
  OINO uses the following open source libraries and npm packages and I would like to thank everyone for their contributions:
214
- - Postgresql support by [node-postgres package](https://www.npmjs.com/package/pg)
215
- - Mariadb / Mysql-support by [mariadb package](https://www.npmjs.com/package/mariadb)
215
+ - Postgresql [node-postgres package](https://www.npmjs.com/package/pg)
216
+ - Mariadb / Mysql [mariadb package](https://www.npmjs.com/package/mariadb)
217
+ - Sql Server [mssql package](https://www.npmjs.com/package/mssql)
218
+ - Custom base encoding [base-x package](https://www.npmjs.com/package/base-x)
216
219
 
217
220
  ## Bun
218
221
  OINO has been developed using the Bun runtime, not because of the speed improvements but for the first class Typescript support and integrated developper experience. Kudos on the bun team for making Typescript work more exiting again.
@@ -38,18 +38,19 @@ class OINODbApiResult extends types_1.OINOResult {
38
38
  * @param headers Headers to include in the response
39
39
  *
40
40
  */
41
- getResponse(headers = {}) {
41
+ async createResponseFromResult(headers = {}) {
42
42
  let response = null;
43
43
  if (this.success && this.data) {
44
- response = new Response(this.data.writeString(this.params.responseType), { status: this.statusCode, statusText: this.statusMessage, headers: headers });
44
+ const body = await this.data.writeString(this.params.responseType);
45
+ response = new Response(body, { status: this.statusCode, statusText: this.statusMessage, headers: headers });
45
46
  }
46
47
  else {
47
- response = new Response(JSON.stringify(this), { status: this.statusCode, statusText: this.statusMessage, headers: headers });
48
+ response = new Response(JSON.stringify(this, null, 3), { status: this.statusCode, statusText: this.statusMessage, headers: headers });
48
49
  }
49
50
  for (let i = 0; i < this.messages.length; i++) {
50
51
  response.headers.set('X-OINO-MESSAGE-' + i, this.messages[i]);
51
52
  }
52
- return response;
53
+ return Promise.resolve(response);
53
54
  }
54
55
  }
55
56
  exports.OINODbApiResult = OINODbApiResult;
@@ -62,9 +63,10 @@ class OINODbHtmlTemplate extends index_js_1.OINOHtmlTemplate {
62
63
  * Creates HTML Response from API modelset.
63
64
  *
64
65
  * @param modelset OINO API dataset
66
+ * @param overrideValues values to override in the data
65
67
  *
66
68
  */
67
- renderFromDbData(modelset) {
69
+ async renderFromDbData(modelset, overrideValues) {
68
70
  index_js_1.OINOBenchmark.start("OINOHtmlTemplate", "renderFromDbData");
69
71
  let html = "";
70
72
  const dataset = modelset.dataset;
@@ -72,14 +74,18 @@ class OINODbHtmlTemplate extends index_js_1.OINOHtmlTemplate {
72
74
  const api = modelset.datamodel.api;
73
75
  const modified_index = datamodel.findFieldIndexByName(api.params.cacheModifiedField || "");
74
76
  let last_modified = this.modified;
77
+ // OINOLog.debug("OINOHtmlTemplate.renderFromDbData", {last_modified:last_modified})
75
78
  while (!dataset.isEof()) {
76
79
  const row = dataset.getRow();
77
80
  if (modified_index >= 0) {
78
81
  last_modified = Math.max(last_modified, new Date(row[modified_index]).getTime());
82
+ // OINOLog.debug("OINOHtmlTemplate.renderFromDbData", {last_modified:last_modified})
79
83
  }
80
84
  let row_id_seed = datamodel.getRowPrimarykeyValues(row).join(' ');
81
85
  let primary_key_values = [];
82
- let html_row = this.template.replaceAll('###' + index_js_1.OINODbConfig.OINODB_ID_FIELD + '###', '###createHtmlFromData_temporary_oinoid###');
86
+ this.clearVariables();
87
+ this.setVariableFromValue(index_js_1.OINODbConfig.OINODB_ID_FIELD, "");
88
+ // let html_row:string = this.template.replaceAll('###' + OINODbConfig.OINODB_ID_FIELD + '###', '###createHtmlFromData_temporary_oinoid###')
83
89
  for (let i = 0; i < datamodel.fields.length; i++) {
84
90
  const f = datamodel.fields[i];
85
91
  let value = f.serializeCell(row[i]);
@@ -90,14 +96,17 @@ class OINODbHtmlTemplate extends index_js_1.OINOHtmlTemplate {
90
96
  primary_key_values.push(value || "");
91
97
  }
92
98
  // OINOLog.debug("renderFromDbData replace field value", {field:f.name, value:value })
93
- html_row = html_row.replaceAll('###' + f.name + '###', index_js_1.OINOStr.encode(value, index_js_1.OINOContentType.html));
99
+ this.setVariableFromValue(f.name, value || "");
94
100
  }
95
- html_row = html_row.replaceAll('###createHtmlFromData_temporary_oinoid###', index_js_1.OINOStr.encode(index_js_1.OINODbConfig.printOINOId(primary_key_values), index_js_1.OINOContentType.html));
96
- html += html_row + "\r\n";
97
- dataset.next();
101
+ this.setVariableFromProperties(overrideValues);
102
+ this.setVariableFromValue(index_js_1.OINODbConfig.OINODB_ID_FIELD, index_js_1.OINODbConfig.printOINOId(primary_key_values));
103
+ // html_row = html_row.replaceAll('###createHtmlFromData_temporary_oinoid###', OINOStr.encode(OINODbConfig.printOINOId(primary_key_values), OINOContentType.html))
104
+ html += this._renderHtml() + "\r\n";
105
+ await dataset.next();
98
106
  }
99
- const result = new index_js_1.OINOHttpResult(html);
100
- result.lastModified = last_modified;
107
+ // OINOLog.debug("OINOHtmlTemplate.renderFromDbData", {last_modified:last_modified})
108
+ this.modified = last_modified;
109
+ const result = this._createHttpResult(html, false);
101
110
  index_js_1.OINOBenchmark.end("OINOHtmlTemplate", "renderFromDbData");
102
111
  return result;
103
112
  }
@@ -317,7 +326,7 @@ class OINODbApi {
317
326
  }
318
327
  else {
319
328
  try {
320
- index_js_1.OINOLog.debug("OINODbApi.doRequest / POST", { rows: rows });
329
+ // OINOLog.debug("OINODbApi.doRequest / POST", {rows:rows})
321
330
  await this._doPost(result, rows);
322
331
  }
323
332
  catch (e) {
@@ -342,7 +351,7 @@ class OINODbApi {
342
351
  result.setError(405, "Unsupported HTTP method '" + method + "'", "DoRequest");
343
352
  }
344
353
  index_js_1.OINOBenchmark.end("OINODbApi", "doRequest", method);
345
- return result;
354
+ return Promise.resolve(result);
346
355
  }
347
356
  }
348
357
  exports.OINODbApi = OINODbApi;
@@ -225,10 +225,10 @@ class OINODbDataModel {
225
225
  const order_sql = params.order?.toSql(this) || "";
226
226
  const limit_sql = params.limit?.toSql(this) || "";
227
227
  // OINOLog.debug("OINODbDataModel.printSqlSelect", {select_sql:result, filter_sql:filter_sql, order_sql:order_sql})
228
- if ((id != "") && (filter_sql != "")) {
228
+ if ((id != null) && (id != "") && (filter_sql != "")) {
229
229
  result += "\nWHERE " + this._printSqlPrimaryKeyCondition(id) + " AND " + filter_sql;
230
230
  }
231
- else if (id != "") {
231
+ else if ((id != null) && (id != "")) {
232
232
  result += "\nWHERE " + this._printSqlPrimaryKeyCondition(id);
233
233
  }
234
234
  else if (filter_sql != "") {
@@ -88,9 +88,9 @@ class OINODbMemoryDataSet extends OINODbDataSet {
88
88
  }
89
89
  }
90
90
  /**
91
- * Is data set empty.
92
- *
93
- */
91
+ * Is data set empty.
92
+ *
93
+ */
94
94
  isEmpty() {
95
95
  return (this._rows.length == 0);
96
96
  }
@@ -102,17 +102,17 @@ class OINODbMemoryDataSet extends OINODbDataSet {
102
102
  return (this._eof);
103
103
  }
104
104
  /**
105
- * Moves dataset to the next row, returns !isEof().
105
+ * Attempts to moves dataset to the next row, possibly waiting for more data to become available. Returns !isEof().
106
106
  *
107
107
  */
108
- next() {
108
+ async next() {
109
109
  if (this._currentRow < this._rows.length - 1) {
110
110
  this._currentRow = this._currentRow + 1;
111
111
  }
112
112
  else {
113
113
  this._eof = true;
114
114
  }
115
- return !this._eof;
115
+ return Promise.resolve(!this._eof);
116
116
  }
117
117
  /**
118
118
  * Gets current row of data.
@@ -111,77 +111,6 @@ class OINODbFactory {
111
111
  // OINOLog.debug("createParamsFromRequest", {params:result})
112
112
  return result;
113
113
  }
114
- /**
115
- * Creates HTML Response from API modelset.
116
- *
117
- * @param modelset OINO API dataset
118
- * @param template HTML template
119
- *
120
- */
121
- static createHtmlFromData(modelset, template) {
122
- let html = "";
123
- const dataset = modelset.dataset;
124
- const datamodel = modelset.datamodel;
125
- while (!dataset.isEof()) {
126
- const row = dataset.getRow();
127
- let row_id_seed = datamodel.getRowPrimarykeyValues(row).join(' ');
128
- let primary_key_values = [];
129
- let html_row = template.replaceAll('###' + index_js_1.OINODbConfig.OINODB_ID_FIELD + '###', '###createHtmlFromData_temporary_oinoid###');
130
- for (let i = 0; i < datamodel.fields.length; i++) {
131
- const f = datamodel.fields[i];
132
- let value = f.serializeCell(row[i]);
133
- if (f.fieldParams.isPrimaryKey) {
134
- if (value && (f instanceof index_js_1.OINONumberDataField) && (datamodel.api.hashid)) {
135
- value = datamodel.api.hashid.encode(value, f.name + " " + row_id_seed);
136
- }
137
- primary_key_values.push(value || "");
138
- }
139
- html_row = html_row.replaceAll('###' + f.name + '###', index_js_1.OINOStr.encode(value, index_js_1.OINOContentType.html));
140
- }
141
- html_row = html_row.replaceAll('###createHtmlFromData_temporary_oinoid###', index_js_1.OINOStr.encode(index_js_1.OINODbConfig.printOINOId(primary_key_values), index_js_1.OINOContentType.html));
142
- html += html_row + "\r\n";
143
- dataset.next();
144
- }
145
- const result = new index_js_1.OINOHttpResult(html);
146
- return result;
147
- }
148
- /**
149
- * Creates HTML Response from API result.
150
- *
151
- * @param result OINOResult-object
152
- * @param template HTML template
153
- * @param includeErrorMessages include debug messages in result
154
- * @param includeWarningMessages include debug messages in result
155
- * @param includeInfoMessages include debug messages in result
156
- * @param includeDebugMessages include debug messages in result
157
- *
158
- */
159
- static createHtmlNotificationFromResult(result, template, includeErrorMessages = false, includeWarningMessages = false, includeInfoMessages = false, includeDebugMessages = false) {
160
- let html = template;
161
- html = html.replaceAll('###statusCode###', index_js_1.OINOStr.encode(result.statusCode.toString(), index_js_1.OINOContentType.html));
162
- html = html.replaceAll('###statusMessage###', index_js_1.OINOStr.encode(result.statusMessage.toString(), index_js_1.OINOContentType.html));
163
- let messages = "";
164
- for (let i = 0; i < result.messages.length; i++) {
165
- if (includeErrorMessages && result.messages[i].startsWith(index_js_1.OINO_ERROR_PREFIX)) {
166
- messages += "<li>" + index_js_1.OINOStr.encode(result.messages[i], index_js_1.OINOContentType.html) + "</li>";
167
- }
168
- if (includeWarningMessages && result.messages[i].startsWith(index_js_1.OINO_WARNING_PREFIX)) {
169
- messages += "<li>" + index_js_1.OINOStr.encode(result.messages[i], index_js_1.OINOContentType.html) + "</li>";
170
- }
171
- if (includeInfoMessages && result.messages[i].startsWith(index_js_1.OINO_INFO_PREFIX)) {
172
- messages += "<li>" + index_js_1.OINOStr.encode(result.messages[i], index_js_1.OINOContentType.html) + "</li>";
173
- }
174
- if (includeDebugMessages && result.messages[i].startsWith(index_js_1.OINO_DEBUG_PREFIX)) {
175
- messages += "<li>" + index_js_1.OINOStr.encode(result.messages[i], index_js_1.OINOContentType.html) + "</li>";
176
- }
177
- }
178
- if (messages) {
179
- html = html.replaceAll('###messages###', "<ul>" + messages + "</ul>");
180
- }
181
- html = html.replace(/###[^#]*###/g, "");
182
- const http_result = new index_js_1.OINOHttpResult(html);
183
- return http_result;
184
- }
185
114
  static _findCsvLineEnd(csvData, start) {
186
115
  const n = csvData.length;
187
116
  if (start >= n) {
@@ -323,21 +252,23 @@ class OINODbFactory {
323
252
  // console.log("createRowFromJsonObj: " + result)
324
253
  for (let i = 0; i < fields.length; i++) {
325
254
  const field = fields[i];
326
- let value = index_js_1.OINOStr.decode(obj[field.name], index_js_1.OINOContentType.json);
255
+ let value = obj[field.name];
327
256
  // console.log("createRowFromJsonObj: key=" + field.name + ", val=" + val)
328
- if ((value === undefined) || (value === null)) {
257
+ if ((value === null) || (value === undefined)) { // must be checed first as null is an object
329
258
  result[i] = value;
330
259
  }
331
- else {
332
- if (Array.isArray(value) || typeof value === "object") { // only single level deep object, rest is handled as JSON-strings
333
- result[i] = JSON.stringify(value).replaceAll("\"", "\\\"");
334
- }
335
- else {
336
- if (value && field.fieldParams.isPrimaryKey && (field instanceof index_js_1.OINONumberDataField) && (datamodel.api.hashid)) {
337
- value = datamodel.api.hashid.decode(value);
338
- }
339
- result[i] = field.deserializeCell(value);
260
+ else if (Array.isArray(value) || typeof value === "object") {
261
+ result[i] = JSON.stringify(value).replaceAll("\"", "\\\""); // only single level deep objects, rest is handled as JSON-strings
262
+ }
263
+ else if (typeof value === "string") {
264
+ value = index_js_1.OINOStr.decode(value, index_js_1.OINOContentType.json);
265
+ if (value && field.fieldParams.isPrimaryKey && (field instanceof index_js_1.OINONumberDataField) && (datamodel.api.hashid)) {
266
+ value = datamodel.api.hashid.decode(value);
340
267
  }
268
+ result[i] = field.deserializeCell(value);
269
+ }
270
+ else {
271
+ result[i] = value; // value types are passed as-is
341
272
  }
342
273
  // console.log("createRowFromJsonObj: result["+i+"]=" + result[i])
343
274
  }
@@ -33,14 +33,15 @@ class OINODbModelSet {
33
33
  this.errors = this.dataset.messages;
34
34
  }
35
35
  _encodeAndHashFieldValue(field, value, contentType, primaryKeyValues, rowIdSeed) {
36
+ let result;
36
37
  if (field.fieldParams.isPrimaryKey) {
37
38
  if (value && (field instanceof index_js_1.OINONumberDataField) && (this.datamodel.api.hashid)) {
38
39
  value = this.datamodel.api.hashid.encode(value, rowIdSeed);
39
40
  }
40
41
  primaryKeyValues.push(value || "");
41
42
  }
42
- value = index_js_1.OINOStr.encode(value, contentType);
43
- return value;
43
+ result = index_js_1.OINOStr.encode(value, contentType);
44
+ return result;
44
45
  }
45
46
  _writeRowJson(row) {
46
47
  // console.log("OINODbModelSet._writeRowJson: row=" + row)
@@ -72,14 +73,16 @@ class OINODbModelSet {
72
73
  // OINOLog_debug("OINODbModelSet._writeRowJson="+json_row)
73
74
  return "{" + json_row + "}";
74
75
  }
75
- _writeStringJson() {
76
+ async _writeStringJson() {
76
77
  let result = "";
77
78
  while (!this.dataset.isEof()) {
78
79
  if (result != "") {
79
80
  result += ",\r\n";
80
81
  }
81
- result += this._writeRowJson(this.dataset.getRow());
82
- this.dataset.next();
82
+ const row = this.dataset.getRow();
83
+ // OINOLog.debug("OINODbModelSet._writeStringJson: row", {row:row})
84
+ result += this._writeRowJson(row);
85
+ await this.dataset.next();
83
86
  }
84
87
  result = "[\r\n" + result + "\r\n]";
85
88
  // OINOLog_debug("OINODbModelSet._writeStringJson="+result)
@@ -117,14 +120,16 @@ class OINODbModelSet {
117
120
  // OINOLog_debug("OINODbModelSet._writeRowCsv="+csv_row)
118
121
  return csv_row;
119
122
  }
120
- _writeStringCsv() {
123
+ async _writeStringCsv() {
121
124
  let result = this._writeHeaderCsv();
122
125
  while (!this.dataset.isEof()) {
123
126
  if (result != "") {
124
127
  result += "\r\n";
125
128
  }
126
- result += this._writeRowCsv(this.dataset.getRow());
127
- this.dataset.next();
129
+ const row = this.dataset.getRow();
130
+ // OINOLog.debug("OINODbModelSet._writeStringCsv: row", {row:row})
131
+ result += this._writeRowCsv(row);
132
+ await this.dataset.next();
128
133
  }
129
134
  // OINOLog_debug("OINODbModelSet._writeStringCsv="+result)
130
135
  return result;
@@ -141,6 +146,7 @@ class OINODbModelSet {
141
146
  return multipartBoundary + "\r\n" + "Content-Disposition: form-data; name=\"" + blockName + "\"; filename=" + blockName + "\"\r\nContent-Type: application/octet-stream\r\nContent-Transfer-Encoding: BASE64\r\n\r\n" + blockValue + "\r\n";
142
147
  }
143
148
  _writeRowFormdata(row) {
149
+ // console.log("OINODbModelSet._writeRowFormdata: row", row)
144
150
  const multipart_boundary = "---------OINOMultipartBoundary35424568"; // this method is just used for test data generation and we want it to be static
145
151
  const model = this.datamodel;
146
152
  const fields = model.fields;
@@ -174,15 +180,13 @@ class OINODbModelSet {
174
180
  return result;
175
181
  }
176
182
  _writeStringFormdata() {
177
- let result = this._writeRowFormdata(this.dataset.getRow());
178
- this.dataset.next();
179
- if (!this.dataset.isEof()) {
180
- index_js_1.OINOLog.warning("OINODbModelSet._writeStringUrlencode: content type " + index_js_1.OINOContentType.formdata + " does not mixed part content and only first row has been written!");
181
- }
183
+ const row = this.dataset.getRow();
184
+ // OINOLog.debug("OINODbModelSet._writeStringFormdata: row", {row:row})
185
+ let result = this._writeRowFormdata(row);
182
186
  return result;
183
187
  }
184
188
  _writeRowUrlencode(row) {
185
- // console.log("OINODbModelSet._writeRowCsv row=" + row)
189
+ // console.log("OINODbModelSet._writeRowUrlencode row=" + row)
186
190
  const model = this.datamodel;
187
191
  const fields = model.fields;
188
192
  let row_id_seed = model.getRowPrimarykeyValues(row).join(' ');
@@ -206,12 +210,14 @@ class OINODbModelSet {
206
210
  // OINOLog_debug("OINODbModelSet._writeRowCsv="+csv_row)
207
211
  return urlencode_row;
208
212
  }
209
- _writeStringUrlencode() {
213
+ async _writeStringUrlencode() {
210
214
  let result = "";
211
215
  let line_count = 0;
212
216
  while (!this.dataset.isEof()) {
213
- result += this._writeRowUrlencode(this.dataset.getRow()) + "\r\n";
214
- this.dataset.next();
217
+ const row = this.dataset.getRow();
218
+ // OINOLog.debug("OINODbModelSet._writeStringUrlencode: row", {row:row})
219
+ result += this._writeRowUrlencode(row) + "\r\n";
220
+ await this.dataset.next();
215
221
  line_count += 1;
216
222
  }
217
223
  // OINOLog_debug("OINODbModelSet._writeStringCsv="+result)
@@ -226,19 +232,19 @@ class OINODbModelSet {
226
232
  * @param [contentType=OINOContentType.json] serialization content type
227
233
  *
228
234
  */
229
- writeString(contentType = index_js_1.OINOContentType.json) {
235
+ async writeString(contentType = index_js_1.OINOContentType.json) {
230
236
  let result = "";
231
237
  if (contentType == index_js_1.OINOContentType.csv) {
232
- result += this._writeStringCsv();
238
+ result += await this._writeStringCsv();
233
239
  }
234
240
  else if (contentType == index_js_1.OINOContentType.json) {
235
- result += this._writeStringJson();
241
+ result += await this._writeStringJson();
236
242
  }
237
243
  else if (contentType == index_js_1.OINOContentType.formdata) {
238
- result += this._writeStringFormdata();
244
+ result += await this._writeStringFormdata();
239
245
  }
240
246
  else if (contentType == index_js_1.OINOContentType.urlencode) {
241
- result += this._writeStringUrlencode();
247
+ result += await this._writeStringUrlencode();
242
248
  }
243
249
  else {
244
250
  index_js_1.OINOLog.error("OINODbModelSet.writeString: content type is only for input!", { contentType: contentType });
@@ -250,15 +256,19 @@ class OINODbModelSet {
250
256
  * field not found or value does not exist.
251
257
  *
252
258
  * @param fieldName name of the field
259
+ * @param serialize serialize the value
253
260
  *
254
261
  */
255
- getValueByFieldName(fieldName) {
262
+ getValueByFieldName(fieldName, serialize = false) {
256
263
  let result = undefined;
257
264
  if (!this.dataset.isEof()) {
258
265
  const current_row = this.dataset.getRow();
259
266
  const field_index = this.datamodel.findFieldIndexByName(fieldName);
260
267
  if (field_index >= 0) {
261
268
  result = current_row[field_index];
269
+ if (serialize) {
270
+ result = this.datamodel.fields[field_index].serializeCell(result);
271
+ }
262
272
  }
263
273
  }
264
274
  return result;
@@ -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 { OINODbDataModel, OINOStringDataField, OINO_ERROR_PREFIX, OINODbModelSet, OINOBenchmark, OINODbFactory, OINOLog, OINODbConfig, OINOHttpResult, OINOHtmlTemplate, OINONumberDataField, OINOContentType, OINOStr } from "./index.js";
6
+ import { OINODbDataModel, OINOStringDataField, OINO_ERROR_PREFIX, OINODbModelSet, OINOBenchmark, OINODbFactory, OINODbConfig, OINOHtmlTemplate, OINONumberDataField } from "./index.js";
7
7
  import { OINOResult } from "@oino-ts/types";
8
8
  import { OINOHashid } from "@oino-ts/hashid";
9
9
  const API_EMPTY_PARAMS = { sqlParams: {} };
@@ -35,18 +35,19 @@ export class OINODbApiResult extends OINOResult {
35
35
  * @param headers Headers to include in the response
36
36
  *
37
37
  */
38
- getResponse(headers = {}) {
38
+ async createResponseFromResult(headers = {}) {
39
39
  let response = null;
40
40
  if (this.success && this.data) {
41
- response = new Response(this.data.writeString(this.params.responseType), { status: this.statusCode, statusText: this.statusMessage, headers: headers });
41
+ const body = await this.data.writeString(this.params.responseType);
42
+ response = new Response(body, { status: this.statusCode, statusText: this.statusMessage, headers: headers });
42
43
  }
43
44
  else {
44
- response = new Response(JSON.stringify(this), { status: this.statusCode, statusText: this.statusMessage, headers: headers });
45
+ response = new Response(JSON.stringify(this, null, 3), { status: this.statusCode, statusText: this.statusMessage, headers: headers });
45
46
  }
46
47
  for (let i = 0; i < this.messages.length; i++) {
47
48
  response.headers.set('X-OINO-MESSAGE-' + i, this.messages[i]);
48
49
  }
49
- return response;
50
+ return Promise.resolve(response);
50
51
  }
51
52
  }
52
53
  /**
@@ -58,9 +59,10 @@ export class OINODbHtmlTemplate extends OINOHtmlTemplate {
58
59
  * Creates HTML Response from API modelset.
59
60
  *
60
61
  * @param modelset OINO API dataset
62
+ * @param overrideValues values to override in the data
61
63
  *
62
64
  */
63
- renderFromDbData(modelset) {
65
+ async renderFromDbData(modelset, overrideValues) {
64
66
  OINOBenchmark.start("OINOHtmlTemplate", "renderFromDbData");
65
67
  let html = "";
66
68
  const dataset = modelset.dataset;
@@ -68,14 +70,18 @@ export class OINODbHtmlTemplate extends OINOHtmlTemplate {
68
70
  const api = modelset.datamodel.api;
69
71
  const modified_index = datamodel.findFieldIndexByName(api.params.cacheModifiedField || "");
70
72
  let last_modified = this.modified;
73
+ // OINOLog.debug("OINOHtmlTemplate.renderFromDbData", {last_modified:last_modified})
71
74
  while (!dataset.isEof()) {
72
75
  const row = dataset.getRow();
73
76
  if (modified_index >= 0) {
74
77
  last_modified = Math.max(last_modified, new Date(row[modified_index]).getTime());
78
+ // OINOLog.debug("OINOHtmlTemplate.renderFromDbData", {last_modified:last_modified})
75
79
  }
76
80
  let row_id_seed = datamodel.getRowPrimarykeyValues(row).join(' ');
77
81
  let primary_key_values = [];
78
- let html_row = this.template.replaceAll('###' + OINODbConfig.OINODB_ID_FIELD + '###', '###createHtmlFromData_temporary_oinoid###');
82
+ this.clearVariables();
83
+ this.setVariableFromValue(OINODbConfig.OINODB_ID_FIELD, "");
84
+ // let html_row:string = this.template.replaceAll('###' + OINODbConfig.OINODB_ID_FIELD + '###', '###createHtmlFromData_temporary_oinoid###')
79
85
  for (let i = 0; i < datamodel.fields.length; i++) {
80
86
  const f = datamodel.fields[i];
81
87
  let value = f.serializeCell(row[i]);
@@ -86,14 +92,17 @@ export class OINODbHtmlTemplate extends OINOHtmlTemplate {
86
92
  primary_key_values.push(value || "");
87
93
  }
88
94
  // OINOLog.debug("renderFromDbData replace field value", {field:f.name, value:value })
89
- html_row = html_row.replaceAll('###' + f.name + '###', OINOStr.encode(value, OINOContentType.html));
95
+ this.setVariableFromValue(f.name, value || "");
90
96
  }
91
- html_row = html_row.replaceAll('###createHtmlFromData_temporary_oinoid###', OINOStr.encode(OINODbConfig.printOINOId(primary_key_values), OINOContentType.html));
92
- html += html_row + "\r\n";
93
- dataset.next();
97
+ this.setVariableFromProperties(overrideValues);
98
+ this.setVariableFromValue(OINODbConfig.OINODB_ID_FIELD, OINODbConfig.printOINOId(primary_key_values));
99
+ // html_row = html_row.replaceAll('###createHtmlFromData_temporary_oinoid###', OINOStr.encode(OINODbConfig.printOINOId(primary_key_values), OINOContentType.html))
100
+ html += this._renderHtml() + "\r\n";
101
+ await dataset.next();
94
102
  }
95
- const result = new OINOHttpResult(html);
96
- result.lastModified = last_modified;
103
+ // OINOLog.debug("OINOHtmlTemplate.renderFromDbData", {last_modified:last_modified})
104
+ this.modified = last_modified;
105
+ const result = this._createHttpResult(html, false);
97
106
  OINOBenchmark.end("OINOHtmlTemplate", "renderFromDbData");
98
107
  return result;
99
108
  }
@@ -312,7 +321,7 @@ export class OINODbApi {
312
321
  }
313
322
  else {
314
323
  try {
315
- OINOLog.debug("OINODbApi.doRequest / POST", { rows: rows });
324
+ // OINOLog.debug("OINODbApi.doRequest / POST", {rows:rows})
316
325
  await this._doPost(result, rows);
317
326
  }
318
327
  catch (e) {
@@ -337,6 +346,6 @@ export class OINODbApi {
337
346
  result.setError(405, "Unsupported HTTP method '" + method + "'", "DoRequest");
338
347
  }
339
348
  OINOBenchmark.end("OINODbApi", "doRequest", method);
340
- return result;
349
+ return Promise.resolve(result);
341
350
  }
342
351
  }
@@ -222,10 +222,10 @@ export class OINODbDataModel {
222
222
  const order_sql = params.order?.toSql(this) || "";
223
223
  const limit_sql = params.limit?.toSql(this) || "";
224
224
  // OINOLog.debug("OINODbDataModel.printSqlSelect", {select_sql:result, filter_sql:filter_sql, order_sql:order_sql})
225
- if ((id != "") && (filter_sql != "")) {
225
+ if ((id != null) && (id != "") && (filter_sql != "")) {
226
226
  result += "\nWHERE " + this._printSqlPrimaryKeyCondition(id) + " AND " + filter_sql;
227
227
  }
228
- else if (id != "") {
228
+ else if ((id != null) && (id != "")) {
229
229
  result += "\nWHERE " + this._printSqlPrimaryKeyCondition(id);
230
230
  }
231
231
  else if (filter_sql != "") {
@@ -84,9 +84,9 @@ export class OINODbMemoryDataSet extends OINODbDataSet {
84
84
  }
85
85
  }
86
86
  /**
87
- * Is data set empty.
88
- *
89
- */
87
+ * Is data set empty.
88
+ *
89
+ */
90
90
  isEmpty() {
91
91
  return (this._rows.length == 0);
92
92
  }
@@ -98,17 +98,17 @@ export class OINODbMemoryDataSet extends OINODbDataSet {
98
98
  return (this._eof);
99
99
  }
100
100
  /**
101
- * Moves dataset to the next row, returns !isEof().
101
+ * Attempts to moves dataset to the next row, possibly waiting for more data to become available. Returns !isEof().
102
102
  *
103
103
  */
104
- next() {
104
+ async next() {
105
105
  if (this._currentRow < this._rows.length - 1) {
106
106
  this._currentRow = this._currentRow + 1;
107
107
  }
108
108
  else {
109
109
  this._eof = true;
110
110
  }
111
- return !this._eof;
111
+ return Promise.resolve(!this._eof);
112
112
  }
113
113
  /**
114
114
  * Gets current row of data.