@naturalcycles/db-lib 8.39.0 → 8.41.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/adapter/file/file.db.d.ts +1 -1
- package/dist/commondao/common.dao.d.ts +8 -8
- package/dist/commondao/common.dao.js +51 -20
- package/dist/commondao/common.dao.model.d.ts +5 -0
- package/dist/db.model.d.ts +7 -0
- package/dist/testing/daoTest.js +4 -4
- package/dist/testing/dbTest.js +4 -4
- package/dist/testing/test.model.d.ts +2 -2
- package/dist/testing/test.model.js +6 -3
- package/package.json +4 -4
- package/src/adapter/file/file.db.ts +2 -2
- package/src/commondao/common.dao.model.ts +6 -0
- package/src/commondao/common.dao.ts +67 -34
- package/src/db.model.ts +8 -0
- package/src/query/dbQuery.ts +2 -2
- package/src/testing/daoTest.ts +4 -4
- package/src/testing/dbTest.ts +4 -4
- package/src/testing/test.model.ts +14 -11
|
@@ -36,7 +36,7 @@ export declare class FileDB extends BaseCommonDB implements CommonDB {
|
|
|
36
36
|
loadFile<ROW extends ObjectWithId>(table: string): Promise<ROW[]>;
|
|
37
37
|
saveFile<ROW extends ObjectWithId>(table: string, _rows: ROW[]): Promise<void>;
|
|
38
38
|
saveFiles<ROW extends ObjectWithId>(ops: DBSaveBatchOperation<ROW>[]): Promise<void>;
|
|
39
|
-
sortRows
|
|
39
|
+
private sortRows;
|
|
40
40
|
private logStarted;
|
|
41
41
|
private logFinished;
|
|
42
42
|
}
|
|
@@ -14,14 +14,14 @@ export declare class CommonDao<BM extends Partial<ObjectWithId<ID>>, DBM extends
|
|
|
14
14
|
cfg: CommonDaoCfg<BM, DBM, TM, ID>;
|
|
15
15
|
constructor(cfg: CommonDaoCfg<BM, DBM, TM, ID>);
|
|
16
16
|
create(part?: Partial<BM>, opt?: CommonDaoOptions): Saved<BM>;
|
|
17
|
-
getById(id: undefined, opt?: CommonDaoOptions): Promise<null>;
|
|
18
|
-
getById(id?: ID, opt?: CommonDaoOptions): Promise<Saved<BM> | null>;
|
|
17
|
+
getById(id: undefined | null, opt?: CommonDaoOptions): Promise<null>;
|
|
18
|
+
getById(id?: ID | null, opt?: CommonDaoOptions): Promise<Saved<BM> | null>;
|
|
19
19
|
getByIdOrEmpty(id: ID, part?: Partial<BM>, opt?: CommonDaoOptions): Promise<Saved<BM>>;
|
|
20
20
|
getByIdAsDBMOrEmpty(id: ID, part?: Partial<BM>, opt?: CommonDaoOptions): Promise<DBM>;
|
|
21
|
-
getByIdAsDBM(id: undefined, opt?: CommonDaoOptions): Promise<null>;
|
|
22
|
-
getByIdAsDBM(id?: ID, opt?: CommonDaoOptions): Promise<DBM | null>;
|
|
23
|
-
getByIdAsTM(id: undefined, opt?: CommonDaoOptions): Promise<null>;
|
|
24
|
-
getByIdAsTM(id?: ID, opt?: CommonDaoOptions): Promise<TM | null>;
|
|
21
|
+
getByIdAsDBM(id: undefined | null, opt?: CommonDaoOptions): Promise<null>;
|
|
22
|
+
getByIdAsDBM(id?: ID | null, opt?: CommonDaoOptions): Promise<DBM | null>;
|
|
23
|
+
getByIdAsTM(id: undefined | null, opt?: CommonDaoOptions): Promise<null>;
|
|
24
|
+
getByIdAsTM(id?: ID | null, opt?: CommonDaoOptions): Promise<TM | null>;
|
|
25
25
|
getByIds(ids: ID[], opt?: CommonDaoOptions): Promise<Saved<BM>[]>;
|
|
26
26
|
getByIdsAsDBM(ids: ID[], opt?: CommonDaoOptions): Promise<DBM[]>;
|
|
27
27
|
requireById(id: ID, opt?: CommonDaoOptions): Promise<Saved<BM>>;
|
|
@@ -103,8 +103,8 @@ export declare class CommonDao<BM extends Partial<ObjectWithId<ID>>, DBM extends
|
|
|
103
103
|
/**
|
|
104
104
|
* @returns number of deleted items
|
|
105
105
|
*/
|
|
106
|
-
deleteById(id: undefined, opt?: CommonDaoOptions): Promise<0>;
|
|
107
|
-
deleteById(id?: ID, opt?: CommonDaoOptions): Promise<number>;
|
|
106
|
+
deleteById(id: undefined | null, opt?: CommonDaoOptions): Promise<0>;
|
|
107
|
+
deleteById(id?: ID | null, opt?: CommonDaoOptions): Promise<number>;
|
|
108
108
|
deleteByIds(ids: ID[], opt?: CommonDaoOptions): Promise<number>;
|
|
109
109
|
/**
|
|
110
110
|
* Pass `stream: true` option to use Streaming: it will Stream the query, batch by 500, and execute
|
|
@@ -28,6 +28,7 @@ class CommonDao {
|
|
|
28
28
|
logLevel: isGAE || isCI ? common_dao_model_1.CommonDaoLogLevel.NONE : common_dao_model_1.CommonDaoLogLevel.OPERATIONS,
|
|
29
29
|
idType: 'string',
|
|
30
30
|
createId: true,
|
|
31
|
+
assignGeneratedIds: false,
|
|
31
32
|
created: true,
|
|
32
33
|
updated: true,
|
|
33
34
|
logger: console,
|
|
@@ -219,7 +220,7 @@ class CommonDao {
|
|
|
219
220
|
(0, js_lib_1._assert)(q._selectedFieldNames?.length === 1, `runQuerySingleColumn requires exactly 1 column to be selected: ${q.pretty()}`);
|
|
220
221
|
const col = q._selectedFieldNames[0];
|
|
221
222
|
const { rows } = await this.runQueryExtended(q, opt);
|
|
222
|
-
return rows.map(r => r[col]);
|
|
223
|
+
return rows.map((r) => r[col]);
|
|
223
224
|
}
|
|
224
225
|
/**
|
|
225
226
|
* Convenience method that runs multiple queries in parallel and then merges their results together.
|
|
@@ -434,13 +435,17 @@ class CommonDao {
|
|
|
434
435
|
}
|
|
435
436
|
}
|
|
436
437
|
assignIdCreatedUpdated(obj, opt = {}) {
|
|
438
|
+
var _a;
|
|
437
439
|
const now = Math.floor(Date.now() / 1000);
|
|
438
440
|
obj.id || (obj.id = this.cfg.hooks.createId?.(obj));
|
|
439
441
|
if (this.cfg.created) {
|
|
440
|
-
|
|
442
|
+
;
|
|
443
|
+
(_a = obj)['created'] || (_a['created'] = obj['updated'] || now);
|
|
441
444
|
}
|
|
442
445
|
if (this.cfg.updated) {
|
|
443
|
-
|
|
446
|
+
;
|
|
447
|
+
obj['updated'] =
|
|
448
|
+
opt.preserveUpdatedCreated && obj['updated'] ? obj['updated'] : now;
|
|
444
449
|
}
|
|
445
450
|
return obj;
|
|
446
451
|
}
|
|
@@ -450,7 +455,7 @@ class CommonDao {
|
|
|
450
455
|
*/
|
|
451
456
|
async save(bm, opt = {}) {
|
|
452
457
|
this.requireWriteAccess();
|
|
453
|
-
const idWasGenerated = !bm.id;
|
|
458
|
+
const idWasGenerated = !bm.id && this.cfg.createId;
|
|
454
459
|
this.assignIdCreatedUpdated(bm, opt); // mutates
|
|
455
460
|
const dbm = await this.bmToDBM(bm, opt);
|
|
456
461
|
const table = opt.table || this.cfg.table;
|
|
@@ -461,10 +466,16 @@ class CommonDao {
|
|
|
461
466
|
}
|
|
462
467
|
const op = `save(${dbm.id})`;
|
|
463
468
|
const started = this.logSaveStarted(op, bm, table);
|
|
469
|
+
const { excludeFromIndexes } = this.cfg;
|
|
470
|
+
const assignGeneratedIds = opt.assignGeneratedIds || this.cfg.assignGeneratedIds;
|
|
464
471
|
await this.cfg.db.saveBatch(table, [dbm], {
|
|
465
|
-
excludeFromIndexes
|
|
472
|
+
excludeFromIndexes,
|
|
473
|
+
assignGeneratedIds,
|
|
466
474
|
...opt,
|
|
467
475
|
});
|
|
476
|
+
if (assignGeneratedIds) {
|
|
477
|
+
bm.id = dbm.id;
|
|
478
|
+
}
|
|
468
479
|
this.logSaveResult(started, op, table);
|
|
469
480
|
return bm;
|
|
470
481
|
}
|
|
@@ -495,24 +506,31 @@ class CommonDao {
|
|
|
495
506
|
const table = opt.table || this.cfg.table;
|
|
496
507
|
// assigning id in case it misses the id
|
|
497
508
|
// will override/set `updated` field, unless opts.preserveUpdated is set
|
|
509
|
+
let row = dbm;
|
|
498
510
|
if (!opt.raw) {
|
|
499
|
-
const idWasGenerated = !dbm.id;
|
|
511
|
+
const idWasGenerated = !dbm.id && this.cfg.createId;
|
|
500
512
|
this.assignIdCreatedUpdated(dbm, opt); // mutates
|
|
501
|
-
|
|
513
|
+
row = this.anyToDBM(dbm, opt);
|
|
502
514
|
if (opt.ensureUniqueId && idWasGenerated)
|
|
503
|
-
await this.ensureUniqueId(table,
|
|
515
|
+
await this.ensureUniqueId(table, row);
|
|
504
516
|
}
|
|
505
517
|
if (this.cfg.immutable && !opt.allowMutability && !opt.saveMethod) {
|
|
506
518
|
opt = { ...opt, saveMethod: 'insert' };
|
|
507
519
|
}
|
|
508
|
-
const op = `saveAsDBM(${
|
|
509
|
-
const started = this.logSaveStarted(op,
|
|
510
|
-
|
|
511
|
-
|
|
520
|
+
const op = `saveAsDBM(${row.id})`;
|
|
521
|
+
const started = this.logSaveStarted(op, row, table);
|
|
522
|
+
const { excludeFromIndexes } = this.cfg;
|
|
523
|
+
const assignGeneratedIds = opt.assignGeneratedIds || this.cfg.assignGeneratedIds;
|
|
524
|
+
await this.cfg.db.saveBatch(table, [row], {
|
|
525
|
+
excludeFromIndexes,
|
|
526
|
+
assignGeneratedIds,
|
|
512
527
|
...opt,
|
|
513
528
|
});
|
|
529
|
+
if (assignGeneratedIds) {
|
|
530
|
+
dbm.id = row.id;
|
|
531
|
+
}
|
|
514
532
|
this.logSaveResult(started, op, table);
|
|
515
|
-
return
|
|
533
|
+
return row;
|
|
516
534
|
}
|
|
517
535
|
async saveBatch(bms, opt = {}) {
|
|
518
536
|
this.requireWriteAccess();
|
|
@@ -529,36 +547,49 @@ class CommonDao {
|
|
|
529
547
|
.map(bm => bm.id)
|
|
530
548
|
.join(', '), 50)})`;
|
|
531
549
|
const started = this.logSaveStarted(op, bms, table);
|
|
550
|
+
const { excludeFromIndexes } = this.cfg;
|
|
551
|
+
const assignGeneratedIds = opt.assignGeneratedIds || this.cfg.assignGeneratedIds;
|
|
532
552
|
await this.cfg.db.saveBatch(table, dbms, {
|
|
533
|
-
excludeFromIndexes
|
|
553
|
+
excludeFromIndexes,
|
|
554
|
+
assignGeneratedIds,
|
|
534
555
|
...opt,
|
|
535
556
|
});
|
|
557
|
+
if (assignGeneratedIds) {
|
|
558
|
+
dbms.forEach((dbm, i) => (bms[i].id = dbm.id));
|
|
559
|
+
}
|
|
536
560
|
this.logSaveResult(started, op, table);
|
|
537
561
|
return bms;
|
|
538
562
|
}
|
|
539
563
|
async saveBatchAsDBM(dbms, opt = {}) {
|
|
540
564
|
this.requireWriteAccess();
|
|
541
565
|
const table = opt.table || this.cfg.table;
|
|
566
|
+
let rows = dbms;
|
|
542
567
|
if (!opt.raw) {
|
|
543
568
|
dbms.forEach(dbm => this.assignIdCreatedUpdated(dbm, opt)); // mutates
|
|
544
|
-
|
|
569
|
+
rows = this.anyToDBMs(dbms, opt);
|
|
545
570
|
if (opt.ensureUniqueId)
|
|
546
571
|
throw new js_lib_1.AppError('ensureUniqueId is not supported in saveBatch');
|
|
547
572
|
}
|
|
548
573
|
if (this.cfg.immutable && !opt.allowMutability && !opt.saveMethod) {
|
|
549
574
|
opt = { ...opt, saveMethod: 'insert' };
|
|
550
575
|
}
|
|
551
|
-
const op = `saveBatchAsDBM ${
|
|
576
|
+
const op = `saveBatchAsDBM ${rows.length} row(s) (${(0, js_lib_1._truncate)(rows
|
|
552
577
|
.slice(0, 10)
|
|
553
578
|
.map(bm => bm.id)
|
|
554
579
|
.join(', '), 50)})`;
|
|
555
|
-
const started = this.logSaveStarted(op,
|
|
556
|
-
|
|
557
|
-
|
|
580
|
+
const started = this.logSaveStarted(op, rows, table);
|
|
581
|
+
const { excludeFromIndexes } = this.cfg;
|
|
582
|
+
const assignGeneratedIds = opt.assignGeneratedIds || this.cfg.assignGeneratedIds;
|
|
583
|
+
await this.cfg.db.saveBatch(table, rows, {
|
|
584
|
+
excludeFromIndexes,
|
|
585
|
+
assignGeneratedIds,
|
|
558
586
|
...opt,
|
|
559
587
|
});
|
|
588
|
+
if (assignGeneratedIds) {
|
|
589
|
+
rows.forEach((row, i) => (dbms[i].id = row.id));
|
|
590
|
+
}
|
|
560
591
|
this.logSaveResult(started, op, table);
|
|
561
|
-
return
|
|
592
|
+
return rows;
|
|
562
593
|
}
|
|
563
594
|
async deleteById(id, opt = {}) {
|
|
564
595
|
if (!id)
|
|
@@ -86,6 +86,11 @@ export interface CommonDaoCfg<BM extends Partial<ObjectWithId<ID>>, DBM extends
|
|
|
86
86
|
* Useful e.g when your DB is generating ids by itself (e.g mysql auto_increment).
|
|
87
87
|
*/
|
|
88
88
|
createId?: boolean;
|
|
89
|
+
/**
|
|
90
|
+
* See the same option in CommonDB.
|
|
91
|
+
* Defaults to false normally.
|
|
92
|
+
*/
|
|
93
|
+
assignGeneratedIds?: boolean;
|
|
89
94
|
/**
|
|
90
95
|
* Defaults to true
|
|
91
96
|
* Set to false to disable `created` field management.
|
package/dist/db.model.d.ts
CHANGED
|
@@ -19,6 +19,13 @@ export interface CommonDBSaveOptions<ROW extends Partial<ObjectWithId> = AnyObje
|
|
|
19
19
|
* Default is `upsert`
|
|
20
20
|
*/
|
|
21
21
|
saveMethod?: CommonDBSaveMethod;
|
|
22
|
+
/**
|
|
23
|
+
* Only applicable to tables where id is "auto-generated by DB", e.g `auto_increment` in MySQL.
|
|
24
|
+
* By default it's false, so, auto-generated id will NOT be assigned/returned.
|
|
25
|
+
* Setting it to true will assign and return auto-generated id (on all rows, one by one).
|
|
26
|
+
* It's not true by default, because getting auto-generated id incurs an overhead of doing extra call (e.g LAST_INSERT_ID() in MySQL).
|
|
27
|
+
*/
|
|
28
|
+
assignGeneratedIds?: boolean;
|
|
22
29
|
}
|
|
23
30
|
export declare type CommonDBStreamOptions = CommonDBOptions;
|
|
24
31
|
export interface CommonDBCreateOptions extends CommonDBOptions {
|
package/dist/testing/daoTest.js
CHANGED
|
@@ -41,7 +41,7 @@ function runCommonDaoTest(db, features = {}, quirks = {}) {
|
|
|
41
41
|
// CREATE TABLE, DROP
|
|
42
42
|
if (createTable) {
|
|
43
43
|
test('createTable, dropIfExists=true', async () => {
|
|
44
|
-
await dao.createTable(test_model_1.testItemDBMJsonSchema
|
|
44
|
+
await dao.createTable(test_model_1.testItemDBMJsonSchema, { dropIfExists: true });
|
|
45
45
|
});
|
|
46
46
|
}
|
|
47
47
|
if (querying) {
|
|
@@ -55,7 +55,7 @@ function runCommonDaoTest(db, features = {}, quirks = {}) {
|
|
|
55
55
|
if (eventualConsistencyDelay)
|
|
56
56
|
await (0, js_lib_1.pDelay)(eventualConsistencyDelay);
|
|
57
57
|
expect(await dao.query().runQuery()).toEqual([]);
|
|
58
|
-
expect(await dao.query().runQueryCount()).
|
|
58
|
+
expect(await dao.query().runQueryCount()).toBe(0);
|
|
59
59
|
});
|
|
60
60
|
}
|
|
61
61
|
// GET empty
|
|
@@ -81,7 +81,7 @@ function runCommonDaoTest(db, features = {}, quirks = {}) {
|
|
|
81
81
|
await dao.save(item3);
|
|
82
82
|
const item3Loaded = await dao.requireById(item3.id);
|
|
83
83
|
(0, dbTest_1.expectMatch)([item3], [item3Loaded], quirks);
|
|
84
|
-
expect(item3Loaded.k2).
|
|
84
|
+
expect(item3Loaded.k2).toBeNull();
|
|
85
85
|
expect(Object.keys(item3)).toContain('k2');
|
|
86
86
|
expect(item3.k2).toBeNull();
|
|
87
87
|
});
|
|
@@ -98,7 +98,7 @@ function runCommonDaoTest(db, features = {}, quirks = {}) {
|
|
|
98
98
|
expected.updated = item3.updated; // as it's mutated
|
|
99
99
|
const item3Loaded = await dao.requireById(item3.id);
|
|
100
100
|
(0, dbTest_1.expectMatch)([expected], [item3Loaded], quirks);
|
|
101
|
-
expect(item3Loaded.k2).
|
|
101
|
+
expect(item3Loaded.k2).toBeUndefined();
|
|
102
102
|
expect(Object.keys(item3Loaded)).not.toContain('k2');
|
|
103
103
|
expect(Object.keys(item3)).toContain('k2');
|
|
104
104
|
expect(item3.k2).toBeUndefined();
|
package/dist/testing/dbTest.js
CHANGED
|
@@ -28,7 +28,7 @@ function runCommonDBTest(db, features = {}, quirks = {}) {
|
|
|
28
28
|
// CREATE TABLE, DROP
|
|
29
29
|
if (createTable) {
|
|
30
30
|
test('createTable, dropIfExists=true', async () => {
|
|
31
|
-
await db.createTable(test_model_1.TEST_TABLE, test_model_1.testItemDBMJsonSchema
|
|
31
|
+
await db.createTable(test_model_1.TEST_TABLE, test_model_1.testItemDBMJsonSchema, { dropIfExists: true });
|
|
32
32
|
});
|
|
33
33
|
}
|
|
34
34
|
if (querying) {
|
|
@@ -42,7 +42,7 @@ function runCommonDBTest(db, features = {}, quirks = {}) {
|
|
|
42
42
|
if (eventualConsistencyDelay)
|
|
43
43
|
await (0, js_lib_1.pDelay)(eventualConsistencyDelay);
|
|
44
44
|
expect((await db.runQuery(queryAll())).rows).toEqual([]);
|
|
45
|
-
expect(await db.runQueryCount(queryAll())).
|
|
45
|
+
expect(await db.runQueryCount(queryAll())).toBe(0);
|
|
46
46
|
});
|
|
47
47
|
}
|
|
48
48
|
// GET empty
|
|
@@ -68,7 +68,7 @@ function runCommonDBTest(db, features = {}, quirks = {}) {
|
|
|
68
68
|
await db.saveBatch(test_model_1.TEST_TABLE, [item3]);
|
|
69
69
|
const item3Loaded = (await db.getByIds(test_model_1.TEST_TABLE, [item3.id]))[0];
|
|
70
70
|
expectMatch([item3], [item3Loaded], quirks);
|
|
71
|
-
expect(item3Loaded.k2).
|
|
71
|
+
expect(item3Loaded.k2).toBeNull();
|
|
72
72
|
});
|
|
73
73
|
}
|
|
74
74
|
if (documentDB) {
|
|
@@ -83,7 +83,7 @@ function runCommonDBTest(db, features = {}, quirks = {}) {
|
|
|
83
83
|
await db.saveBatch(test_model_1.TEST_TABLE, [item3]);
|
|
84
84
|
const item3Loaded = (await db.getByIds(test_model_1.TEST_TABLE, [item3.id]))[0];
|
|
85
85
|
expectMatch([expected], [item3Loaded], quirks);
|
|
86
|
-
expect(item3Loaded.k2).
|
|
86
|
+
expect(item3Loaded.k2).toBeUndefined();
|
|
87
87
|
expect(Object.keys(item3Loaded)).not.toContain('k2');
|
|
88
88
|
});
|
|
89
89
|
}
|
|
@@ -17,8 +17,8 @@ export interface TestItemTM {
|
|
|
17
17
|
export declare const testItemBMSchema: import("@naturalcycles/nodejs-lib").ObjectSchemaTyped<TestItemBM, TestItemBM>;
|
|
18
18
|
export declare const testItemDBMSchema: import("@naturalcycles/nodejs-lib").ObjectSchemaTyped<TestItemDBM, TestItemDBM>;
|
|
19
19
|
export declare const testItemTMSchema: import("@naturalcycles/nodejs-lib").ObjectSchemaTyped<TestItemTM, TestItemTM>;
|
|
20
|
-
export declare const testItemBMJsonSchema: import("@naturalcycles/js-lib
|
|
21
|
-
export declare const testItemDBMJsonSchema: import("@naturalcycles/js-lib
|
|
20
|
+
export declare const testItemBMJsonSchema: import("@naturalcycles/js-lib").JsonSchemaObject<TestItemBM & Partial<import("@naturalcycles/js-lib").SavedDBEntity<string>>>;
|
|
21
|
+
export declare const testItemDBMJsonSchema: import("@naturalcycles/js-lib").JsonSchemaObject<TestItemDBM>;
|
|
22
22
|
export declare function createTestItemDBM(num?: number): TestItemDBM;
|
|
23
23
|
export declare function createTestItemBM(num?: number): Saved<TestItemBM>;
|
|
24
24
|
export declare function createTestItemsDBM(count?: number): TestItemDBM[];
|
|
@@ -31,8 +31,10 @@ exports.testItemBMJsonSchema = js_lib_1.jsonSchema
|
|
|
31
31
|
even: js_lib_1.jsonSchema.boolean().optional(),
|
|
32
32
|
b1: js_lib_1.jsonSchema.buffer().optional(),
|
|
33
33
|
})
|
|
34
|
-
.baseDBEntity()
|
|
35
|
-
|
|
34
|
+
.baseDBEntity()
|
|
35
|
+
.build();
|
|
36
|
+
exports.testItemDBMJsonSchema = js_lib_1.jsonSchema
|
|
37
|
+
.rootObject({
|
|
36
38
|
// todo: figure out how to not copy-paste these 3 fields
|
|
37
39
|
id: js_lib_1.jsonSchema.string(),
|
|
38
40
|
created: js_lib_1.jsonSchema.unixTimestamp(),
|
|
@@ -42,7 +44,8 @@ exports.testItemDBMJsonSchema = js_lib_1.jsonSchema.rootObject({
|
|
|
42
44
|
k3: js_lib_1.jsonSchema.number().optional(),
|
|
43
45
|
even: js_lib_1.jsonSchema.boolean().optional(),
|
|
44
46
|
b1: js_lib_1.jsonSchema.buffer().optional(),
|
|
45
|
-
})
|
|
47
|
+
})
|
|
48
|
+
.build();
|
|
46
49
|
function createTestItemDBM(num = 1) {
|
|
47
50
|
return {
|
|
48
51
|
id: `id${num}`,
|
package/package.json
CHANGED
|
@@ -10,9 +10,9 @@
|
|
|
10
10
|
},
|
|
11
11
|
"devDependencies": {
|
|
12
12
|
"@naturalcycles/bench-lib": "^1.0.0",
|
|
13
|
-
"@naturalcycles/dev-lib": "^
|
|
14
|
-
"@types/node": "^
|
|
15
|
-
"jest": "^
|
|
13
|
+
"@naturalcycles/dev-lib": "^13.0.0",
|
|
14
|
+
"@types/node": "^18.0.3",
|
|
15
|
+
"jest": "^29.0.0",
|
|
16
16
|
"weak-napi": "^2.0.2"
|
|
17
17
|
},
|
|
18
18
|
"files": [
|
|
@@ -42,7 +42,7 @@
|
|
|
42
42
|
"engines": {
|
|
43
43
|
"node": ">=14.15"
|
|
44
44
|
},
|
|
45
|
-
"version": "8.
|
|
45
|
+
"version": "8.41.0",
|
|
46
46
|
"description": "Lowest Common Denominator API to supported Databases",
|
|
47
47
|
"keywords": [
|
|
48
48
|
"db",
|
|
@@ -256,11 +256,11 @@ export class FileDB extends BaseCommonDB implements CommonDB {
|
|
|
256
256
|
this.logFinished(started, op)
|
|
257
257
|
}
|
|
258
258
|
|
|
259
|
-
sortRows<ROW>(rows: ROW[]): ROW[] {
|
|
259
|
+
private sortRows<ROW extends ObjectWithId>(rows: ROW[]): ROW[] {
|
|
260
260
|
rows = rows.map(r => _filterUndefinedValues(r))
|
|
261
261
|
|
|
262
262
|
if (this.cfg.sortOnSave) {
|
|
263
|
-
_sortBy(rows, r => r[this.cfg.sortOnSave!.name], true)
|
|
263
|
+
_sortBy(rows, r => r[this.cfg.sortOnSave!.name as keyof ROW], true)
|
|
264
264
|
if (this.cfg.sortOnSave.descending) rows.reverse() // mutates
|
|
265
265
|
}
|
|
266
266
|
|
|
@@ -119,6 +119,12 @@ export interface CommonDaoCfg<
|
|
|
119
119
|
*/
|
|
120
120
|
createId?: boolean
|
|
121
121
|
|
|
122
|
+
/**
|
|
123
|
+
* See the same option in CommonDB.
|
|
124
|
+
* Defaults to false normally.
|
|
125
|
+
*/
|
|
126
|
+
assignGeneratedIds?: boolean
|
|
127
|
+
|
|
122
128
|
/**
|
|
123
129
|
* Defaults to true
|
|
124
130
|
* Set to false to disable `created` field management.
|
|
@@ -73,6 +73,7 @@ export class CommonDao<
|
|
|
73
73
|
logLevel: isGAE || isCI ? CommonDaoLogLevel.NONE : CommonDaoLogLevel.OPERATIONS,
|
|
74
74
|
idType: 'string',
|
|
75
75
|
createId: true,
|
|
76
|
+
assignGeneratedIds: false,
|
|
76
77
|
created: true,
|
|
77
78
|
updated: true,
|
|
78
79
|
logger: console,
|
|
@@ -83,7 +84,7 @@ export class CommonDao<
|
|
|
83
84
|
beforeDBMValidate: dbm => dbm,
|
|
84
85
|
beforeDBMToBM: dbm => dbm as any,
|
|
85
86
|
beforeBMToDBM: bm => bm as any,
|
|
86
|
-
beforeTMToBM: tm => tm,
|
|
87
|
+
beforeTMToBM: tm => tm as any,
|
|
87
88
|
beforeBMToTM: bm => bm as any,
|
|
88
89
|
anonymize: dbm => dbm,
|
|
89
90
|
onValidationError: err => err,
|
|
@@ -111,9 +112,9 @@ export class CommonDao<
|
|
|
111
112
|
}
|
|
112
113
|
|
|
113
114
|
// GET
|
|
114
|
-
async getById(id: undefined, opt?: CommonDaoOptions): Promise<null>
|
|
115
|
-
async getById(id?: ID, opt?: CommonDaoOptions): Promise<Saved<BM> | null>
|
|
116
|
-
async getById(id?: ID, opt: CommonDaoOptions = {}): Promise<Saved<BM> | null> {
|
|
115
|
+
async getById(id: undefined | null, opt?: CommonDaoOptions): Promise<null>
|
|
116
|
+
async getById(id?: ID | null, opt?: CommonDaoOptions): Promise<Saved<BM> | null>
|
|
117
|
+
async getById(id?: ID | null, opt: CommonDaoOptions = {}): Promise<Saved<BM> | null> {
|
|
117
118
|
if (!id) return null
|
|
118
119
|
const op = `getById(${id})`
|
|
119
120
|
const table = opt.table || this.cfg.table
|
|
@@ -153,9 +154,9 @@ export class CommonDao<
|
|
|
153
154
|
return await this.bmToDBM(bm, opt)
|
|
154
155
|
}
|
|
155
156
|
|
|
156
|
-
async getByIdAsDBM(id: undefined, opt?: CommonDaoOptions): Promise<null>
|
|
157
|
-
async getByIdAsDBM(id?: ID, opt?: CommonDaoOptions): Promise<DBM | null>
|
|
158
|
-
async getByIdAsDBM(id?: ID, opt: CommonDaoOptions = {}): Promise<DBM | null> {
|
|
157
|
+
async getByIdAsDBM(id: undefined | null, opt?: CommonDaoOptions): Promise<null>
|
|
158
|
+
async getByIdAsDBM(id?: ID | null, opt?: CommonDaoOptions): Promise<DBM | null>
|
|
159
|
+
async getByIdAsDBM(id?: ID | null, opt: CommonDaoOptions = {}): Promise<DBM | null> {
|
|
159
160
|
if (!id) return null
|
|
160
161
|
const op = `getByIdAsDBM(${id})`
|
|
161
162
|
const table = opt.table || this.cfg.table
|
|
@@ -168,9 +169,9 @@ export class CommonDao<
|
|
|
168
169
|
return dbm || null
|
|
169
170
|
}
|
|
170
171
|
|
|
171
|
-
async getByIdAsTM(id: undefined, opt?: CommonDaoOptions): Promise<null>
|
|
172
|
-
async getByIdAsTM(id?: ID, opt?: CommonDaoOptions): Promise<TM | null>
|
|
173
|
-
async getByIdAsTM(id?: ID, opt: CommonDaoOptions = {}): Promise<TM | null> {
|
|
172
|
+
async getByIdAsTM(id: undefined | null, opt?: CommonDaoOptions): Promise<null>
|
|
173
|
+
async getByIdAsTM(id?: ID | null, opt?: CommonDaoOptions): Promise<TM | null>
|
|
174
|
+
async getByIdAsTM(id?: ID | null, opt: CommonDaoOptions = {}): Promise<TM | null> {
|
|
174
175
|
if (!id) return null
|
|
175
176
|
const op = `getByIdAsTM(${id})`
|
|
176
177
|
const table = opt.table || this.cfg.table
|
|
@@ -301,7 +302,7 @@ export class CommonDao<
|
|
|
301
302
|
const col = q._selectedFieldNames[0]!
|
|
302
303
|
|
|
303
304
|
const { rows } = await this.runQueryExtended(q, opt)
|
|
304
|
-
return rows.map(r => r[col
|
|
305
|
+
return rows.map((r: any) => r[col])
|
|
305
306
|
}
|
|
306
307
|
|
|
307
308
|
/**
|
|
@@ -593,11 +594,12 @@ export class CommonDao<
|
|
|
593
594
|
obj.id ||= this.cfg.hooks!.createId?.(obj as BM)
|
|
594
595
|
|
|
595
596
|
if (this.cfg.created) {
|
|
596
|
-
obj['created'] ||= obj['updated'] || now
|
|
597
|
+
;(obj as any)['created'] ||= (obj as any)['updated'] || now
|
|
597
598
|
}
|
|
598
599
|
|
|
599
600
|
if (this.cfg.updated) {
|
|
600
|
-
obj
|
|
601
|
+
;(obj as any)['updated'] =
|
|
602
|
+
opt.preserveUpdatedCreated && (obj as any)['updated'] ? (obj as any)['updated'] : now
|
|
601
603
|
}
|
|
602
604
|
|
|
603
605
|
return obj as any
|
|
@@ -609,7 +611,7 @@ export class CommonDao<
|
|
|
609
611
|
*/
|
|
610
612
|
async save(bm: Unsaved<BM>, opt: CommonDaoSaveOptions<DBM> = {}): Promise<Saved<BM>> {
|
|
611
613
|
this.requireWriteAccess()
|
|
612
|
-
const idWasGenerated = !bm.id
|
|
614
|
+
const idWasGenerated = !bm.id && this.cfg.createId
|
|
613
615
|
this.assignIdCreatedUpdated(bm, opt) // mutates
|
|
614
616
|
const dbm = await this.bmToDBM(bm as BM, opt)
|
|
615
617
|
const table = opt.table || this.cfg.table
|
|
@@ -619,11 +621,18 @@ export class CommonDao<
|
|
|
619
621
|
}
|
|
620
622
|
const op = `save(${dbm.id})`
|
|
621
623
|
const started = this.logSaveStarted(op, bm, table)
|
|
624
|
+
const { excludeFromIndexes } = this.cfg
|
|
625
|
+
const assignGeneratedIds = opt.assignGeneratedIds || this.cfg.assignGeneratedIds
|
|
622
626
|
await this.cfg.db.saveBatch(table, [dbm], {
|
|
623
|
-
excludeFromIndexes
|
|
627
|
+
excludeFromIndexes,
|
|
628
|
+
assignGeneratedIds,
|
|
624
629
|
...opt,
|
|
625
630
|
})
|
|
626
631
|
|
|
632
|
+
if (assignGeneratedIds) {
|
|
633
|
+
bm.id = dbm.id as any
|
|
634
|
+
}
|
|
635
|
+
|
|
627
636
|
this.logSaveResult(started, op, table)
|
|
628
637
|
return bm as any
|
|
629
638
|
}
|
|
@@ -666,23 +675,32 @@ export class CommonDao<
|
|
|
666
675
|
|
|
667
676
|
// assigning id in case it misses the id
|
|
668
677
|
// will override/set `updated` field, unless opts.preserveUpdated is set
|
|
678
|
+
let row = dbm
|
|
669
679
|
if (!opt.raw) {
|
|
670
|
-
const idWasGenerated = !dbm.id
|
|
680
|
+
const idWasGenerated = !dbm.id && this.cfg.createId
|
|
671
681
|
this.assignIdCreatedUpdated(dbm, opt) // mutates
|
|
672
|
-
|
|
673
|
-
if (opt.ensureUniqueId && idWasGenerated) await this.ensureUniqueId(table,
|
|
682
|
+
row = this.anyToDBM(dbm, opt)
|
|
683
|
+
if (opt.ensureUniqueId && idWasGenerated) await this.ensureUniqueId(table, row)
|
|
674
684
|
}
|
|
675
685
|
if (this.cfg.immutable && !opt.allowMutability && !opt.saveMethod) {
|
|
676
686
|
opt = { ...opt, saveMethod: 'insert' }
|
|
677
687
|
}
|
|
678
|
-
const op = `saveAsDBM(${
|
|
679
|
-
const started = this.logSaveStarted(op,
|
|
680
|
-
|
|
681
|
-
|
|
688
|
+
const op = `saveAsDBM(${row.id})`
|
|
689
|
+
const started = this.logSaveStarted(op, row, table)
|
|
690
|
+
const { excludeFromIndexes } = this.cfg
|
|
691
|
+
const assignGeneratedIds = opt.assignGeneratedIds || this.cfg.assignGeneratedIds
|
|
692
|
+
await this.cfg.db.saveBatch(table, [row], {
|
|
693
|
+
excludeFromIndexes,
|
|
694
|
+
assignGeneratedIds,
|
|
682
695
|
...opt,
|
|
683
696
|
})
|
|
697
|
+
|
|
698
|
+
if (assignGeneratedIds) {
|
|
699
|
+
dbm.id = row.id
|
|
700
|
+
}
|
|
701
|
+
|
|
684
702
|
this.logSaveResult(started, op, table)
|
|
685
|
-
return
|
|
703
|
+
return row
|
|
686
704
|
}
|
|
687
705
|
|
|
688
706
|
async saveBatch(bms: Unsaved<BM>[], opt: CommonDaoSaveOptions<DBM> = {}): Promise<Saved<BM>[]> {
|
|
@@ -703,12 +721,19 @@ export class CommonDao<
|
|
|
703
721
|
50,
|
|
704
722
|
)})`
|
|
705
723
|
const started = this.logSaveStarted(op, bms, table)
|
|
724
|
+
const { excludeFromIndexes } = this.cfg
|
|
725
|
+
const assignGeneratedIds = opt.assignGeneratedIds || this.cfg.assignGeneratedIds
|
|
706
726
|
|
|
707
727
|
await this.cfg.db.saveBatch(table, dbms, {
|
|
708
|
-
excludeFromIndexes
|
|
728
|
+
excludeFromIndexes,
|
|
729
|
+
assignGeneratedIds,
|
|
709
730
|
...opt,
|
|
710
731
|
})
|
|
711
732
|
|
|
733
|
+
if (assignGeneratedIds) {
|
|
734
|
+
dbms.forEach((dbm, i) => (bms[i]!.id = dbm.id as any))
|
|
735
|
+
}
|
|
736
|
+
|
|
712
737
|
this.logSaveResult(started, op, table)
|
|
713
738
|
|
|
714
739
|
return bms as any[]
|
|
@@ -717,39 +742,47 @@ export class CommonDao<
|
|
|
717
742
|
async saveBatchAsDBM(dbms: DBM[], opt: CommonDaoSaveOptions<DBM> = {}): Promise<DBM[]> {
|
|
718
743
|
this.requireWriteAccess()
|
|
719
744
|
const table = opt.table || this.cfg.table
|
|
745
|
+
let rows = dbms
|
|
720
746
|
if (!opt.raw) {
|
|
721
747
|
dbms.forEach(dbm => this.assignIdCreatedUpdated(dbm, opt)) // mutates
|
|
722
|
-
|
|
748
|
+
rows = this.anyToDBMs(dbms, opt)
|
|
723
749
|
if (opt.ensureUniqueId) throw new AppError('ensureUniqueId is not supported in saveBatch')
|
|
724
750
|
}
|
|
725
751
|
if (this.cfg.immutable && !opt.allowMutability && !opt.saveMethod) {
|
|
726
752
|
opt = { ...opt, saveMethod: 'insert' }
|
|
727
753
|
}
|
|
728
|
-
const op = `saveBatchAsDBM ${
|
|
729
|
-
|
|
754
|
+
const op = `saveBatchAsDBM ${rows.length} row(s) (${_truncate(
|
|
755
|
+
rows
|
|
730
756
|
.slice(0, 10)
|
|
731
757
|
.map(bm => bm.id)
|
|
732
758
|
.join(', '),
|
|
733
759
|
50,
|
|
734
760
|
)})`
|
|
735
|
-
const started = this.logSaveStarted(op,
|
|
761
|
+
const started = this.logSaveStarted(op, rows, table)
|
|
762
|
+
const { excludeFromIndexes } = this.cfg
|
|
763
|
+
const assignGeneratedIds = opt.assignGeneratedIds || this.cfg.assignGeneratedIds
|
|
736
764
|
|
|
737
|
-
await this.cfg.db.saveBatch(table,
|
|
738
|
-
excludeFromIndexes
|
|
765
|
+
await this.cfg.db.saveBatch(table, rows, {
|
|
766
|
+
excludeFromIndexes,
|
|
767
|
+
assignGeneratedIds,
|
|
739
768
|
...opt,
|
|
740
769
|
})
|
|
741
770
|
|
|
771
|
+
if (assignGeneratedIds) {
|
|
772
|
+
rows.forEach((row, i) => (dbms[i]!.id = row.id))
|
|
773
|
+
}
|
|
774
|
+
|
|
742
775
|
this.logSaveResult(started, op, table)
|
|
743
|
-
return
|
|
776
|
+
return rows
|
|
744
777
|
}
|
|
745
778
|
|
|
746
779
|
// DELETE
|
|
747
780
|
/**
|
|
748
781
|
* @returns number of deleted items
|
|
749
782
|
*/
|
|
750
|
-
async deleteById(id: undefined, opt?: CommonDaoOptions): Promise<0>
|
|
751
|
-
async deleteById(id?: ID, opt?: CommonDaoOptions): Promise<number>
|
|
752
|
-
async deleteById(id?: ID, opt: CommonDaoOptions = {}): Promise<number> {
|
|
783
|
+
async deleteById(id: undefined | null, opt?: CommonDaoOptions): Promise<0>
|
|
784
|
+
async deleteById(id?: ID | null, opt?: CommonDaoOptions): Promise<number>
|
|
785
|
+
async deleteById(id?: ID | null, opt: CommonDaoOptions = {}): Promise<number> {
|
|
753
786
|
if (!id) return 0
|
|
754
787
|
this.requireWriteAccess()
|
|
755
788
|
this.requireObjectMutability(opt)
|
package/src/db.model.ts
CHANGED
|
@@ -24,6 +24,14 @@ export interface CommonDBSaveOptions<ROW extends Partial<ObjectWithId> = AnyObje
|
|
|
24
24
|
* Default is `upsert`
|
|
25
25
|
*/
|
|
26
26
|
saveMethod?: CommonDBSaveMethod
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Only applicable to tables where id is "auto-generated by DB", e.g `auto_increment` in MySQL.
|
|
30
|
+
* By default it's false, so, auto-generated id will NOT be assigned/returned.
|
|
31
|
+
* Setting it to true will assign and return auto-generated id (on all rows, one by one).
|
|
32
|
+
* It's not true by default, because getting auto-generated id incurs an overhead of doing extra call (e.g LAST_INSERT_ID() in MySQL).
|
|
33
|
+
*/
|
|
34
|
+
assignGeneratedIds?: boolean
|
|
27
35
|
}
|
|
28
36
|
|
|
29
37
|
export type CommonDBStreamOptions = CommonDBOptions
|
package/src/query/dbQuery.ts
CHANGED
|
@@ -186,8 +186,8 @@ export class DBQuery<ROW extends ObjectWithId = AnyObjectWithId> {
|
|
|
186
186
|
}
|
|
187
187
|
|
|
188
188
|
tokens.push(
|
|
189
|
-
...this._filters.map(f => `${f.name}${f.op}${f.val}`),
|
|
190
|
-
...this._orders.map(o => `order by ${o.name}${o.descending ? ' desc' : ''}`),
|
|
189
|
+
...this._filters.map(f => `${f.name as string}${f.op}${f.val}`),
|
|
190
|
+
...this._orders.map(o => `order by ${o.name as string}${o.descending ? ' desc' : ''}`),
|
|
191
191
|
)
|
|
192
192
|
|
|
193
193
|
if (this._groupByFieldNames) {
|
package/src/testing/daoTest.ts
CHANGED
|
@@ -66,7 +66,7 @@ export function runCommonDaoTest(
|
|
|
66
66
|
// CREATE TABLE, DROP
|
|
67
67
|
if (createTable) {
|
|
68
68
|
test('createTable, dropIfExists=true', async () => {
|
|
69
|
-
await dao.createTable(testItemDBMJsonSchema
|
|
69
|
+
await dao.createTable(testItemDBMJsonSchema, { dropIfExists: true })
|
|
70
70
|
})
|
|
71
71
|
}
|
|
72
72
|
|
|
@@ -84,7 +84,7 @@ export function runCommonDaoTest(
|
|
|
84
84
|
test('runQuery(all), runQueryCount should return empty', async () => {
|
|
85
85
|
if (eventualConsistencyDelay) await pDelay(eventualConsistencyDelay)
|
|
86
86
|
expect(await dao.query().runQuery()).toEqual([])
|
|
87
|
-
expect(await dao.query().runQueryCount()).
|
|
87
|
+
expect(await dao.query().runQueryCount()).toBe(0)
|
|
88
88
|
})
|
|
89
89
|
}
|
|
90
90
|
|
|
@@ -114,7 +114,7 @@ export function runCommonDaoTest(
|
|
|
114
114
|
await dao.save(item3)
|
|
115
115
|
const item3Loaded = await dao.requireById(item3.id)
|
|
116
116
|
expectMatch([item3], [item3Loaded], quirks)
|
|
117
|
-
expect(item3Loaded.k2).
|
|
117
|
+
expect(item3Loaded.k2).toBeNull()
|
|
118
118
|
expect(Object.keys(item3)).toContain('k2')
|
|
119
119
|
expect(item3.k2).toBeNull()
|
|
120
120
|
})
|
|
@@ -135,7 +135,7 @@ export function runCommonDaoTest(
|
|
|
135
135
|
|
|
136
136
|
const item3Loaded = await dao.requireById(item3.id)
|
|
137
137
|
expectMatch([expected], [item3Loaded], quirks)
|
|
138
|
-
expect(item3Loaded.k2).
|
|
138
|
+
expect(item3Loaded.k2).toBeUndefined()
|
|
139
139
|
expect(Object.keys(item3Loaded)).not.toContain('k2')
|
|
140
140
|
expect(Object.keys(item3)).toContain('k2')
|
|
141
141
|
expect(item3.k2).toBeUndefined()
|
package/src/testing/dbTest.ts
CHANGED
|
@@ -110,7 +110,7 @@ export function runCommonDBTest(
|
|
|
110
110
|
// CREATE TABLE, DROP
|
|
111
111
|
if (createTable) {
|
|
112
112
|
test('createTable, dropIfExists=true', async () => {
|
|
113
|
-
await db.createTable(TEST_TABLE, testItemDBMJsonSchema
|
|
113
|
+
await db.createTable(TEST_TABLE, testItemDBMJsonSchema, { dropIfExists: true })
|
|
114
114
|
})
|
|
115
115
|
}
|
|
116
116
|
|
|
@@ -128,7 +128,7 @@ export function runCommonDBTest(
|
|
|
128
128
|
test('runQuery(all), runQueryCount should return empty', async () => {
|
|
129
129
|
if (eventualConsistencyDelay) await pDelay(eventualConsistencyDelay)
|
|
130
130
|
expect((await db.runQuery(queryAll())).rows).toEqual([])
|
|
131
|
-
expect(await db.runQueryCount(queryAll())).
|
|
131
|
+
expect(await db.runQueryCount(queryAll())).toBe(0)
|
|
132
132
|
})
|
|
133
133
|
}
|
|
134
134
|
|
|
@@ -158,7 +158,7 @@ export function runCommonDBTest(
|
|
|
158
158
|
await db.saveBatch(TEST_TABLE, [item3])
|
|
159
159
|
const item3Loaded = (await db.getByIds<TestItemDBM>(TEST_TABLE, [item3.id]))[0]!
|
|
160
160
|
expectMatch([item3], [item3Loaded], quirks)
|
|
161
|
-
expect(item3Loaded.k2).
|
|
161
|
+
expect(item3Loaded.k2).toBeNull()
|
|
162
162
|
})
|
|
163
163
|
}
|
|
164
164
|
|
|
@@ -175,7 +175,7 @@ export function runCommonDBTest(
|
|
|
175
175
|
await db.saveBatch(TEST_TABLE, [item3])
|
|
176
176
|
const item3Loaded = (await db.getByIds<TestItemDBM>(TEST_TABLE, [item3.id]))[0]!
|
|
177
177
|
expectMatch([expected], [item3Loaded], quirks)
|
|
178
|
-
expect(item3Loaded.k2).
|
|
178
|
+
expect(item3Loaded.k2).toBeUndefined()
|
|
179
179
|
expect(Object.keys(item3Loaded)).not.toContain('k2')
|
|
180
180
|
})
|
|
181
181
|
}
|
|
@@ -58,18 +58,21 @@ export const testItemBMJsonSchema = jsonSchema
|
|
|
58
58
|
b1: jsonSchema.buffer().optional(),
|
|
59
59
|
})
|
|
60
60
|
.baseDBEntity()
|
|
61
|
+
.build()
|
|
61
62
|
|
|
62
|
-
export const testItemDBMJsonSchema = jsonSchema
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
63
|
+
export const testItemDBMJsonSchema = jsonSchema
|
|
64
|
+
.rootObject<TestItemDBM>({
|
|
65
|
+
// todo: figure out how to not copy-paste these 3 fields
|
|
66
|
+
id: jsonSchema.string(),
|
|
67
|
+
created: jsonSchema.unixTimestamp(),
|
|
68
|
+
updated: jsonSchema.unixTimestamp(),
|
|
69
|
+
k1: jsonSchema.string(),
|
|
70
|
+
k2: jsonSchema.string().optional(),
|
|
71
|
+
k3: jsonSchema.number().optional(),
|
|
72
|
+
even: jsonSchema.boolean().optional(),
|
|
73
|
+
b1: jsonSchema.buffer().optional(),
|
|
74
|
+
})
|
|
75
|
+
.build()
|
|
73
76
|
|
|
74
77
|
export function createTestItemDBM(num = 1): TestItemDBM {
|
|
75
78
|
return {
|