@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 +14 -11
- package/dist/cjs/OINODbApi.js +23 -14
- package/dist/cjs/OINODbDataModel.js +2 -2
- package/dist/cjs/OINODbDataSet.js +6 -6
- package/dist/cjs/OINODbFactory.js +13 -82
- package/dist/cjs/OINODbModelSet.js +33 -23
- package/dist/esm/OINODbApi.js +24 -15
- package/dist/esm/OINODbDataModel.js +2 -2
- package/dist/esm/OINODbDataSet.js +6 -6
- package/dist/esm/OINODbFactory.js +14 -83
- package/dist/esm/OINODbModelSet.js +33 -23
- package/dist/types/OINODbApi.d.ts +3 -2
- package/dist/types/OINODbDataSet.d.ts +7 -7
- package/dist/types/OINODbFactory.d.ts +1 -21
- package/dist/types/OINODbModelSet.d.ts +3 -2
- package/package.json +2 -2
- package/src/OINODbApi.test.ts +126 -100
- package/src/OINODbApi.ts +23 -14
- package/src/OINODbDataModel.ts +2 -2
- package/src/OINODbDataSet.ts +6 -9
- package/src/OINODbFactory.ts +16 -87
- package/src/OINODbModelSet.ts +34 -24
package/README.md
CHANGED
|
@@ -10,15 +10,15 @@
|
|
|
10
10
|
# GETTING STARTED
|
|
11
11
|
|
|
12
12
|
### Setup
|
|
13
|
-
Install the `@oino-ts/
|
|
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/
|
|
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/
|
|
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.
|
|
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
|
|
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
|
|
215
|
-
- Mariadb / Mysql
|
|
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.
|
package/dist/cjs/OINODbApi.js
CHANGED
|
@@ -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
|
-
|
|
41
|
+
async createResponseFromResult(headers = {}) {
|
|
42
42
|
let response = null;
|
|
43
43
|
if (this.success && this.data) {
|
|
44
|
-
|
|
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
|
-
|
|
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
|
-
|
|
99
|
+
this.setVariableFromValue(f.name, value || "");
|
|
94
100
|
}
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
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
|
-
|
|
100
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
*
|
|
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 =
|
|
255
|
+
let value = obj[field.name];
|
|
327
256
|
// console.log("createRowFromJsonObj: key=" + field.name + ", val=" + val)
|
|
328
|
-
if ((value ===
|
|
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
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
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
|
-
|
|
43
|
-
return
|
|
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
|
-
|
|
82
|
-
|
|
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
|
-
|
|
127
|
-
|
|
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
|
-
|
|
178
|
-
|
|
179
|
-
|
|
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.
|
|
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
|
-
|
|
214
|
-
|
|
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;
|
package/dist/esm/OINODbApi.js
CHANGED
|
@@ -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,
|
|
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
|
-
|
|
38
|
+
async createResponseFromResult(headers = {}) {
|
|
39
39
|
let response = null;
|
|
40
40
|
if (this.success && this.data) {
|
|
41
|
-
|
|
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
|
-
|
|
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
|
-
|
|
95
|
+
this.setVariableFromValue(f.name, value || "");
|
|
90
96
|
}
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
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
|
-
|
|
96
|
-
|
|
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", {
|
|
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
|
-
|
|
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
|
-
*
|
|
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.
|