@oino-ts/db 0.0.11 → 0.0.13
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 +6 -6
- package/dist/cjs/OINODbApi.js +94 -10
- package/dist/cjs/OINODbDataField.js +5 -2
- package/dist/cjs/OINODbDataModel.js +1 -1
- package/dist/cjs/OINODbFactory.js +61 -83
- package/dist/cjs/OINODbRequestParams.js +55 -15
- package/dist/cjs/index.js +4 -1
- package/dist/esm/OINODbApi.js +92 -9
- package/dist/esm/OINODbDataField.js +5 -2
- package/dist/esm/OINODbDataModel.js +2 -2
- package/dist/esm/OINODbFactory.js +61 -83
- package/dist/esm/OINODbRequestParams.js +55 -15
- package/dist/esm/index.js +2 -2
- package/dist/types/OINODbApi.d.ts +28 -4
- package/dist/types/OINODbFactory.d.ts +16 -31
- package/dist/types/OINODbRequestParams.d.ts +20 -5
- package/dist/types/index.d.ts +10 -4
- package/package.json +2 -2
- package/src/OINODbApi.test.ts +9 -9
- package/src/OINODbApi.ts +100 -10
- package/src/OINODbDataField.ts +5 -3
- package/src/OINODbDataModel.ts +1 -1
- package/src/OINODbFactory.ts +70 -91
- package/src/OINODbRequestParams.ts +54 -16
- package/src/index.ts +11 -5
package/README.md
CHANGED
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
```
|
|
23
23
|
|
|
24
24
|
### Register database and logger
|
|
25
|
-
Register your database implementation and logger (see [`OINOConsoleLog`](https://pragmatta.github.io/oino-ts/classes/
|
|
25
|
+
Register your database implementation and logger (see [`OINOConsoleLog`](https://pragmatta.github.io/oino-ts/classes/types_src.OINOConsoleLog.html) how to implement your own)
|
|
26
26
|
|
|
27
27
|
```
|
|
28
28
|
OINOLog.setLogger(new OINOConsoleLog())
|
|
@@ -30,13 +30,13 @@
|
|
|
30
30
|
```
|
|
31
31
|
|
|
32
32
|
### Create a database
|
|
33
|
-
Creating a database connection [`OINODb`](https://pragmatta.github.io/oino-ts/classes/
|
|
33
|
+
Creating a database connection [`OINODb`](https://pragmatta.github.io/oino-ts/classes/db_src.OINODb.html) is done by passing [`OINODbParams`](https://pragmatta.github.io/oino-ts/types/db_src.OINODbParams.html) to the factory method. For [`OINODbBunSqlite`](https://pragmatta.github.io/oino-ts/classes/db_bunsqlite_src.OINODbBunSqlite.html) that means a file url for the database file, for others network host, port, credentials etc.
|
|
34
34
|
```
|
|
35
35
|
const db:OINODb = await OINOFactory.createDb( { type: "OINODbBunSqlite", url: "file://../localDb/northwind.sqlite" } )
|
|
36
36
|
```
|
|
37
37
|
|
|
38
38
|
### Create an API
|
|
39
|
-
From a database you can create an [`OINOApi`](https://pragmatta.github.io/oino-ts/classes/
|
|
39
|
+
From a database you can create an [`OINOApi`](https://pragmatta.github.io/oino-ts/classes/db_src.OINODbApi.html) by passing [`OINOApiParams`](https://pragmatta.github.io/oino-ts/types/db_src.OINODbApiParams.html) with table name and preferences to the factory method.
|
|
40
40
|
```
|
|
41
41
|
const api_employees:OINOApi = await OINOFactory.createApi(db, { tableName: "Employees", excludeFields:["BirthDate"] })
|
|
42
42
|
```
|
|
@@ -49,7 +49,7 @@
|
|
|
49
49
|
```
|
|
50
50
|
|
|
51
51
|
### Write results back to HTTP Response
|
|
52
|
-
The results for a GET request will contain [`OINOModelSet`](https://pragmatta.github.io/oino-ts/classes/
|
|
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
54
|
return new Response(result.modelset.writeString(OINOContentType.json))
|
|
55
55
|
```
|
|
@@ -134,7 +134,7 @@
|
|
|
134
134
|
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
135
|
|
|
136
136
|
## Power Of SQL
|
|
137
|
-
Since OINO controls the SQL, WHERE-conditions can be defined with [`OINOSqlFilter`](https://pragmatta.github.io/oino-ts/classes/
|
|
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
138
|
|
|
139
139
|
## Swagger Support
|
|
140
140
|
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.
|
|
@@ -149,7 +149,7 @@
|
|
|
149
149
|
OINO is developped Typescript first but compiles to standard CommonJS and the NPM packages should work on either ESM / CommonJS. Checkout sample apps `readmeApp` (ESM) and `nodeApp` (CommonJS).
|
|
150
150
|
|
|
151
151
|
## HTMX support
|
|
152
|
-
OINO is [htmx.org](https://htmx.org) friendly, allowing easy translation of [`OINODataRow`](https://pragmatta.github.io/oino-ts/types/
|
|
152
|
+
OINO is [htmx.org](https://htmx.org) friendly, allowing easy translation of [`OINODataRow`](https://pragmatta.github.io/oino-ts/types/db_src.OINODataRow.html) to HTML output using templates (cf. the [htmx sample app](https://github.com/pragmatta/oino-ts/tree/main/samples/htmxApp)).
|
|
153
153
|
|
|
154
154
|
### Hashids
|
|
155
155
|
Autoinc numeric id's are very pragmatic and fit well with OINO (e.g. using a form without primary key fields to insert new rows with database assigned ids). However it's not always sensible to share information about the sequence. Hashids solve this by masking the original values by encrypting the ids using AES-128 and some randomness. Length of the hashid can be chosen from 12-32 characters where longer ids provide more security. However this should not be considereded a cryptographic solution for keeping ids secret but rather making it infeasible to iterate all ids.
|
package/dist/cjs/OINODbApi.js
CHANGED
|
@@ -5,29 +5,102 @@
|
|
|
5
5
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
6
6
|
*/
|
|
7
7
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
-
exports.OINODbApi = exports.OINODbApiResult = void 0;
|
|
8
|
+
exports.OINODbApi = exports.OINODbHtmlTemplate = exports.OINODbApiResult = void 0;
|
|
9
9
|
const index_js_1 = require("./index.js");
|
|
10
|
+
const types_1 = require("@oino-ts/types");
|
|
10
11
|
const hashid_1 = require("@oino-ts/hashid");
|
|
12
|
+
const API_EMPTY_PARAMS = { sqlParams: {} };
|
|
11
13
|
/**
|
|
12
14
|
* OINO API request result object with returned data and/or http status code/message and
|
|
13
15
|
* error / warning messages.
|
|
14
16
|
*
|
|
15
17
|
*/
|
|
16
|
-
class OINODbApiResult extends
|
|
18
|
+
class OINODbApiResult extends types_1.OINOResult {
|
|
19
|
+
/** DbApi request params */
|
|
20
|
+
params;
|
|
17
21
|
/** Returned data if any */
|
|
18
22
|
data;
|
|
19
23
|
/**
|
|
20
24
|
* Constructor of OINODbApiResult.
|
|
21
25
|
*
|
|
26
|
+
* @param params DbApi request parameters
|
|
22
27
|
* @param data result data
|
|
23
28
|
*
|
|
24
29
|
*/
|
|
25
|
-
constructor(data) {
|
|
30
|
+
constructor(params, data) {
|
|
26
31
|
super();
|
|
32
|
+
this.params = params;
|
|
27
33
|
this.data = data;
|
|
28
34
|
}
|
|
35
|
+
/**
|
|
36
|
+
* Creates a HTTP Response from API results.
|
|
37
|
+
*
|
|
38
|
+
* @param headers Headers to include in the response
|
|
39
|
+
*
|
|
40
|
+
*/
|
|
41
|
+
getResponse(headers = {}) {
|
|
42
|
+
let response = null;
|
|
43
|
+
if (this.success && this.data) {
|
|
44
|
+
response = new Response(this.data.writeString(this.params.responseType), { status: this.statusCode, statusText: this.statusMessage, headers: headers });
|
|
45
|
+
}
|
|
46
|
+
else {
|
|
47
|
+
response = new Response(JSON.stringify(this), { status: this.statusCode, statusText: this.statusMessage, headers: headers });
|
|
48
|
+
}
|
|
49
|
+
for (let i = 0; i < this.messages.length; i++) {
|
|
50
|
+
response.headers.set('X-OINO-MESSAGE-' + i, this.messages[i]);
|
|
51
|
+
}
|
|
52
|
+
return response;
|
|
53
|
+
}
|
|
29
54
|
}
|
|
30
55
|
exports.OINODbApiResult = OINODbApiResult;
|
|
56
|
+
/**
|
|
57
|
+
* Specialized HTML template that can render ´OINODbApiResult´.
|
|
58
|
+
*
|
|
59
|
+
*/
|
|
60
|
+
class OINODbHtmlTemplate extends index_js_1.OINOHtmlTemplate {
|
|
61
|
+
/**
|
|
62
|
+
* Creates HTML Response from API modelset.
|
|
63
|
+
*
|
|
64
|
+
* @param modelset OINO API dataset
|
|
65
|
+
*
|
|
66
|
+
*/
|
|
67
|
+
renderFromDbData(modelset) {
|
|
68
|
+
let html = "";
|
|
69
|
+
const dataset = modelset.dataset;
|
|
70
|
+
const datamodel = modelset.datamodel;
|
|
71
|
+
const api = modelset.datamodel.api;
|
|
72
|
+
const modified_index = datamodel.findFieldIndexByName(api.params.cacheModifiedField || "");
|
|
73
|
+
let last_modified = this.modified;
|
|
74
|
+
while (!dataset.isEof()) {
|
|
75
|
+
const row = dataset.getRow();
|
|
76
|
+
if (modified_index >= 0) {
|
|
77
|
+
last_modified = Math.max(last_modified, new Date(row[modified_index]).getTime());
|
|
78
|
+
}
|
|
79
|
+
let row_id_seed = datamodel.getRowPrimarykeyValues(row).join(' ');
|
|
80
|
+
let primary_key_values = [];
|
|
81
|
+
let html_row = this.template.replaceAll('###' + index_js_1.OINODbConfig.OINODB_ID_FIELD + '###', '###createHtmlFromData_temporary_oinoid###');
|
|
82
|
+
for (let i = 0; i < datamodel.fields.length; i++) {
|
|
83
|
+
const f = datamodel.fields[i];
|
|
84
|
+
let value = f.serializeCell(row[i]);
|
|
85
|
+
if (f.fieldParams.isPrimaryKey) {
|
|
86
|
+
if (value && (f instanceof index_js_1.OINONumberDataField) && (datamodel.api.hashid)) {
|
|
87
|
+
value = datamodel.api.hashid.encode(value, f.name + " " + row_id_seed);
|
|
88
|
+
}
|
|
89
|
+
primary_key_values.push(value || "");
|
|
90
|
+
}
|
|
91
|
+
// OINOLog.debug("renderFromDbData replace field value", {field:f.name, value:value })
|
|
92
|
+
html_row = html_row.replaceAll('###' + f.name + '###', index_js_1.OINOStr.encode(value, index_js_1.OINOContentType.html));
|
|
93
|
+
}
|
|
94
|
+
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));
|
|
95
|
+
html += html_row + "\r\n";
|
|
96
|
+
dataset.next();
|
|
97
|
+
}
|
|
98
|
+
const result = new index_js_1.OINOHttpResult(html);
|
|
99
|
+
result.lastModified = last_modified;
|
|
100
|
+
return result;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
exports.OINODbHtmlTemplate = OINODbHtmlTemplate;
|
|
31
104
|
/**
|
|
32
105
|
* API class with method to process HTTP REST requests.
|
|
33
106
|
*
|
|
@@ -99,7 +172,7 @@ class OINODbApi {
|
|
|
99
172
|
}
|
|
100
173
|
async _doGet(result, id, params) {
|
|
101
174
|
index_js_1.OINOBenchmark.start("doGet");
|
|
102
|
-
const sql = this.datamodel.printSqlSelect(id, params.sqlParams);
|
|
175
|
+
const sql = this.datamodel.printSqlSelect(id, params.sqlParams || {});
|
|
103
176
|
// OINOLog.debug("OINODbApi.doGet sql", {sql:sql})
|
|
104
177
|
try {
|
|
105
178
|
const sql_res = await this.db.sqlSelect(sql);
|
|
@@ -201,19 +274,31 @@ class OINODbApi {
|
|
|
201
274
|
*
|
|
202
275
|
* @param method HTTP verb (uppercase)
|
|
203
276
|
* @param id URL id of the REST request
|
|
204
|
-
* @param body HTTP body data as string
|
|
277
|
+
* @param body HTTP body data as either serialized string or unserialized JS object / OINODataRow-array
|
|
205
278
|
* @param params HTTP URL parameters as key-value-pairs
|
|
206
279
|
*
|
|
207
280
|
*/
|
|
208
|
-
async doRequest(method, id, body, params) {
|
|
281
|
+
async doRequest(method, id, body, params = API_EMPTY_PARAMS) {
|
|
209
282
|
index_js_1.OINOBenchmark.start("doRequest");
|
|
210
|
-
|
|
211
|
-
|
|
283
|
+
// OINOLog.debug("OINODbApi.doRequest enter", {method:method, id:id, body:body, params:params})
|
|
284
|
+
let result = new OINODbApiResult(params);
|
|
285
|
+
let rows = [];
|
|
286
|
+
if ((method == "POST") || (method == "PUT")) {
|
|
287
|
+
if (Array.isArray(body)) {
|
|
288
|
+
rows = body;
|
|
289
|
+
}
|
|
290
|
+
else if (typeof (body) == "object") {
|
|
291
|
+
rows = [index_js_1.OINODbFactory.createRowFromObject(this.datamodel, body)];
|
|
292
|
+
}
|
|
293
|
+
else if (typeof (body) == "string") {
|
|
294
|
+
rows = index_js_1.OINODbFactory.createRows(this.datamodel, body, params);
|
|
295
|
+
}
|
|
296
|
+
// OINOLog.debug("OINODbApi.doRequest - OINODataRow rows", {rows:rows})
|
|
297
|
+
}
|
|
212
298
|
if (method == "GET") {
|
|
213
299
|
await this._doGet(result, id, params);
|
|
214
300
|
}
|
|
215
301
|
else if (method == "PUT") {
|
|
216
|
-
const rows = index_js_1.OINODbFactory.createRows(this.datamodel, body, params);
|
|
217
302
|
if (!id) {
|
|
218
303
|
result.setError(400, "HTTP PUT method requires an URL ID for the row that is updated!", "DoRequest");
|
|
219
304
|
}
|
|
@@ -230,7 +315,6 @@ class OINODbApi {
|
|
|
230
315
|
}
|
|
231
316
|
}
|
|
232
317
|
else if (method == "POST") {
|
|
233
|
-
const rows = index_js_1.OINODbFactory.createRows(this.datamodel, body, params);
|
|
234
318
|
if (id) {
|
|
235
319
|
result.setError(400, "HTTP POST method must not have an URL ID as it does not target an existing row but creates a new one!", "DoRequest");
|
|
236
320
|
}
|
|
@@ -235,8 +235,11 @@ class OINONumberDataField extends OINODbDataField {
|
|
|
235
235
|
*
|
|
236
236
|
*/
|
|
237
237
|
deserializeCell(value) {
|
|
238
|
-
if (
|
|
239
|
-
return
|
|
238
|
+
if (value === undefined) {
|
|
239
|
+
return undefined;
|
|
240
|
+
}
|
|
241
|
+
else if ((value == "") || (value == null)) {
|
|
242
|
+
return null;
|
|
240
243
|
}
|
|
241
244
|
else {
|
|
242
245
|
return Number.parseFloat(value);
|
|
@@ -241,7 +241,7 @@ class OINODbDataModel {
|
|
|
241
241
|
result += "\nLIMIT " + limit_sql;
|
|
242
242
|
}
|
|
243
243
|
result += ";";
|
|
244
|
-
|
|
244
|
+
// OINOLog.debug("OINODbDataModel.printSqlSelect", {result:result})
|
|
245
245
|
return result;
|
|
246
246
|
}
|
|
247
247
|
/**
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
*/
|
|
7
7
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
8
|
exports.OINODbFactory = void 0;
|
|
9
|
+
const OINOResult_js_1 = require("../../types/src/OINOResult.js");
|
|
9
10
|
const index_js_1 = require("./index.js");
|
|
10
11
|
/**
|
|
11
12
|
* Static factory class for easily creating things based on data
|
|
@@ -58,8 +59,21 @@ class OINODbFactory {
|
|
|
58
59
|
* @param request HTTP Request
|
|
59
60
|
*/
|
|
60
61
|
static createParamsFromRequest(request) {
|
|
61
|
-
let result = { sqlParams: {} };
|
|
62
62
|
const url = new URL(request.url);
|
|
63
|
+
let sql_params = {};
|
|
64
|
+
const filter = url.searchParams.get(index_js_1.OINODbConfig.OINODB_SQL_FILTER_PARAM);
|
|
65
|
+
if (filter) {
|
|
66
|
+
sql_params.filter = index_js_1.OINODbSqlFilter.parse(filter);
|
|
67
|
+
}
|
|
68
|
+
const order = url.searchParams.get(index_js_1.OINODbConfig.OINODB_SQL_ORDER_PARAM);
|
|
69
|
+
if (order) {
|
|
70
|
+
sql_params.order = index_js_1.OINODbSqlOrder.parse(order);
|
|
71
|
+
}
|
|
72
|
+
const limit = url.searchParams.get(index_js_1.OINODbConfig.OINODB_SQL_LIMIT_PARAM);
|
|
73
|
+
if (limit) {
|
|
74
|
+
sql_params.limit = index_js_1.OINODbSqlLimit.parse(limit);
|
|
75
|
+
}
|
|
76
|
+
let result = { sqlParams: sql_params };
|
|
63
77
|
const content_type = request.headers.get("content-type");
|
|
64
78
|
if (content_type == index_js_1.OINOContentType.csv) {
|
|
65
79
|
result.requestType = index_js_1.OINOContentType.csv;
|
|
@@ -87,42 +101,17 @@ class OINODbFactory {
|
|
|
87
101
|
if (result.responseType === undefined) {
|
|
88
102
|
result.responseType = index_js_1.OINOContentType.json;
|
|
89
103
|
}
|
|
90
|
-
const
|
|
91
|
-
if (
|
|
92
|
-
result.
|
|
104
|
+
const last_modified = request.headers.get("if-modified-since");
|
|
105
|
+
if (last_modified) {
|
|
106
|
+
result.lastModified = new Date(last_modified).getTime();
|
|
93
107
|
}
|
|
94
|
-
const
|
|
95
|
-
if (
|
|
96
|
-
result.
|
|
97
|
-
}
|
|
98
|
-
const limit = url.searchParams.get(index_js_1.OINODbConfig.OINODB_SQL_LIMIT_PARAM);
|
|
99
|
-
if (limit) {
|
|
100
|
-
result.sqlParams.limit = new index_js_1.OINODbSqlLimit(limit);
|
|
108
|
+
const etags = request.headers.get("if-none-match")?.split(',').map(e => e.trim());
|
|
109
|
+
if (etags) {
|
|
110
|
+
result.etags = etags;
|
|
101
111
|
}
|
|
102
112
|
// OINOLog.debug("createParamsFromRequest", {params:result})
|
|
103
113
|
return result;
|
|
104
114
|
}
|
|
105
|
-
/**
|
|
106
|
-
* Creates a HTTP Response from API results.
|
|
107
|
-
*
|
|
108
|
-
* @param apiResult API results
|
|
109
|
-
* @param requestParams API request parameters
|
|
110
|
-
* @param responseHeaders Headers to include in the response
|
|
111
|
-
*
|
|
112
|
-
*/
|
|
113
|
-
static createResponseFromApiResult(apiResult, requestParams, responseHeaders = {}) {
|
|
114
|
-
let response = null;
|
|
115
|
-
if (apiResult.success && apiResult.data) {
|
|
116
|
-
response = new Response(apiResult.data.writeString(requestParams.responseType), { status: apiResult.statusCode, statusText: apiResult.statusMessage, headers: responseHeaders });
|
|
117
|
-
}
|
|
118
|
-
else {
|
|
119
|
-
response = new Response(JSON.stringify(apiResult), { status: apiResult.statusCode, statusText: apiResult.statusMessage, headers: responseHeaders });
|
|
120
|
-
}
|
|
121
|
-
for (let i = 0; i < apiResult.messages.length; i++) {
|
|
122
|
-
response.headers.set('X-OINO-MESSAGE-' + i, apiResult.messages[i]);
|
|
123
|
-
}
|
|
124
|
-
return response;
|
|
125
|
-
}
|
|
126
115
|
/**
|
|
127
116
|
* Creates HTML Response from API modelset.
|
|
128
117
|
*
|
|
@@ -131,7 +120,7 @@ class OINODbFactory {
|
|
|
131
120
|
*
|
|
132
121
|
*/
|
|
133
122
|
static createHtmlFromData(modelset, template) {
|
|
134
|
-
let
|
|
123
|
+
let html = "";
|
|
135
124
|
const dataset = modelset.dataset;
|
|
136
125
|
const datamodel = modelset.datamodel;
|
|
137
126
|
while (!dataset.isEof()) {
|
|
@@ -151,44 +140,16 @@ class OINODbFactory {
|
|
|
151
140
|
html_row = html_row.replaceAll('###' + f.name + '###', index_js_1.OINOStr.encode(value, index_js_1.OINOContentType.html));
|
|
152
141
|
}
|
|
153
142
|
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));
|
|
154
|
-
|
|
143
|
+
html += html_row + "\r\n";
|
|
155
144
|
dataset.next();
|
|
156
145
|
}
|
|
157
|
-
|
|
158
|
-
}
|
|
159
|
-
/**
|
|
160
|
-
* Creates HTML Response from a row id.
|
|
161
|
-
*
|
|
162
|
-
* @param oinoId OINO id
|
|
163
|
-
* @param template HTML template
|
|
164
|
-
*
|
|
165
|
-
*/
|
|
166
|
-
static createHtmlFromOinoId(oinoId, template) {
|
|
167
|
-
let result = template.replaceAll('###' + index_js_1.OINODbConfig.OINODB_ID_FIELD + '###', index_js_1.OINOStr.encode(oinoId, index_js_1.OINOContentType.html));
|
|
168
|
-
return result;
|
|
169
|
-
}
|
|
170
|
-
/**
|
|
171
|
-
* Creates HTML Response from object properties.
|
|
172
|
-
*
|
|
173
|
-
* @param object object
|
|
174
|
-
* @param template HTML template
|
|
175
|
-
*
|
|
176
|
-
*/
|
|
177
|
-
static createHtmlFromObject(object, template) {
|
|
178
|
-
let result = template;
|
|
179
|
-
for (let key in object) {
|
|
180
|
-
const value = object[key];
|
|
181
|
-
if (value) {
|
|
182
|
-
result = result.replaceAll('###' + key + '###', index_js_1.OINOStr.encode(value.toString(), index_js_1.OINOContentType.html));
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
result = result.replace(/###[^#]*###/g, "");
|
|
146
|
+
const result = new OINOResult_js_1.OINOHttpResult(html);
|
|
186
147
|
return result;
|
|
187
148
|
}
|
|
188
149
|
/**
|
|
189
150
|
* Creates HTML Response from API result.
|
|
190
151
|
*
|
|
191
|
-
* @param
|
|
152
|
+
* @param result OINOResult-object
|
|
192
153
|
* @param template HTML template
|
|
193
154
|
* @param includeErrorMessages include debug messages in result
|
|
194
155
|
* @param includeWarningMessages include debug messages in result
|
|
@@ -196,30 +157,31 @@ class OINODbFactory {
|
|
|
196
157
|
* @param includeDebugMessages include debug messages in result
|
|
197
158
|
*
|
|
198
159
|
*/
|
|
199
|
-
static
|
|
200
|
-
let
|
|
201
|
-
|
|
202
|
-
|
|
160
|
+
static createHtmlNotificationFromResult(result, template, includeErrorMessages = false, includeWarningMessages = false, includeInfoMessages = false, includeDebugMessages = false) {
|
|
161
|
+
let html = template;
|
|
162
|
+
html = html.replaceAll('###statusCode###', index_js_1.OINOStr.encode(result.statusCode.toString(), index_js_1.OINOContentType.html));
|
|
163
|
+
html = html.replaceAll('###statusMessage###', index_js_1.OINOStr.encode(result.statusMessage.toString(), index_js_1.OINOContentType.html));
|
|
203
164
|
let messages = "";
|
|
204
|
-
for (let i = 0; i <
|
|
205
|
-
if (includeErrorMessages &&
|
|
206
|
-
messages += "<li>" + index_js_1.OINOStr.encode(
|
|
165
|
+
for (let i = 0; i < result.messages.length; i++) {
|
|
166
|
+
if (includeErrorMessages && result.messages[i].startsWith(index_js_1.OINO_ERROR_PREFIX)) {
|
|
167
|
+
messages += "<li>" + index_js_1.OINOStr.encode(result.messages[i], index_js_1.OINOContentType.html) + "</li>";
|
|
207
168
|
}
|
|
208
|
-
if (includeWarningMessages &&
|
|
209
|
-
messages += "<li>" + index_js_1.OINOStr.encode(
|
|
169
|
+
if (includeWarningMessages && result.messages[i].startsWith(index_js_1.OINO_WARNING_PREFIX)) {
|
|
170
|
+
messages += "<li>" + index_js_1.OINOStr.encode(result.messages[i], index_js_1.OINOContentType.html) + "</li>";
|
|
210
171
|
}
|
|
211
|
-
if (includeInfoMessages &&
|
|
212
|
-
messages += "<li>" + index_js_1.OINOStr.encode(
|
|
172
|
+
if (includeInfoMessages && result.messages[i].startsWith(index_js_1.OINO_INFO_PREFIX)) {
|
|
173
|
+
messages += "<li>" + index_js_1.OINOStr.encode(result.messages[i], index_js_1.OINOContentType.html) + "</li>";
|
|
213
174
|
}
|
|
214
|
-
if (includeDebugMessages &&
|
|
215
|
-
messages += "<li>" + index_js_1.OINOStr.encode(
|
|
175
|
+
if (includeDebugMessages && result.messages[i].startsWith(index_js_1.OINO_DEBUG_PREFIX)) {
|
|
176
|
+
messages += "<li>" + index_js_1.OINOStr.encode(result.messages[i], index_js_1.OINOContentType.html) + "</li>";
|
|
216
177
|
}
|
|
217
178
|
}
|
|
218
179
|
if (messages) {
|
|
219
|
-
|
|
180
|
+
html = html.replaceAll('###messages###', "<ul>" + messages + "</ul>");
|
|
220
181
|
}
|
|
221
|
-
|
|
222
|
-
|
|
182
|
+
html = html.replace(/###[^#]*###/g, "");
|
|
183
|
+
const http_result = new OINOResult_js_1.OINOHttpResult(html);
|
|
184
|
+
return http_result;
|
|
223
185
|
}
|
|
224
186
|
static _findCsvLineEnd(csvData, start) {
|
|
225
187
|
const n = csvData.length;
|
|
@@ -496,7 +458,7 @@ class OINODbFactory {
|
|
|
496
458
|
start = end;
|
|
497
459
|
end = this._findMultipartBoundary(data, multipartBoundary, start);
|
|
498
460
|
}
|
|
499
|
-
|
|
461
|
+
// OINOLog.debug("createRowFromFormdata: next row", {row:row})
|
|
500
462
|
result.push(row);
|
|
501
463
|
return result;
|
|
502
464
|
}
|
|
@@ -507,7 +469,7 @@ class OINODbFactory {
|
|
|
507
469
|
const data_parts = data.trim().split('&');
|
|
508
470
|
for (let i = 0; i < data_parts.length; i++) {
|
|
509
471
|
const param_parts = data_parts[i].split('=');
|
|
510
|
-
|
|
472
|
+
// OINOLog.debug("createRowFromUrlencoded: next param", {param_parts:param_parts})
|
|
511
473
|
if (param_parts.length == 2) {
|
|
512
474
|
const key = index_js_1.OINOStr.decodeUrlencode(param_parts[0]) || "";
|
|
513
475
|
const field_index = datamodel.findFieldIndexByName(key);
|
|
@@ -525,7 +487,7 @@ class OINODbFactory {
|
|
|
525
487
|
}
|
|
526
488
|
// const value = requestParams[]
|
|
527
489
|
}
|
|
528
|
-
console.log("createRowFromUrlencoded: next row=" + row)
|
|
490
|
+
// console.log("createRowFromUrlencoded: next row=" + row)
|
|
529
491
|
result.push(row);
|
|
530
492
|
return result;
|
|
531
493
|
}
|
|
@@ -559,5 +521,21 @@ class OINODbFactory {
|
|
|
559
521
|
return [];
|
|
560
522
|
}
|
|
561
523
|
}
|
|
524
|
+
/**
|
|
525
|
+
* Create one data row from javascript object based on the datamodel.
|
|
526
|
+
* NOTE! Data assumed to be unserialized i.e. of the native type (string, number, boolean, Buffer)
|
|
527
|
+
*
|
|
528
|
+
* @param datamodel datamodel of the api
|
|
529
|
+
* @param data data as javascript object
|
|
530
|
+
*
|
|
531
|
+
*/
|
|
532
|
+
static createRowFromObject(datamodel, data) {
|
|
533
|
+
const fields = datamodel.fields;
|
|
534
|
+
let result = new Array(fields.length);
|
|
535
|
+
for (let i = 0; i < fields.length; i++) {
|
|
536
|
+
result[i] = data[fields[i].name];
|
|
537
|
+
}
|
|
538
|
+
return result;
|
|
539
|
+
}
|
|
562
540
|
}
|
|
563
541
|
exports.OINODbFactory = OINODbFactory;
|
|
@@ -173,7 +173,7 @@ class OINODbSqlFilter {
|
|
|
173
173
|
result += this._rightSide;
|
|
174
174
|
}
|
|
175
175
|
}
|
|
176
|
-
|
|
176
|
+
// OINOLog.debug("OINOFilter.toSql", {result:result})
|
|
177
177
|
return "(" + result + ")";
|
|
178
178
|
}
|
|
179
179
|
}
|
|
@@ -185,26 +185,47 @@ exports.OINODbSqlFilter = OINODbSqlFilter;
|
|
|
185
185
|
class OINODbSqlOrder {
|
|
186
186
|
static _orderColumnRegex = /^\s*(\w+)\s?(ASC|DESC)?\s*?$/i;
|
|
187
187
|
_columns;
|
|
188
|
-
|
|
188
|
+
_descending;
|
|
189
189
|
/**
|
|
190
190
|
* Constructor for `OINODbSqlOrder`.
|
|
191
191
|
*
|
|
192
|
-
* @param
|
|
192
|
+
* @param column_or_array single or array of columns to order on
|
|
193
|
+
* @param descending_or_array single or array of booleans if ordes is descending
|
|
193
194
|
*
|
|
194
195
|
*/
|
|
195
|
-
constructor(
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
196
|
+
constructor(column_or_array, descending_or_array) {
|
|
197
|
+
index_js_1.OINOLog.debug("OINODbSqlOrder.constructor", { columns: column_or_array, directions: descending_or_array });
|
|
198
|
+
if (Array.isArray(column_or_array)) {
|
|
199
|
+
this._columns = column_or_array;
|
|
200
|
+
}
|
|
201
|
+
else {
|
|
202
|
+
this._columns = [column_or_array];
|
|
203
|
+
}
|
|
204
|
+
if (Array.isArray(descending_or_array)) {
|
|
205
|
+
this._descending = descending_or_array;
|
|
206
|
+
}
|
|
207
|
+
else {
|
|
208
|
+
this._descending = [descending_or_array];
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
/**
|
|
212
|
+
* Constructor for `OINODbSqlOrder` as parser of http parameter.
|
|
213
|
+
*
|
|
214
|
+
* @param orderString string representation of ordering from HTTP-request
|
|
215
|
+
*
|
|
216
|
+
*/
|
|
217
|
+
static parse(orderString) {
|
|
218
|
+
let columns = [];
|
|
219
|
+
let directions = [];
|
|
199
220
|
const column_strings = orderString.split(',');
|
|
200
221
|
for (let i = 0; i < column_strings.length; i++) {
|
|
201
222
|
let match = OINODbSqlOrder._orderColumnRegex.exec(column_strings[i]);
|
|
202
223
|
if (match != null) {
|
|
203
|
-
|
|
204
|
-
|
|
224
|
+
columns.push(match[1]);
|
|
225
|
+
directions.push((match[2] || "DESC").toUpperCase() == "DESC");
|
|
205
226
|
}
|
|
206
227
|
}
|
|
207
|
-
|
|
228
|
+
return new OINODbSqlOrder(columns, directions);
|
|
208
229
|
}
|
|
209
230
|
/**
|
|
210
231
|
* Does filter contain any valid conditions.
|
|
@@ -231,7 +252,13 @@ class OINODbSqlOrder {
|
|
|
231
252
|
if (result) {
|
|
232
253
|
result += ",";
|
|
233
254
|
}
|
|
234
|
-
result += dataModel.api.db.printSqlColumnname(field.name) + " "
|
|
255
|
+
result += dataModel.api.db.printSqlColumnname(field.name) + " ";
|
|
256
|
+
if (this._descending[i]) {
|
|
257
|
+
result += "DESC";
|
|
258
|
+
}
|
|
259
|
+
else {
|
|
260
|
+
result += "ASC";
|
|
261
|
+
}
|
|
235
262
|
}
|
|
236
263
|
}
|
|
237
264
|
// OINOLog.debug("OINODbSqlOrder.toSql", {result:result})
|
|
@@ -249,12 +276,25 @@ class OINODbSqlLimit {
|
|
|
249
276
|
/**
|
|
250
277
|
* Constructor for `OINODbSqlLimit`.
|
|
251
278
|
*
|
|
252
|
-
* @param
|
|
279
|
+
* @param limit maximum number of items to return
|
|
280
|
+
*
|
|
281
|
+
*/
|
|
282
|
+
constructor(limit) {
|
|
283
|
+
this._limit = limit;
|
|
284
|
+
}
|
|
285
|
+
/**
|
|
286
|
+
* Constructor for `OINODbSqlLimit` as parser of http parameter.
|
|
287
|
+
*
|
|
288
|
+
* @param limitString string representation of limit from HTTP-request
|
|
253
289
|
*
|
|
254
290
|
*/
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
291
|
+
static parse(limitString) {
|
|
292
|
+
try {
|
|
293
|
+
return new OINODbSqlLimit(Number.parseInt(limitString));
|
|
294
|
+
}
|
|
295
|
+
catch {
|
|
296
|
+
return new OINODbSqlLimit(-1);
|
|
297
|
+
}
|
|
258
298
|
}
|
|
259
299
|
/**
|
|
260
300
|
* Does filter contain any valid conditions.
|
package/dist/cjs/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.OINODB_EMPTY_ROWS = exports.OINODB_EMPTY_ROW = exports.OINODbSwagger = exports.OINODbFactory = exports.OINODbConfig = exports.OINODbSqlBooleanOperation = exports.OINODbSqlLimit = exports.OINODbSqlComparison = exports.OINODbSqlOrder = exports.OINODbSqlFilter = exports.OINODbMemoryDataSet = exports.OINODbDataSet = exports.OINODb = exports.OINODatetimeDataField = exports.OINOBlobDataField = exports.OINOStringDataField = exports.OINONumberDataField = exports.OINOBooleanDataField = exports.OINODbDataField = exports.OINODbModelSet = exports.OINODbDataModel = exports.OINODbApi = exports.OINODbApiResult = exports.OINOResult = exports.OINOConsoleLog = exports.OINOLogLevel = exports.OINOLog = exports.OINOBenchmark = exports.OINOStr = exports.OINO_DEBUG_PREFIX = exports.OINO_INFO_PREFIX = exports.OINO_WARNING_PREFIX = exports.OINO_ERROR_PREFIX = exports.OINOContentType = void 0;
|
|
3
|
+
exports.OINODB_EMPTY_ROWS = exports.OINODB_EMPTY_ROW = exports.OINODbSwagger = exports.OINODbFactory = exports.OINODbConfig = exports.OINODbSqlBooleanOperation = exports.OINODbSqlLimit = exports.OINODbSqlComparison = exports.OINODbSqlOrder = exports.OINODbSqlFilter = exports.OINODbMemoryDataSet = exports.OINODbDataSet = exports.OINODb = exports.OINODatetimeDataField = exports.OINOBlobDataField = exports.OINOStringDataField = exports.OINONumberDataField = exports.OINOBooleanDataField = exports.OINODbDataField = exports.OINODbModelSet = exports.OINODbDataModel = exports.OINODbApi = exports.OINODbHtmlTemplate = exports.OINODbApiResult = exports.OINOHtmlTemplate = exports.OINOHttpResult = exports.OINOResult = exports.OINOConsoleLog = exports.OINOLogLevel = exports.OINOLog = exports.OINOBenchmark = exports.OINOStr = exports.OINO_DEBUG_PREFIX = exports.OINO_INFO_PREFIX = exports.OINO_WARNING_PREFIX = exports.OINO_ERROR_PREFIX = exports.OINOContentType = void 0;
|
|
4
4
|
const types_1 = require("@oino-ts/types");
|
|
5
5
|
Object.defineProperty(exports, "OINOContentType", { enumerable: true, get: function () { return types_1.OINOContentType; } });
|
|
6
6
|
var types_2 = require("@oino-ts/types");
|
|
@@ -14,8 +14,11 @@ Object.defineProperty(exports, "OINOLog", { enumerable: true, get: function () {
|
|
|
14
14
|
Object.defineProperty(exports, "OINOLogLevel", { enumerable: true, get: function () { return types_2.OINOLogLevel; } });
|
|
15
15
|
Object.defineProperty(exports, "OINOConsoleLog", { enumerable: true, get: function () { return types_2.OINOConsoleLog; } });
|
|
16
16
|
Object.defineProperty(exports, "OINOResult", { enumerable: true, get: function () { return types_2.OINOResult; } });
|
|
17
|
+
Object.defineProperty(exports, "OINOHttpResult", { enumerable: true, get: function () { return types_2.OINOHttpResult; } });
|
|
18
|
+
Object.defineProperty(exports, "OINOHtmlTemplate", { enumerable: true, get: function () { return types_2.OINOHtmlTemplate; } });
|
|
17
19
|
var OINODbApi_js_1 = require("./OINODbApi.js");
|
|
18
20
|
Object.defineProperty(exports, "OINODbApiResult", { enumerable: true, get: function () { return OINODbApi_js_1.OINODbApiResult; } });
|
|
21
|
+
Object.defineProperty(exports, "OINODbHtmlTemplate", { enumerable: true, get: function () { return OINODbApi_js_1.OINODbHtmlTemplate; } });
|
|
19
22
|
Object.defineProperty(exports, "OINODbApi", { enumerable: true, get: function () { return OINODbApi_js_1.OINODbApi; } });
|
|
20
23
|
var OINODbDataModel_js_1 = require("./OINODbDataModel.js");
|
|
21
24
|
Object.defineProperty(exports, "OINODbDataModel", { enumerable: true, get: function () { return OINODbDataModel_js_1.OINODbDataModel; } });
|