@oino-ts/db 0.21.2 → 1.0.1
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 +30 -144
- 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 +31 -145
- 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.test.ts
CHANGED
|
@@ -1,498 +1,507 @@
|
|
|
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 { expect, test } from "bun:test";
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
import {
|
|
11
|
-
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
15
|
-
|
|
16
|
-
import {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
const
|
|
21
|
-
const
|
|
22
|
-
const
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
{ type: "
|
|
36
|
-
{ type: "
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
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
|
-
"[HTTP GET] select *: GET
|
|
111
|
-
"[HTTP
|
|
112
|
-
"[HTTP
|
|
113
|
-
"[HTTP
|
|
114
|
-
"[HTTP
|
|
115
|
-
"[HTTP
|
|
116
|
-
"[HTTP
|
|
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
|
-
expect(
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
const
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
const
|
|
198
|
-
const
|
|
199
|
-
const
|
|
200
|
-
|
|
201
|
-
const
|
|
202
|
-
const
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
const
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
const
|
|
210
|
-
|
|
211
|
-
const
|
|
212
|
-
|
|
213
|
-
const
|
|
214
|
-
|
|
215
|
-
const
|
|
216
|
-
const
|
|
217
|
-
const
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
const
|
|
221
|
-
const
|
|
222
|
-
const
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
const
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
})
|
|
231
|
-
|
|
232
|
-
target_group = "[
|
|
233
|
-
await test(target_name + target_db + target_table + target_group + "
|
|
234
|
-
expect(
|
|
235
|
-
})
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
expect(encodeData(
|
|
252
|
-
})
|
|
253
|
-
|
|
254
|
-
await test(target_name + target_db + target_table + target_group + " select * with
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
expect(
|
|
261
|
-
})
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
expect(
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
expect(encodeResult((await api.doApiRequest(
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
expect(
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
await test(target_name + target_db + target_table + target_group + " update
|
|
297
|
-
expect(encodeResult(
|
|
298
|
-
expect(encodeResult(
|
|
299
|
-
expect(encodeData(await (await api.doApiRequest(get_request_with_rowid)).data?.writeString(OINOContentType.
|
|
300
|
-
})
|
|
301
|
-
|
|
302
|
-
put_dataset.first()
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
expect(
|
|
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
|
-
const
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
batch_rows[
|
|
381
|
-
batch_rows[
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
expect(
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
}
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
const
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
const
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
const
|
|
419
|
-
const
|
|
420
|
-
const
|
|
421
|
-
|
|
422
|
-
const
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
}
|
|
428
|
-
const
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
target_group = "[OWASP
|
|
441
|
-
await test(target_name + target_db + target_table + target_group + "
|
|
442
|
-
const
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
}
|
|
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 { expect, test } from "bun:test";
|
|
8
|
+
import { Buffer } from "node:buffer"
|
|
9
|
+
|
|
10
|
+
import { OINODbBunSqlite } from "@oino-ts/db-bunsqlite"
|
|
11
|
+
import { OINODbPostgresql } from "@oino-ts/db-postgresql"
|
|
12
|
+
import { OINODbMariadb } from "@oino-ts/db-mariadb"
|
|
13
|
+
import { OINODbMsSql } from "@oino-ts/db-mssql"
|
|
14
|
+
import { OINOQueryAggregate, OINOQuerySelect, OINOApiRequest } from "@oino-ts/common";
|
|
15
|
+
|
|
16
|
+
import { OINOContentType, OINOBenchmark, OINOConsoleLog, OINOLogLevel, OINOLog, OINODataRow, OINODataField, OINOStringDataField, OINOMemoryDataset, OINOApiParams, OINOQueryFilter, OINOConfig, OINOQueryOrder, OINOQueryLimit, OINOApiResult, OINONumberDataField, OINODatetimeDataField, OINOModelSet, OINOQueryParams, OINOApiHtmlTemplate } from "@oino-ts/common";
|
|
17
|
+
|
|
18
|
+
import { OINODbApi, OINODb, OINODbFactory, OINODbParams } from "./index.js";
|
|
19
|
+
|
|
20
|
+
const OINODB_POSTGRESQL_TOKEN = process.env.OINODB_POSTGRESQL_TOKEN || console.error("OINODB_POSTGRESQL_TOKEN not set") || ""
|
|
21
|
+
const OINODB_MARIADB_TOKEN = process.env.OINODB_MARIADB_TOKEN || console.error("OINODB_MARIADB_TOKEN not set") || ""
|
|
22
|
+
const OINOCLOUD_MSSQL_TEST_SRV = process.env.OINOCLOUD_MSSQL_TEST_SRV || console.error("OINOCLOUD_MSSQL_TEST_SRV not set") || ""
|
|
23
|
+
const OINOCLOUD_MSSQL_TEST_USER = process.env.OINOCLOUD_MSSQL_TEST_USER || console.error("OINOCLOUD_MSSQL_TEST_USER not set") || ""
|
|
24
|
+
const OINOCLOUD_MSSQL_TEST_PWD = process.env.OINOCLOUD_DB_NORTHWIND_PWD || console.error("OINOCLOUD_DB_ACCOUNT_PWD not set") || ""
|
|
25
|
+
|
|
26
|
+
type OINOTestParams = {
|
|
27
|
+
name: string
|
|
28
|
+
apiParams: OINOApiParams
|
|
29
|
+
queryParams: OINOQueryParams
|
|
30
|
+
postRow: OINODataRow
|
|
31
|
+
putRow: OINODataRow
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const DATABASES:OINODbParams[] = [
|
|
35
|
+
{ type: "OINODbBunSqlite", url:"file://./localDb/northwind.sqlite", database: "Northwind" },
|
|
36
|
+
{ type: "OINODbPostgresql", url: "localhost", database: "Northwind", port:5432, user: "node", password: OINODB_POSTGRESQL_TOKEN },
|
|
37
|
+
{ type: "OINODbMariadb", url: "127.0.0.1", database: "Northwind", port:6543, user: "node", password: OINODB_MARIADB_TOKEN },
|
|
38
|
+
{ type: "OINODbMsSql", url: OINOCLOUD_MSSQL_TEST_SRV, database: "Northwind", port:1433, user: OINOCLOUD_MSSQL_TEST_USER, password: OINOCLOUD_MSSQL_TEST_PWD }
|
|
39
|
+
]
|
|
40
|
+
|
|
41
|
+
const API_TESTS:OINOTestParams[] = [
|
|
42
|
+
{
|
|
43
|
+
name: "API 1",
|
|
44
|
+
apiParams: { apiName: "Orders", tableName: "Orders" },
|
|
45
|
+
queryParams: { filter: OINOQueryFilter.and(
|
|
46
|
+
OINOQueryFilter.parse("(ShipPostalCode)-like(0502%)"),
|
|
47
|
+
OINOQueryFilter.parse("-isnull(ShipRegion)")
|
|
48
|
+
),
|
|
49
|
+
order: OINOQueryOrder.parse("ShipPostalCode-,Freight+"),
|
|
50
|
+
limit: OINOQueryLimit.parse("5 page 2")
|
|
51
|
+
},
|
|
52
|
+
postRow: [30000,"CACTU",1,new Date("2024-04-05"),new Date("2024-04-06"),new Date("2024-04-07"),2,"184.75","a'b\"c%d_e\tf\rg\nh\\i","Garden House Crowther Way","Cowes","British Isles","PO31 7PJ","UK"],
|
|
53
|
+
putRow: [30000,"CACTU",1,new Date("2023-04-05"),new Date("2023-04-06"),new Date("2023-04-07"),2,"847.51","k'l\"m%n_o\tp\rq\nr\\s","59 rue de l'Abbaye","Cowes2","Western Europe","PO31 8PJ","UK"]
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
name: "API 2",
|
|
57
|
+
apiParams: { apiName: "Products", tableName: "Products", failOnOversizedValues: true },
|
|
58
|
+
queryParams: { filter: OINOQueryFilter.and(
|
|
59
|
+
OINOQueryFilter.parse("(UnitsInStock)-le(5)"),
|
|
60
|
+
OINOQueryFilter.parse("(UnitsInStock)-ne(4)"),
|
|
61
|
+
),
|
|
62
|
+
order: OINOQueryOrder.parse("UnitsInStock,UnitPrice"),
|
|
63
|
+
limit: OINOQueryLimit.parse("7")
|
|
64
|
+
},
|
|
65
|
+
postRow: [99, "Umeshu", 1, 1, "500 ml", 12.99, 2, 0, 20, 0],
|
|
66
|
+
putRow: [99, "Umeshu", 1, 1, undefined, 24.99, 3, 0, 20, 0]
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
name: "API 3",
|
|
70
|
+
apiParams: { apiName: "Employees", tableName: "Employees", hashidKey: "12345678901234567890123456789012", hashidStaticIds:true, returnInsertedIds:true },
|
|
71
|
+
queryParams: { filter: OINOQueryFilter.parse("(TitleOfCourtesy)-eq(Ms.)"), order: OINOQueryOrder.parse("LastName asc"), limit: OINOQueryLimit.parse("5") },
|
|
72
|
+
postRow: [99, "LastName", "FirstName", "Title", "TitleOfCourtesy", new Date("2024-04-06"), new Date("2024-04-07"), "Address", "City", "Region", 12345, "EU", "123 456 7890", "9876", Buffer.from("0001020304", "hex"), "Line1\nLine2", 1, "http://accweb/emmployees/lastnamefirstname.bmp"],
|
|
73
|
+
putRow: [99, "LastName2", "FirstName2", null, "TitleOfCourtesy2", new Date("2023-04-06"), new Date("2023-04-07"), "Address2", "City2", "Region2", 54321, "EU2", "234 567 8901", "8765", Buffer.from("0506070809", "hex"), "Line3\nLine4", 1, "http://accweb/emmployees/lastnamefirstname.bmp"],
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
name: "API 4",
|
|
77
|
+
apiParams: { apiName: "OrderDetails", tableName: "OrderDetails" },
|
|
78
|
+
queryParams: { aggregate: OINOQueryAggregate.parse("count(OrderID),count(ProductID),avg(UnitPrice),sum(Quantity)"), select: OINOQuerySelect.parse("OrderID,ProductID,UnitPrice,Quantity,Discount"), order: OINOQueryOrder.parse("Discount asc") },
|
|
79
|
+
postRow: [10249,77,12.34,56,0],
|
|
80
|
+
putRow: [10249,77,23.45,67,0]
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
]
|
|
84
|
+
|
|
85
|
+
const OWASP_TESTS:OINOTestParams[] = [
|
|
86
|
+
{
|
|
87
|
+
name: "OWASP 1",
|
|
88
|
+
apiParams: { apiName: "Products", tableName: "Products", failOnOversizedValues: true },
|
|
89
|
+
queryParams: { filter: OINOQueryFilter.parse("(1)-eq(1)") },
|
|
90
|
+
postRow: [99, "' FOO", 1, 1],
|
|
91
|
+
putRow: [99, "; FOO", 1, 1]
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
name: "OWASP 2",
|
|
95
|
+
apiParams: { apiName: "Products", tableName: "Products", failOnOversizedValues: true },
|
|
96
|
+
queryParams: { order: OINOQueryOrder.parse("1 asc") },
|
|
97
|
+
postRow: [99, "' FOO", 1, 1],
|
|
98
|
+
putRow: [99, "; FOO", 1, 1]
|
|
99
|
+
},
|
|
100
|
+
{
|
|
101
|
+
name: "OWASP 3",
|
|
102
|
+
apiParams: { apiName: "Products", tableName: "Products", failOnOversizedValues: true },
|
|
103
|
+
queryParams: { filter: OINOQueryFilter.parse("(ProductID)-eq(FOO)") },
|
|
104
|
+
postRow: [99, "\" FOO", 1, 1],
|
|
105
|
+
putRow: [99, "\\ FOO", 1, 1]
|
|
106
|
+
}
|
|
107
|
+
]
|
|
108
|
+
|
|
109
|
+
const API_CROSSCHECKS:string[] = [
|
|
110
|
+
"[HTTP GET] select *: GET JSON 1",
|
|
111
|
+
"[HTTP GET] select *: DOWNLOAD RESPONSE HEADERS 1",
|
|
112
|
+
"[HTTP GET] select *: DOWNLOAD RESPONSE BODY 1",
|
|
113
|
+
"[HTTP GET] select * with template: GET HTML 1",
|
|
114
|
+
"[HTTP GET] select *: GET RECORD 1",
|
|
115
|
+
"[HTTP POST] insert: GET JSON 1",
|
|
116
|
+
"[HTTP POST] insert: GET CSV 1",
|
|
117
|
+
"[HTTP PUT] update JSON: GET JSON 1",
|
|
118
|
+
"[HTTP PUT] update CSV: GET CSV 1",
|
|
119
|
+
"[HTTP PUT] update FORMDATA: GET FORMDATA 1",
|
|
120
|
+
"[HTTP PUT] update URLENCODE: GET URLENCODE 1",
|
|
121
|
+
"[BATCH UPDATE] reversed values: GET reversed data 1",
|
|
122
|
+
"[BATCH UPDATE] reversed values: GET restored data 1"
|
|
123
|
+
]
|
|
124
|
+
|
|
125
|
+
const OWASP_CROSSCHECKS:string[] = [
|
|
126
|
+
"[OWASP POST] POST: POST JSON 1",
|
|
127
|
+
"[OWASP PUT] PUT: OWASP PUT RESULT 1"
|
|
128
|
+
]
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
Math.random()
|
|
132
|
+
|
|
133
|
+
OINOLog.setInstance(new OINOConsoleLog(OINOLogLevel.warning))
|
|
134
|
+
// OINOLog.setLogLevel(OINOLogLevel.debug, "@oino-ts/db-mssql", "OINODbMsSql", "printSqlSelect")
|
|
135
|
+
OINODbFactory.registerDb("OINODbBunSqlite", OINODbBunSqlite)
|
|
136
|
+
OINODbFactory.registerDb("OINODbPostgresql", OINODbPostgresql)
|
|
137
|
+
OINODbFactory.registerDb("OINODbMariadb", OINODbMariadb)
|
|
138
|
+
OINODbFactory.registerDb("OINODbMsSql", OINODbMsSql)
|
|
139
|
+
|
|
140
|
+
OINOBenchmark.setEnabled(["doApiRequest"])
|
|
141
|
+
OINOBenchmark.reset()
|
|
142
|
+
|
|
143
|
+
function encodeData(s:string|undefined):string {
|
|
144
|
+
return s?.replaceAll(/(\\[nrt\"\`\\]?)/g, (match, p1) => {
|
|
145
|
+
// return "\\" + p1;
|
|
146
|
+
return encodeURIComponent(p1);
|
|
147
|
+
}) || ""
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
function encodeResult(o:any|undefined):string {
|
|
151
|
+
return JSON.stringify(o || {}, null, 3).replaceAll(/\`/g, "'").replaceAll(/(\\[nrt\"\\]?)/g, (match, p1) => {
|
|
152
|
+
return encodeURIComponent(p1);
|
|
153
|
+
})
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
function createApiTemplate(api:OINODbApi):OINOApiHtmlTemplate {
|
|
157
|
+
let template_str = ""
|
|
158
|
+
for (let i=0; i<api.datamodel.fields.length; i++) {
|
|
159
|
+
template_str += "<input type='text' name='" + api.datamodel.fields[i].name + "' value='{{{" + api.datamodel.fields[i].name + "}}}'></input>"
|
|
160
|
+
}
|
|
161
|
+
return new OINOApiHtmlTemplate(template_str, -1, "fi", "medium")
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
export async function OINOTestApi(dbParams:OINODbParams, testParams: OINOTestParams) {
|
|
165
|
+
let target_name:string = ""
|
|
166
|
+
if (testParams.name) {
|
|
167
|
+
target_name = "[" + testParams.name + "]"
|
|
168
|
+
}
|
|
169
|
+
const target_db:string = "[" + dbParams.type + "]"
|
|
170
|
+
let target_table:string = "[" + testParams.apiParams.tableName + "]"
|
|
171
|
+
let target_group:string = "[CONNECTION]"
|
|
172
|
+
|
|
173
|
+
if (dbParams.type != "OINODbBunSqlite") { // no passwords in BunSqlite, it will never fail
|
|
174
|
+
const wrong_pwd_params:OINODbParams = Object.assign({}, dbParams)
|
|
175
|
+
wrong_pwd_params.password = "WRONG_PASSWORD"
|
|
176
|
+
const wrong_pwd_db:OINODb = await OINODbFactory.createDb( wrong_pwd_params, false, false )
|
|
177
|
+
await test(target_name + target_db + target_table + target_group + " connection error", async () => {
|
|
178
|
+
expect(wrong_pwd_db).toBeDefined()
|
|
179
|
+
|
|
180
|
+
const connect_res = await wrong_pwd_db.connect()
|
|
181
|
+
expect(connect_res.success).toBe(false)
|
|
182
|
+
expect(connect_res.statusText).toMatchSnapshot("CONNECTION ERROR")
|
|
183
|
+
})
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
// const db:OINODb = await OINODbFactory.createDb( dbParams )
|
|
187
|
+
const db:OINODb = await OINODbFactory.createDb( dbParams )
|
|
188
|
+
await test(target_name + target_db + target_table + target_group + " connection success", async () => {
|
|
189
|
+
expect(db).toBeDefined()
|
|
190
|
+
expect(db.isConnected).toBe(true)
|
|
191
|
+
expect(db.isValidated).toBe(true)
|
|
192
|
+
})
|
|
193
|
+
|
|
194
|
+
const api:OINODbApi = await OINODbFactory.createApi(db, testParams.apiParams)
|
|
195
|
+
api.setDebugOnError(true) // we want debug output (e.g. used sql and exceptions) so that we know that failing tests fail for the correct reason
|
|
196
|
+
|
|
197
|
+
const post_dataset:OINOMemoryDataset = new OINOMemoryDataset([testParams.postRow])
|
|
198
|
+
const post_modelset:OINOModelSet = new OINOModelSet(api.datamodel, post_dataset)
|
|
199
|
+
const post_body_json:string = await post_modelset.writeString(OINOContentType.json)
|
|
200
|
+
|
|
201
|
+
const put_dataset:OINOMemoryDataset = new OINOMemoryDataset([testParams.putRow])
|
|
202
|
+
const put_modelset:OINOModelSet = new OINOModelSet(api.datamodel, put_dataset)
|
|
203
|
+
const put_body_json = await put_modelset.writeString(OINOContentType.json)
|
|
204
|
+
const put_body_csv = await put_modelset.writeString(OINOContentType.csv)
|
|
205
|
+
const put_body_formdata = await put_modelset.writeString(OINOContentType.formdata)
|
|
206
|
+
const put_body_urlencode = await put_modelset.writeString(OINOContentType.urlencode)
|
|
207
|
+
|
|
208
|
+
// const new_row_id:string = OINOConfig.printOINOId(post_modelset.datamodel.getRowPrimarykeyValues(apiDataset.postRow))
|
|
209
|
+
const new_row_id:string = OINOConfig.printOINOId(post_modelset.datamodel.getRowPrimarykeyValues(testParams.postRow, true))
|
|
210
|
+
|
|
211
|
+
const sql_params:OINOQueryParams = Object.assign({}, testParams.queryParams)
|
|
212
|
+
|
|
213
|
+
const request_url = new URL("http://localhost/" + api.params.apiName)
|
|
214
|
+
|
|
215
|
+
const get_request:OINOApiRequest = new OINOApiRequest({ url: request_url, method: "GET" })
|
|
216
|
+
const get_request_with_download:OINOApiRequest = new OINOApiRequest({ url: request_url, method: "GET", responseDownload: "download.csv" })
|
|
217
|
+
const get_request_with_rowid:OINOApiRequest = new OINOApiRequest({ url: request_url, method: "GET", rowId: new_row_id })
|
|
218
|
+
const get_request_with_sql_params:OINOApiRequest = new OINOApiRequest({ url: request_url, method: "GET", queryParams: sql_params })
|
|
219
|
+
|
|
220
|
+
const post_request:OINOApiRequest = new OINOApiRequest({ url: request_url, method: "POST", rowData: post_body_json })
|
|
221
|
+
const post_request_with_id:OINOApiRequest = new OINOApiRequest({ url: request_url, method: "POST", rowId: new_row_id, rowData: post_body_json })
|
|
222
|
+
const post_request_no_data:OINOApiRequest = new OINOApiRequest({ url: request_url, method: "POST", rowData: "{}" })
|
|
223
|
+
|
|
224
|
+
const put_request:OINOApiRequest = new OINOApiRequest({ url: request_url, method: "PUT", rowId: new_row_id, rowData: put_body_json })
|
|
225
|
+
const put_request_with_json:OINOApiRequest = new OINOApiRequest({ url: request_url, method: "PUT", requestType: OINOContentType.json, rowId: new_row_id, rowData: put_body_json })
|
|
226
|
+
const put_request_with_csv:OINOApiRequest = new OINOApiRequest({ url: request_url, method: "PUT", requestType: OINOContentType.csv, rowId: new_row_id, rowData: put_body_csv })
|
|
227
|
+
const put_request_with_urlencode:OINOApiRequest = new OINOApiRequest({ url: request_url, method: "PUT", requestType: OINOContentType.urlencode, rowId: new_row_id, rowData: put_body_urlencode })
|
|
228
|
+
const put_request_with_empty_data:OINOApiRequest = new OINOApiRequest({ url: request_url, method: "PUT", rowId: new_row_id, rowData: "{}" })
|
|
229
|
+
|
|
230
|
+
const delete_request:OINOApiRequest = new OINOApiRequest({ url: request_url, method: "DELETE", rowId: new_row_id })
|
|
231
|
+
|
|
232
|
+
target_group = "[SCHEMA]"
|
|
233
|
+
await test(target_name + target_db + target_table + target_group + " public properties", async () => {
|
|
234
|
+
expect(api.datamodel.printFieldPublicPropertiesJson()).toMatchSnapshot("SCHEMA")
|
|
235
|
+
})
|
|
236
|
+
|
|
237
|
+
target_group = "[HTTP GET]"
|
|
238
|
+
await test(target_name + target_db + target_table + target_group + " select *", async () => {
|
|
239
|
+
expect(encodeData(await (await api.doApiRequest(get_request)).data?.writeString())).toMatchSnapshot("GET JSON")
|
|
240
|
+
})
|
|
241
|
+
|
|
242
|
+
await test(target_name + target_db + target_table + target_group + " select *", async () => {
|
|
243
|
+
const download_result = await api.doApiRequest(get_request_with_download)
|
|
244
|
+
const download_response = await download_result.writeApiResponse()
|
|
245
|
+
expect(download_response.status).toBe(200)
|
|
246
|
+
expect(JSON.stringify(download_response.headers)).toMatchSnapshot("DOWNLOAD RESPONSE HEADERS")
|
|
247
|
+
expect(await download_response.text()).toMatchSnapshot("DOWNLOAD RESPONSE BODY")
|
|
248
|
+
})
|
|
249
|
+
|
|
250
|
+
await test(target_name + target_db + target_table + target_group + " select *", async () => {
|
|
251
|
+
expect(encodeData(JSON.stringify(await (await api.doApiRequest(get_request)).data?.exportAsRecord()))).toMatchSnapshot("GET RECORD")
|
|
252
|
+
})
|
|
253
|
+
|
|
254
|
+
await test(target_name + target_db + target_table + target_group + " select * with template", async () => {
|
|
255
|
+
const template = createApiTemplate(api)
|
|
256
|
+
const api_result:OINOApiResult = await api.doApiRequest(get_request)
|
|
257
|
+
expect(api_result.success).toBe(true)
|
|
258
|
+
const render_res = await template.renderFromDbData(api_result.data!)
|
|
259
|
+
const html = render_res.body
|
|
260
|
+
expect(encodeData(html)).toMatchSnapshot("GET HTML")
|
|
261
|
+
})
|
|
262
|
+
|
|
263
|
+
await test(target_name + target_db + target_table + target_group + " select * with filter", async () => {
|
|
264
|
+
expect(encodeData(await (await api.doApiRequest(get_request_with_sql_params)).data?.writeString())).toMatchSnapshot("GET JSON FILTER")
|
|
265
|
+
})
|
|
266
|
+
|
|
267
|
+
target_group = "[HTTP POST]"
|
|
268
|
+
await test(target_name + target_db + target_table + target_group + " insert with id", async () => {
|
|
269
|
+
expect(encodeResult((await api.doApiRequest(post_request_with_id)))).toMatchSnapshot("POST")
|
|
270
|
+
})
|
|
271
|
+
await test(target_name + target_db + target_table + target_group + " insert", async () => {
|
|
272
|
+
const post_res = await api.doApiRequest(post_request)
|
|
273
|
+
if (testParams.apiParams.returnInsertedIds) {
|
|
274
|
+
expect(encodeData(await post_res.data?.writeString())).toMatchSnapshot("POST RETURN ID")
|
|
275
|
+
} else {
|
|
276
|
+
expect(encodeResult(post_res)).toMatchSnapshot("POST")
|
|
277
|
+
}
|
|
278
|
+
expect(encodeData(await (await api.doApiRequest(get_request_with_rowid)).data?.writeString())).toMatchSnapshot("GET JSON")
|
|
279
|
+
expect(encodeData(await (await api.doApiRequest(get_request_with_rowid)).data?.writeString(OINOContentType.csv))).toMatchSnapshot("GET CSV")
|
|
280
|
+
})
|
|
281
|
+
await test(target_name + target_db + target_table + target_group + " insert no data", async () => {
|
|
282
|
+
expect(encodeResult((await api.doApiRequest(post_request_no_data)))).toMatchSnapshot("POST")
|
|
283
|
+
})
|
|
284
|
+
await test(target_name + target_db + target_table + target_group + " insert duplicate", async () => {
|
|
285
|
+
expect(encodeResult((await api.doApiRequest(post_request)))).toMatchSnapshot("POST")
|
|
286
|
+
})
|
|
287
|
+
|
|
288
|
+
target_group = "[HTTP PUT]"
|
|
289
|
+
await test(target_name + target_db + target_table + target_group + " update JSON", async () => {
|
|
290
|
+
expect(encodeResult((await api.doApiRequest(put_request)))).toMatchSnapshot("PUT JSON reset")
|
|
291
|
+
expect(encodeResult((await api.doApiRequest(put_request_with_json)))).toMatchSnapshot("PUT JSON")
|
|
292
|
+
expect(encodeData(await (await api.doApiRequest(get_request_with_rowid)).data?.writeString())).toMatchSnapshot("GET JSON")
|
|
293
|
+
})
|
|
294
|
+
|
|
295
|
+
put_dataset.first()
|
|
296
|
+
await test(target_name + target_db + target_table + target_group + " update CSV", async () => {
|
|
297
|
+
expect(encodeResult((await api.doApiRequest(put_request)))).toMatchSnapshot("PUT CSV reset")
|
|
298
|
+
expect(encodeResult((await api.doApiRequest(put_request_with_csv)))).toMatchSnapshot("PUT CSV")
|
|
299
|
+
expect(encodeData(await (await api.doApiRequest(get_request_with_rowid)).data?.writeString(OINOContentType.csv))).toMatchSnapshot("GET CSV")
|
|
300
|
+
})
|
|
301
|
+
|
|
302
|
+
put_dataset.first()
|
|
303
|
+
const multipart_boundary = put_body_formdata.substring(0, put_body_formdata.indexOf('\r'))
|
|
304
|
+
const put_body_formdata_normalized = put_body_formdata.replaceAll(multipart_boundary, "---------OINO999999999")
|
|
305
|
+
await test(target_name + target_db + target_table + target_group + " update FORMDATA", async () => {
|
|
306
|
+
expect(encodeResult(await (await api.doApiRequest(put_request)))).toMatchSnapshot("PUT FORMDATA reset")
|
|
307
|
+
expect(encodeResult(await (await api.doApiRequest(new OINOApiRequest({ url: request_url, method: "PUT", requestType: OINOContentType.formdata, multipartBoundary: "---------OINO999999999", rowId: new_row_id, rowData: put_body_formdata_normalized }))))).toMatchSnapshot("PUT FORMDATA")
|
|
308
|
+
expect(encodeData(await (await api.doApiRequest(get_request_with_rowid)).data?.writeString(OINOContentType.formdata))).toMatchSnapshot("GET FORMDATA")
|
|
309
|
+
})
|
|
310
|
+
|
|
311
|
+
put_dataset.first()
|
|
312
|
+
await test(target_name + target_db + target_table + target_group + " update URLENCODE", async () => {
|
|
313
|
+
expect(encodeResult((await api.doApiRequest(put_request)))).toMatchSnapshot("PUT URLENCODE reset")
|
|
314
|
+
expect(encodeResult((await api.doApiRequest(put_request_with_urlencode)))).toMatchSnapshot("PUT URLENCODE")
|
|
315
|
+
expect(encodeData(await (await api.doApiRequest(get_request_with_rowid)).data?.writeString(OINOContentType.urlencode))).toMatchSnapshot("GET URLENCODE")
|
|
316
|
+
})
|
|
317
|
+
|
|
318
|
+
await test(target_name + target_db + target_table + target_group + " update no data", async () => {
|
|
319
|
+
expect(encodeResult((await api.doApiRequest(put_request_with_empty_data)))).toMatchSnapshot("PUT")
|
|
320
|
+
})
|
|
321
|
+
|
|
322
|
+
const primary_keys:OINODataField[] = api.datamodel.filterFields((field:OINODataField) => { return field.fieldParams.isPrimaryKey })
|
|
323
|
+
if (primary_keys.length != 1) {
|
|
324
|
+
OINOLog.info("@oino-ts/db", "OINODbApi.test.ts", "OINOTestApi", "HTTP PUT table " + testParams.apiParams.tableName + " does not have an individual primary key so 'invalid null' and 'oversized data' tests are skipped", {})
|
|
325
|
+
} else {
|
|
326
|
+
const id_field:string = primary_keys[0].name
|
|
327
|
+
const notnull_fields:OINODataField[] = api.datamodel.filterFields((field:OINODataField) => { return (field.fieldParams.isPrimaryKey == false) && (field.fieldParams.isNotNull == true) })
|
|
328
|
+
if (notnull_fields.length > 0) {
|
|
329
|
+
const invalid_null_value = "[{\"" + id_field + "\":\"" + new_row_id + "\",\"" + notnull_fields[0].name + "\":null}]"
|
|
330
|
+
await test(target_name + target_db + target_table + target_group + " update with invalid null value", async () => {
|
|
331
|
+
expect(encodeResult((await api.doApiRequest(new OINOApiRequest({ url: request_url, method: "PUT", rowId: new_row_id, rowData: invalid_null_value }))))).toMatchSnapshot("PUT invalid null")
|
|
332
|
+
})
|
|
333
|
+
}
|
|
334
|
+
const maxsize_fields:OINODataField[] = api.datamodel.filterFields((field:OINODataField) => { return (field instanceof OINOStringDataField) && (field.fieldParams.isPrimaryKey == false) && (field.maxLength > 0) })
|
|
335
|
+
if (maxsize_fields.length > 0) {
|
|
336
|
+
const oversized_value = "[{\"" + id_field + "\":\"" + new_row_id + "\",\"" + maxsize_fields[0].name + "\":\"" + "".padEnd(maxsize_fields[0].maxLength+1, "z") + "\"}]"
|
|
337
|
+
await test(target_name + target_db + target_table + target_group + " update with oversized data", async () => {
|
|
338
|
+
expect(encodeResult((await api.doApiRequest(new OINOApiRequest({ url: request_url, method: "PUT", rowId: new_row_id, rowData: oversized_value }))))).toMatchSnapshot("PUT oversized value")
|
|
339
|
+
})
|
|
340
|
+
}
|
|
341
|
+
const numeric_fields:OINODataField[] = api.datamodel.filterFields((field:OINODataField) => { return (field instanceof OINONumberDataField) && (field.fieldParams.isPrimaryKey == false) })
|
|
342
|
+
if (numeric_fields.length > 0) {
|
|
343
|
+
const nan_value = "[{\"" + id_field + "\":\"" + new_row_id + "\",\"" + numeric_fields[0].name + "\":\"" + "; FOO" + "\"}]"
|
|
344
|
+
await test(target_name + target_db + target_table + target_group + " update NAN-value", async () => {
|
|
345
|
+
expect(encodeResult((await api.doApiRequest(new OINOApiRequest({ url: request_url, method: "PUT", rowId: new_row_id, rowData: nan_value }))))).toMatchSnapshot("PUT NAN-value")
|
|
346
|
+
})
|
|
347
|
+
}
|
|
348
|
+
const date_fields:OINODataField[] = api.datamodel.filterFields((field:OINODataField) => { return (field instanceof OINODatetimeDataField) && (field.fieldParams.isPrimaryKey == false) })
|
|
349
|
+
if (date_fields.length > 0) {
|
|
350
|
+
const non_date = "[{\"" + id_field + "\":\"" + new_row_id + "\",\"" + date_fields[0].name + "\":\"" + "; FOO" + "\"}]"
|
|
351
|
+
await test(target_name + target_db + target_table + target_group + " update invalid date value", async () => {
|
|
352
|
+
expect(encodeResult((await api.doApiRequest(new OINOApiRequest({ url: request_url, method: "PUT", rowId: new_row_id, rowData: non_date }))))).toMatchSnapshot("PUT invalid date value")
|
|
353
|
+
})
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
target_group = "[BATCH UPDATE]"
|
|
358
|
+
const reversable_fields:OINODataField[] = api.datamodel.filterFields((field:OINODataField) => { return ((field instanceof OINOStringDataField) || (field instanceof OINONumberDataField)) && (field.fieldParams.isPrimaryKey == false) && (field.fieldParams.isForeignKey == false) })
|
|
359
|
+
if (reversable_fields.length == 0) {
|
|
360
|
+
OINOLog.info("@oino-ts/db", "OINODbApi.test.ts", "OINOTestApi", "BATCH UPDATE table " + testParams.apiParams.tableName + " does not have numeric fields and batch update tests are skipped", {})
|
|
361
|
+
} else {
|
|
362
|
+
const batch_field = reversable_fields[0]
|
|
363
|
+
const batch_field_name:string = batch_field.name
|
|
364
|
+
const batch_field_index:number = api.datamodel.findFieldIndexByName(batch_field_name)
|
|
365
|
+
const batch_value = testParams.putRow[batch_field_index]
|
|
366
|
+
let batch_reversed_value
|
|
367
|
+
if (batch_field instanceof OINOStringDataField) {
|
|
368
|
+
batch_reversed_value = (batch_value as string).split("").reverse().join("")
|
|
369
|
+
} else {
|
|
370
|
+
batch_reversed_value = -(batch_value as number)
|
|
371
|
+
}
|
|
372
|
+
const batch_rows = [
|
|
373
|
+
[...testParams.putRow] as OINODataRow,
|
|
374
|
+
[...testParams.putRow] as OINODataRow,
|
|
375
|
+
[...testParams.putRow] as OINODataRow
|
|
376
|
+
]
|
|
377
|
+
|
|
378
|
+
await test(target_name + target_db + target_table + target_group + " reversed values", async () => {
|
|
379
|
+
batch_rows[0][batch_field_index] = batch_reversed_value
|
|
380
|
+
batch_rows[1][batch_field_index] = batch_value
|
|
381
|
+
batch_rows[2][batch_field_index] = batch_reversed_value
|
|
382
|
+
const batch_update_result = await api.doBatchApiRequest( new OINOApiRequest({ url: request_url, method: "PUT", rowData: batch_rows }))
|
|
383
|
+
expect(batch_update_result.success).toBe(true)
|
|
384
|
+
expect(encodeResult(batch_update_result)).toMatchSnapshot("PUT reversed data")
|
|
385
|
+
|
|
386
|
+
const get_reversed_data = await (await api.doApiRequest(get_request_with_rowid)).data?.writeString(OINOContentType.csv)
|
|
387
|
+
expect(encodeData(get_reversed_data)).toMatchSnapshot("GET reversed data")
|
|
388
|
+
|
|
389
|
+
batch_rows[0][batch_field_index] = batch_value
|
|
390
|
+
batch_rows[1][batch_field_index] = batch_reversed_value
|
|
391
|
+
batch_rows[2][batch_field_index] = batch_value
|
|
392
|
+
const batch_restore_result = await api.doBatchApiRequest( new OINOApiRequest({ url: request_url, method: "PUT", rowData: batch_rows }))
|
|
393
|
+
expect(batch_restore_result.success).toBe(true)
|
|
394
|
+
expect(encodeResult(batch_restore_result)).toMatchSnapshot("PUT restored data")
|
|
395
|
+
|
|
396
|
+
const get_restored_data = await (await api.doApiRequest(get_request_with_rowid)).data?.writeString(OINOContentType.csv)
|
|
397
|
+
expect(encodeData(get_restored_data)).toMatchSnapshot("GET restored data")
|
|
398
|
+
})
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
target_group = "[HTTP DELETE]"
|
|
402
|
+
await test(target_name + target_db + target_table + target_group + " remove", async () => {
|
|
403
|
+
expect(encodeResult((await api.doApiRequest(delete_request)))).toMatchSnapshot("DELETE")
|
|
404
|
+
expect(encodeData(await (await api.doApiRequest(get_request_with_rowid)).data?.writeString())).toMatchSnapshot("GET JSON")
|
|
405
|
+
})
|
|
406
|
+
|
|
407
|
+
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
export async function OINOTestOwasp(dbParams:OINODbParams, testParams: OINOTestParams) {
|
|
411
|
+
const db:OINODb = await OINODbFactory.createDb( dbParams )
|
|
412
|
+
const api:OINODbApi = await OINODbFactory.createApi(db, testParams.apiParams)
|
|
413
|
+
|
|
414
|
+
const post_dataset:OINOMemoryDataset = new OINOMemoryDataset([testParams.postRow])
|
|
415
|
+
const post_modelset:OINOModelSet = new OINOModelSet(api.datamodel, post_dataset)
|
|
416
|
+
const post_body_json:string = await post_modelset.writeString(OINOContentType.json)
|
|
417
|
+
|
|
418
|
+
const put_dataset:OINOMemoryDataset = new OINOMemoryDataset([testParams.putRow])
|
|
419
|
+
const put_modelset:OINOModelSet = new OINOModelSet(api.datamodel, put_dataset)
|
|
420
|
+
const put_body_json:string = await put_modelset.writeString(OINOContentType.json)
|
|
421
|
+
|
|
422
|
+
const new_row_id:string = OINOConfig.printOINOId(post_modelset.datamodel.getRowPrimarykeyValues(testParams.postRow, true))
|
|
423
|
+
|
|
424
|
+
const sql_params:OINOQueryParams = Object.assign({}, testParams.queryParams)
|
|
425
|
+
|
|
426
|
+
const url = new URL("http://localhost/" + api.params.apiName)
|
|
427
|
+
const get_request_with_rowid = new OINOApiRequest({ url: url, method: "GET", rowId: new_row_id })
|
|
428
|
+
const get_request_with_sql_params = new OINOApiRequest({ url: url, method: "GET", queryParams: sql_params })
|
|
429
|
+
const post_request = new OINOApiRequest({ url: url, method: "POST", rowData: post_body_json })
|
|
430
|
+
const put_request = new OINOApiRequest({ url: url, method: "PUT", rowId: new_row_id, rowData: put_body_json })
|
|
431
|
+
const delete_request = new OINOApiRequest({ url: url, method: "DELETE", rowId: new_row_id })
|
|
432
|
+
|
|
433
|
+
let target_name:string = ""
|
|
434
|
+
if (testParams.name) {
|
|
435
|
+
target_name = "[" + testParams.name + "]"
|
|
436
|
+
}
|
|
437
|
+
const target_db:string = "[" + dbParams.type + "]"
|
|
438
|
+
let target_table:string = "[" + testParams.apiParams.tableName + "]"
|
|
439
|
+
|
|
440
|
+
let target_group = "[OWASP GET]"
|
|
441
|
+
await test(target_name + target_db + target_table + target_group + " GET with filter", async () => {
|
|
442
|
+
const get_res:OINOApiResult = await api.doApiRequest(get_request_with_sql_params)
|
|
443
|
+
if (get_res.success) {
|
|
444
|
+
expect(encodeData(await get_res.data?.writeString())).toMatchSnapshot("OWASP GET DATA")
|
|
445
|
+
} else {
|
|
446
|
+
expect(encodeResult(get_res)).toMatchSnapshot("OWASP GET RESULT")
|
|
447
|
+
}
|
|
448
|
+
})
|
|
449
|
+
target_group = "[OWASP POST]"
|
|
450
|
+
await test(target_name + target_db + target_table + target_group + " POST", async () => {
|
|
451
|
+
const post_res:OINOApiResult = await api.doApiRequest(post_request)
|
|
452
|
+
expect(encodeResult(post_res)).toMatchSnapshot("OWASP POST RESULT")
|
|
453
|
+
expect(encodeData(await (await api.doApiRequest(get_request_with_rowid)).data?.writeString())).toMatchSnapshot("POST JSON")
|
|
454
|
+
})
|
|
455
|
+
|
|
456
|
+
target_group = "[OWASP PUT]"
|
|
457
|
+
await test(target_name + target_db + target_table + target_group + " PUT", async () => {
|
|
458
|
+
const post_res:OINOApiResult = await api.doApiRequest( put_request)
|
|
459
|
+
expect(encodeResult(post_res)).toMatchSnapshot("OWASP PUT RESULT")
|
|
460
|
+
expect(encodeData(await (await api.doApiRequest(get_request_with_rowid)).data?.writeString())).toMatchSnapshot("PUT JSON")
|
|
461
|
+
})
|
|
462
|
+
|
|
463
|
+
target_group = "[OWASP DELETE]"
|
|
464
|
+
await test(target_name + target_db + target_table + target_group + " DELETE", async () => {
|
|
465
|
+
expect(encodeResult((await api.doApiRequest(delete_request)))).toMatchSnapshot("DELETE")
|
|
466
|
+
expect(encodeData(await (await api.doApiRequest(get_request_with_rowid)).data?.writeString())).toMatchSnapshot("DELETE JSON")
|
|
467
|
+
})
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
|
|
471
|
+
for (let db of DATABASES) {
|
|
472
|
+
for (let api_test of API_TESTS) {
|
|
473
|
+
await OINOTestApi(db, api_test)
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
for (let db of DATABASES) {
|
|
478
|
+
for (let owasp_test of OWASP_TESTS) {
|
|
479
|
+
await OINOTestOwasp(db, owasp_test)
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
|
|
484
|
+
const snapshot_file = Bun.file("./node_modules/@oino-ts/db/src/__snapshots__/OINODbApi.test.ts.snap")
|
|
485
|
+
await Bun.write("./node_modules/@oino-ts/db/src/__snapshots__/OINODbApi.test.ts.snap.js", snapshot_file) // copy snapshots as .js so require works (note! if run with --update-snapshots, it's still the old file)
|
|
486
|
+
const snapshots = require("./__snapshots__/OINODbApi.test.ts.snap.js")
|
|
487
|
+
|
|
488
|
+
for (let i=0; i<DATABASES.length-1; i++) {
|
|
489
|
+
const db1:string = DATABASES[i].type
|
|
490
|
+
const db2:string = DATABASES[i+1].type
|
|
491
|
+
for (let api_test of API_TESTS) {
|
|
492
|
+
const table_name = api_test.apiParams.tableName
|
|
493
|
+
for (let crosscheck of API_CROSSCHECKS) {
|
|
494
|
+
test("cross check {" + db1 + "} and {" + db2 + "} table {" + table_name + "} snapshots on {" + crosscheck + "}", () => {
|
|
495
|
+
expect(snapshots["[" + api_test.name + "][" + db1 + "][" + table_name + "]" + crosscheck]).toMatch(snapshots["[" + api_test.name + "][" + db2 + "][" + table_name + "]" + crosscheck])
|
|
496
|
+
})
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
for (let owasp_test of OWASP_TESTS) {
|
|
500
|
+
const table_name = owasp_test.apiParams.tableName
|
|
501
|
+
for (let crosscheck of OWASP_CROSSCHECKS) {
|
|
502
|
+
test("cross check {" + db1 + "} and {" + db2 + "} table {" + table_name + "} snapshots on {" + crosscheck + "}", () => {
|
|
503
|
+
expect(snapshots["[" + owasp_test.name + "][" + db1 + "][" + table_name + "]" + crosscheck]).toMatch(snapshots["[" + owasp_test.name + "][" + db2 + "][" + table_name + "]" + crosscheck])
|
|
504
|
+
})
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
}
|