@oino-ts/db 0.21.1 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/OINODb.js +6 -144
- package/dist/cjs/OINODbApi.js +50 -318
- package/dist/cjs/OINODbConfig.js +10 -10
- package/dist/cjs/OINODbConstants.js +10 -0
- package/dist/cjs/OINODbDataField.js +28 -70
- package/dist/cjs/OINODbDataModel.js +29 -143
- package/dist/cjs/OINODbFactory.js +2 -2
- package/dist/cjs/OINODbModelSet.js +23 -23
- package/dist/cjs/OINODbQueryParams.js +201 -0
- package/dist/cjs/index.js +12 -41
- package/dist/esm/OINODb.js +6 -142
- package/dist/esm/OINODbApi.js +49 -314
- package/dist/esm/OINODbConstants.js +7 -0
- package/dist/esm/OINODbDataModel.js +29 -143
- package/dist/esm/OINODbFactory.js +1 -1
- package/dist/esm/OINODbQueryParams.js +194 -0
- package/dist/esm/index.js +4 -14
- package/dist/types/OINODb.d.ts +6 -173
- package/dist/types/OINODbApi.d.ts +18 -104
- package/dist/types/OINODbConstants.d.ts +23 -0
- package/dist/types/OINODbDataModel.d.ts +7 -61
- package/dist/types/OINODbFactory.d.ts +5 -2
- package/dist/types/OINODbQueryParams.d.ts +72 -0
- package/dist/types/index.d.ts +4 -108
- package/package.json +37 -37
- package/src/OINODb.ts +99 -348
- package/src/OINODbApi.test.ts +507 -498
- package/src/OINODbApi.ts +389 -667
- package/src/OINODbConstants.ts +32 -0
- package/src/OINODbDataModel.ts +191 -307
- package/src/OINODbFactory.ts +73 -68
- package/src/OINODbQueryParams.ts +203 -0
- package/src/index.ts +6 -118
- package/src/OINODbConfig.ts +0 -98
- package/src/OINODbDataField.ts +0 -405
- package/src/OINODbModelSet.ts +0 -353
- package/src/OINODbParser.ts +0 -438
- package/src/OINODbSqlParams.ts +0 -593
- package/src/OINODbSwagger.ts +0 -209
package/dist/cjs/OINODb.js
CHANGED
|
@@ -5,16 +5,15 @@
|
|
|
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.
|
|
8
|
+
exports.OINODb = void 0;
|
|
9
9
|
const common_1 = require("@oino-ts/common");
|
|
10
|
-
const index_js_1 = require("./index.js");
|
|
11
10
|
/**
|
|
12
11
|
* Base class for database abstraction, implementing methods for connecting, making queries and parsing/formatting data
|
|
13
12
|
* between SQL and serialization formats.
|
|
14
13
|
*
|
|
15
14
|
*/
|
|
16
|
-
class OINODb {
|
|
17
|
-
|
|
15
|
+
class OINODb extends common_1.OINODataSource {
|
|
16
|
+
dbParams;
|
|
18
17
|
/** Name of the database */
|
|
19
18
|
name;
|
|
20
19
|
isConnected = false;
|
|
@@ -24,8 +23,9 @@ class OINODb {
|
|
|
24
23
|
* @param params database parameters
|
|
25
24
|
*/
|
|
26
25
|
constructor(params) {
|
|
27
|
-
|
|
28
|
-
this.
|
|
26
|
+
super();
|
|
27
|
+
this.dbParams = { ...params }; // make a shallow copy of params so that changes to them do not affect the original object
|
|
28
|
+
this.name = this.dbParams.database;
|
|
29
29
|
}
|
|
30
30
|
/**
|
|
31
31
|
* Print SQL select statement with DB specific formatting.
|
|
@@ -74,141 +74,3 @@ class OINODb {
|
|
|
74
74
|
}
|
|
75
75
|
}
|
|
76
76
|
exports.OINODb = OINODb;
|
|
77
|
-
/**
|
|
78
|
-
* Base class for SQL results that can be asynchronously iterated (but
|
|
79
|
-
* not necessarity rewinded). Idea is to handle database specific mechanisms
|
|
80
|
-
* for returning and formatting conventions in the database specific
|
|
81
|
-
* implementation. Data might be in memory or streamed in chunks and
|
|
82
|
-
* `OINODbDataSet` will serve it out consistently.
|
|
83
|
-
*
|
|
84
|
-
*/
|
|
85
|
-
class OINODbDataSet extends common_1.OINOResult {
|
|
86
|
-
_data;
|
|
87
|
-
/** Error messages */
|
|
88
|
-
messages;
|
|
89
|
-
/**
|
|
90
|
-
* Constructor for `OINODbDataSet`.
|
|
91
|
-
*
|
|
92
|
-
* @param data internal database specific data type (constructor will throw if invalid)
|
|
93
|
-
* @param messages error messages from SQL-query
|
|
94
|
-
*
|
|
95
|
-
*/
|
|
96
|
-
constructor(data, messages = []) {
|
|
97
|
-
super();
|
|
98
|
-
this._data = data;
|
|
99
|
-
this.messages = messages;
|
|
100
|
-
}
|
|
101
|
-
/**
|
|
102
|
-
* Checks if the messages contain errors.
|
|
103
|
-
*
|
|
104
|
-
*/
|
|
105
|
-
hasErrors() {
|
|
106
|
-
for (let i = 0; i < this.messages.length; i++) {
|
|
107
|
-
if (this.messages[i].startsWith(common_1.OINO_ERROR_PREFIX)) {
|
|
108
|
-
return true;
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
return false;
|
|
112
|
-
}
|
|
113
|
-
/**
|
|
114
|
-
* Checks if the messages contain errors.
|
|
115
|
-
*
|
|
116
|
-
*/
|
|
117
|
-
getFirstError() {
|
|
118
|
-
for (let i = 0; i < this.messages.length; i++) {
|
|
119
|
-
if (this.messages[i].startsWith(common_1.OINO_ERROR_PREFIX)) {
|
|
120
|
-
return this.messages[i];
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
return "";
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
exports.OINODbDataSet = OINODbDataSet;
|
|
127
|
-
/**
|
|
128
|
-
* Generic in memory implementation of a data set where data is an array of rows. Used
|
|
129
|
-
* by BunSqlite and automated testing. Can be rewinded.
|
|
130
|
-
*
|
|
131
|
-
*/
|
|
132
|
-
class OINODbMemoryDataSet extends OINODbDataSet {
|
|
133
|
-
_rows;
|
|
134
|
-
_currentRow;
|
|
135
|
-
_eof;
|
|
136
|
-
/**
|
|
137
|
-
* Constructor of `OINODbMemoryDataSet`.
|
|
138
|
-
*
|
|
139
|
-
* @param data data as OINODataRow[] (constructor will throw if invalid)
|
|
140
|
-
* @param errors error messages from SQL-query
|
|
141
|
-
*
|
|
142
|
-
*/
|
|
143
|
-
constructor(data, errors = []) {
|
|
144
|
-
super(data, errors);
|
|
145
|
-
if ((data == null) || !(Array.isArray(data))) {
|
|
146
|
-
throw new Error(common_1.OINO_ERROR_PREFIX + ": Data needs to be compatible with OINORow[]!"); // TODO: maybe check all rows
|
|
147
|
-
}
|
|
148
|
-
this._rows = data;
|
|
149
|
-
if (this.isEmpty()) {
|
|
150
|
-
this._currentRow = -1;
|
|
151
|
-
this._eof = true;
|
|
152
|
-
}
|
|
153
|
-
else {
|
|
154
|
-
this._currentRow = 0;
|
|
155
|
-
this._eof = false;
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
/**
|
|
159
|
-
* Is data set empty.
|
|
160
|
-
*
|
|
161
|
-
*/
|
|
162
|
-
isEmpty() {
|
|
163
|
-
return (this._rows.length == 0);
|
|
164
|
-
}
|
|
165
|
-
/**
|
|
166
|
-
* Is there no more content, i.e. either dataset is empty or we have moved beyond last line
|
|
167
|
-
*
|
|
168
|
-
*/
|
|
169
|
-
isEof() {
|
|
170
|
-
return (this._eof);
|
|
171
|
-
}
|
|
172
|
-
/**
|
|
173
|
-
* Attempts to moves dataset to the next row, possibly waiting for more data to become available. Returns !isEof().
|
|
174
|
-
*
|
|
175
|
-
*/
|
|
176
|
-
async next() {
|
|
177
|
-
if (this._currentRow < this._rows.length - 1) {
|
|
178
|
-
this._currentRow = this._currentRow + 1;
|
|
179
|
-
}
|
|
180
|
-
else {
|
|
181
|
-
this._eof = true;
|
|
182
|
-
}
|
|
183
|
-
return Promise.resolve(!this._eof);
|
|
184
|
-
}
|
|
185
|
-
/**
|
|
186
|
-
* Gets current row of data.
|
|
187
|
-
*
|
|
188
|
-
*/
|
|
189
|
-
getRow() {
|
|
190
|
-
if ((this._currentRow >= 0) && (this._currentRow < this._rows.length)) {
|
|
191
|
-
return this._rows[this._currentRow];
|
|
192
|
-
}
|
|
193
|
-
else {
|
|
194
|
-
return index_js_1.OINODB_EMPTY_ROW;
|
|
195
|
-
}
|
|
196
|
-
}
|
|
197
|
-
/**
|
|
198
|
-
* Gets all rows of data.
|
|
199
|
-
*
|
|
200
|
-
*/
|
|
201
|
-
async getAllRows() {
|
|
202
|
-
return this._rows; // at the moment theres no result streaming, so we can just return the rows
|
|
203
|
-
}
|
|
204
|
-
/**
|
|
205
|
-
* Rewinds data set to the first row, returns !isEof().
|
|
206
|
-
*
|
|
207
|
-
*/
|
|
208
|
-
first() {
|
|
209
|
-
this._currentRow = 0;
|
|
210
|
-
this._eof = this._rows.length == 0;
|
|
211
|
-
return !this._eof;
|
|
212
|
-
}
|
|
213
|
-
}
|
|
214
|
-
exports.OINODbMemoryDataSet = OINODbMemoryDataSet;
|
package/dist/cjs/OINODbApi.js
CHANGED
|
@@ -5,281 +5,19 @@
|
|
|
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 =
|
|
9
|
-
const node_buffer_1 = require("node:buffer");
|
|
8
|
+
exports.OINODbApi = void 0;
|
|
10
9
|
const common_1 = require("@oino-ts/common");
|
|
11
|
-
const index_js_1 = require("./index.js");
|
|
12
|
-
const hashid_1 = require("@oino-ts/hashid");
|
|
13
|
-
class OINODbApiRequest extends common_1.OINOHttpRequest {
|
|
14
|
-
rowId;
|
|
15
|
-
rowData;
|
|
16
|
-
sqlParams;
|
|
17
|
-
constructor(init) {
|
|
18
|
-
super(init);
|
|
19
|
-
this.rowId = init?.rowId || "";
|
|
20
|
-
this.rowData = init?.rowData || null; // rowData is not compatible with OINOHttpRequest body so it's not automatically set, caller can set both if needed
|
|
21
|
-
this.sqlParams = init?.sqlParams || {};
|
|
22
|
-
if (init?.filter) {
|
|
23
|
-
if (init.filter instanceof index_js_1.OINODbSqlFilter) {
|
|
24
|
-
this.sqlParams.filter = init.filter;
|
|
25
|
-
}
|
|
26
|
-
else {
|
|
27
|
-
this.sqlParams.filter = index_js_1.OINODbSqlFilter.parse(init.filter);
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
if (!this.sqlParams.filter) {
|
|
31
|
-
const filter_params = this.url?.searchParams.getAll(index_js_1.OINODbConfig.OINODB_SQL_FILTER_PARAM) || [];
|
|
32
|
-
for (let i = 0; i < filter_params.length; i++) {
|
|
33
|
-
const f = index_js_1.OINODbSqlFilter.parse(filter_params[i]);
|
|
34
|
-
if (i > 0) {
|
|
35
|
-
this.sqlParams.filter = index_js_1.OINODbSqlFilter.combine(this.sqlParams.filter, index_js_1.OINODbSqlBooleanOperation.and, f);
|
|
36
|
-
}
|
|
37
|
-
else {
|
|
38
|
-
this.sqlParams.filter = f;
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
if (init?.order) {
|
|
43
|
-
if (init.order instanceof index_js_1.OINODbSqlOrder) {
|
|
44
|
-
this.sqlParams.order = init.order;
|
|
45
|
-
}
|
|
46
|
-
else {
|
|
47
|
-
this.sqlParams.order = index_js_1.OINODbSqlOrder.parse(init.order);
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
if (!this.sqlParams.order) {
|
|
51
|
-
const order_param = this.url?.searchParams.get(index_js_1.OINODbConfig.OINODB_SQL_ORDER_PARAM);
|
|
52
|
-
if (order_param) {
|
|
53
|
-
this.sqlParams.order = index_js_1.OINODbSqlOrder.parse(order_param);
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
if (init?.limit) {
|
|
57
|
-
if (init.limit instanceof index_js_1.OINODbSqlLimit) {
|
|
58
|
-
this.sqlParams.limit = init.limit;
|
|
59
|
-
}
|
|
60
|
-
else {
|
|
61
|
-
this.sqlParams.limit = index_js_1.OINODbSqlLimit.parse(init.limit);
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
if (!this.sqlParams.limit) {
|
|
65
|
-
const limit_param = this.url?.searchParams.get(index_js_1.OINODbConfig.OINODB_SQL_LIMIT_PARAM);
|
|
66
|
-
if (limit_param) {
|
|
67
|
-
this.sqlParams.limit = index_js_1.OINODbSqlLimit.parse(limit_param);
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
if (init?.aggregate) {
|
|
71
|
-
if (init.aggregate instanceof index_js_1.OINODbSqlAggregate) {
|
|
72
|
-
this.sqlParams.aggregate = init.aggregate;
|
|
73
|
-
}
|
|
74
|
-
else {
|
|
75
|
-
this.sqlParams.aggregate = index_js_1.OINODbSqlAggregate.parse(init.aggregate);
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
if (!this.sqlParams.aggregate) {
|
|
79
|
-
const aggregate_param = this.url?.searchParams.get(index_js_1.OINODbConfig.OINODB_SQL_AGGREGATE_PARAM);
|
|
80
|
-
if (aggregate_param) {
|
|
81
|
-
this.sqlParams.aggregate = index_js_1.OINODbSqlAggregate.parse(aggregate_param);
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
if (init?.select) {
|
|
85
|
-
if (init.select instanceof index_js_1.OINODbSqlSelect) {
|
|
86
|
-
this.sqlParams.select = init.select;
|
|
87
|
-
}
|
|
88
|
-
else {
|
|
89
|
-
this.sqlParams.select = index_js_1.OINODbSqlSelect.parse(init.select);
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
if (!this.sqlParams.select) {
|
|
93
|
-
const select_param = this.url?.searchParams.get(index_js_1.OINODbConfig.OINODB_SQL_SELECT_PARAM);
|
|
94
|
-
if (select_param) {
|
|
95
|
-
this.sqlParams.select = index_js_1.OINODbSqlSelect.parse(select_param);
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
static async fromFetchRequest(request, rowId, rowData, sqlParams) {
|
|
100
|
-
return new OINODbApiRequest({
|
|
101
|
-
url: new URL(request.url),
|
|
102
|
-
method: request.method,
|
|
103
|
-
headers: Object.fromEntries(request.headers),
|
|
104
|
-
rowId: rowId,
|
|
105
|
-
rowData: rowData ?? node_buffer_1.Buffer.from(await request.arrayBuffer()),
|
|
106
|
-
sqlParams: sqlParams
|
|
107
|
-
});
|
|
108
|
-
}
|
|
109
|
-
static fromHttpRequest(request, rowId, rowData, sqlParams) {
|
|
110
|
-
return new OINODbApiRequest({
|
|
111
|
-
url: typeof request.url === "string" ? new URL(request.url) : request.url,
|
|
112
|
-
method: request.method,
|
|
113
|
-
headers: Object.fromEntries(request.headers),
|
|
114
|
-
rowId: rowId,
|
|
115
|
-
rowData: rowData ?? request.bodyAsBuffer(),
|
|
116
|
-
requestType: request.requestType,
|
|
117
|
-
responseType: request.responseType,
|
|
118
|
-
multipartBoundary: request.multipartBoundary,
|
|
119
|
-
lastModified: request.lastModified,
|
|
120
|
-
sqlParams: sqlParams
|
|
121
|
-
});
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
exports.OINODbApiRequest = OINODbApiRequest;
|
|
125
|
-
/**
|
|
126
|
-
* OINO API request result object with returned data and/or http status code/message and
|
|
127
|
-
* error / warning messages.
|
|
128
|
-
*
|
|
129
|
-
*/
|
|
130
|
-
class OINODbApiResult extends common_1.OINOResult {
|
|
131
|
-
/** DbApi request params */
|
|
132
|
-
request;
|
|
133
|
-
/** Returned data if any */
|
|
134
|
-
data;
|
|
135
|
-
/**
|
|
136
|
-
* Constructor of OINODbApiResult.
|
|
137
|
-
*
|
|
138
|
-
* @param request DbApi request parameters
|
|
139
|
-
* @param data result data
|
|
140
|
-
*
|
|
141
|
-
*/
|
|
142
|
-
constructor(request, data) {
|
|
143
|
-
super();
|
|
144
|
-
this.request = request;
|
|
145
|
-
this.data = data;
|
|
146
|
-
}
|
|
147
|
-
/**
|
|
148
|
-
* Creates a HTTP Response from API results.
|
|
149
|
-
*
|
|
150
|
-
* @param headers Headers to include in the response
|
|
151
|
-
*
|
|
152
|
-
*/
|
|
153
|
-
async writeApiResponse(headers = {}) {
|
|
154
|
-
let response = null;
|
|
155
|
-
if (this.success && this.data) {
|
|
156
|
-
const body = await this.data.writeString(this.request.responseType);
|
|
157
|
-
response = new Response(body, { status: this.status, statusText: this.statusText, headers: headers });
|
|
158
|
-
}
|
|
159
|
-
else {
|
|
160
|
-
response = new Response(JSON.stringify(this, null, 3), { status: this.status, statusText: this.statusText, headers: headers });
|
|
161
|
-
}
|
|
162
|
-
for (let i = 0; i < this.messages.length; i++) {
|
|
163
|
-
response.headers.set('X-OINO-MESSAGE-' + i, this.messages[i]);
|
|
164
|
-
}
|
|
165
|
-
return Promise.resolve(response);
|
|
166
|
-
}
|
|
167
|
-
}
|
|
168
|
-
exports.OINODbApiResult = OINODbApiResult;
|
|
169
|
-
/**
|
|
170
|
-
* Specialized HTML template that can render ´OINODbApiResult´.
|
|
171
|
-
*
|
|
172
|
-
*/
|
|
173
|
-
class OINODbHtmlTemplate extends common_1.OINOHtmlTemplate {
|
|
174
|
-
/** Locale validation regex */
|
|
175
|
-
static LOCALE_REGEX = /^(\w\w)(\-\w\w)?$/;
|
|
176
|
-
/** Locale formatter */
|
|
177
|
-
_locale;
|
|
178
|
-
_numberDecimals = -1;
|
|
179
|
-
/**
|
|
180
|
-
* Constructor of OINODbHtmlTemplate.
|
|
181
|
-
*
|
|
182
|
-
* @param template HTML template string
|
|
183
|
-
* @param numberDecimals Number of decimals to use for numbers, -1 for no formatting
|
|
184
|
-
* @param dateLocaleStr Datetime format string, either "iso" for ISO8601 or "default" for system default or valid locale string
|
|
185
|
-
* @param dateLocaleStyle Datetime format style, either "short/medium/long/full" or Intl.DateTimeFormat options
|
|
186
|
-
*
|
|
187
|
-
*/
|
|
188
|
-
constructor(template, numberDecimals = -1, dateLocaleStr = "", dateLocaleStyle = "") {
|
|
189
|
-
super(template);
|
|
190
|
-
let locale_opts;
|
|
191
|
-
if ((dateLocaleStyle == null) || (dateLocaleStyle == "")) {
|
|
192
|
-
locale_opts = { dateStyle: "medium", timeStyle: "medium" };
|
|
193
|
-
}
|
|
194
|
-
else if (typeof dateLocaleStyle == "string") {
|
|
195
|
-
locale_opts = { dateStyle: dateLocaleStyle, timeStyle: dateLocaleStyle };
|
|
196
|
-
}
|
|
197
|
-
else {
|
|
198
|
-
locale_opts = dateLocaleStyle;
|
|
199
|
-
}
|
|
200
|
-
this._locale = null;
|
|
201
|
-
this._numberDecimals = numberDecimals;
|
|
202
|
-
if ((dateLocaleStr != null) && (dateLocaleStr != "") && OINODbHtmlTemplate.LOCALE_REGEX.test(dateLocaleStr)) {
|
|
203
|
-
try {
|
|
204
|
-
this._locale = new Intl.DateTimeFormat(dateLocaleStr, locale_opts);
|
|
205
|
-
}
|
|
206
|
-
catch (e) { }
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
/**
|
|
210
|
-
* Creates HTML Response from API modelset.
|
|
211
|
-
*
|
|
212
|
-
* @param modelset OINO API dataset
|
|
213
|
-
* @param overrideValues values to override in the data
|
|
214
|
-
*
|
|
215
|
-
*/
|
|
216
|
-
async renderFromDbData(modelset, overrideValues) {
|
|
217
|
-
common_1.OINOBenchmark.startMetric("OINOHtmlTemplate", "renderFromDbData");
|
|
218
|
-
let html = "";
|
|
219
|
-
const dataset = modelset.dataset;
|
|
220
|
-
const datamodel = modelset.datamodel;
|
|
221
|
-
const api = modelset.datamodel.api;
|
|
222
|
-
const modified_index = datamodel.findFieldIndexByName(api.params.cacheModifiedField || "");
|
|
223
|
-
let last_modified = this.modified;
|
|
224
|
-
while (!dataset.isEof()) {
|
|
225
|
-
const row = dataset.getRow();
|
|
226
|
-
if (modified_index >= 0) {
|
|
227
|
-
last_modified = Math.max(last_modified, new Date(row[modified_index]).getTime());
|
|
228
|
-
}
|
|
229
|
-
let row_id_seed = datamodel.getRowPrimarykeyValues(row).join(' ');
|
|
230
|
-
let primary_key_values = [];
|
|
231
|
-
this.clearVariables();
|
|
232
|
-
this.setVariableFromValue(index_js_1.OINODbConfig.OINODB_ID_FIELD, "");
|
|
233
|
-
for (let i = 0; i < datamodel.fields.length; i++) {
|
|
234
|
-
const f = datamodel.fields[i];
|
|
235
|
-
let value;
|
|
236
|
-
if ((f instanceof index_js_1.OINODatetimeDataField) && (this._locale != null)) {
|
|
237
|
-
value = f.serializeCellWithLocale(row[i], this._locale);
|
|
238
|
-
}
|
|
239
|
-
else if ((f instanceof index_js_1.OINONumberDataField) && (this._numberDecimals >= 0) && (typeof row[i] === "number")) {
|
|
240
|
-
// console.debug("renderFromDbData number decimals", { field: f.name, value: row[i], type: typeof row[i] });
|
|
241
|
-
value = row[i].toFixed(this._numberDecimals);
|
|
242
|
-
}
|
|
243
|
-
else {
|
|
244
|
-
value = f.serializeCell(row[i]);
|
|
245
|
-
}
|
|
246
|
-
if (f.fieldParams.isPrimaryKey || f.fieldParams.isForeignKey) {
|
|
247
|
-
if (value && (f instanceof index_js_1.OINONumberDataField) && (datamodel.api.hashid)) {
|
|
248
|
-
value = datamodel.api.hashid.encode(value, f.name + " " + row_id_seed);
|
|
249
|
-
}
|
|
250
|
-
if (f.fieldParams.isPrimaryKey) {
|
|
251
|
-
primary_key_values.push(value || "");
|
|
252
|
-
}
|
|
253
|
-
}
|
|
254
|
-
this.setVariableFromValue(f.name, value || "");
|
|
255
|
-
}
|
|
256
|
-
this.setVariableFromProperties(overrideValues);
|
|
257
|
-
this.setVariableFromValue(index_js_1.OINODbConfig.OINODB_ID_FIELD, index_js_1.OINODbConfig.printOINOId(primary_key_values));
|
|
258
|
-
html += this._renderHtml() + "\r\n";
|
|
259
|
-
await dataset.next();
|
|
260
|
-
}
|
|
261
|
-
this.modified = last_modified;
|
|
262
|
-
const result = this._createHttpResult(html);
|
|
263
|
-
common_1.OINOBenchmark.endMetric("OINOHtmlTemplate", "renderFromDbData");
|
|
264
|
-
return result;
|
|
265
|
-
}
|
|
266
|
-
}
|
|
267
|
-
exports.OINODbHtmlTemplate = OINODbHtmlTemplate;
|
|
268
10
|
/**
|
|
269
11
|
* API class with method to process HTTP REST requests.
|
|
270
12
|
*
|
|
271
13
|
*/
|
|
272
|
-
class OINODbApi {
|
|
273
|
-
/**
|
|
274
|
-
_debugOnError = false;
|
|
275
|
-
/** API database reference */
|
|
14
|
+
class OINODbApi extends common_1.OINOApi {
|
|
15
|
+
/** DB reference */
|
|
276
16
|
db;
|
|
277
|
-
/**
|
|
278
|
-
|
|
279
|
-
/**
|
|
280
|
-
|
|
281
|
-
/** API hashid */
|
|
282
|
-
hashid;
|
|
17
|
+
/** DB parameters reference */
|
|
18
|
+
dbParams;
|
|
19
|
+
/** DB datamodel reference */
|
|
20
|
+
dbDatamodel = null;
|
|
283
21
|
/**
|
|
284
22
|
* Constructor of API object.
|
|
285
23
|
* NOTE! OINODb.initDatamodel must be called if created manually instead of the factory.
|
|
@@ -289,23 +27,22 @@ class OINODbApi {
|
|
|
289
27
|
*
|
|
290
28
|
*/
|
|
291
29
|
constructor(db, params) {
|
|
30
|
+
super(db, params);
|
|
292
31
|
if (!params.tableName) {
|
|
293
|
-
throw new Error(common_1.OINO_ERROR_PREFIX + ":
|
|
32
|
+
throw new Error(common_1.OINO_ERROR_PREFIX + ": OINOApiParams needs to define a table name!");
|
|
294
33
|
}
|
|
295
34
|
this.db = db;
|
|
296
|
-
this.
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
this.hashid = null;
|
|
303
|
-
}
|
|
35
|
+
this.dbParams = params;
|
|
36
|
+
}
|
|
37
|
+
initializeDatamodel(datamodel) {
|
|
38
|
+
this.dbDatamodel = datamodel;
|
|
39
|
+
this.datamodel = datamodel;
|
|
40
|
+
this.initialized = true;
|
|
304
41
|
}
|
|
305
42
|
_validateRow(result, row, requirePrimaryKey) {
|
|
306
43
|
let field;
|
|
307
|
-
for (let i = 0; i < this.
|
|
308
|
-
field = this.
|
|
44
|
+
for (let i = 0; i < this.dbDatamodel.fields.length; i++) {
|
|
45
|
+
field = this.dbDatamodel.fields[i];
|
|
309
46
|
const val = row[i];
|
|
310
47
|
if ((val === null) && ((field.fieldParams.isNotNull) || (field.fieldParams.isPrimaryKey))) { // null is a valid SQL value except if it's not allowed
|
|
311
48
|
result.setError(405, "Field '" + field.name + "' is not allowed to be NULL!", "ValidateRowValues");
|
|
@@ -313,14 +50,14 @@ class OINODbApi {
|
|
|
313
50
|
else if ((val === undefined) && (requirePrimaryKey) && (field.fieldParams.isPrimaryKey) && (!field.fieldParams.isAutoInc)) {
|
|
314
51
|
result.setError(405, "Primary key '" + field.name + "' is not autoinc and missing from the data!", "ValidateRowValues");
|
|
315
52
|
}
|
|
316
|
-
else if ((val !== undefined) && (this.
|
|
53
|
+
else if ((val !== undefined) && (this.dbParams.failOnUpdateOnAutoinc) && (field.fieldParams.isAutoInc)) {
|
|
317
54
|
result.setError(405, "Autoinc field '" + field.name + "' can't be updated!", "ValidateRowValues");
|
|
318
55
|
}
|
|
319
56
|
else {
|
|
320
|
-
if ((field instanceof
|
|
57
|
+
if ((field instanceof common_1.OINOStringDataField) && ((field.maxLength > 0))) {
|
|
321
58
|
const str_val = val?.toString() || "";
|
|
322
59
|
if (str_val.length > field.maxLength) {
|
|
323
|
-
if (this.
|
|
60
|
+
if (this.dbParams.failOnOversizedValues) {
|
|
324
61
|
result.setError(405, "Field '" + field.name + "' length (" + str_val.length + ") exceeds maximum (" + field.maxLength + ") and can't be set!", "ValidateRowValues");
|
|
325
62
|
}
|
|
326
63
|
else {
|
|
@@ -340,7 +77,7 @@ class OINODbApi {
|
|
|
340
77
|
rows = data;
|
|
341
78
|
}
|
|
342
79
|
else if (data != null) {
|
|
343
|
-
rows =
|
|
80
|
+
rows = common_1.OINOParser.createRows(this.datamodel, data, request.requestType, request.multipartBoundary);
|
|
344
81
|
}
|
|
345
82
|
}
|
|
346
83
|
catch (e) {
|
|
@@ -351,7 +88,7 @@ class OINODbApi {
|
|
|
351
88
|
async _doGet(result, rowId, request) {
|
|
352
89
|
let sql = "";
|
|
353
90
|
try {
|
|
354
|
-
sql = this.
|
|
91
|
+
sql = this.dbDatamodel.printSqlSelect(rowId, request.queryParams || {});
|
|
355
92
|
common_1.OINOLog.debug("@oino-ts/db", "OINODbApi", "_doGet", "Print SQL", { sql: sql });
|
|
356
93
|
const sql_res = await this.db.sqlSelect(sql);
|
|
357
94
|
if (sql_res.success == false) {
|
|
@@ -361,7 +98,7 @@ class OINODbApi {
|
|
|
361
98
|
}
|
|
362
99
|
}
|
|
363
100
|
else {
|
|
364
|
-
result.data = new
|
|
101
|
+
result.data = new common_1.OINOModelSet(this.datamodel, sql_res, request.queryParams);
|
|
365
102
|
}
|
|
366
103
|
}
|
|
367
104
|
catch (e) {
|
|
@@ -376,11 +113,11 @@ class OINODbApi {
|
|
|
376
113
|
let sql = "";
|
|
377
114
|
try {
|
|
378
115
|
for (let i = 0; i < rows.length; i++) {
|
|
379
|
-
this._validateRow(result, rows[i], this.
|
|
116
|
+
this._validateRow(result, rows[i], this.dbParams.failOnInsertWithoutKey || false);
|
|
380
117
|
if (result.success) {
|
|
381
|
-
sql += this.
|
|
118
|
+
sql += this.dbDatamodel.printSqlInsert(rows[i]);
|
|
382
119
|
}
|
|
383
|
-
else if (this.
|
|
120
|
+
else if (this.dbParams.failOnAnyInvalidRows == false) {
|
|
384
121
|
result.setOk(); // individual rows may fail and will just be messages in response similar to executing multiple sql statements
|
|
385
122
|
}
|
|
386
123
|
}
|
|
@@ -397,8 +134,8 @@ class OINODbApi {
|
|
|
397
134
|
result.addDebug("OINO POST SQL [" + sql + "]", "DoPost");
|
|
398
135
|
}
|
|
399
136
|
}
|
|
400
|
-
else if (this.
|
|
401
|
-
result.data = new
|
|
137
|
+
else if (this.dbParams.returnInsertedIds) {
|
|
138
|
+
result.data = new common_1.OINOModelSet(this.datamodel, sql_res, request.queryParams); // return the inserted ids as data
|
|
402
139
|
}
|
|
403
140
|
}
|
|
404
141
|
}
|
|
@@ -415,12 +152,12 @@ class OINODbApi {
|
|
|
415
152
|
try {
|
|
416
153
|
// this._validateRowValues(result, row, false)
|
|
417
154
|
for (let i = 0; i < rows.length; i++) {
|
|
418
|
-
const row_id = id ||
|
|
419
|
-
this._validateRow(result, rows[i], this.
|
|
155
|
+
const row_id = id || common_1.OINOConfig.printOINOId(this.dbDatamodel.getRowPrimarykeyValues(rows[i], this.hashid != null));
|
|
156
|
+
this._validateRow(result, rows[i], this.dbParams.failOnInsertWithoutKey || false);
|
|
420
157
|
if (result.success) {
|
|
421
|
-
sql += this.
|
|
158
|
+
sql += this.dbDatamodel.printSqlUpdate(row_id, rows[i]);
|
|
422
159
|
}
|
|
423
|
-
else if (this.
|
|
160
|
+
else if (this.dbParams.failOnAnyInvalidRows == false) {
|
|
424
161
|
result.setOk(); // individual rows may fail and will just be messages in response similar to executing multiple sql statements
|
|
425
162
|
}
|
|
426
163
|
}
|
|
@@ -452,17 +189,17 @@ class OINODbApi {
|
|
|
452
189
|
try {
|
|
453
190
|
if (rows != null) {
|
|
454
191
|
for (let i = 0; i < rows.length; i++) {
|
|
455
|
-
const row_id =
|
|
192
|
+
const row_id = common_1.OINOConfig.printOINOId(this.dbDatamodel.getRowPrimarykeyValues(rows[i], this.hashid != null));
|
|
456
193
|
if (row_id) {
|
|
457
|
-
sql += this.
|
|
194
|
+
sql += this.dbDatamodel.printSqlDelete(row_id);
|
|
458
195
|
}
|
|
459
|
-
else if (this.
|
|
196
|
+
else if (this.dbParams.failOnAnyInvalidRows == false) {
|
|
460
197
|
result.setOk(); // individual rows may fail and will just be messages in response similar to executing multiple sql statements
|
|
461
198
|
}
|
|
462
199
|
}
|
|
463
200
|
}
|
|
464
201
|
else if (id) {
|
|
465
|
-
sql = this.
|
|
202
|
+
sql = this.dbDatamodel.printSqlDelete(id);
|
|
466
203
|
}
|
|
467
204
|
if ((sql == "") && result.success) {
|
|
468
205
|
result.setError(405, "No valid rows for DELETE!", "DoDelete"); // only set error if there are multiple rows and no valid sql was created
|
|
@@ -487,14 +224,6 @@ class OINODbApi {
|
|
|
487
224
|
}
|
|
488
225
|
}
|
|
489
226
|
}
|
|
490
|
-
/**
|
|
491
|
-
* Enable or disable debug output on errors.
|
|
492
|
-
*
|
|
493
|
-
* @param debugOnError true to enable debug output on errors, false to disable
|
|
494
|
-
*/
|
|
495
|
-
setDebugOnError(debugOnError) {
|
|
496
|
-
this._debugOnError = debugOnError;
|
|
497
|
-
}
|
|
498
227
|
/**
|
|
499
228
|
* Method for handling a HTTP REST request with GET, POST, PUT, DELETE corresponding to
|
|
500
229
|
* SQL select, insert, update and delete.
|
|
@@ -502,11 +231,11 @@ class OINODbApi {
|
|
|
502
231
|
* @param request OINO HTTP request object containing all parameters of the REST request
|
|
503
232
|
* @param rowId URL id of the REST request
|
|
504
233
|
* @param rowData HTTP body data as either serialized string or unserialized JS object or OINODataRow-array or Buffer/Uint8Array binary data
|
|
505
|
-
* @param
|
|
234
|
+
* @param queryParams SQL parameters for the REST request
|
|
506
235
|
*
|
|
507
236
|
*/
|
|
508
|
-
async doHttpRequest(request, rowId, rowData,
|
|
509
|
-
const api_request =
|
|
237
|
+
async doHttpRequest(request, rowId, rowData, queryParams) {
|
|
238
|
+
const api_request = common_1.OINOApiRequest.fromHttpRequest(request, rowId, rowData, queryParams);
|
|
510
239
|
return this.doApiRequest(api_request);
|
|
511
240
|
}
|
|
512
241
|
/**
|
|
@@ -516,17 +245,20 @@ class OINODbApi {
|
|
|
516
245
|
* @param method HTTP method of the REST request
|
|
517
246
|
* @param rowId URL id of the REST request
|
|
518
247
|
* @param rowData HTTP body data as either serialized string or unserialized JS object or OINODataRow-array or Buffer/Uint8Array binary data
|
|
519
|
-
* @param
|
|
248
|
+
* @param queryParams SQL parameters for the REST request
|
|
520
249
|
* @param contentType content type of the HTTP body data, default is JSON
|
|
521
250
|
*
|
|
522
251
|
*/
|
|
523
|
-
async doRequest(method, rowId, rowData,
|
|
524
|
-
return this.doApiRequest(new
|
|
252
|
+
async doRequest(method, rowId, rowData, queryParams, contentType = common_1.OINOContentType.json) {
|
|
253
|
+
return this.doApiRequest(new common_1.OINOApiRequest({ method: method, rowId: rowId, rowData: rowData, queryParams: queryParams, requestType: contentType }));
|
|
525
254
|
}
|
|
526
255
|
async doApiRequest(request) {
|
|
256
|
+
if (this.initialized == false) {
|
|
257
|
+
throw new Error(common_1.OINO_ERROR_PREFIX + ": API is not initialized yet!");
|
|
258
|
+
}
|
|
527
259
|
common_1.OINOBenchmark.startMetric("OINODbApi", "doRequest." + request.method);
|
|
528
260
|
common_1.OINOLog.debug("@oino-ts/db", "OINODbApi", "doRequest", "Request", { method: request.method, id: request.rowId, data: request.rowData });
|
|
529
|
-
let result = new
|
|
261
|
+
let result = new common_1.OINOApiResult(request);
|
|
530
262
|
let rows = [];
|
|
531
263
|
if ((request.method == "POST") || (request.method == "PUT")) {
|
|
532
264
|
rows = this._parseData(result, request);
|
|
@@ -593,8 +325,8 @@ class OINODbApi {
|
|
|
593
325
|
* @param rowData HTTP body data as either serialized string or unserialized JS object or OINODataRow-array or Buffer/Uint8Array binary data
|
|
594
326
|
*
|
|
595
327
|
*/
|
|
596
|
-
async doBatchUpdate(method, rowId, rowData,
|
|
597
|
-
return this.doApiRequest(new
|
|
328
|
+
async doBatchUpdate(method, rowId, rowData, queryParams) {
|
|
329
|
+
return this.doApiRequest(new common_1.OINOApiRequest({ method: method, rowId: rowId, rowData: rowData, queryParams: queryParams }));
|
|
598
330
|
}
|
|
599
331
|
/**
|
|
600
332
|
* Method for handling a HTTP REST request with batch update using PUT or DELETE methods.
|
|
@@ -602,9 +334,9 @@ class OINODbApi {
|
|
|
602
334
|
* @param request HTTP URL parameters as key-value-pairs
|
|
603
335
|
*
|
|
604
336
|
*/
|
|
605
|
-
async
|
|
337
|
+
async doBatchApiRequest(request) {
|
|
606
338
|
common_1.OINOLog.debug("@oino-ts/db", "OINODbApi", "doBatchUpdate", "Request", { request: request, data: request.rowData });
|
|
607
|
-
let result = new
|
|
339
|
+
let result = new common_1.OINOApiResult(request);
|
|
608
340
|
if ((request.method != "PUT") && (request.method != "DELETE")) {
|
|
609
341
|
result.setError(500, "Batch update only supports PUT and DELETE methods!", "DoBatchUpdate");
|
|
610
342
|
return Promise.resolve(result);
|