@naturalcycles/db-lib 9.5.0 → 9.7.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/commondao/common.dao.d.ts +16 -10
- package/dist/commondao/common.dao.js +108 -116
- package/dist/commondao/common.dao.model.d.ts +0 -30
- package/dist/testing/daoTest.js +1 -2
- package/dist/testing/dbTest.js +1 -1
- package/dist/testing/index.d.ts +2 -2
- package/dist/testing/index.js +1 -3
- package/dist/testing/test.model.d.ts +0 -2
- package/dist/testing/test.model.js +1 -21
- package/package.json +2 -2
- package/src/commondao/common.dao.model.ts +0 -33
- package/src/commondao/common.dao.ts +118 -138
- package/src/testing/daoTest.ts +2 -4
- package/src/testing/dbTest.ts +2 -2
- package/src/testing/index.ts +0 -4
- package/src/testing/test.model.ts +0 -22
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { Transform } from 'node:stream';
|
|
3
3
|
import { AsyncMapper, BaseDBEntity, CommonLogger, JsonSchemaObject, JsonSchemaRootObject, UnixTimestampMillisNumber, Unsaved, ZodSchema } from '@naturalcycles/js-lib';
|
|
4
4
|
import { AjvSchema, ObjectSchema, ReadableTyped } from '@naturalcycles/nodejs-lib';
|
|
5
|
-
import { CommonDBTransactionOptions,
|
|
5
|
+
import { CommonDBTransactionOptions, DBPatch, DBTransaction, RunQueryResult } from '../db.model';
|
|
6
6
|
import { DBQuery, RunnableDBQuery } from '../query/dbQuery';
|
|
7
7
|
import { CommonDaoCfg, CommonDaoCreateOptions, CommonDaoOptions, CommonDaoSaveBatchOptions, CommonDaoSaveOptions, CommonDaoStreamDeleteOptions, CommonDaoStreamForEachOptions, CommonDaoStreamOptions, CommonDaoStreamSaveOptions } from './common.dao.model';
|
|
8
8
|
/**
|
|
@@ -19,7 +19,6 @@ export declare class CommonDao<BM extends BaseDBEntity, DBM extends BaseDBEntity
|
|
|
19
19
|
getById(id: undefined | null, opt?: CommonDaoOptions): Promise<null>;
|
|
20
20
|
getById(id?: string | null, opt?: CommonDaoOptions): Promise<BM | null>;
|
|
21
21
|
getByIdOrEmpty(id: string, part?: Partial<BM>, opt?: CommonDaoOptions): Promise<BM>;
|
|
22
|
-
getByIdAsDBMOrEmpty(id: string, part?: Partial<BM>, opt?: CommonDaoOptions): Promise<DBM>;
|
|
23
22
|
getByIdAsDBM(id: undefined | null, opt?: CommonDaoOptions): Promise<null>;
|
|
24
23
|
getByIdAsDBM(id?: string | null, opt?: CommonDaoOptions): Promise<DBM | null>;
|
|
25
24
|
getByIds(ids: string[], opt?: CommonDaoOptions): Promise<BM[]>;
|
|
@@ -79,10 +78,6 @@ export declare class CommonDao<BM extends BaseDBEntity, DBM extends BaseDBEntity
|
|
|
79
78
|
* "Returns", just to have a type of "Saved"
|
|
80
79
|
*/
|
|
81
80
|
assignIdCreatedUpdated<T extends BaseDBEntity>(obj: Partial<T>, opt?: CommonDaoOptions): T;
|
|
82
|
-
/**
|
|
83
|
-
* Mutates with id, created, updated
|
|
84
|
-
*/
|
|
85
|
-
save(bm: Unsaved<BM>, opt?: CommonDaoSaveOptions<BM, DBM>): Promise<BM>;
|
|
86
81
|
/**
|
|
87
82
|
* 1. Applies the patch
|
|
88
83
|
* 2. If object is the same after patching - skips saving it
|
|
@@ -117,7 +112,11 @@ export declare class CommonDao<BM extends BaseDBEntity, DBM extends BaseDBEntity
|
|
|
117
112
|
* Like patch, but runs all operations within a Transaction.
|
|
118
113
|
*/
|
|
119
114
|
patchInTransaction(bm: BM, patch: Partial<BM>, opt?: CommonDaoSaveBatchOptions<DBM>): Promise<BM>;
|
|
120
|
-
|
|
115
|
+
/**
|
|
116
|
+
* Mutates with id, created, updated
|
|
117
|
+
*/
|
|
118
|
+
save(bm: Unsaved<BM>, opt?: CommonDaoSaveOptions<BM, DBM>): Promise<BM>;
|
|
119
|
+
saveAsDBM(dbm: Unsaved<DBM>, opt?: CommonDaoSaveOptions<BM, DBM>): Promise<DBM>;
|
|
121
120
|
saveBatch(bms: Unsaved<BM>[], opt?: CommonDaoSaveBatchOptions<DBM>): Promise<BM[]>;
|
|
122
121
|
saveBatchAsDBM(dbms: Unsaved<DBM>[], opt?: CommonDaoSaveBatchOptions<DBM>): Promise<DBM[]>;
|
|
123
122
|
/**
|
|
@@ -130,7 +129,6 @@ export declare class CommonDao<BM extends BaseDBEntity, DBM extends BaseDBEntity
|
|
|
130
129
|
/**
|
|
131
130
|
* @returns number of deleted items
|
|
132
131
|
*/
|
|
133
|
-
deleteById(id: undefined | null, opt?: CommonDaoOptions): Promise<0>;
|
|
134
132
|
deleteById(id?: string | null, opt?: CommonDaoOptions): Promise<number>;
|
|
135
133
|
deleteByIds(ids: string[], opt?: CommonDaoOptions): Promise<number>;
|
|
136
134
|
/**
|
|
@@ -161,7 +159,7 @@ export declare class CommonDao<BM extends BaseDBEntity, DBM extends BaseDBEntity
|
|
|
161
159
|
*
|
|
162
160
|
* Does NOT mutate the object.
|
|
163
161
|
*/
|
|
164
|
-
validateAndConvert<T>(obj: Partial<T>, schema: ObjectSchema<T> | AjvSchema<T> | ZodSchema<T> | undefined,
|
|
162
|
+
validateAndConvert<T>(obj: Partial<T>, schema: ObjectSchema<T> | AjvSchema<T> | ZodSchema<T> | undefined, opt?: CommonDaoOptions): any;
|
|
165
163
|
getTableSchema(): Promise<JsonSchemaRootObject<DBM>>;
|
|
166
164
|
createTable(schema: JsonSchemaObject<DBM>, opt?: CommonDaoCreateOptions): Promise<void>;
|
|
167
165
|
/**
|
|
@@ -194,8 +192,16 @@ export declare class CommonDaoTransaction {
|
|
|
194
192
|
rollback(): Promise<void>;
|
|
195
193
|
getById<BM extends BaseDBEntity, DBM extends BaseDBEntity>(dao: CommonDao<BM, DBM>, id?: string | null, opt?: CommonDaoOptions): Promise<BM | null>;
|
|
196
194
|
getByIds<BM extends BaseDBEntity, DBM extends BaseDBEntity>(dao: CommonDao<BM, DBM>, ids: string[], opt?: CommonDaoOptions): Promise<BM[]>;
|
|
197
|
-
save<BM extends BaseDBEntity, DBM extends BaseDBEntity>(dao: CommonDao<BM, DBM>, bm: Unsaved<BM>, opt?:
|
|
195
|
+
save<BM extends BaseDBEntity, DBM extends BaseDBEntity>(dao: CommonDao<BM, DBM>, bm: Unsaved<BM>, opt?: CommonDaoSaveOptions<BM, DBM>): Promise<BM>;
|
|
198
196
|
saveBatch<BM extends BaseDBEntity, DBM extends BaseDBEntity>(dao: CommonDao<BM, DBM>, bms: Unsaved<BM>[], opt?: CommonDaoSaveBatchOptions<DBM>): Promise<BM[]>;
|
|
197
|
+
/**
|
|
198
|
+
* DaoTransaction.patch does not load from DB.
|
|
199
|
+
* It assumes the bm was previously loaded in the same Transaction, hence could not be
|
|
200
|
+
* concurrently modified. Hence it's safe to not sync with DB.
|
|
201
|
+
*
|
|
202
|
+
* So, this method is a rather simple convenience "Object.assign and then save".
|
|
203
|
+
*/
|
|
204
|
+
patch<BM extends BaseDBEntity, DBM extends BaseDBEntity>(dao: CommonDao<BM, DBM>, bm: BM, patch: Partial<BM>, opt?: CommonDaoSaveOptions<BM, DBM>): Promise<BM>;
|
|
199
205
|
deleteById(dao: CommonDao<any>, id?: string | null, opt?: CommonDaoOptions): Promise<number>;
|
|
200
206
|
deleteByIds(dao: CommonDao<any>, ids: string[], opt?: CommonDaoOptions): Promise<number>;
|
|
201
207
|
}
|
|
@@ -4,7 +4,6 @@ exports.CommonDaoTransaction = exports.CommonDao = void 0;
|
|
|
4
4
|
const js_lib_1 = require("@naturalcycles/js-lib");
|
|
5
5
|
const nodejs_lib_1 = require("@naturalcycles/nodejs-lib");
|
|
6
6
|
const cnst_1 = require("../cnst");
|
|
7
|
-
const db_model_1 = require("../db.model");
|
|
8
7
|
const dbQuery_1 = require("../query/dbQuery");
|
|
9
8
|
const common_dao_model_1 = require("./common.dao.model");
|
|
10
9
|
const isGAE = !!process.env['GAE_INSTANCE'];
|
|
@@ -33,9 +32,6 @@ class CommonDao {
|
|
|
33
32
|
hooks: {
|
|
34
33
|
parseNaturalId: () => ({}),
|
|
35
34
|
beforeCreate: bm => bm,
|
|
36
|
-
beforeDBMValidate: dbm => dbm,
|
|
37
|
-
beforeDBMToBM: dbm => dbm,
|
|
38
|
-
beforeBMToDBM: bm => bm,
|
|
39
35
|
anonymize: dbm => dbm,
|
|
40
36
|
onValidationError: err => err,
|
|
41
37
|
...cfg.hooks,
|
|
@@ -53,7 +49,7 @@ class CommonDao {
|
|
|
53
49
|
const bm = this.cfg.hooks.beforeCreate(part);
|
|
54
50
|
// First assignIdCreatedUpdated, then validate!
|
|
55
51
|
this.assignIdCreatedUpdated(bm, opt);
|
|
56
|
-
return this.validateAndConvert(bm, this.cfg.bmSchema,
|
|
52
|
+
return this.validateAndConvert(bm, this.cfg.bmSchema, opt);
|
|
57
53
|
}
|
|
58
54
|
async getById(id, opt = {}) {
|
|
59
55
|
if (!id)
|
|
@@ -62,10 +58,10 @@ class CommonDao {
|
|
|
62
58
|
const table = opt.table || this.cfg.table;
|
|
63
59
|
const started = this.logStarted(op, table);
|
|
64
60
|
let dbm = (await (opt.tx || this.cfg.db).getByIds(table, [id]))[0];
|
|
65
|
-
if (dbm &&
|
|
61
|
+
if (dbm && this.cfg.hooks.afterLoad) {
|
|
66
62
|
dbm = (await this.cfg.hooks.afterLoad(dbm)) || undefined;
|
|
67
63
|
}
|
|
68
|
-
const bm =
|
|
64
|
+
const bm = await this.dbmToBM(dbm, opt);
|
|
69
65
|
this.logResult(started, op, bm, table);
|
|
70
66
|
return bm || null;
|
|
71
67
|
}
|
|
@@ -75,13 +71,6 @@ class CommonDao {
|
|
|
75
71
|
return bm;
|
|
76
72
|
return this.create({ ...part, id }, opt);
|
|
77
73
|
}
|
|
78
|
-
async getByIdAsDBMOrEmpty(id, part = {}, opt) {
|
|
79
|
-
const dbm = await this.getByIdAsDBM(id, opt);
|
|
80
|
-
if (dbm)
|
|
81
|
-
return dbm;
|
|
82
|
-
const bm = this.create({ ...part, id }, opt);
|
|
83
|
-
return await this.bmToDBM(bm, opt);
|
|
84
|
-
}
|
|
85
74
|
async getByIdAsDBM(id, opt = {}) {
|
|
86
75
|
if (!id)
|
|
87
76
|
return null;
|
|
@@ -89,12 +78,10 @@ class CommonDao {
|
|
|
89
78
|
const table = opt.table || this.cfg.table;
|
|
90
79
|
const started = this.logStarted(op, table);
|
|
91
80
|
let [dbm] = await (opt.tx || this.cfg.db).getByIds(table, [id]);
|
|
92
|
-
if (dbm &&
|
|
81
|
+
if (dbm && this.cfg.hooks.afterLoad) {
|
|
93
82
|
dbm = (await this.cfg.hooks.afterLoad(dbm)) || undefined;
|
|
94
83
|
}
|
|
95
|
-
|
|
96
|
-
dbm = this.anyToDBM(dbm, opt);
|
|
97
|
-
}
|
|
84
|
+
dbm = this.anyToDBM(dbm, opt);
|
|
98
85
|
this.logResult(started, op, dbm, table);
|
|
99
86
|
return dbm || null;
|
|
100
87
|
}
|
|
@@ -105,10 +92,10 @@ class CommonDao {
|
|
|
105
92
|
const table = opt.table || this.cfg.table;
|
|
106
93
|
const started = this.logStarted(op, table);
|
|
107
94
|
let dbms = await (opt.tx || this.cfg.db).getByIds(table, ids);
|
|
108
|
-
if (
|
|
95
|
+
if (this.cfg.hooks.afterLoad && dbms.length) {
|
|
109
96
|
dbms = (await (0, js_lib_1.pMap)(dbms, async (dbm) => await this.cfg.hooks.afterLoad(dbm))).filter(js_lib_1._isTruthy);
|
|
110
97
|
}
|
|
111
|
-
const bms =
|
|
98
|
+
const bms = await this.dbmsToBM(dbms, opt);
|
|
112
99
|
this.logResult(started, op, bms, table);
|
|
113
100
|
return bms;
|
|
114
101
|
}
|
|
@@ -119,7 +106,7 @@ class CommonDao {
|
|
|
119
106
|
const table = opt.table || this.cfg.table;
|
|
120
107
|
const started = this.logStarted(op, table);
|
|
121
108
|
let dbms = await (opt.tx || this.cfg.db).getByIds(table, ids);
|
|
122
|
-
if (
|
|
109
|
+
if (this.cfg.hooks.afterLoad && dbms.length) {
|
|
123
110
|
dbms = (await (0, js_lib_1.pMap)(dbms, async (dbm) => await this.cfg.hooks.afterLoad(dbm))).filter(js_lib_1._isTruthy);
|
|
124
111
|
}
|
|
125
112
|
this.logResult(started, op, dbms, table);
|
|
@@ -218,10 +205,10 @@ class CommonDao {
|
|
|
218
205
|
const started = this.logStarted(op, q.table);
|
|
219
206
|
let { rows, ...queryResult } = await this.cfg.db.runQuery(q, opt);
|
|
220
207
|
const partialQuery = !!q._selectedFieldNames;
|
|
221
|
-
if (
|
|
208
|
+
if (this.cfg.hooks.afterLoad && rows.length) {
|
|
222
209
|
rows = (await (0, js_lib_1.pMap)(rows, async (dbm) => await this.cfg.hooks.afterLoad(dbm))).filter(js_lib_1._isTruthy);
|
|
223
210
|
}
|
|
224
|
-
const bms = partialQuery
|
|
211
|
+
const bms = partialQuery ? rows : await this.dbmsToBM(rows, opt);
|
|
225
212
|
this.logResult(started, op, bms, q.table);
|
|
226
213
|
return {
|
|
227
214
|
rows: bms,
|
|
@@ -237,11 +224,11 @@ class CommonDao {
|
|
|
237
224
|
const op = `runQueryAsDBM(${q.pretty()})`;
|
|
238
225
|
const started = this.logStarted(op, q.table);
|
|
239
226
|
let { rows, ...queryResult } = await this.cfg.db.runQuery(q, opt);
|
|
240
|
-
if (
|
|
227
|
+
if (this.cfg.hooks.afterLoad && rows.length) {
|
|
241
228
|
rows = (await (0, js_lib_1.pMap)(rows, async (dbm) => await this.cfg.hooks.afterLoad(dbm))).filter(js_lib_1._isTruthy);
|
|
242
229
|
}
|
|
243
230
|
const partialQuery = !!q._selectedFieldNames;
|
|
244
|
-
const dbms = partialQuery
|
|
231
|
+
const dbms = partialQuery ? rows : this.anyToDBMs(rows, opt);
|
|
245
232
|
this.logResult(started, op, dbms, q.table);
|
|
246
233
|
return { rows: dbms, ...queryResult };
|
|
247
234
|
}
|
|
@@ -268,7 +255,7 @@ class CommonDao {
|
|
|
268
255
|
this.cfg.db.streamQuery(q, opt),
|
|
269
256
|
(0, nodejs_lib_1.transformMap)(async (dbm) => {
|
|
270
257
|
count++;
|
|
271
|
-
if (partialQuery
|
|
258
|
+
if (partialQuery)
|
|
272
259
|
return dbm;
|
|
273
260
|
if (this.cfg.hooks.afterLoad) {
|
|
274
261
|
dbm = (await this.cfg.hooks.afterLoad(dbm));
|
|
@@ -307,7 +294,7 @@ class CommonDao {
|
|
|
307
294
|
this.cfg.db.streamQuery(q, opt),
|
|
308
295
|
(0, nodejs_lib_1.transformMap)(async (dbm) => {
|
|
309
296
|
count++;
|
|
310
|
-
if (partialQuery
|
|
297
|
+
if (partialQuery)
|
|
311
298
|
return dbm;
|
|
312
299
|
if (this.cfg.hooks.afterLoad) {
|
|
313
300
|
dbm = (await this.cfg.hooks.afterLoad(dbm));
|
|
@@ -343,7 +330,7 @@ class CommonDao {
|
|
|
343
330
|
opt.errorMode ||= js_lib_1.ErrorMode.SUPPRESS;
|
|
344
331
|
const partialQuery = !!q._selectedFieldNames;
|
|
345
332
|
const stream = this.cfg.db.streamQuery(q, opt);
|
|
346
|
-
if (partialQuery
|
|
333
|
+
if (partialQuery)
|
|
347
334
|
return stream;
|
|
348
335
|
return stream
|
|
349
336
|
.on('error', err => stream.emit('error', err))
|
|
@@ -374,7 +361,7 @@ class CommonDao {
|
|
|
374
361
|
opt.errorMode ||= js_lib_1.ErrorMode.SUPPRESS;
|
|
375
362
|
const stream = this.cfg.db.streamQuery(q, opt);
|
|
376
363
|
const partialQuery = !!q._selectedFieldNames;
|
|
377
|
-
if (partialQuery
|
|
364
|
+
if (partialQuery)
|
|
378
365
|
return stream;
|
|
379
366
|
return (stream
|
|
380
367
|
// optimization: 1 validation is enough
|
|
@@ -457,45 +444,6 @@ class CommonDao {
|
|
|
457
444
|
return obj;
|
|
458
445
|
}
|
|
459
446
|
// SAVE
|
|
460
|
-
/**
|
|
461
|
-
* Mutates with id, created, updated
|
|
462
|
-
*/
|
|
463
|
-
async save(bm, opt = {}) {
|
|
464
|
-
this.requireWriteAccess();
|
|
465
|
-
if (opt.skipIfEquals && (0, js_lib_1._deepJsonEquals)(bm, opt.skipIfEquals)) {
|
|
466
|
-
// Skipping the save operation
|
|
467
|
-
return bm;
|
|
468
|
-
}
|
|
469
|
-
const idWasGenerated = !bm.id && this.cfg.generateId;
|
|
470
|
-
this.assignIdCreatedUpdated(bm, opt); // mutates
|
|
471
|
-
(0, js_lib_1._typeCast)(bm);
|
|
472
|
-
let dbm = await this.bmToDBM(bm, opt);
|
|
473
|
-
if (this.cfg.hooks.beforeSave) {
|
|
474
|
-
dbm = (await this.cfg.hooks.beforeSave(dbm));
|
|
475
|
-
if (dbm === null)
|
|
476
|
-
return bm;
|
|
477
|
-
}
|
|
478
|
-
const table = opt.table || this.cfg.table;
|
|
479
|
-
if (opt.ensureUniqueId && idWasGenerated)
|
|
480
|
-
await this.ensureUniqueId(table, dbm);
|
|
481
|
-
if (this.cfg.immutable && !opt.allowMutability && !opt.saveMethod) {
|
|
482
|
-
opt = { ...opt, saveMethod: 'insert' };
|
|
483
|
-
}
|
|
484
|
-
const op = `save(${dbm.id})`;
|
|
485
|
-
const started = this.logSaveStarted(op, bm, table);
|
|
486
|
-
const { excludeFromIndexes } = this.cfg;
|
|
487
|
-
const assignGeneratedIds = opt.assignGeneratedIds || this.cfg.assignGeneratedIds;
|
|
488
|
-
await (opt.tx || this.cfg.db).saveBatch(table, [dbm], {
|
|
489
|
-
excludeFromIndexes,
|
|
490
|
-
assignGeneratedIds,
|
|
491
|
-
...opt,
|
|
492
|
-
});
|
|
493
|
-
if (assignGeneratedIds) {
|
|
494
|
-
bm.id = dbm.id;
|
|
495
|
-
}
|
|
496
|
-
this.logSaveResult(started, op, table);
|
|
497
|
-
return bm;
|
|
498
|
-
}
|
|
499
447
|
/**
|
|
500
448
|
* 1. Applies the patch
|
|
501
449
|
* 2. If object is the same after patching - skips saving it
|
|
@@ -591,19 +539,55 @@ class CommonDao {
|
|
|
591
539
|
return await this.patch(bm, patch, { ...opt, tx: daoTx.tx });
|
|
592
540
|
});
|
|
593
541
|
}
|
|
542
|
+
/**
|
|
543
|
+
* Mutates with id, created, updated
|
|
544
|
+
*/
|
|
545
|
+
async save(bm, opt = {}) {
|
|
546
|
+
this.requireWriteAccess();
|
|
547
|
+
if (opt.skipIfEquals && (0, js_lib_1._deepJsonEquals)(bm, opt.skipIfEquals)) {
|
|
548
|
+
// Skipping the save operation
|
|
549
|
+
return bm;
|
|
550
|
+
}
|
|
551
|
+
const idWasGenerated = !bm.id && this.cfg.generateId;
|
|
552
|
+
this.assignIdCreatedUpdated(bm, opt); // mutates
|
|
553
|
+
(0, js_lib_1._typeCast)(bm);
|
|
554
|
+
let dbm = await this.bmToDBM(bm, opt); // validates BM
|
|
555
|
+
if (this.cfg.hooks.beforeSave) {
|
|
556
|
+
dbm = (await this.cfg.hooks.beforeSave(dbm));
|
|
557
|
+
if (dbm === null)
|
|
558
|
+
return bm;
|
|
559
|
+
}
|
|
560
|
+
const table = opt.table || this.cfg.table;
|
|
561
|
+
if (opt.ensureUniqueId && idWasGenerated)
|
|
562
|
+
await this.ensureUniqueId(table, dbm);
|
|
563
|
+
if (this.cfg.immutable && !opt.allowMutability && !opt.saveMethod) {
|
|
564
|
+
opt = { ...opt, saveMethod: 'insert' };
|
|
565
|
+
}
|
|
566
|
+
const op = `save(${dbm.id})`;
|
|
567
|
+
const started = this.logSaveStarted(op, bm, table);
|
|
568
|
+
const { excludeFromIndexes } = this.cfg;
|
|
569
|
+
const assignGeneratedIds = opt.assignGeneratedIds || this.cfg.assignGeneratedIds;
|
|
570
|
+
await (opt.tx || this.cfg.db).saveBatch(table, [dbm], {
|
|
571
|
+
excludeFromIndexes,
|
|
572
|
+
assignGeneratedIds,
|
|
573
|
+
...opt,
|
|
574
|
+
});
|
|
575
|
+
if (assignGeneratedIds) {
|
|
576
|
+
bm.id = dbm.id;
|
|
577
|
+
}
|
|
578
|
+
this.logSaveResult(started, op, table);
|
|
579
|
+
return bm;
|
|
580
|
+
}
|
|
594
581
|
async saveAsDBM(dbm, opt = {}) {
|
|
595
582
|
this.requireWriteAccess();
|
|
596
583
|
const table = opt.table || this.cfg.table;
|
|
597
584
|
// assigning id in case it misses the id
|
|
598
585
|
// will override/set `updated` field, unless opts.preserveUpdated is set
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
if (opt.ensureUniqueId && idWasGenerated)
|
|
605
|
-
await this.ensureUniqueId(table, row);
|
|
606
|
-
}
|
|
586
|
+
const idWasGenerated = !dbm.id && this.cfg.generateId;
|
|
587
|
+
this.assignIdCreatedUpdated(dbm, opt); // mutates
|
|
588
|
+
let row = this.anyToDBM(dbm, opt);
|
|
589
|
+
if (opt.ensureUniqueId && idWasGenerated)
|
|
590
|
+
await this.ensureUniqueId(table, row);
|
|
607
591
|
if (this.cfg.immutable && !opt.allowMutability && !opt.saveMethod) {
|
|
608
592
|
opt = { ...opt, saveMethod: 'insert' };
|
|
609
593
|
}
|
|
@@ -665,13 +649,10 @@ class CommonDao {
|
|
|
665
649
|
return [];
|
|
666
650
|
this.requireWriteAccess();
|
|
667
651
|
const table = opt.table || this.cfg.table;
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
if (opt.ensureUniqueId)
|
|
673
|
-
throw new js_lib_1.AppError('ensureUniqueId is not supported in saveBatch');
|
|
674
|
-
}
|
|
652
|
+
dbms.forEach(dbm => this.assignIdCreatedUpdated(dbm, opt)); // mutates
|
|
653
|
+
let rows = this.anyToDBMs(dbms, opt);
|
|
654
|
+
if (opt.ensureUniqueId)
|
|
655
|
+
throw new js_lib_1.AppError('ensureUniqueId is not supported in saveBatch');
|
|
675
656
|
if (this.cfg.immutable && !opt.allowMutability && !opt.saveMethod) {
|
|
676
657
|
opt = { ...opt, saveMethod: 'insert' };
|
|
677
658
|
}
|
|
@@ -748,17 +729,14 @@ class CommonDao {
|
|
|
748
729
|
(0, nodejs_lib_1.writableVoid)(),
|
|
749
730
|
];
|
|
750
731
|
}
|
|
732
|
+
// DELETE
|
|
733
|
+
/**
|
|
734
|
+
* @returns number of deleted items
|
|
735
|
+
*/
|
|
751
736
|
async deleteById(id, opt = {}) {
|
|
752
737
|
if (!id)
|
|
753
738
|
return 0;
|
|
754
|
-
this.
|
|
755
|
-
this.requireObjectMutability(opt);
|
|
756
|
-
const op = `deleteById(${id})`;
|
|
757
|
-
const table = opt.table || this.cfg.table;
|
|
758
|
-
const started = this.logStarted(op, table);
|
|
759
|
-
const count = await this.cfg.db.deleteByIds(table, [id], opt);
|
|
760
|
-
this.logSaveResult(started, op, table);
|
|
761
|
-
return count;
|
|
739
|
+
return await this.deleteByIds([id], opt);
|
|
762
740
|
}
|
|
763
741
|
async deleteByIds(ids, opt = {}) {
|
|
764
742
|
if (!ids.length)
|
|
@@ -842,9 +820,15 @@ class CommonDao {
|
|
|
842
820
|
dbm = this.cfg.hooks.anonymize(dbm);
|
|
843
821
|
}
|
|
844
822
|
// DBM > BM
|
|
845
|
-
|
|
823
|
+
let bm;
|
|
824
|
+
if (this.cfg.hooks.beforeDBMToBM) {
|
|
825
|
+
bm = await this.cfg.hooks.beforeDBMToBM(dbm);
|
|
826
|
+
}
|
|
827
|
+
else {
|
|
828
|
+
bm = dbm;
|
|
829
|
+
}
|
|
846
830
|
// Validate/convert BM
|
|
847
|
-
return this.validateAndConvert(bm, this.cfg.bmSchema,
|
|
831
|
+
return this.validateAndConvert(bm, this.cfg.bmSchema, opt);
|
|
848
832
|
}
|
|
849
833
|
async dbmsToBM(dbms, opt = {}) {
|
|
850
834
|
return await (0, js_lib_1.pMap)(dbms, async (dbm) => await this.dbmToBM(dbm, opt));
|
|
@@ -852,16 +836,21 @@ class CommonDao {
|
|
|
852
836
|
async bmToDBM(bm, opt) {
|
|
853
837
|
if (bm === undefined)
|
|
854
838
|
return;
|
|
855
|
-
// optimization: no need to run the BM validation, since DBM will be validated anyway
|
|
856
|
-
// Validate/convert BM
|
|
857
|
-
// bm gets assigned to the new reference
|
|
858
|
-
// bm = this.validateAndConvert(bm, this.cfg.bmSchema, DBModelType.BM, opt)
|
|
859
839
|
// should not do it on load, but only on save!
|
|
860
840
|
// this.assignIdCreatedUpdated(bm, opt)
|
|
841
|
+
// bm gets assigned to the new reference
|
|
842
|
+
bm = this.validateAndConvert(bm, this.cfg.bmSchema, opt);
|
|
861
843
|
// BM > DBM
|
|
862
|
-
|
|
844
|
+
let dbm;
|
|
845
|
+
if (this.cfg.hooks.beforeBMToDBM) {
|
|
846
|
+
dbm = { ...(await this.cfg.hooks.beforeBMToDBM(bm)) };
|
|
847
|
+
}
|
|
848
|
+
else {
|
|
849
|
+
dbm = bm;
|
|
850
|
+
}
|
|
863
851
|
// Validate/convert DBM
|
|
864
|
-
return this.validateAndConvert(dbm, this.cfg.dbmSchema,
|
|
852
|
+
// return this.validateAndConvert(dbm, this.cfg.dbmSchema, DBModelType.DBM, opt)
|
|
853
|
+
return dbm;
|
|
865
854
|
}
|
|
866
855
|
async bmsToDBM(bms, opt = {}) {
|
|
867
856
|
// try/catch?
|
|
@@ -873,11 +862,14 @@ class CommonDao {
|
|
|
873
862
|
// this shouldn't be happening on load! but should on save!
|
|
874
863
|
// this.assignIdCreatedUpdated(dbm, opt)
|
|
875
864
|
dbm = { ...dbm, ...this.cfg.hooks.parseNaturalId(dbm.id) };
|
|
865
|
+
// todo: is this the right place?
|
|
866
|
+
// todo: is anyToDBM even needed?
|
|
876
867
|
if (opt.anonymize) {
|
|
877
868
|
dbm = this.cfg.hooks.anonymize(dbm);
|
|
878
869
|
}
|
|
879
870
|
// Validate/convert DBM
|
|
880
|
-
return this.validateAndConvert(dbm, this.cfg.dbmSchema,
|
|
871
|
+
// return this.validateAndConvert(dbm, this.cfg.dbmSchema, DBModelType.DBM, opt)
|
|
872
|
+
return dbm;
|
|
881
873
|
}
|
|
882
874
|
anyToDBMs(entities, opt = {}) {
|
|
883
875
|
return entities.map(entity => this.anyToDBM(entity, opt));
|
|
@@ -888,10 +880,7 @@ class CommonDao {
|
|
|
888
880
|
*
|
|
889
881
|
* Does NOT mutate the object.
|
|
890
882
|
*/
|
|
891
|
-
validateAndConvert(obj, schema,
|
|
892
|
-
// `raw` option completely bypasses any processing
|
|
893
|
-
if (opt.raw)
|
|
894
|
-
return obj;
|
|
883
|
+
validateAndConvert(obj, schema, opt = {}) {
|
|
895
884
|
// Kirill 2021-10-18: I realized that there's little reason to keep removing null values
|
|
896
885
|
// So, from now on we'll preserve them
|
|
897
886
|
// "undefined" values, I believe, are/were not saved to/from DB anyway (due to e.g JSON.stringify removing them)
|
|
@@ -901,23 +890,14 @@ class CommonDao {
|
|
|
901
890
|
// obj = _filterNullishValues(obj as any)
|
|
902
891
|
// We still filter `undefined` values here, because `beforeDBMToBM` can return undefined values
|
|
903
892
|
// and they can be annoying with snapshot tests
|
|
904
|
-
|
|
905
|
-
obj = (0, js_lib_1._filterNullishValues)(obj);
|
|
906
|
-
}
|
|
907
|
-
else {
|
|
908
|
-
obj = (0, js_lib_1._filterUndefinedValues)(obj);
|
|
909
|
-
}
|
|
910
|
-
// Pre-validation hooks
|
|
911
|
-
if (modelType === db_model_1.DBModelType.DBM) {
|
|
912
|
-
obj = this.cfg.hooks.beforeDBMValidate(obj);
|
|
913
|
-
}
|
|
893
|
+
obj = (0, js_lib_1._filterUndefinedValues)(obj);
|
|
914
894
|
// Return as is if no schema is passed or if `skipConversion` is set
|
|
915
895
|
if (!schema || opt.skipConversion) {
|
|
916
896
|
return obj;
|
|
917
897
|
}
|
|
918
898
|
// This will Convert and Validate
|
|
919
899
|
const table = opt.table || this.cfg.table;
|
|
920
|
-
const objectName = table
|
|
900
|
+
const objectName = table;
|
|
921
901
|
let error;
|
|
922
902
|
let convertedValue;
|
|
923
903
|
if (schema instanceof js_lib_1.ZodSchema) {
|
|
@@ -1070,11 +1050,23 @@ class CommonDaoTransaction {
|
|
|
1070
1050
|
// }
|
|
1071
1051
|
// }
|
|
1072
1052
|
async save(dao, bm, opt) {
|
|
1073
|
-
return
|
|
1053
|
+
return await dao.save(bm, { ...opt, tx: this.tx });
|
|
1074
1054
|
}
|
|
1075
1055
|
async saveBatch(dao, bms, opt) {
|
|
1076
1056
|
return await dao.saveBatch(bms, { ...opt, tx: this.tx });
|
|
1077
1057
|
}
|
|
1058
|
+
/**
|
|
1059
|
+
* DaoTransaction.patch does not load from DB.
|
|
1060
|
+
* It assumes the bm was previously loaded in the same Transaction, hence could not be
|
|
1061
|
+
* concurrently modified. Hence it's safe to not sync with DB.
|
|
1062
|
+
*
|
|
1063
|
+
* So, this method is a rather simple convenience "Object.assign and then save".
|
|
1064
|
+
*/
|
|
1065
|
+
async patch(dao, bm, patch, opt) {
|
|
1066
|
+
const skipIfEquals = (0, js_lib_1._deepCopy)(bm);
|
|
1067
|
+
Object.assign(bm, patch);
|
|
1068
|
+
return await dao.save(bm, { ...opt, skipIfEquals, tx: this.tx });
|
|
1069
|
+
}
|
|
1078
1070
|
async deleteById(dao, id, opt) {
|
|
1079
1071
|
if (!id)
|
|
1080
1072
|
return 0;
|
|
@@ -28,16 +28,6 @@ export interface CommonDaoHooks<BM extends BaseDBEntity, DBM extends BaseDBEntit
|
|
|
28
28
|
* - patch, patchAsDBM
|
|
29
29
|
*/
|
|
30
30
|
beforeCreate: (bm: Partial<BM>) => Partial<BM>;
|
|
31
|
-
/**
|
|
32
|
-
* Called when loading things "as DBM" and validation is not skipped.
|
|
33
|
-
* When loading things as BM/TM - other hooks get involved instead:
|
|
34
|
-
* - beforeDBMToBM
|
|
35
|
-
* - beforeBMToTM
|
|
36
|
-
*
|
|
37
|
-
* TODO: maybe rename those to `validateAs(model)`
|
|
38
|
-
* as it only validates "final state", not intermediate
|
|
39
|
-
*/
|
|
40
|
-
beforeDBMValidate: (dbm: Partial<DBM>) => Partial<DBM>;
|
|
41
31
|
beforeDBMToBM: (dbm: DBM) => Partial<BM> | Promise<Partial<BM>>;
|
|
42
32
|
beforeBMToDBM: (bm: BM) => Partial<DBM> | Promise<Partial<DBM>>;
|
|
43
33
|
/**
|
|
@@ -109,7 +99,6 @@ export interface CommonDaoCfg<BM extends BaseDBEntity, DBM extends BaseDBEntity
|
|
|
109
99
|
/**
|
|
110
100
|
* Joi, AjvSchema or ZodSchema is supported.
|
|
111
101
|
*/
|
|
112
|
-
dbmSchema?: ObjectSchema<DBM> | AjvSchema<DBM> | ZodSchema<DBM>;
|
|
113
102
|
bmSchema?: ObjectSchema<BM> | AjvSchema<BM> | ZodSchema<BM>;
|
|
114
103
|
excludeFromIndexes?: (keyof DBM)[];
|
|
115
104
|
/**
|
|
@@ -161,16 +150,6 @@ export interface CommonDaoCfg<BM extends BaseDBEntity, DBM extends BaseDBEntity
|
|
|
161
150
|
* Set to false to disable `updated` field management.
|
|
162
151
|
*/
|
|
163
152
|
useUpdatedProperty?: boolean;
|
|
164
|
-
/**
|
|
165
|
-
* Default is false.
|
|
166
|
-
* If true - will run `_filterNullishValues` inside `validateAndConvert` function
|
|
167
|
-
* (instead of `_filterUndefinedValues`).
|
|
168
|
-
* This was the old db-lib behavior.
|
|
169
|
-
* This option allows to keep backwards-compatible behavior.
|
|
170
|
-
*
|
|
171
|
-
* @deprecated
|
|
172
|
-
*/
|
|
173
|
-
filterNullishValues?: boolean;
|
|
174
153
|
/**
|
|
175
154
|
* Defaults to false.
|
|
176
155
|
* If true - run patch operations (patch, patchById) in a Transaction.
|
|
@@ -198,15 +177,6 @@ export interface CommonDaoOptions extends CommonDBOptions {
|
|
|
198
177
|
* @default false
|
|
199
178
|
*/
|
|
200
179
|
skipConversion?: boolean;
|
|
201
|
-
/**
|
|
202
|
-
* If true - will SKIP ANY transformation/processing, will return DB objects as they are. Will also skip created/updated/id
|
|
203
|
-
* generation.
|
|
204
|
-
*
|
|
205
|
-
* Useful for performance/streaming/pipelines.
|
|
206
|
-
*
|
|
207
|
-
* @default false
|
|
208
|
-
*/
|
|
209
|
-
raw?: boolean;
|
|
210
180
|
/**
|
|
211
181
|
* @default false
|
|
212
182
|
*/
|
package/dist/testing/daoTest.js
CHANGED
|
@@ -13,7 +13,6 @@ function runCommonDaoTest(db, quirks = {}) {
|
|
|
13
13
|
const dao = new common_dao_1.CommonDao({
|
|
14
14
|
table: test_model_1.TEST_TABLE,
|
|
15
15
|
db,
|
|
16
|
-
dbmSchema: test_model_1.testItemDBMSchema,
|
|
17
16
|
bmSchema: test_model_1.testItemBMSchema,
|
|
18
17
|
logStarted: true,
|
|
19
18
|
logLevel: __1.CommonDaoLogLevel.DATA_FULL,
|
|
@@ -32,7 +31,7 @@ function runCommonDaoTest(db, quirks = {}) {
|
|
|
32
31
|
// CREATE TABLE, DROP
|
|
33
32
|
if (support.createTable) {
|
|
34
33
|
test('createTable, dropIfExists=true', async () => {
|
|
35
|
-
await dao.createTable(test_model_1.
|
|
34
|
+
await dao.createTable(test_model_1.testItemBMJsonSchema, { dropIfExists: true });
|
|
36
35
|
});
|
|
37
36
|
}
|
|
38
37
|
if (support.queries) {
|
package/dist/testing/dbTest.js
CHANGED
|
@@ -20,7 +20,7 @@ function runCommonDBTest(db, quirks = {}) {
|
|
|
20
20
|
// CREATE TABLE, DROP
|
|
21
21
|
if (support.createTable) {
|
|
22
22
|
test('createTable, dropIfExists=true', async () => {
|
|
23
|
-
await db.createTable(test_model_1.TEST_TABLE, test_model_1.
|
|
23
|
+
await db.createTable(test_model_1.TEST_TABLE, test_model_1.testItemBMJsonSchema, { dropIfExists: true });
|
|
24
24
|
});
|
|
25
25
|
}
|
|
26
26
|
if (support.queries) {
|
package/dist/testing/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { runCommonDaoTest } from './daoTest';
|
|
2
2
|
import { CommonDBImplementationQuirks, runCommonDBTest } from './dbTest';
|
|
3
3
|
import { runCommonKeyValueDBTest } from './keyValueDBTest';
|
|
4
|
-
import { createTestItemBM, createTestItemDBM, createTestItemsBM, createTestItemsDBM, TestItemBM, testItemBMJsonSchema, testItemBMSchema, TestItemDBM,
|
|
4
|
+
import { createTestItemBM, createTestItemDBM, createTestItemsBM, createTestItemsDBM, TestItemBM, testItemBMJsonSchema, testItemBMSchema, TestItemDBM, TestItemTM, testItemTMSchema, TEST_TABLE } from './test.model';
|
|
5
5
|
export type { TestItemDBM, TestItemBM, TestItemTM, CommonDBImplementationQuirks };
|
|
6
|
-
export { TEST_TABLE, createTestItemDBM, createTestItemBM, createTestItemsDBM, createTestItemsBM,
|
|
6
|
+
export { TEST_TABLE, createTestItemDBM, createTestItemBM, createTestItemsDBM, createTestItemsBM, testItemBMSchema, testItemTMSchema, testItemBMJsonSchema, runCommonDBTest, runCommonDaoTest, runCommonKeyValueDBTest, };
|
package/dist/testing/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.runCommonKeyValueDBTest = exports.runCommonDaoTest = exports.runCommonDBTest = exports.
|
|
3
|
+
exports.runCommonKeyValueDBTest = exports.runCommonDaoTest = exports.runCommonDBTest = exports.testItemBMJsonSchema = exports.testItemTMSchema = exports.testItemBMSchema = exports.createTestItemsBM = exports.createTestItemsDBM = exports.createTestItemBM = exports.createTestItemDBM = exports.TEST_TABLE = void 0;
|
|
4
4
|
const daoTest_1 = require("./daoTest");
|
|
5
5
|
Object.defineProperty(exports, "runCommonDaoTest", { enumerable: true, get: function () { return daoTest_1.runCommonDaoTest; } });
|
|
6
6
|
const dbTest_1 = require("./dbTest");
|
|
@@ -14,7 +14,5 @@ Object.defineProperty(exports, "createTestItemsBM", { enumerable: true, get: fun
|
|
|
14
14
|
Object.defineProperty(exports, "createTestItemsDBM", { enumerable: true, get: function () { return test_model_1.createTestItemsDBM; } });
|
|
15
15
|
Object.defineProperty(exports, "testItemBMJsonSchema", { enumerable: true, get: function () { return test_model_1.testItemBMJsonSchema; } });
|
|
16
16
|
Object.defineProperty(exports, "testItemBMSchema", { enumerable: true, get: function () { return test_model_1.testItemBMSchema; } });
|
|
17
|
-
Object.defineProperty(exports, "testItemDBMJsonSchema", { enumerable: true, get: function () { return test_model_1.testItemDBMJsonSchema; } });
|
|
18
|
-
Object.defineProperty(exports, "testItemDBMSchema", { enumerable: true, get: function () { return test_model_1.testItemDBMSchema; } });
|
|
19
17
|
Object.defineProperty(exports, "testItemTMSchema", { enumerable: true, get: function () { return test_model_1.testItemTMSchema; } });
|
|
20
18
|
Object.defineProperty(exports, "TEST_TABLE", { enumerable: true, get: function () { return test_model_1.TEST_TABLE; } });
|
|
@@ -15,10 +15,8 @@ export interface TestItemTM {
|
|
|
15
15
|
even?: boolean;
|
|
16
16
|
}
|
|
17
17
|
export declare const testItemBMSchema: import("joi").ObjectSchema<TestItemBM>;
|
|
18
|
-
export declare const testItemDBMSchema: import("joi").ObjectSchema<TestItemDBM>;
|
|
19
18
|
export declare const testItemTMSchema: import("joi").ObjectSchema<TestItemTM>;
|
|
20
19
|
export declare const testItemBMJsonSchema: JsonSchemaObject<TestItemBM>;
|
|
21
|
-
export declare const testItemDBMJsonSchema: JsonSchemaObject<TestItemDBM>;
|
|
22
20
|
export declare function createTestItemDBM(num?: number): TestItemDBM;
|
|
23
21
|
export declare function createTestItemBM(num?: number): TestItemBM;
|
|
24
22
|
export declare function createTestItemsDBM(count?: number): TestItemDBM[];
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.createTestItemsBM = exports.createTestItemsDBM = exports.createTestItemBM = exports.createTestItemDBM = exports.
|
|
3
|
+
exports.createTestItemsBM = exports.createTestItemsDBM = exports.createTestItemBM = exports.createTestItemDBM = exports.testItemBMJsonSchema = exports.testItemTMSchema = exports.testItemBMSchema = exports.TEST_TABLE = void 0;
|
|
4
4
|
const js_lib_1 = require("@naturalcycles/js-lib");
|
|
5
5
|
const nodejs_lib_1 = require("@naturalcycles/nodejs-lib");
|
|
6
6
|
const MOCK_TS_2018_06_21 = 1529539200;
|
|
@@ -12,13 +12,6 @@ exports.testItemBMSchema = (0, nodejs_lib_1.objectSchema)({
|
|
|
12
12
|
even: nodejs_lib_1.booleanSchema.optional(),
|
|
13
13
|
b1: nodejs_lib_1.binarySchema.optional(),
|
|
14
14
|
}).concat(nodejs_lib_1.baseDBEntitySchema);
|
|
15
|
-
exports.testItemDBMSchema = (0, nodejs_lib_1.objectSchema)({
|
|
16
|
-
k1: nodejs_lib_1.stringSchema,
|
|
17
|
-
k2: nodejs_lib_1.stringSchema.allow(null).optional(),
|
|
18
|
-
k3: nodejs_lib_1.numberSchema.optional(),
|
|
19
|
-
even: nodejs_lib_1.booleanSchema.optional(),
|
|
20
|
-
b1: nodejs_lib_1.binarySchema.optional(),
|
|
21
|
-
}).concat(nodejs_lib_1.baseDBEntitySchema);
|
|
22
15
|
exports.testItemTMSchema = (0, nodejs_lib_1.objectSchema)({
|
|
23
16
|
k1: nodejs_lib_1.stringSchema,
|
|
24
17
|
even: nodejs_lib_1.booleanSchema.optional(),
|
|
@@ -37,19 +30,6 @@ exports.testItemBMJsonSchema = js_lib_1.jsonSchema
|
|
|
37
30
|
})
|
|
38
31
|
.baseDBEntity()
|
|
39
32
|
.build();
|
|
40
|
-
exports.testItemDBMJsonSchema = js_lib_1.jsonSchema
|
|
41
|
-
.rootObject({
|
|
42
|
-
// todo: figure out how to not copy-paste these 3 fields
|
|
43
|
-
id: js_lib_1.jsonSchema.string(),
|
|
44
|
-
created: js_lib_1.jsonSchema.unixTimestamp(),
|
|
45
|
-
updated: js_lib_1.jsonSchema.unixTimestamp(),
|
|
46
|
-
k1: js_lib_1.jsonSchema.string(),
|
|
47
|
-
k2: js_lib_1.jsonSchema.string().optional(),
|
|
48
|
-
k3: js_lib_1.jsonSchema.number().optional(),
|
|
49
|
-
even: js_lib_1.jsonSchema.boolean().optional(),
|
|
50
|
-
b1: js_lib_1.jsonSchema.buffer().optional(),
|
|
51
|
-
})
|
|
52
|
-
.build();
|
|
53
33
|
function createTestItemDBM(num = 1) {
|
|
54
34
|
return {
|
|
55
35
|
id: `id${num}`,
|