@oino-ts/db 0.7.1 → 0.8.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 +1 -2
- package/dist/cjs/OINODbApi.js +24 -40
- package/dist/cjs/OINODbDataField.js +1 -8
- package/dist/cjs/OINODbDataModel.js +4 -9
- package/dist/cjs/OINODbFactory.js +1 -4
- package/dist/cjs/OINODbModelSet.js +4 -19
- package/dist/cjs/OINODbParser.js +15 -29
- package/dist/cjs/OINODbSqlParams.js +14 -19
- package/dist/esm/OINODb.js +2 -3
- package/dist/esm/OINODbApi.js +25 -41
- package/dist/esm/OINODbDataField.js +1 -8
- package/dist/esm/OINODbDataModel.js +5 -10
- package/dist/esm/OINODbFactory.js +2 -5
- package/dist/esm/OINODbModelSet.js +4 -19
- package/dist/esm/OINODbParser.js +15 -29
- package/dist/esm/OINODbSqlParams.js +14 -19
- package/dist/types/OINODbApi.d.ts +0 -1
- package/package.json +3 -3
- package/src/OINODb.ts +2 -3
- package/src/OINODbApi.test.ts +6 -25
- package/src/OINODbApi.ts +24 -39
- package/src/OINODbDataField.ts +1 -8
- package/src/OINODbDataModel.ts +4 -10
- package/src/OINODbFactory.ts +2 -6
- package/src/OINODbModelSet.ts +4 -20
- package/src/OINODbParser.ts +15 -29
- package/src/OINODbSqlParams.ts +14 -19
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
4
4
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
5
5
|
*/
|
|
6
|
-
import { OINO_ERROR_PREFIX, OINODbConfig, OINONumberDataField, OINODB_UNDEFINED } from "./index.js";
|
|
6
|
+
import { OINO_ERROR_PREFIX, OINODbConfig, OINONumberDataField, OINOLog, OINODB_UNDEFINED } from "./index.js";
|
|
7
7
|
/**
|
|
8
8
|
* OINO Datamodel object for representing one database table and it's columns.
|
|
9
9
|
*
|
|
@@ -25,7 +25,6 @@ export class OINODbDataModel {
|
|
|
25
25
|
this._columnLookup = {};
|
|
26
26
|
this.api = api;
|
|
27
27
|
this.fields = [];
|
|
28
|
-
// OINOLog_debug("OINODbDataModel (" + tableName + "):\n" + this._printTableDebug("\n"))
|
|
29
28
|
}
|
|
30
29
|
/**
|
|
31
30
|
* Initialize datamodel from SQL schema.
|
|
@@ -71,7 +70,6 @@ export class OINODbDataModel {
|
|
|
71
70
|
for (let i = 0; i < this.fields.length; i++) {
|
|
72
71
|
const f = this.fields[i];
|
|
73
72
|
const val = row[i];
|
|
74
|
-
// OINOLog_debug("OINODbDataModel._printSqlUpdateValues", {field:f.name, primary_key:f.fieldParams.isPrimaryKey, val:val})
|
|
75
73
|
if ((!f.fieldParams.isPrimaryKey) && (val !== undefined)) {
|
|
76
74
|
if (result != "") {
|
|
77
75
|
result += ",";
|
|
@@ -98,7 +96,6 @@ export class OINODbDataModel {
|
|
|
98
96
|
if (value == "") { // ids are user input and could be specially crafted to be empty
|
|
99
97
|
throw new Error(OINO_ERROR_PREFIX + ": empty condition for id '" + id_value + "' for table " + this.api.params.tableName);
|
|
100
98
|
}
|
|
101
|
-
// OINOLog.debug("OINODbDataModel._printSqlPrimaryKeyCondition", {field:f.name, value:value, id_value:id_value})
|
|
102
99
|
result += f.printSqlColumnName() + "=" + value;
|
|
103
100
|
i = i + 1;
|
|
104
101
|
}
|
|
@@ -125,7 +122,6 @@ export class OINODbDataModel {
|
|
|
125
122
|
*
|
|
126
123
|
*/
|
|
127
124
|
findFieldByName(name) {
|
|
128
|
-
// OINOLog.debug("OINODbDataModel.findFieldByName", {_columnLookup:this._columnLookup})
|
|
129
125
|
const i = this._columnLookup[name];
|
|
130
126
|
if (i >= 0) {
|
|
131
127
|
return this.fields[i];
|
|
@@ -141,7 +137,6 @@ export class OINODbDataModel {
|
|
|
141
137
|
*
|
|
142
138
|
*/
|
|
143
139
|
findFieldIndexByName(name) {
|
|
144
|
-
// OINOLog.debug("OINODbDataModel.findFieldIndexByName", {_columnLookup:this._columnLookup})
|
|
145
140
|
const i = this._columnLookup[name];
|
|
146
141
|
if (i >= 0) {
|
|
147
142
|
return i;
|
|
@@ -232,13 +227,11 @@ export class OINODbDataModel {
|
|
|
232
227
|
else {
|
|
233
228
|
column_names = this._printSqlColumnNames(params.select);
|
|
234
229
|
}
|
|
235
|
-
// OINOLog.debug("OINODbDataModel.printSqlSelect", {column_names:column_names})
|
|
236
230
|
const order_sql = params.order?.toSql(this) || "";
|
|
237
231
|
const limit_sql = params.limit?.toSql(this) || "";
|
|
238
232
|
const filter_sql = params.filter?.toSql(this) || "";
|
|
239
233
|
const groupby_sql = params.aggregate?.toSql(this, params.select) || "";
|
|
240
234
|
let where_sql = "";
|
|
241
|
-
// OINOLog.debug("OINODbDataModel.printSqlSelect", {order_sql:order_sql, limit_sql:limit_sql, filter_sql:filter_sql, groupby_sql:groupby_sql})
|
|
242
235
|
if ((id != null) && (id != "") && (filter_sql != "")) {
|
|
243
236
|
where_sql = this._printSqlPrimaryKeyCondition(id) + " AND " + filter_sql;
|
|
244
237
|
}
|
|
@@ -249,7 +242,7 @@ export class OINODbDataModel {
|
|
|
249
242
|
where_sql = filter_sql;
|
|
250
243
|
}
|
|
251
244
|
const result = this.api.db.printSqlSelect(this.api.params.tableName, column_names, where_sql, order_sql, limit_sql, groupby_sql);
|
|
252
|
-
|
|
245
|
+
OINOLog.debug("@oinots/db", "OINODbDataModel", "printSqlSelect", "Result", { sql: result });
|
|
253
246
|
return result;
|
|
254
247
|
}
|
|
255
248
|
/**
|
|
@@ -260,6 +253,7 @@ export class OINODbDataModel {
|
|
|
260
253
|
*/
|
|
261
254
|
printSqlInsert(row) {
|
|
262
255
|
let result = "INSERT INTO " + this.api.db.printSqlTablename(this.api.params.tableName) + " " + this._printSqlInsertColumnsAndValues(row) + ";";
|
|
256
|
+
OINOLog.debug("@oinots/db", "OINODbDataModel", "printSqlInsert", "Result", { sql: result });
|
|
263
257
|
return result;
|
|
264
258
|
}
|
|
265
259
|
/**
|
|
@@ -271,7 +265,7 @@ export class OINODbDataModel {
|
|
|
271
265
|
*/
|
|
272
266
|
printSqlUpdate(id, row) {
|
|
273
267
|
let result = "UPDATE " + this.api.db.printSqlTablename(this.api.params.tableName) + " SET " + this._printSqlUpdateValues(row) + " WHERE " + this._printSqlPrimaryKeyCondition(id) + ";";
|
|
274
|
-
|
|
268
|
+
OINOLog.debug("@oinots/db", "OINODbDataModel", "printSqlUpdate", "Result", { sql: result });
|
|
275
269
|
return result;
|
|
276
270
|
}
|
|
277
271
|
/**
|
|
@@ -282,6 +276,7 @@ export class OINODbDataModel {
|
|
|
282
276
|
*/
|
|
283
277
|
printSqlDelete(id) {
|
|
284
278
|
let result = "DELETE FROM " + this.api.db.printSqlTablename(this.api.params.tableName) + " WHERE " + this._printSqlPrimaryKeyCondition(id) + ";";
|
|
279
|
+
OINOLog.debug("@oinots/db", "OINODbDataModel", "printSqlDelete", "Result", { sql: result });
|
|
285
280
|
return result;
|
|
286
281
|
}
|
|
287
282
|
}
|
|
@@ -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 { OINODbApi, OINOContentType, OINODbSqlFilter, OINODbConfig, OINODbSqlOrder, OINODbSqlLimit, OINODbSqlAggregate, OINODbSqlSelect } from "./index.js";
|
|
6
|
+
import { OINODbApi, OINOContentType, OINODbSqlFilter, OINODbConfig, OINODbSqlOrder, OINODbSqlLimit, OINODbSqlAggregate, OINODbSqlSelect, OINOLog } from "./index.js";
|
|
7
7
|
/**
|
|
8
8
|
* Static factory class for easily creating things based on data
|
|
9
9
|
*
|
|
@@ -18,7 +18,6 @@ export class OINODbFactory {
|
|
|
18
18
|
* @param dbTypeClass constructor for creating a database of that type
|
|
19
19
|
*/
|
|
20
20
|
static registerDb(dbName, dbTypeClass) {
|
|
21
|
-
// OINOLog.debug("OINODbFactory.registerDb", {dbType:dbName})
|
|
22
21
|
this._dbRegistry[dbName] = dbTypeClass;
|
|
23
22
|
}
|
|
24
23
|
/**
|
|
@@ -106,12 +105,10 @@ export class OINODbFactory {
|
|
|
106
105
|
result.requestType = OINOContentType.json;
|
|
107
106
|
}
|
|
108
107
|
const response_type = url.searchParams.get(OINODbConfig.OINODB_RESPONSE_TYPE) || request.headers.get("accept"); // accept header can be overridden by query parameter
|
|
109
|
-
// OINOLog.debug("createParamsFromRequest: accept headers", {accept:accept})
|
|
110
108
|
const accept_types = response_type?.split(', ') || [];
|
|
111
109
|
for (let i = 0; i < accept_types.length; i++) {
|
|
112
110
|
if (Object.values(OINOContentType).includes(accept_types[i])) {
|
|
113
111
|
result.responseType = accept_types[i];
|
|
114
|
-
// OINOLog.debug("createParamsFromRequest: response type found", {respnse_type:result.responseType})
|
|
115
112
|
break;
|
|
116
113
|
}
|
|
117
114
|
}
|
|
@@ -126,7 +123,7 @@ export class OINODbFactory {
|
|
|
126
123
|
if (etags) {
|
|
127
124
|
result.etags = etags;
|
|
128
125
|
}
|
|
129
|
-
|
|
126
|
+
OINOLog.debug("@oinots/db", "OINODbFactory", "createParamsFromRequest", "Result", { params: result });
|
|
130
127
|
return result;
|
|
131
128
|
}
|
|
132
129
|
}
|
|
@@ -60,7 +60,7 @@ export class OINODbModelSet {
|
|
|
60
60
|
}
|
|
61
61
|
let value = f.serializeCell(row[i]);
|
|
62
62
|
if (value === undefined) {
|
|
63
|
-
|
|
63
|
+
OINOLog.info("@oinots/db", "OINODbModelSet", "_writeRowJson", "Undefined value skipped", { field_name: f.name });
|
|
64
64
|
}
|
|
65
65
|
else if (value === null) {
|
|
66
66
|
json_row += "," + OINOStr.encode(f.name, OINOContentType.json) + ":null";
|
|
@@ -76,7 +76,6 @@ export class OINODbModelSet {
|
|
|
76
76
|
}
|
|
77
77
|
}
|
|
78
78
|
json_row = OINOStr.encode(OINODbConfig.OINODB_ID_FIELD, OINOContentType.json) + ":" + OINOStr.encode(OINODbConfig.printOINOId(primary_key_values), OINOContentType.json) + json_row;
|
|
79
|
-
// OINOLog_debug("OINODbModelSet._writeRowJson="+json_row)
|
|
80
79
|
return "{" + json_row + "}";
|
|
81
80
|
}
|
|
82
81
|
async _writeStringJson() {
|
|
@@ -86,12 +85,10 @@ export class OINODbModelSet {
|
|
|
86
85
|
result += ",\r\n";
|
|
87
86
|
}
|
|
88
87
|
const row = this.dataset.getRow();
|
|
89
|
-
// OINOLog.debug("OINODbModelSet._writeStringJson: row", {row:row})
|
|
90
88
|
result += this._writeRowJson(row);
|
|
91
89
|
await this.dataset.next();
|
|
92
90
|
}
|
|
93
91
|
result = "[\r\n" + result + "\r\n]";
|
|
94
|
-
// OINOLog_debug("OINODbModelSet._writeStringJson="+result)
|
|
95
92
|
return result;
|
|
96
93
|
}
|
|
97
94
|
_writeHeaderCsv() {
|
|
@@ -101,11 +98,9 @@ export class OINODbModelSet {
|
|
|
101
98
|
for (let i = 0; i < fields.length; i++) {
|
|
102
99
|
csv_header += ",\"" + fields[i].name + "\"";
|
|
103
100
|
}
|
|
104
|
-
// OINOLog_debug("OINODbModelSet._writeHeaderCsv="+csv_header)
|
|
105
101
|
return csv_header;
|
|
106
102
|
}
|
|
107
103
|
_writeRowCsv(row) {
|
|
108
|
-
// OINOLog_debug("OINODbModelSet._writeRowCsv", {row:row})
|
|
109
104
|
const model = this.datamodel;
|
|
110
105
|
const fields = model.fields;
|
|
111
106
|
let row_id_seed = model.getRowPrimarykeyValues(row).join(' ');
|
|
@@ -126,7 +121,6 @@ export class OINODbModelSet {
|
|
|
126
121
|
}
|
|
127
122
|
}
|
|
128
123
|
csv_row = OINOStr.encode(OINODbConfig.printOINOId(primary_key_values), OINOContentType.csv) + csv_row;
|
|
129
|
-
// OINOLog_debug("OINODbModelSet._writeRowCsv="+csv_row)
|
|
130
124
|
return csv_row;
|
|
131
125
|
}
|
|
132
126
|
async _writeStringCsv() {
|
|
@@ -136,11 +130,9 @@ export class OINODbModelSet {
|
|
|
136
130
|
result += "\r\n";
|
|
137
131
|
}
|
|
138
132
|
const row = this.dataset.getRow();
|
|
139
|
-
// OINOLog.debug("OINODbModelSet._writeStringCsv: row", {row:row})
|
|
140
133
|
result += this._writeRowCsv(row);
|
|
141
134
|
await this.dataset.next();
|
|
142
135
|
}
|
|
143
|
-
// OINOLog_debug("OINODbModelSet._writeStringCsv="+result)
|
|
144
136
|
return result;
|
|
145
137
|
}
|
|
146
138
|
_writeRowFormdataParameterBlock(blockName, blockValue, multipartBoundary) {
|
|
@@ -155,7 +147,6 @@ export class OINODbModelSet {
|
|
|
155
147
|
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";
|
|
156
148
|
}
|
|
157
149
|
_writeRowFormdata(row) {
|
|
158
|
-
// console.log("OINODbModelSet._writeRowFormdata: row", row)
|
|
159
150
|
const multipart_boundary = "---------OINOMultipartBoundary35424568"; // this method is just used for test data generation and we want it to be static
|
|
160
151
|
const model = this.datamodel;
|
|
161
152
|
const fields = model.fields;
|
|
@@ -171,7 +162,7 @@ export class OINODbModelSet {
|
|
|
171
162
|
let formdata_block = "";
|
|
172
163
|
let is_file = (f instanceof OINOBlobDataField);
|
|
173
164
|
if (value === undefined) {
|
|
174
|
-
OINOLog.info("OINODbModelSet
|
|
165
|
+
OINOLog.info("@oinots/db", "OINODbModelSet", "_writeRowFormdata", "Undefined value skipped", { field_name: f.name });
|
|
175
166
|
}
|
|
176
167
|
else if (value === null) {
|
|
177
168
|
formdata_block = this._writeRowFormdataParameterBlock(fields[i].name, null, multipart_boundary);
|
|
@@ -185,7 +176,6 @@ export class OINODbModelSet {
|
|
|
185
176
|
formdata_block = this._writeRowFormdataParameterBlock(fields[i].name, value, multipart_boundary);
|
|
186
177
|
}
|
|
187
178
|
}
|
|
188
|
-
// OINOLog.debug("OINODbModelSet._writeRowFormdata next block", {formdata_block:formdata_block})
|
|
189
179
|
result += formdata_block;
|
|
190
180
|
}
|
|
191
181
|
result = this._writeRowFormdataParameterBlock(OINODbConfig.OINODB_ID_FIELD, OINODbConfig.printOINOId(primary_key_values), multipart_boundary) + result;
|
|
@@ -193,12 +183,10 @@ export class OINODbModelSet {
|
|
|
193
183
|
}
|
|
194
184
|
_writeStringFormdata() {
|
|
195
185
|
const row = this.dataset.getRow();
|
|
196
|
-
// OINOLog.debug("OINODbModelSet._writeStringFormdata: row", {row:row})
|
|
197
186
|
let result = this._writeRowFormdata(row);
|
|
198
187
|
return result;
|
|
199
188
|
}
|
|
200
189
|
_writeRowUrlencode(row) {
|
|
201
|
-
// console.log("OINODbModelSet._writeRowUrlencode row=" + row)
|
|
202
190
|
const model = this.datamodel;
|
|
203
191
|
const fields = model.fields;
|
|
204
192
|
let row_id_seed = model.getRowPrimarykeyValues(row).join(' ');
|
|
@@ -222,7 +210,6 @@ export class OINODbModelSet {
|
|
|
222
210
|
}
|
|
223
211
|
}
|
|
224
212
|
urlencode_row = OINOStr.encode(OINODbConfig.OINODB_ID_FIELD, OINOContentType.urlencode) + "=" + OINOStr.encode(OINODbConfig.printOINOId(primary_key_values), OINOContentType.urlencode) + "&" + urlencode_row;
|
|
225
|
-
// OINOLog_debug("OINODbModelSet._writeRowCsv="+csv_row)
|
|
226
213
|
return urlencode_row;
|
|
227
214
|
}
|
|
228
215
|
async _writeStringUrlencode() {
|
|
@@ -230,14 +217,12 @@ export class OINODbModelSet {
|
|
|
230
217
|
let line_count = 0;
|
|
231
218
|
while (!this.dataset.isEof()) {
|
|
232
219
|
const row = this.dataset.getRow();
|
|
233
|
-
// OINOLog.debug("OINODbModelSet._writeStringUrlencode: row", {row:row})
|
|
234
220
|
result += this._writeRowUrlencode(row) + "\r\n";
|
|
235
221
|
await this.dataset.next();
|
|
236
222
|
line_count += 1;
|
|
237
223
|
}
|
|
238
|
-
// OINOLog_debug("OINODbModelSet._writeStringCsv="+result)
|
|
239
224
|
if (line_count > 1) {
|
|
240
|
-
OINOLog.warning("OINODbModelSet
|
|
225
|
+
OINOLog.warning("@oinots/db", "OINODbModelSet", "_writeStringUrlencode", "Content type " + OINOContentType.urlencode + " does not officially support multiline content!", {});
|
|
241
226
|
}
|
|
242
227
|
return result;
|
|
243
228
|
}
|
|
@@ -262,7 +247,7 @@ export class OINODbModelSet {
|
|
|
262
247
|
result += await this._writeStringUrlencode();
|
|
263
248
|
}
|
|
264
249
|
else {
|
|
265
|
-
OINOLog.error("OINODbModelSet
|
|
250
|
+
OINOLog.error("@oinots/db", "OINODbModelSet", "writeString", "Content type is only for input!", { contentType: contentType });
|
|
266
251
|
}
|
|
267
252
|
return result;
|
|
268
253
|
}
|
package/dist/esm/OINODbParser.js
CHANGED
|
@@ -52,11 +52,11 @@ export class OINODbParser {
|
|
|
52
52
|
return this._createRowFromUrlencoded(datamodel, data);
|
|
53
53
|
}
|
|
54
54
|
else if (requestParams.requestType == OINOContentType.html) {
|
|
55
|
-
OINOLog.error("HTML can't be used as an input content type!", { contentType: OINOContentType.html });
|
|
55
|
+
OINOLog.error("@oinots/db", "OINODbParser", "createRowsFromText", "HTML can't be used as an input content type!", { contentType: OINOContentType.html });
|
|
56
56
|
return [];
|
|
57
57
|
}
|
|
58
58
|
else {
|
|
59
|
-
OINOLog.error("Unrecognized input content type!", { contentType: requestParams.requestType });
|
|
59
|
+
OINOLog.error("@oinots/db", "OINODbParser", "createRowsFromText", "Unrecognized input content type!", { contentType: requestParams.requestType });
|
|
60
60
|
return [];
|
|
61
61
|
}
|
|
62
62
|
}
|
|
@@ -82,11 +82,11 @@ export class OINODbParser {
|
|
|
82
82
|
return this._createRowFromUrlencoded(datamodel, data.toString()); // data is urlencoded so it's a string
|
|
83
83
|
}
|
|
84
84
|
else if (requestParams.requestType == OINOContentType.html) {
|
|
85
|
-
OINOLog.error("HTML can't be used as an input content type!", { contentType: OINOContentType.html });
|
|
85
|
+
OINOLog.error("@oinots/db", "OINODbParser", "createRowsFromBlob", "HTML can't be used as an input content type!", { contentType: OINOContentType.html });
|
|
86
86
|
return [];
|
|
87
87
|
}
|
|
88
88
|
else {
|
|
89
|
-
OINOLog.error("Unrecognized input content type!", { contentType: requestParams.requestType });
|
|
89
|
+
OINOLog.error("@oinots/db", "OINODbParser", "createRowsFromBlob", "Unrecognized input content type!", { contentType: requestParams.requestType });
|
|
90
90
|
return [];
|
|
91
91
|
}
|
|
92
92
|
}
|
|
@@ -199,7 +199,6 @@ export class OINODbParser {
|
|
|
199
199
|
field_to_header_mapping[i] = headers.indexOf(datamodel.fields[i].name);
|
|
200
200
|
headers_found = headers_found || (field_to_header_mapping[i] >= 0);
|
|
201
201
|
}
|
|
202
|
-
// OINOLog.debug("createRowFromCsv", {headers:headers, field_to_header_mapping:field_to_header_mapping})
|
|
203
202
|
if (!headers_found) {
|
|
204
203
|
return result;
|
|
205
204
|
}
|
|
@@ -240,7 +239,7 @@ export class OINODbParser {
|
|
|
240
239
|
result.push(row);
|
|
241
240
|
}
|
|
242
241
|
else {
|
|
243
|
-
OINOLog.warning("
|
|
242
|
+
OINOLog.warning("@oinots/db", "OINODbParser", "_createRowFromCsv", "Empty row skipped", {});
|
|
244
243
|
}
|
|
245
244
|
start = end;
|
|
246
245
|
end = start;
|
|
@@ -281,7 +280,7 @@ export class OINODbParser {
|
|
|
281
280
|
return result;
|
|
282
281
|
}
|
|
283
282
|
else {
|
|
284
|
-
OINOLog.warning("
|
|
283
|
+
OINOLog.warning("@oinots/db", "OINODbParser", "_createRowFromJsonObj", "Empty row skipped", {});
|
|
285
284
|
return undefined;
|
|
286
285
|
}
|
|
287
286
|
}
|
|
@@ -331,18 +330,15 @@ export class OINODbParser {
|
|
|
331
330
|
const n = data.length;
|
|
332
331
|
let start = this._findMultipartBoundary(data, multipartBoundary, 0);
|
|
333
332
|
let end = this._findMultipartBoundary(data, multipartBoundary, start);
|
|
334
|
-
// OINOLog.debug("createRowFromFormdata: enter", {start:start, end:end, multipartBoundary:multipartBoundary})
|
|
335
333
|
const row = new Array(datamodel.fields.length);
|
|
336
334
|
let has_data = false;
|
|
337
335
|
while (end < n) {
|
|
338
|
-
// OINOLog.debug("createRowFromFormdata: next block", {start:start, end:end, block:data.substring(start, end)})
|
|
339
336
|
let block_ok = true;
|
|
340
337
|
let l = this._parseMultipartLine(data, start);
|
|
341
|
-
// OINOLog.debug("createRowFromFormdata: next line", {start:start, end:end, line:l})
|
|
342
338
|
start += l.length + 2;
|
|
343
339
|
const header_matches = OINODbParser._multipartHeaderRegex.exec(l);
|
|
344
340
|
if (!header_matches) {
|
|
345
|
-
OINOLog.warning("
|
|
341
|
+
OINOLog.warning("@oinots/db", "OINODbParser", "_createRowFromFormdata", "Unsupported block skipped", { header_line: l });
|
|
346
342
|
block_ok = false;
|
|
347
343
|
}
|
|
348
344
|
else {
|
|
@@ -350,18 +346,16 @@ export class OINODbParser {
|
|
|
350
346
|
const is_file = header_matches[3] != null;
|
|
351
347
|
let is_base64 = false;
|
|
352
348
|
const field_index = datamodel.findFieldIndexByName(field_name);
|
|
353
|
-
// OINOLog.debug("createRowFromFormdata: header", {field_name:field_name, field_index:field_index, is_file:is_file, is_base64:is_base64})
|
|
354
349
|
if (field_index < 0) {
|
|
355
|
-
OINOLog.warning("
|
|
350
|
+
OINOLog.warning("@oinots/db", "OINODbParser", "_createRowFromFormdata", "Form field not found and skipped!", { field_name: field_name });
|
|
356
351
|
block_ok = false;
|
|
357
352
|
}
|
|
358
353
|
else {
|
|
359
354
|
const field = datamodel.fields[field_index];
|
|
360
355
|
l = this._parseMultipartLine(data, start);
|
|
361
|
-
// OINOLog.debug("createRowFromFormdata: next line", {start:start, end:end, line:l})
|
|
362
356
|
while (block_ok && (l != '')) {
|
|
363
357
|
if (l.startsWith('Content-Type:') && (l.indexOf('multipart/mixed') >= 0)) {
|
|
364
|
-
OINOLog.warning("
|
|
358
|
+
OINOLog.warning("@oinots/db", "OINODbParser", "_createRowFromFormdata", "Mixed multipart files not supported and skipped!", { header_line: l });
|
|
365
359
|
block_ok = false;
|
|
366
360
|
}
|
|
367
361
|
else if (l.startsWith('Content-Transfer-Encoding:') && (l.indexOf('BASE64') >= 0)) {
|
|
@@ -369,14 +363,12 @@ export class OINODbParser {
|
|
|
369
363
|
}
|
|
370
364
|
start += l.length + 2;
|
|
371
365
|
l = this._parseMultipartLine(data, start);
|
|
372
|
-
// OINOLog.debug("createRowFromFormdata: next line", {start:start, end:end, line:l})
|
|
373
366
|
}
|
|
374
367
|
start += 2;
|
|
375
368
|
if (!block_ok) {
|
|
376
|
-
OINOLog.warning("
|
|
369
|
+
OINOLog.warning("@oinots/db", "OINODbParser", "_createRowFromFormdata", "Invalid block skipped", { field_name: field_name });
|
|
377
370
|
}
|
|
378
371
|
else if (start + multipartBoundary.length + 2 >= end) {
|
|
379
|
-
// OINOLog.debug("OINODbFactory.createRowFromFormdata: null value", {field_name:field_name})
|
|
380
372
|
row[field_index] = null;
|
|
381
373
|
}
|
|
382
374
|
else if (is_file) {
|
|
@@ -389,11 +381,9 @@ export class OINODbParser {
|
|
|
389
381
|
const value = data.subarray(start, e - 2);
|
|
390
382
|
row[field_index] = value;
|
|
391
383
|
}
|
|
392
|
-
// console.log("OINODbFactory.createRowFromFormdata: file field", {field_name:field_name, value:row[field_index]})
|
|
393
384
|
}
|
|
394
385
|
else {
|
|
395
386
|
let value = OINOStr.decode(this._parseMultipartLine(data, start).trim(), OINOContentType.formdata);
|
|
396
|
-
// OINOLog.debug("OINODbFactory.createRowFromFormdata: parse form field", {field_name:field_name, value:value})
|
|
397
387
|
if (value && (field.fieldParams.isPrimaryKey || field.fieldParams.isForeignKey) && (field instanceof OINONumberDataField) && (datamodel.api.hashid)) {
|
|
398
388
|
value = datamodel.api.hashid.decode(value);
|
|
399
389
|
}
|
|
@@ -405,21 +395,19 @@ export class OINODbParser {
|
|
|
405
395
|
start = end;
|
|
406
396
|
end = this._findMultipartBoundary(data, multipartBoundary, start);
|
|
407
397
|
}
|
|
408
|
-
// OINOLog.debug("createRowFromFormdata: next row", {row:row})
|
|
409
398
|
if (has_data) {
|
|
410
399
|
result.push(row);
|
|
411
400
|
}
|
|
412
401
|
else {
|
|
413
|
-
OINOLog.warning("
|
|
402
|
+
OINOLog.warning("@oinots/db", "OINODbParser", "_createRowFromFormdata", "Empty row skipped", {});
|
|
414
403
|
}
|
|
415
404
|
}
|
|
416
405
|
catch (e) {
|
|
417
|
-
OINOLog.
|
|
406
|
+
OINOLog.exception("@oinots/db", "OINODbParser", "_createRowFromFormdata", "Exception parsing formdata", { message: e.message, stack: e.stack });
|
|
418
407
|
}
|
|
419
408
|
return result;
|
|
420
409
|
}
|
|
421
410
|
static _createRowFromUrlencoded(datamodel, data) {
|
|
422
|
-
// OINOLog.debug("createRowFromUrlencoded: enter", {data:data})
|
|
423
411
|
let result = [];
|
|
424
412
|
const row = new Array(datamodel.fields.length);
|
|
425
413
|
let has_data = false;
|
|
@@ -427,12 +415,11 @@ export class OINODbParser {
|
|
|
427
415
|
try {
|
|
428
416
|
for (let i = 0; i < data_parts.length; i++) {
|
|
429
417
|
const param_parts = data_parts[i].split('=');
|
|
430
|
-
// OINOLog.debug("createRowFromUrlencoded: next param", {param_parts:param_parts})
|
|
431
418
|
if (param_parts.length == 2) {
|
|
432
419
|
const key = OINOStr.decodeUrlencode(param_parts[0]) || "";
|
|
433
420
|
const field_index = datamodel.findFieldIndexByName(key);
|
|
434
421
|
if (field_index < 0) {
|
|
435
|
-
OINOLog.info("
|
|
422
|
+
OINOLog.info("@oinots/db", "OINODbParser", "_createRowFromUrlencoded", "Param field not found", { field: key });
|
|
436
423
|
}
|
|
437
424
|
else {
|
|
438
425
|
const field = datamodel.fields[field_index];
|
|
@@ -450,13 +437,12 @@ export class OINODbParser {
|
|
|
450
437
|
result.push(row);
|
|
451
438
|
}
|
|
452
439
|
else {
|
|
453
|
-
OINOLog.warning("
|
|
440
|
+
OINOLog.warning("@oinots/db", "OINODbParser", "_createRowFromUrlencoded", "Empty row skipped", {});
|
|
454
441
|
}
|
|
455
442
|
}
|
|
456
443
|
catch (e) {
|
|
457
|
-
OINOLog.
|
|
444
|
+
OINOLog.exception("@oinots/db", "OINODbParser", "_createRowFromUrlencoded", "Exception parsing urlencoded data", { message: e.message, stack: e.stack });
|
|
458
445
|
}
|
|
459
|
-
// console.log("createRowFromUrlencoded: next row=" + row)
|
|
460
446
|
return result;
|
|
461
447
|
}
|
|
462
448
|
}
|
|
@@ -55,7 +55,7 @@ export class OINODbSqlFilter {
|
|
|
55
55
|
((operation !== null) && (Object.values(OINODbSqlComparison).includes(operation)) && (typeof (leftSide) == "string") && (leftSide != "") && (typeof (rightSide) == "string") && (rightSide != "")) ||
|
|
56
56
|
((operation == OINODbSqlBooleanOperation.not) && (leftSide == "") && (rightSide instanceof OINODbSqlFilter)) ||
|
|
57
57
|
(((operation == OINODbSqlBooleanOperation.and) || (operation == OINODbSqlBooleanOperation.or)) && (leftSide instanceof OINODbSqlFilter) && (rightSide instanceof OINODbSqlFilter)))) {
|
|
58
|
-
OINOLog.
|
|
58
|
+
OINOLog.error("@oinots/db", "OINODbSqlFilter", "constructor", "Unsupported OINODbSqlFilter format", { leftSide: leftSide, operation: operation, rightSide: rightSide });
|
|
59
59
|
throw new Error(OINO_ERROR_PREFIX + ": Unsupported OINODbSqlFilter format!");
|
|
60
60
|
}
|
|
61
61
|
this._leftSide = leftSide;
|
|
@@ -69,7 +69,6 @@ export class OINODbSqlFilter {
|
|
|
69
69
|
*
|
|
70
70
|
*/
|
|
71
71
|
static parse(filterString) {
|
|
72
|
-
// OINOLog_debug("OINODbSqlFilter.constructor", {filterString:filterString})
|
|
73
72
|
if (!filterString) {
|
|
74
73
|
return new OINODbSqlFilter("", null, "");
|
|
75
74
|
}
|
|
@@ -85,11 +84,11 @@ export class OINODbSqlFilter {
|
|
|
85
84
|
}
|
|
86
85
|
else {
|
|
87
86
|
let boolean_parts = OINOStr.splitByBrackets(filterString, true, false, '(', ')');
|
|
88
|
-
// OINOLog_debug("OINODbSqlFilter.constructor", {boolean_parts:boolean_parts})
|
|
89
87
|
if (boolean_parts.length == 3 && (boolean_parts[1].match(OINODbSqlFilter._booleanOperationRegex))) {
|
|
90
88
|
return new OINODbSqlFilter(OINODbSqlFilter.parse(boolean_parts[0]), boolean_parts[1].trim().toLowerCase().substring(1), OINODbSqlFilter.parse(boolean_parts[2]));
|
|
91
89
|
}
|
|
92
90
|
else {
|
|
91
|
+
OINOLog.error("@oinots/db", "OINODbSqlFilter", "constructor", "Invalid filter", { filterString: filterString });
|
|
93
92
|
throw new Error(OINO_ERROR_PREFIX + ": Invalid filter '" + filterString + "'"); // invalid filter could be a security risk, stop processing
|
|
94
93
|
}
|
|
95
94
|
}
|
|
@@ -146,7 +145,6 @@ export class OINODbSqlFilter {
|
|
|
146
145
|
*
|
|
147
146
|
*/
|
|
148
147
|
toSql(dataModel) {
|
|
149
|
-
// OINOLog.debug("OINODbSqlFilter.toSql", {_leftSide:this._leftSide, _operator:this._operator, _rightSide:this._rightSide})
|
|
150
148
|
if (this.isEmpty()) {
|
|
151
149
|
return "";
|
|
152
150
|
}
|
|
@@ -158,7 +156,7 @@ export class OINODbSqlFilter {
|
|
|
158
156
|
else {
|
|
159
157
|
field = dataModel.findFieldByName(this._leftSide);
|
|
160
158
|
if (!field) {
|
|
161
|
-
OINOLog.error("OINODbSqlFilter
|
|
159
|
+
OINOLog.error("@oinots/db", "OINODbSqlFilter", "toSql", "Invalid field!", { field: this._leftSide });
|
|
162
160
|
throw new Error(OINO_ERROR_PREFIX + ": OINODbSqlFilter.toSql - Invalid field '" + this._leftSide + "'"); // invalid field name could be a security risk, stop processing
|
|
163
161
|
}
|
|
164
162
|
result += dataModel.api.db.printSqlColumnname(field?.name || this._leftSide);
|
|
@@ -169,14 +167,15 @@ export class OINODbSqlFilter {
|
|
|
169
167
|
}
|
|
170
168
|
else {
|
|
171
169
|
const value = field.deserializeCell(this._rightSide);
|
|
172
|
-
if (
|
|
173
|
-
OINOLog.error("OINODbSqlFilter
|
|
170
|
+
if ((value == null) || (value === "")) {
|
|
171
|
+
OINOLog.error("@oinots/db", "OINODbSqlFilter", "toSql", "Invalid value!", { value: value });
|
|
174
172
|
throw new Error(OINO_ERROR_PREFIX + ": OINODbSqlFilter.toSql - Invalid value '" + value + "'"); // invalid value could be a security risk, stop processing
|
|
175
173
|
}
|
|
176
174
|
result += field.printCellAsSqlValue(value);
|
|
177
175
|
}
|
|
178
|
-
|
|
179
|
-
|
|
176
|
+
result = "(" + result + ")";
|
|
177
|
+
OINOLog.debug("@oinots/db", "OINODbSqlFilter", "toSql", "Result", { sql: result });
|
|
178
|
+
return result;
|
|
180
179
|
}
|
|
181
180
|
}
|
|
182
181
|
/**
|
|
@@ -195,7 +194,6 @@ export class OINODbSqlOrder {
|
|
|
195
194
|
*
|
|
196
195
|
*/
|
|
197
196
|
constructor(column_or_array, descending_or_array) {
|
|
198
|
-
OINOLog.debug("OINODbSqlOrder.constructor", { columns: column_or_array, directions: descending_or_array });
|
|
199
197
|
if (Array.isArray(column_or_array)) {
|
|
200
198
|
this._columns = column_or_array;
|
|
201
199
|
}
|
|
@@ -246,12 +244,11 @@ export class OINODbSqlOrder {
|
|
|
246
244
|
if (this.isEmpty()) {
|
|
247
245
|
return "";
|
|
248
246
|
}
|
|
249
|
-
// OINOLog.debug("OINODbSqlOrder.toSql", {columns:this._columns, directions:this._directions})
|
|
250
247
|
let result = "";
|
|
251
248
|
for (let i = 0; i < this._columns.length; i++) {
|
|
252
249
|
const field = dataModel.findFieldByName(this._columns[i]);
|
|
253
250
|
if (!field) {
|
|
254
|
-
OINOLog.error("OINODbSqlOrder
|
|
251
|
+
OINOLog.error("@oinots/db", "OINODbSqlOrder", "toSql", "Invalid field!", { field: this._columns[i] });
|
|
255
252
|
throw new Error(OINO_ERROR_PREFIX + ": OINODbSqlOrder.toSql - Invalid field '" + this._columns[i] + "'"); // invalid field name could be a security risk, stop processing
|
|
256
253
|
}
|
|
257
254
|
if (result) {
|
|
@@ -265,7 +262,7 @@ export class OINODbSqlOrder {
|
|
|
265
262
|
result += "ASC";
|
|
266
263
|
}
|
|
267
264
|
}
|
|
268
|
-
|
|
265
|
+
OINOLog.debug("@oinots/db", "OINODbSqlOrder", "toSql", "Result", { sql: result });
|
|
269
266
|
return result;
|
|
270
267
|
}
|
|
271
268
|
}
|
|
@@ -327,6 +324,7 @@ export class OINODbSqlLimit {
|
|
|
327
324
|
if (this._page > 0) {
|
|
328
325
|
result += " OFFSET " + (this._limit * (this._page - 1) + 1).toString();
|
|
329
326
|
}
|
|
327
|
+
OINOLog.debug("@oinots/db", "OINODbSqlLimit", "toSql", "Result", { sql: result });
|
|
330
328
|
return result;
|
|
331
329
|
}
|
|
332
330
|
}
|
|
@@ -373,7 +371,6 @@ export class OINODbSqlAggregate {
|
|
|
373
371
|
const aggregator_parts = aggregatorString.split(',');
|
|
374
372
|
for (let i = 0; i < aggregator_parts.length; i++) {
|
|
375
373
|
let match = OINODbSqlAggregate._aggregateRegex.exec(aggregator_parts[i]);
|
|
376
|
-
// OINOLog.debug("OINODbSqlAggregate.parse - next aggregator", {aggregator: aggregator_parts[i], match:match})
|
|
377
374
|
if ((match != null) && (match.length == 3)) {
|
|
378
375
|
funtions.push(match[1]);
|
|
379
376
|
fields.push(match[2]);
|
|
@@ -406,8 +403,9 @@ export class OINODbSqlAggregate {
|
|
|
406
403
|
result += f.printSqlColumnName() + ",";
|
|
407
404
|
}
|
|
408
405
|
}
|
|
409
|
-
|
|
410
|
-
|
|
406
|
+
result = result.substring(0, result.length - 1);
|
|
407
|
+
OINOLog.debug("@oinots/db", "OINODbSqlAggregate", "toSql", "Result", { sql: result });
|
|
408
|
+
return result;
|
|
411
409
|
}
|
|
412
410
|
/**
|
|
413
411
|
* Print non-aggregated fields as SQL GROUP BY-condition based on the datamodel of the API.
|
|
@@ -434,7 +432,6 @@ export class OINODbSqlAggregate {
|
|
|
434
432
|
}
|
|
435
433
|
}
|
|
436
434
|
}
|
|
437
|
-
// OINOLog.debug("OINODbSqlAggregate.printSqlColumnNames", {result:result})
|
|
438
435
|
return result.substring(0, result.length - 1);
|
|
439
436
|
}
|
|
440
437
|
/**
|
|
@@ -459,7 +456,6 @@ export class OINODbSqlSelect {
|
|
|
459
456
|
*
|
|
460
457
|
*/
|
|
461
458
|
constructor(columns) {
|
|
462
|
-
// OINOLog.debug("OINODbSqlSelect.constructor", {columns:columns})
|
|
463
459
|
this._columns = columns;
|
|
464
460
|
}
|
|
465
461
|
/**
|
|
@@ -490,7 +486,6 @@ export class OINODbSqlSelect {
|
|
|
490
486
|
*
|
|
491
487
|
*/
|
|
492
488
|
isSelected(field) {
|
|
493
|
-
// OINOLog.debug("OINODbSqlSelect.isSelected", {column:column, columns:this._columns})
|
|
494
489
|
return ((this._columns.length == 0) || (field.fieldParams.isPrimaryKey == true) || (this._columns.includes(field.name)));
|
|
495
490
|
}
|
|
496
491
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@oino-ts/db",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.0",
|
|
4
4
|
"description": "OINO TS library package for publishing an SQL database tables as a REST API.",
|
|
5
5
|
"author": "Matias Kiviniemi (pragmatta)",
|
|
6
6
|
"license": "MPL-2.0",
|
|
@@ -19,12 +19,12 @@
|
|
|
19
19
|
"module": "./dist/esm/index.js",
|
|
20
20
|
"types": "./dist/types/index.d.ts",
|
|
21
21
|
"dependencies": {
|
|
22
|
-
"@oino-ts/common": "0.
|
|
22
|
+
"@oino-ts/common": "0.8.0"
|
|
23
23
|
},
|
|
24
24
|
"devDependencies": {
|
|
25
25
|
"@types/node": "^20.14.10",
|
|
26
26
|
"@types/bun": "^1.1.14",
|
|
27
|
-
"@oino-ts/types": "0.
|
|
27
|
+
"@oino-ts/types": "0.8.0",
|
|
28
28
|
"typedoc": "^0.25.13"
|
|
29
29
|
},
|
|
30
30
|
"files": [
|
package/src/OINODb.ts
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
import { OINODbParams, OINODbApi, OINODataCell, OINO_ERROR_PREFIX, OINODataRow, OINODB_EMPTY_ROW, OINOResult } from "./index.js"
|
|
7
|
+
import { OINODbParams, OINODbApi, OINODataCell, OINO_ERROR_PREFIX, OINODataRow, OINODB_EMPTY_ROW, OINOResult, OINOLog } from "./index.js"
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
10
|
* Base class for database abstraction, implementing methods for connecting, making queries and parsing/formatting data
|
|
@@ -124,7 +124,6 @@ export abstract class OINODb {
|
|
|
124
124
|
*/
|
|
125
125
|
printSqlSelect(tableName:string, columnNames:string, whereCondition:string, orderCondition:string, limitCondition:string, groupByCondition: string): string {
|
|
126
126
|
let result:string = "SELECT " + columnNames + " FROM " + tableName;
|
|
127
|
-
// OINOLog.debug("OINODb.printSqlSelect", {tableName:tableName, columnNames:columnNames, whereCondition:whereCondition, orderCondition:orderCondition, limitCondition:limitCondition })
|
|
128
127
|
if (whereCondition != "") {
|
|
129
128
|
result += " WHERE " + whereCondition
|
|
130
129
|
}
|
|
@@ -138,7 +137,7 @@ export abstract class OINODb {
|
|
|
138
137
|
result += " LIMIT " + limitCondition
|
|
139
138
|
}
|
|
140
139
|
result += ";"
|
|
141
|
-
|
|
140
|
+
OINOLog.debug("@oinots/db", "OINODb", "printSqlSelect", "Result", {sql:result})
|
|
142
141
|
return result;
|
|
143
142
|
}
|
|
144
143
|
}
|