@oino-ts/db 0.21.2 → 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/src/OINODbApi.ts
CHANGED
|
@@ -1,668 +1,390 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
3
|
-
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
4
|
-
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
if (
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
if (
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
}
|
|
391
|
-
}
|
|
392
|
-
}
|
|
393
|
-
|
|
394
|
-
private async _doPost(result:OINODbApiResult, rows:OINODataRow[], request:OINODbApiRequest):Promise<void> {
|
|
395
|
-
let sql:string = ""
|
|
396
|
-
try {
|
|
397
|
-
for (let i=0; i<rows.length; i++) {
|
|
398
|
-
this._validateRow(result, rows[i], this.params.failOnInsertWithoutKey||false)
|
|
399
|
-
if (result.success) {
|
|
400
|
-
sql += this.datamodel.printSqlInsert(rows[i])
|
|
401
|
-
|
|
402
|
-
} else if (this.params.failOnAnyInvalidRows == false) {
|
|
403
|
-
result.setOk() // individual rows may fail and will just be messages in response similar to executing multiple sql statements
|
|
404
|
-
}
|
|
405
|
-
}
|
|
406
|
-
if ((sql == "") && result.success) {
|
|
407
|
-
result.setError(405, "No valid rows for POST!", "DoPost")
|
|
408
|
-
|
|
409
|
-
} else if (result.success) {
|
|
410
|
-
OINOLog.debug("@oino-ts/db", "OINODbApi", "_doPost", "Print SQL", {sql:sql})
|
|
411
|
-
const sql_res:OINODbDataSet = await this.db.sqlExec(sql)
|
|
412
|
-
if (sql_res.success == false) {
|
|
413
|
-
result.setError(500, sql_res.statusText, "DoPost")
|
|
414
|
-
if (this._debugOnError) {
|
|
415
|
-
result.addDebug("OINO POST MESSAGES [" + sql_res.statusText + "]", "DoPost")
|
|
416
|
-
result.addDebug("OINO POST SQL [" + sql + "]", "DoPost")
|
|
417
|
-
}
|
|
418
|
-
} else if (this.params.returnInsertedIds) {
|
|
419
|
-
result.data = new OINODbModelSet(this.datamodel, sql_res, request.sqlParams) // return the inserted ids as data
|
|
420
|
-
}
|
|
421
|
-
}
|
|
422
|
-
} catch (e:any) {
|
|
423
|
-
result.setError(500, "Unhandled exception in doPost: " + e.message, "DoPost")
|
|
424
|
-
OINOLog.exception("@oino-ts/db", "OINODbApi", "_doPost", "exception in post request", {message:e.message, stack:e.stack})
|
|
425
|
-
if (this._debugOnError) {
|
|
426
|
-
result.addDebug("OINO POST SQL [" + sql + "]", "DoPost")
|
|
427
|
-
}
|
|
428
|
-
}
|
|
429
|
-
}
|
|
430
|
-
|
|
431
|
-
private async _doPut(result:OINODbApiResult, id:string|null, rows:OINODataRow[]):Promise<void> {
|
|
432
|
-
let sql:string = ""
|
|
433
|
-
try {
|
|
434
|
-
// this._validateRowValues(result, row, false)
|
|
435
|
-
for (let i=0; i<rows.length; i++) {
|
|
436
|
-
const row_id = id || OINODbConfig.printOINOId(this.datamodel.getRowPrimarykeyValues(rows[i], this.hashid != null))
|
|
437
|
-
this._validateRow(result, rows[i], this.params.failOnInsertWithoutKey||false)
|
|
438
|
-
if (result.success) {
|
|
439
|
-
sql += this.datamodel.printSqlUpdate(row_id, rows[i])
|
|
440
|
-
|
|
441
|
-
} else if (this.params.failOnAnyInvalidRows == false) {
|
|
442
|
-
result.setOk() // individual rows may fail and will just be messages in response similar to executing multiple sql statements
|
|
443
|
-
}
|
|
444
|
-
}
|
|
445
|
-
if ((sql == "") && result.success) {
|
|
446
|
-
result.setError(405, "No valid rows for PUT!", "DoPut") // only set error if there are multiple rows and no valid sql was created
|
|
447
|
-
|
|
448
|
-
} else if (result.success) {
|
|
449
|
-
OINOLog.debug("@oino-ts/db", "OINODbApi", "_doPut", "Print SQL", {sql:sql})
|
|
450
|
-
const sql_res:OINODbDataSet = await this.db.sqlExec(sql)
|
|
451
|
-
if (sql_res.success == false) {
|
|
452
|
-
result.setError(500, sql_res.statusText, "DoPut")
|
|
453
|
-
if (this._debugOnError) {
|
|
454
|
-
result.addDebug("OINO PUT MESSAGES [" + sql_res.statusText + "]", "DoPut")
|
|
455
|
-
result.addDebug("OINO PUT SQL [" + sql + "]", "DoPut")
|
|
456
|
-
}
|
|
457
|
-
}
|
|
458
|
-
}
|
|
459
|
-
} catch (e:any) {
|
|
460
|
-
result.setError(500, "Unhandled exception: " + e.message, "DoPut")
|
|
461
|
-
OINOLog.exception("@oino-ts/db", "OINODbApi", "_doPut", "exception in put request", {message:e.message, stack:e.stack})
|
|
462
|
-
if (this._debugOnError) {
|
|
463
|
-
result.addDebug("OINO PUT SQL [" + sql + "]", "DoPut")
|
|
464
|
-
}
|
|
465
|
-
}
|
|
466
|
-
}
|
|
467
|
-
|
|
468
|
-
private async _doDelete(result:OINODbApiResult, id:string|null, rows:OINODataRow[]|null):Promise<void> {
|
|
469
|
-
let sql:string = ""
|
|
470
|
-
try {
|
|
471
|
-
if (rows != null) {
|
|
472
|
-
for (let i=0; i<rows.length; i++) {
|
|
473
|
-
const row_id = OINODbConfig.printOINOId(this.datamodel.getRowPrimarykeyValues(rows[i], this.hashid != null))
|
|
474
|
-
if (row_id) {
|
|
475
|
-
sql += this.datamodel.printSqlDelete(row_id)
|
|
476
|
-
} else if (this.params.failOnAnyInvalidRows == false) {
|
|
477
|
-
result.setOk() // individual rows may fail and will just be messages in response similar to executing multiple sql statements
|
|
478
|
-
}
|
|
479
|
-
}
|
|
480
|
-
} else if (id) {
|
|
481
|
-
sql = this.datamodel.printSqlDelete(id)
|
|
482
|
-
}
|
|
483
|
-
if ((sql == "") && result.success) {
|
|
484
|
-
result.setError(405, "No valid rows for DELETE!", "DoDelete") // only set error if there are multiple rows and no valid sql was created
|
|
485
|
-
|
|
486
|
-
} else if (result.success) {
|
|
487
|
-
|
|
488
|
-
OINOLog.debug("@oino-ts/db", "OINODbApi", "_doDelete", "Print SQL", {sql:sql})
|
|
489
|
-
const sql_res:OINODbDataSet = await this.db.sqlExec(sql)
|
|
490
|
-
if (sql_res.success == false) {
|
|
491
|
-
result.setError(500, sql_res.statusText, "DoDelete")
|
|
492
|
-
if (this._debugOnError) {
|
|
493
|
-
result.addDebug("OINO DELETE MESSAGES [" + sql_res.statusText + "]", "DoDelete")
|
|
494
|
-
result.addDebug("OINO DELETE SQL [" + sql + "]", "DoDelete")
|
|
495
|
-
}
|
|
496
|
-
}
|
|
497
|
-
}
|
|
498
|
-
} catch (e:any) {
|
|
499
|
-
result.setError(500, "Unhandled exception: " + e.message, "DoDelete")
|
|
500
|
-
OINOLog.exception("@oino-ts/db", "OINODbApi", "_doDelete", "exception in delete request", {message:e.message, stack:e.stack})
|
|
501
|
-
if (this._debugOnError) {
|
|
502
|
-
result.addDebug("OINO DELETE SQL [" + sql + "]", "DoDelete")
|
|
503
|
-
}
|
|
504
|
-
}
|
|
505
|
-
}
|
|
506
|
-
|
|
507
|
-
/**
|
|
508
|
-
* Enable or disable debug output on errors.
|
|
509
|
-
*
|
|
510
|
-
* @param debugOnError true to enable debug output on errors, false to disable
|
|
511
|
-
*/
|
|
512
|
-
setDebugOnError(debugOnError:boolean) {
|
|
513
|
-
this._debugOnError = debugOnError
|
|
514
|
-
}
|
|
515
|
-
|
|
516
|
-
/**
|
|
517
|
-
* Method for handling a HTTP REST request with GET, POST, PUT, DELETE corresponding to
|
|
518
|
-
* SQL select, insert, update and delete.
|
|
519
|
-
*
|
|
520
|
-
* @param request OINO HTTP request object containing all parameters of the REST request
|
|
521
|
-
* @param rowId URL id of the REST request
|
|
522
|
-
* @param rowData HTTP body data as either serialized string or unserialized JS object or OINODataRow-array or Buffer/Uint8Array binary data
|
|
523
|
-
* @param sqlParams SQL parameters for the REST request
|
|
524
|
-
*
|
|
525
|
-
*/
|
|
526
|
-
async doHttpRequest(request: OINOHttpRequest, rowId:string, rowData:OINODbApiData, sqlParams:OINODbSqlParams):Promise<OINODbApiResult> {
|
|
527
|
-
const api_request = OINODbApiRequest.fromHttpRequest(request, rowId, rowData, sqlParams)
|
|
528
|
-
return this.doApiRequest(api_request)
|
|
529
|
-
}
|
|
530
|
-
/**
|
|
531
|
-
* Method for handling a HTTP REST request with GET, POST, PUT, DELETE corresponding to
|
|
532
|
-
* SQL select, insert, update and delete.
|
|
533
|
-
*
|
|
534
|
-
* @param method HTTP method of the REST request
|
|
535
|
-
* @param rowId URL id of the REST request
|
|
536
|
-
* @param rowData HTTP body data as either serialized string or unserialized JS object or OINODataRow-array or Buffer/Uint8Array binary data
|
|
537
|
-
* @param sqlParams SQL parameters for the REST request
|
|
538
|
-
* @param contentType content type of the HTTP body data, default is JSON
|
|
539
|
-
*
|
|
540
|
-
*/
|
|
541
|
-
async doRequest(method:string, rowId:string, rowData:OINODbApiData, sqlParams:OINODbSqlParams, contentType:OINOContentType = OINOContentType.json):Promise<OINODbApiResult> {
|
|
542
|
-
return this.doApiRequest(new OINODbApiRequest({method: method, rowId: rowId, rowData: rowData, sqlParams: sqlParams, requestType: contentType}))
|
|
543
|
-
}
|
|
544
|
-
|
|
545
|
-
async doApiRequest(request:OINODbApiRequest):Promise<OINODbApiResult> {
|
|
546
|
-
OINOBenchmark.startMetric("OINODbApi", "doRequest." + request.method)
|
|
547
|
-
OINOLog.debug("@oino-ts/db", "OINODbApi", "doRequest", "Request", {method:request.method, id:request.rowId, data:request.rowData})
|
|
548
|
-
let result:OINODbApiResult = new OINODbApiResult(request)
|
|
549
|
-
let rows:OINODataRow[] = []
|
|
550
|
-
if ((request.method == "POST") || (request.method == "PUT")) {
|
|
551
|
-
rows = this._parseData(result, request)
|
|
552
|
-
}
|
|
553
|
-
if (request.method == "GET") {
|
|
554
|
-
await this._doGet(result, request.rowId, request)
|
|
555
|
-
|
|
556
|
-
} else if (request.method == "PUT") {
|
|
557
|
-
if (!request.rowId) {
|
|
558
|
-
result.setError(400, "HTTP PUT method requires an URL ID for the row that is updated!", "DoRequest")
|
|
559
|
-
|
|
560
|
-
} else if (rows.length != 1) {
|
|
561
|
-
result.setError(400, "HTTP PUT method requires exactly one row in the body data!", "DoRequest")
|
|
562
|
-
|
|
563
|
-
} else {
|
|
564
|
-
try {
|
|
565
|
-
await this._doPut(result, request.rowId, rows)
|
|
566
|
-
|
|
567
|
-
} catch (e:any) {
|
|
568
|
-
result.setError(500, "Unhandled exception in HTTP PUT doRequest: " + e.message, "DoRequest")
|
|
569
|
-
}
|
|
570
|
-
}
|
|
571
|
-
} else if (request.method == "POST") {
|
|
572
|
-
if (request.rowId) {
|
|
573
|
-
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")
|
|
574
|
-
|
|
575
|
-
} else if (rows.length == 0) {
|
|
576
|
-
result.setError(400, "HTTP POST method requires at least one row in the body data!", "DoRequest")
|
|
577
|
-
|
|
578
|
-
} else {
|
|
579
|
-
try {
|
|
580
|
-
await this._doPost(result, rows, request)
|
|
581
|
-
|
|
582
|
-
} catch (e:any) {
|
|
583
|
-
result.setError(500, "Unhandled exception in HTTP POST doRequest: " + e.message, "DoRequest")
|
|
584
|
-
}
|
|
585
|
-
}
|
|
586
|
-
} else if (request.method == "DELETE") {
|
|
587
|
-
if (!request.rowId) {
|
|
588
|
-
result.setError(400, "HTTP DELETE method requires an id!", "DoRequest")
|
|
589
|
-
|
|
590
|
-
} else {
|
|
591
|
-
try {
|
|
592
|
-
await this._doDelete(result, request.rowId, null)
|
|
593
|
-
|
|
594
|
-
} catch (e:any) {
|
|
595
|
-
result.setError(500, "Unhandled exception in HTTP DELETE doRequest: " + e.message, "DoRequest")
|
|
596
|
-
}
|
|
597
|
-
}
|
|
598
|
-
} else {
|
|
599
|
-
result.setError(405, "Unsupported HTTP method '" + request.method + "' for REST request", "DoRequest")
|
|
600
|
-
}
|
|
601
|
-
OINOBenchmark.endMetric("OINODbApi", "doRequest." + request.method, result.status != 500)
|
|
602
|
-
return Promise.resolve(result)
|
|
603
|
-
}
|
|
604
|
-
|
|
605
|
-
/**
|
|
606
|
-
* Method for handling a HTTP REST request with batch update using PUT or DELETE methods.
|
|
607
|
-
*
|
|
608
|
-
* @param method HTTP method of the REST request
|
|
609
|
-
* @param rowId URL id of the REST request
|
|
610
|
-
* @param rowData HTTP body data as either serialized string or unserialized JS object or OINODataRow-array or Buffer/Uint8Array binary data
|
|
611
|
-
*
|
|
612
|
-
*/
|
|
613
|
-
async doBatchUpdate(method:string, rowId:string, rowData:OINODbApiData, sqlParams?: OINODbSqlParams):Promise<OINODbApiResult> {
|
|
614
|
-
return this.doApiRequest(new OINODbApiRequest({ method: method, rowId: rowId, rowData: rowData, sqlParams: sqlParams }))
|
|
615
|
-
}
|
|
616
|
-
/**
|
|
617
|
-
* Method for handling a HTTP REST request with batch update using PUT or DELETE methods.
|
|
618
|
-
*
|
|
619
|
-
* @param request HTTP URL parameters as key-value-pairs
|
|
620
|
-
*
|
|
621
|
-
*/
|
|
622
|
-
async runBatchUpdate(request:OINODbApiRequest):Promise<OINODbApiResult> {
|
|
623
|
-
OINOLog.debug("@oino-ts/db", "OINODbApi", "doBatchUpdate", "Request", {request:request, data:request.rowData})
|
|
624
|
-
let result:OINODbApiResult = new OINODbApiResult(request)
|
|
625
|
-
if ((request.method != "PUT") && (request.method != "DELETE")) {
|
|
626
|
-
result.setError(500, "Batch update only supports PUT and DELETE methods!", "DoBatchUpdate")
|
|
627
|
-
return Promise.resolve(result)
|
|
628
|
-
}
|
|
629
|
-
OINOBenchmark.startMetric("OINODbApi", "doBatchUpdate." + request.method)
|
|
630
|
-
const rows:OINODataRow[] = [] = this._parseData(result, request)
|
|
631
|
-
if (request.method == "PUT") {
|
|
632
|
-
|
|
633
|
-
try {
|
|
634
|
-
await this._doPut(result, null, rows)
|
|
635
|
-
|
|
636
|
-
} catch (e:any) {
|
|
637
|
-
result.setError(500, "Unhandled exception in HTTP PUT doRequest: " + e.message, "DoBatchUpdate")
|
|
638
|
-
}
|
|
639
|
-
|
|
640
|
-
} else if (request.method == "DELETE") {
|
|
641
|
-
try {
|
|
642
|
-
await this._doDelete(result, null, rows)
|
|
643
|
-
|
|
644
|
-
} catch (e:any) {
|
|
645
|
-
result.setError(500, "Unhandled exception in HTTP DELETE doRequest: " + e.message, "DoBatchUpdate")
|
|
646
|
-
}
|
|
647
|
-
}
|
|
648
|
-
OINOBenchmark.endMetric("OINODbApi", "doBatchUpdate." + request.method, result.status != 500)
|
|
649
|
-
return Promise.resolve(result)
|
|
650
|
-
}
|
|
651
|
-
|
|
652
|
-
/**
|
|
653
|
-
* Method to check if a field is included in the API params.
|
|
654
|
-
*
|
|
655
|
-
* @param fieldName name of the field
|
|
656
|
-
*
|
|
657
|
-
*/
|
|
658
|
-
|
|
659
|
-
public isFieldIncluded(fieldName:string):boolean {
|
|
660
|
-
const params = this.params
|
|
661
|
-
return (
|
|
662
|
-
((params.excludeFieldPrefix == undefined) || (params.excludeFieldPrefix == "") || (fieldName.startsWith(params.excludeFieldPrefix) == false)) &&
|
|
663
|
-
((params.excludeFields == undefined) || (params.excludeFields.length == 0) || (params.excludeFields.indexOf(fieldName) < 0)) &&
|
|
664
|
-
((params.includeFields == undefined) || (params.includeFields.length == 0) || (params.includeFields.indexOf(fieldName) >= 0))
|
|
665
|
-
)
|
|
666
|
-
}
|
|
667
|
-
|
|
1
|
+
/*
|
|
2
|
+
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
3
|
+
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
4
|
+
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { OINOApi, OINOApiParams, OINOLog, OINOBenchmark, OINOHttpRequest, OINOHttpResult, OINOApiRequest, OINOApiResult, OINOHtmlTemplate, OINOContentType, OINODataRow, OINODataCell, OINODataSet, OINODataField, OINOStringDataField, OINOConfig, OINONumberDataField, OINODatetimeDataField, OINOQueryParams, OINOApiData, OINOModelSet, OINOParser, OINO_ERROR_PREFIX } from "@oino-ts/common";
|
|
8
|
+
import { OINODb } from "./OINODb.js"
|
|
9
|
+
import { OINODbDataModel } from "./OINODbDataModel.js"
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* API class with method to process HTTP REST requests.
|
|
14
|
+
*
|
|
15
|
+
*/
|
|
16
|
+
export class OINODbApi extends OINOApi {
|
|
17
|
+
/** DB reference */
|
|
18
|
+
readonly db: OINODb
|
|
19
|
+
|
|
20
|
+
/** DB parameters reference */
|
|
21
|
+
readonly dbParams: OINOApiParams
|
|
22
|
+
|
|
23
|
+
/** DB datamodel reference */
|
|
24
|
+
dbDatamodel: OINODbDataModel|null = null
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Constructor of API object.
|
|
28
|
+
* NOTE! OINODb.initDatamodel must be called if created manually instead of the factory.
|
|
29
|
+
*
|
|
30
|
+
* @param db database for the API
|
|
31
|
+
* @param params parameters for the API
|
|
32
|
+
*
|
|
33
|
+
*/
|
|
34
|
+
constructor (db: OINODb, params:OINOApiParams) {
|
|
35
|
+
super(db, params)
|
|
36
|
+
if (!params.tableName) {
|
|
37
|
+
throw new Error(OINO_ERROR_PREFIX + ": OINOApiParams needs to define a table name!")
|
|
38
|
+
}
|
|
39
|
+
this.db = db
|
|
40
|
+
this.dbParams = params
|
|
41
|
+
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
initializeDatamodel(datamodel: OINODbDataModel) {
|
|
45
|
+
this.dbDatamodel = datamodel
|
|
46
|
+
this.datamodel = datamodel
|
|
47
|
+
this.initialized = true
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
private _validateRow(result:OINOApiResult, row:OINODataRow, requirePrimaryKey:boolean):void {
|
|
51
|
+
let field:OINODataField
|
|
52
|
+
for (let i=0; i<this.dbDatamodel!.fields.length; i++) {
|
|
53
|
+
field = this.dbDatamodel!.fields[i]
|
|
54
|
+
const val:OINODataCell = row[i]
|
|
55
|
+
if ((val === null) && ((field.fieldParams.isNotNull)||(field.fieldParams.isPrimaryKey))) { // null is a valid SQL value except if it's not allowed
|
|
56
|
+
result.setError(405, "Field '" + field.name + "' is not allowed to be NULL!", "ValidateRowValues")
|
|
57
|
+
|
|
58
|
+
} else if ((val === undefined) && (requirePrimaryKey) && (field.fieldParams.isPrimaryKey) && (!field.fieldParams.isAutoInc)) {
|
|
59
|
+
result.setError(405, "Primary key '" + field.name + "' is not autoinc and missing from the data!", "ValidateRowValues")
|
|
60
|
+
|
|
61
|
+
} else if ((val !== undefined) && (this.dbParams.failOnUpdateOnAutoinc) && (field.fieldParams.isAutoInc)) {
|
|
62
|
+
result.setError(405, "Autoinc field '" + field.name + "' can't be updated!", "ValidateRowValues")
|
|
63
|
+
|
|
64
|
+
} else {
|
|
65
|
+
if ((field instanceof OINOStringDataField) && ((field.maxLength > 0))){
|
|
66
|
+
const str_val = val?.toString() || ""
|
|
67
|
+
if (str_val.length > field.maxLength) {
|
|
68
|
+
if (this.dbParams.failOnOversizedValues) {
|
|
69
|
+
result.setError(405, "Field '" + field.name + "' length (" + str_val.length + ") exceeds maximum (" + field.maxLength + ") and can't be set!", "ValidateRowValues")
|
|
70
|
+
} else {
|
|
71
|
+
result.addWarning("Field '" + field.name + "' length (" + str_val.length + ") exceeds maximum (" + field.maxLength + ") and might truncate or fail.", "ValidateRowValues")
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
//logDebug("OINODbApi.validateHttpValues", {result:result})
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
private _parseData(httpResult:OINOApiResult, request:OINOApiRequest):OINODataRow[] {
|
|
82
|
+
let rows:OINODataRow[] = []
|
|
83
|
+
const data = request.rowData ?? request.body
|
|
84
|
+
try {
|
|
85
|
+
if (Array.isArray(data)) {
|
|
86
|
+
rows = data as OINODataRow[]
|
|
87
|
+
} else if (data != null) {
|
|
88
|
+
rows = OINOParser.createRows(this.datamodel!, data, request.requestType, request.multipartBoundary)
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
} catch (e:any) {
|
|
92
|
+
httpResult.setError(400, "Invalid data: " + e.message, "DoRequest")
|
|
93
|
+
}
|
|
94
|
+
return rows
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
private async _doGet(result:OINOApiResult, rowId:string, request:OINOApiRequest):Promise<void> {
|
|
98
|
+
let sql:string = ""
|
|
99
|
+
try {
|
|
100
|
+
sql = this.dbDatamodel!.printSqlSelect(rowId, request.queryParams || {})
|
|
101
|
+
OINOLog.debug("@oino-ts/db", "OINODbApi", "_doGet", "Print SQL", {sql:sql})
|
|
102
|
+
const sql_res:OINODataSet = await this.db.sqlSelect(sql)
|
|
103
|
+
if (sql_res.success == false) {
|
|
104
|
+
result.setError(500, sql_res.statusText, "DoGet")
|
|
105
|
+
if (this._debugOnError) {
|
|
106
|
+
result.addDebug("OINO GET SQL [" + sql + "]", "DoPut")
|
|
107
|
+
}
|
|
108
|
+
} else {
|
|
109
|
+
result.data = new OINOModelSet(this.datamodel!, sql_res, request.queryParams)
|
|
110
|
+
}
|
|
111
|
+
} catch (e:any) {
|
|
112
|
+
result.setError(500, "Unhandled exception in doGet: " + e.message, "DoGet")
|
|
113
|
+
OINOLog.exception("@oino-ts/db", "OINODbApi", "_doGet", "exception in get request", {message:e.message, stack:e.stack})
|
|
114
|
+
if (this._debugOnError) {
|
|
115
|
+
result.addDebug("OINO GET SQL [" + sql + "]", "DoGet")
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
private async _doPost(result:OINOApiResult, rows:OINODataRow[], request:OINOApiRequest):Promise<void> {
|
|
121
|
+
let sql:string = ""
|
|
122
|
+
try {
|
|
123
|
+
for (let i=0; i<rows.length; i++) {
|
|
124
|
+
this._validateRow(result, rows[i], this.dbParams.failOnInsertWithoutKey||false)
|
|
125
|
+
if (result.success) {
|
|
126
|
+
sql += this.dbDatamodel!.printSqlInsert(rows[i])
|
|
127
|
+
|
|
128
|
+
} else if (this.dbParams.failOnAnyInvalidRows == false) {
|
|
129
|
+
result.setOk() // individual rows may fail and will just be messages in response similar to executing multiple sql statements
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
if ((sql == "") && result.success) {
|
|
133
|
+
result.setError(405, "No valid rows for POST!", "DoPost")
|
|
134
|
+
|
|
135
|
+
} else if (result.success) {
|
|
136
|
+
OINOLog.debug("@oino-ts/db", "OINODbApi", "_doPost", "Print SQL", {sql:sql})
|
|
137
|
+
const sql_res:OINODataSet = await this.db.sqlExec(sql)
|
|
138
|
+
if (sql_res.success == false) {
|
|
139
|
+
result.setError(500, sql_res.statusText, "DoPost")
|
|
140
|
+
if (this._debugOnError) {
|
|
141
|
+
result.addDebug("OINO POST MESSAGES [" + sql_res.statusText + "]", "DoPost")
|
|
142
|
+
result.addDebug("OINO POST SQL [" + sql + "]", "DoPost")
|
|
143
|
+
}
|
|
144
|
+
} else if (this.dbParams.returnInsertedIds) {
|
|
145
|
+
result.data = new OINOModelSet(this.datamodel!, sql_res, request.queryParams) // return the inserted ids as data
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
} catch (e:any) {
|
|
149
|
+
result.setError(500, "Unhandled exception in doPost: " + e.message, "DoPost")
|
|
150
|
+
OINOLog.exception("@oino-ts/db", "OINODbApi", "_doPost", "exception in post request", {message:e.message, stack:e.stack})
|
|
151
|
+
if (this._debugOnError) {
|
|
152
|
+
result.addDebug("OINO POST SQL [" + sql + "]", "DoPost")
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
private async _doPut(result:OINOApiResult, id:string|null, rows:OINODataRow[]):Promise<void> {
|
|
158
|
+
let sql:string = ""
|
|
159
|
+
try {
|
|
160
|
+
// this._validateRowValues(result, row, false)
|
|
161
|
+
for (let i=0; i<rows.length; i++) {
|
|
162
|
+
const row_id = id || OINOConfig.printOINOId(this.dbDatamodel!.getRowPrimarykeyValues(rows[i], this.hashid != null))
|
|
163
|
+
this._validateRow(result, rows[i], this.dbParams.failOnInsertWithoutKey||false)
|
|
164
|
+
if (result.success) {
|
|
165
|
+
sql += this.dbDatamodel!.printSqlUpdate(row_id, rows[i])
|
|
166
|
+
|
|
167
|
+
} else if (this.dbParams.failOnAnyInvalidRows == false) {
|
|
168
|
+
result.setOk() // individual rows may fail and will just be messages in response similar to executing multiple sql statements
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
if ((sql == "") && result.success) {
|
|
172
|
+
result.setError(405, "No valid rows for PUT!", "DoPut") // only set error if there are multiple rows and no valid sql was created
|
|
173
|
+
|
|
174
|
+
} else if (result.success) {
|
|
175
|
+
OINOLog.debug("@oino-ts/db", "OINODbApi", "_doPut", "Print SQL", {sql:sql})
|
|
176
|
+
const sql_res:OINODataSet = await this.db.sqlExec(sql)
|
|
177
|
+
if (sql_res.success == false) {
|
|
178
|
+
result.setError(500, sql_res.statusText, "DoPut")
|
|
179
|
+
if (this._debugOnError) {
|
|
180
|
+
result.addDebug("OINO PUT MESSAGES [" + sql_res.statusText + "]", "DoPut")
|
|
181
|
+
result.addDebug("OINO PUT SQL [" + sql + "]", "DoPut")
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
} catch (e:any) {
|
|
186
|
+
result.setError(500, "Unhandled exception: " + e.message, "DoPut")
|
|
187
|
+
OINOLog.exception("@oino-ts/db", "OINODbApi", "_doPut", "exception in put request", {message:e.message, stack:e.stack})
|
|
188
|
+
if (this._debugOnError) {
|
|
189
|
+
result.addDebug("OINO PUT SQL [" + sql + "]", "DoPut")
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
private async _doDelete(result:OINOApiResult, id:string|null, rows:OINODataRow[]|null):Promise<void> {
|
|
195
|
+
let sql:string = ""
|
|
196
|
+
try {
|
|
197
|
+
if (rows != null) {
|
|
198
|
+
for (let i=0; i<rows.length; i++) {
|
|
199
|
+
const row_id = OINOConfig.printOINOId(this.dbDatamodel!.getRowPrimarykeyValues(rows[i], this.hashid != null))
|
|
200
|
+
if (row_id) {
|
|
201
|
+
sql += this.dbDatamodel!.printSqlDelete(row_id)
|
|
202
|
+
} else if (this.dbParams.failOnAnyInvalidRows == false) {
|
|
203
|
+
result.setOk() // individual rows may fail and will just be messages in response similar to executing multiple sql statements
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
} else if (id) {
|
|
207
|
+
sql = this.dbDatamodel!.printSqlDelete(id)
|
|
208
|
+
}
|
|
209
|
+
if ((sql == "") && result.success) {
|
|
210
|
+
result.setError(405, "No valid rows for DELETE!", "DoDelete") // only set error if there are multiple rows and no valid sql was created
|
|
211
|
+
|
|
212
|
+
} else if (result.success) {
|
|
213
|
+
|
|
214
|
+
OINOLog.debug("@oino-ts/db", "OINODbApi", "_doDelete", "Print SQL", {sql:sql})
|
|
215
|
+
const sql_res:OINODataSet = await this.db.sqlExec(sql)
|
|
216
|
+
if (sql_res.success == false) {
|
|
217
|
+
result.setError(500, sql_res.statusText, "DoDelete")
|
|
218
|
+
if (this._debugOnError) {
|
|
219
|
+
result.addDebug("OINO DELETE MESSAGES [" + sql_res.statusText + "]", "DoDelete")
|
|
220
|
+
result.addDebug("OINO DELETE SQL [" + sql + "]", "DoDelete")
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
} catch (e:any) {
|
|
225
|
+
result.setError(500, "Unhandled exception: " + e.message, "DoDelete")
|
|
226
|
+
OINOLog.exception("@oino-ts/db", "OINODbApi", "_doDelete", "exception in delete request", {message:e.message, stack:e.stack})
|
|
227
|
+
if (this._debugOnError) {
|
|
228
|
+
result.addDebug("OINO DELETE SQL [" + sql + "]", "DoDelete")
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
/**
|
|
234
|
+
* Method for handling a HTTP REST request with GET, POST, PUT, DELETE corresponding to
|
|
235
|
+
* SQL select, insert, update and delete.
|
|
236
|
+
*
|
|
237
|
+
* @param request OINO HTTP request object containing all parameters of the REST request
|
|
238
|
+
* @param rowId URL id of the REST request
|
|
239
|
+
* @param rowData HTTP body data as either serialized string or unserialized JS object or OINODataRow-array or Buffer/Uint8Array binary data
|
|
240
|
+
* @param queryParams SQL parameters for the REST request
|
|
241
|
+
*
|
|
242
|
+
*/
|
|
243
|
+
async doHttpRequest(request: OINOHttpRequest, rowId:string, rowData:OINOApiData, queryParams:OINOQueryParams):Promise<OINOApiResult> {
|
|
244
|
+
const api_request = OINOApiRequest.fromHttpRequest(request, rowId, rowData, queryParams)
|
|
245
|
+
return this.doApiRequest(api_request)
|
|
246
|
+
}
|
|
247
|
+
/**
|
|
248
|
+
* Method for handling a HTTP REST request with GET, POST, PUT, DELETE corresponding to
|
|
249
|
+
* SQL select, insert, update and delete.
|
|
250
|
+
*
|
|
251
|
+
* @param method HTTP method of the REST request
|
|
252
|
+
* @param rowId URL id of the REST request
|
|
253
|
+
* @param rowData HTTP body data as either serialized string or unserialized JS object or OINODataRow-array or Buffer/Uint8Array binary data
|
|
254
|
+
* @param queryParams SQL parameters for the REST request
|
|
255
|
+
* @param contentType content type of the HTTP body data, default is JSON
|
|
256
|
+
*
|
|
257
|
+
*/
|
|
258
|
+
async doRequest(method:string, rowId:string, rowData:OINOApiData, queryParams:OINOQueryParams, contentType:OINOContentType = OINOContentType.json):Promise<OINOApiResult> {
|
|
259
|
+
return this.doApiRequest(new OINOApiRequest({method: method, rowId: rowId, rowData: rowData, queryParams: queryParams, requestType: contentType}))
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
async doApiRequest(request:OINOApiRequest):Promise<OINOApiResult> {
|
|
263
|
+
if (this.initialized == false) {
|
|
264
|
+
throw new Error(OINO_ERROR_PREFIX + ": API is not initialized yet!")
|
|
265
|
+
}
|
|
266
|
+
OINOBenchmark.startMetric("OINODbApi", "doRequest." + request.method)
|
|
267
|
+
OINOLog.debug("@oino-ts/db", "OINODbApi", "doRequest", "Request", {method:request.method, id:request.rowId, data:request.rowData})
|
|
268
|
+
let result:OINOApiResult = new OINOApiResult(request)
|
|
269
|
+
let rows:OINODataRow[] = []
|
|
270
|
+
if ((request.method == "POST") || (request.method == "PUT")) {
|
|
271
|
+
rows = this._parseData(result, request)
|
|
272
|
+
}
|
|
273
|
+
if (request.method == "GET") {
|
|
274
|
+
await this._doGet(result, request.rowId, request)
|
|
275
|
+
|
|
276
|
+
} else if (request.method == "PUT") {
|
|
277
|
+
if (!request.rowId) {
|
|
278
|
+
result.setError(400, "HTTP PUT method requires an URL ID for the row that is updated!", "DoRequest")
|
|
279
|
+
|
|
280
|
+
} else if (rows.length != 1) {
|
|
281
|
+
result.setError(400, "HTTP PUT method requires exactly one row in the body data!", "DoRequest")
|
|
282
|
+
|
|
283
|
+
} else {
|
|
284
|
+
try {
|
|
285
|
+
await this._doPut(result, request.rowId, rows)
|
|
286
|
+
|
|
287
|
+
} catch (e:any) {
|
|
288
|
+
result.setError(500, "Unhandled exception in HTTP PUT doRequest: " + e.message, "DoRequest")
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
} else if (request.method == "POST") {
|
|
292
|
+
if (request.rowId) {
|
|
293
|
+
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")
|
|
294
|
+
|
|
295
|
+
} else if (rows.length == 0) {
|
|
296
|
+
result.setError(400, "HTTP POST method requires at least one row in the body data!", "DoRequest")
|
|
297
|
+
|
|
298
|
+
} else {
|
|
299
|
+
try {
|
|
300
|
+
await this._doPost(result, rows, request)
|
|
301
|
+
|
|
302
|
+
} catch (e:any) {
|
|
303
|
+
result.setError(500, "Unhandled exception in HTTP POST doRequest: " + e.message, "DoRequest")
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
} else if (request.method == "DELETE") {
|
|
307
|
+
if (!request.rowId) {
|
|
308
|
+
result.setError(400, "HTTP DELETE method requires an id!", "DoRequest")
|
|
309
|
+
|
|
310
|
+
} else {
|
|
311
|
+
try {
|
|
312
|
+
await this._doDelete(result, request.rowId, null)
|
|
313
|
+
|
|
314
|
+
} catch (e:any) {
|
|
315
|
+
result.setError(500, "Unhandled exception in HTTP DELETE doRequest: " + e.message, "DoRequest")
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
} else {
|
|
319
|
+
result.setError(405, "Unsupported HTTP method '" + request.method + "' for REST request", "DoRequest")
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
OINOBenchmark.endMetric("OINODbApi", "doRequest." + request.method, result.status != 500)
|
|
323
|
+
|
|
324
|
+
return Promise.resolve(result)
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
/**
|
|
328
|
+
* Method for handling a HTTP REST request with batch update using PUT or DELETE methods.
|
|
329
|
+
*
|
|
330
|
+
* @param method HTTP method of the REST request
|
|
331
|
+
* @param rowId URL id of the REST request
|
|
332
|
+
* @param rowData HTTP body data as either serialized string or unserialized JS object or OINODataRow-array or Buffer/Uint8Array binary data
|
|
333
|
+
*
|
|
334
|
+
*/
|
|
335
|
+
async doBatchUpdate(method:string, rowId:string, rowData:OINOApiData, queryParams?: OINOQueryParams):Promise<OINOApiResult> {
|
|
336
|
+
return this.doApiRequest(new OINOApiRequest({ method: method, rowId: rowId, rowData: rowData, queryParams: queryParams }))
|
|
337
|
+
}
|
|
338
|
+
/**
|
|
339
|
+
* Method for handling a HTTP REST request with batch update using PUT or DELETE methods.
|
|
340
|
+
*
|
|
341
|
+
* @param request HTTP URL parameters as key-value-pairs
|
|
342
|
+
*
|
|
343
|
+
*/
|
|
344
|
+
async doBatchApiRequest(request:OINOApiRequest):Promise<OINOApiResult> {
|
|
345
|
+
OINOLog.debug("@oino-ts/db", "OINODbApi", "doBatchUpdate", "Request", {request:request, data:request.rowData})
|
|
346
|
+
let result:OINOApiResult = new OINOApiResult(request)
|
|
347
|
+
if ((request.method != "PUT") && (request.method != "DELETE")) {
|
|
348
|
+
result.setError(500, "Batch update only supports PUT and DELETE methods!", "DoBatchUpdate")
|
|
349
|
+
return Promise.resolve(result)
|
|
350
|
+
}
|
|
351
|
+
OINOBenchmark.startMetric("OINODbApi", "doBatchUpdate." + request.method)
|
|
352
|
+
const rows:OINODataRow[] = [] = this._parseData(result, request)
|
|
353
|
+
if (request.method == "PUT") {
|
|
354
|
+
|
|
355
|
+
try {
|
|
356
|
+
await this._doPut(result, null, rows)
|
|
357
|
+
|
|
358
|
+
} catch (e:any) {
|
|
359
|
+
result.setError(500, "Unhandled exception in HTTP PUT doRequest: " + e.message, "DoBatchUpdate")
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
} else if (request.method == "DELETE") {
|
|
363
|
+
try {
|
|
364
|
+
await this._doDelete(result, null, rows)
|
|
365
|
+
|
|
366
|
+
} catch (e:any) {
|
|
367
|
+
result.setError(500, "Unhandled exception in HTTP DELETE doRequest: " + e.message, "DoBatchUpdate")
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
OINOBenchmark.endMetric("OINODbApi", "doBatchUpdate." + request.method, result.status != 500)
|
|
371
|
+
return Promise.resolve(result)
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
/**
|
|
375
|
+
* Method to check if a field is included in the API params.
|
|
376
|
+
*
|
|
377
|
+
* @param fieldName name of the field
|
|
378
|
+
*
|
|
379
|
+
*/
|
|
380
|
+
|
|
381
|
+
public isFieldIncluded(fieldName:string):boolean {
|
|
382
|
+
const params = this.params
|
|
383
|
+
return (
|
|
384
|
+
((params.excludeFieldPrefix == undefined) || (params.excludeFieldPrefix == "") || (fieldName.startsWith(params.excludeFieldPrefix) == false)) &&
|
|
385
|
+
((params.excludeFields == undefined) || (params.excludeFields.length == 0) || (params.excludeFields.indexOf(fieldName) < 0)) &&
|
|
386
|
+
((params.includeFields == undefined) || (params.includeFields.length == 0) || (params.includeFields.indexOf(fieldName) >= 0))
|
|
387
|
+
)
|
|
388
|
+
}
|
|
389
|
+
|
|
668
390
|
}
|