@naturalcycles/db-lib 9.5.0 → 9.6.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 +2 -2
- package/dist/commondao/common.dao.js +52 -62
- 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 +1 -1
- package/src/commondao/common.dao.model.ts +0 -33
- package/src/commondao/common.dao.ts +51 -69
- 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
|
/**
|
|
@@ -161,7 +161,7 @@ export declare class CommonDao<BM extends BaseDBEntity, DBM extends BaseDBEntity
|
|
|
161
161
|
*
|
|
162
162
|
* Does NOT mutate the object.
|
|
163
163
|
*/
|
|
164
|
-
validateAndConvert<T>(obj: Partial<T>, schema: ObjectSchema<T> | AjvSchema<T> | ZodSchema<T> | undefined,
|
|
164
|
+
validateAndConvert<T>(obj: Partial<T>, schema: ObjectSchema<T> | AjvSchema<T> | ZodSchema<T> | undefined, opt?: CommonDaoOptions): any;
|
|
165
165
|
getTableSchema(): Promise<JsonSchemaRootObject<DBM>>;
|
|
166
166
|
createTable(schema: JsonSchemaObject<DBM>, opt?: CommonDaoCreateOptions): Promise<void>;
|
|
167
167
|
/**
|
|
@@ -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
|
}
|
|
@@ -89,12 +85,10 @@ class CommonDao {
|
|
|
89
85
|
const table = opt.table || this.cfg.table;
|
|
90
86
|
const started = this.logStarted(op, table);
|
|
91
87
|
let [dbm] = await (opt.tx || this.cfg.db).getByIds(table, [id]);
|
|
92
|
-
if (dbm &&
|
|
88
|
+
if (dbm && this.cfg.hooks.afterLoad) {
|
|
93
89
|
dbm = (await this.cfg.hooks.afterLoad(dbm)) || undefined;
|
|
94
90
|
}
|
|
95
|
-
|
|
96
|
-
dbm = this.anyToDBM(dbm, opt);
|
|
97
|
-
}
|
|
91
|
+
dbm = this.anyToDBM(dbm, opt);
|
|
98
92
|
this.logResult(started, op, dbm, table);
|
|
99
93
|
return dbm || null;
|
|
100
94
|
}
|
|
@@ -105,10 +99,10 @@ class CommonDao {
|
|
|
105
99
|
const table = opt.table || this.cfg.table;
|
|
106
100
|
const started = this.logStarted(op, table);
|
|
107
101
|
let dbms = await (opt.tx || this.cfg.db).getByIds(table, ids);
|
|
108
|
-
if (
|
|
102
|
+
if (this.cfg.hooks.afterLoad && dbms.length) {
|
|
109
103
|
dbms = (await (0, js_lib_1.pMap)(dbms, async (dbm) => await this.cfg.hooks.afterLoad(dbm))).filter(js_lib_1._isTruthy);
|
|
110
104
|
}
|
|
111
|
-
const bms =
|
|
105
|
+
const bms = await this.dbmsToBM(dbms, opt);
|
|
112
106
|
this.logResult(started, op, bms, table);
|
|
113
107
|
return bms;
|
|
114
108
|
}
|
|
@@ -119,7 +113,7 @@ class CommonDao {
|
|
|
119
113
|
const table = opt.table || this.cfg.table;
|
|
120
114
|
const started = this.logStarted(op, table);
|
|
121
115
|
let dbms = await (opt.tx || this.cfg.db).getByIds(table, ids);
|
|
122
|
-
if (
|
|
116
|
+
if (this.cfg.hooks.afterLoad && dbms.length) {
|
|
123
117
|
dbms = (await (0, js_lib_1.pMap)(dbms, async (dbm) => await this.cfg.hooks.afterLoad(dbm))).filter(js_lib_1._isTruthy);
|
|
124
118
|
}
|
|
125
119
|
this.logResult(started, op, dbms, table);
|
|
@@ -218,10 +212,10 @@ class CommonDao {
|
|
|
218
212
|
const started = this.logStarted(op, q.table);
|
|
219
213
|
let { rows, ...queryResult } = await this.cfg.db.runQuery(q, opt);
|
|
220
214
|
const partialQuery = !!q._selectedFieldNames;
|
|
221
|
-
if (
|
|
215
|
+
if (this.cfg.hooks.afterLoad && rows.length) {
|
|
222
216
|
rows = (await (0, js_lib_1.pMap)(rows, async (dbm) => await this.cfg.hooks.afterLoad(dbm))).filter(js_lib_1._isTruthy);
|
|
223
217
|
}
|
|
224
|
-
const bms = partialQuery
|
|
218
|
+
const bms = partialQuery ? rows : await this.dbmsToBM(rows, opt);
|
|
225
219
|
this.logResult(started, op, bms, q.table);
|
|
226
220
|
return {
|
|
227
221
|
rows: bms,
|
|
@@ -237,11 +231,11 @@ class CommonDao {
|
|
|
237
231
|
const op = `runQueryAsDBM(${q.pretty()})`;
|
|
238
232
|
const started = this.logStarted(op, q.table);
|
|
239
233
|
let { rows, ...queryResult } = await this.cfg.db.runQuery(q, opt);
|
|
240
|
-
if (
|
|
234
|
+
if (this.cfg.hooks.afterLoad && rows.length) {
|
|
241
235
|
rows = (await (0, js_lib_1.pMap)(rows, async (dbm) => await this.cfg.hooks.afterLoad(dbm))).filter(js_lib_1._isTruthy);
|
|
242
236
|
}
|
|
243
237
|
const partialQuery = !!q._selectedFieldNames;
|
|
244
|
-
const dbms = partialQuery
|
|
238
|
+
const dbms = partialQuery ? rows : this.anyToDBMs(rows, opt);
|
|
245
239
|
this.logResult(started, op, dbms, q.table);
|
|
246
240
|
return { rows: dbms, ...queryResult };
|
|
247
241
|
}
|
|
@@ -268,7 +262,7 @@ class CommonDao {
|
|
|
268
262
|
this.cfg.db.streamQuery(q, opt),
|
|
269
263
|
(0, nodejs_lib_1.transformMap)(async (dbm) => {
|
|
270
264
|
count++;
|
|
271
|
-
if (partialQuery
|
|
265
|
+
if (partialQuery)
|
|
272
266
|
return dbm;
|
|
273
267
|
if (this.cfg.hooks.afterLoad) {
|
|
274
268
|
dbm = (await this.cfg.hooks.afterLoad(dbm));
|
|
@@ -307,7 +301,7 @@ class CommonDao {
|
|
|
307
301
|
this.cfg.db.streamQuery(q, opt),
|
|
308
302
|
(0, nodejs_lib_1.transformMap)(async (dbm) => {
|
|
309
303
|
count++;
|
|
310
|
-
if (partialQuery
|
|
304
|
+
if (partialQuery)
|
|
311
305
|
return dbm;
|
|
312
306
|
if (this.cfg.hooks.afterLoad) {
|
|
313
307
|
dbm = (await this.cfg.hooks.afterLoad(dbm));
|
|
@@ -343,7 +337,7 @@ class CommonDao {
|
|
|
343
337
|
opt.errorMode ||= js_lib_1.ErrorMode.SUPPRESS;
|
|
344
338
|
const partialQuery = !!q._selectedFieldNames;
|
|
345
339
|
const stream = this.cfg.db.streamQuery(q, opt);
|
|
346
|
-
if (partialQuery
|
|
340
|
+
if (partialQuery)
|
|
347
341
|
return stream;
|
|
348
342
|
return stream
|
|
349
343
|
.on('error', err => stream.emit('error', err))
|
|
@@ -374,7 +368,7 @@ class CommonDao {
|
|
|
374
368
|
opt.errorMode ||= js_lib_1.ErrorMode.SUPPRESS;
|
|
375
369
|
const stream = this.cfg.db.streamQuery(q, opt);
|
|
376
370
|
const partialQuery = !!q._selectedFieldNames;
|
|
377
|
-
if (partialQuery
|
|
371
|
+
if (partialQuery)
|
|
378
372
|
return stream;
|
|
379
373
|
return (stream
|
|
380
374
|
// optimization: 1 validation is enough
|
|
@@ -469,7 +463,7 @@ class CommonDao {
|
|
|
469
463
|
const idWasGenerated = !bm.id && this.cfg.generateId;
|
|
470
464
|
this.assignIdCreatedUpdated(bm, opt); // mutates
|
|
471
465
|
(0, js_lib_1._typeCast)(bm);
|
|
472
|
-
let dbm = await this.bmToDBM(bm, opt);
|
|
466
|
+
let dbm = await this.bmToDBM(bm, opt); // validates BM
|
|
473
467
|
if (this.cfg.hooks.beforeSave) {
|
|
474
468
|
dbm = (await this.cfg.hooks.beforeSave(dbm));
|
|
475
469
|
if (dbm === null)
|
|
@@ -596,14 +590,11 @@ class CommonDao {
|
|
|
596
590
|
const table = opt.table || this.cfg.table;
|
|
597
591
|
// assigning id in case it misses the id
|
|
598
592
|
// 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
|
-
}
|
|
593
|
+
const idWasGenerated = !dbm.id && this.cfg.generateId;
|
|
594
|
+
this.assignIdCreatedUpdated(dbm, opt); // mutates
|
|
595
|
+
let row = this.anyToDBM(dbm, opt);
|
|
596
|
+
if (opt.ensureUniqueId && idWasGenerated)
|
|
597
|
+
await this.ensureUniqueId(table, row);
|
|
607
598
|
if (this.cfg.immutable && !opt.allowMutability && !opt.saveMethod) {
|
|
608
599
|
opt = { ...opt, saveMethod: 'insert' };
|
|
609
600
|
}
|
|
@@ -665,13 +656,10 @@ class CommonDao {
|
|
|
665
656
|
return [];
|
|
666
657
|
this.requireWriteAccess();
|
|
667
658
|
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
|
-
}
|
|
659
|
+
dbms.forEach(dbm => this.assignIdCreatedUpdated(dbm, opt)); // mutates
|
|
660
|
+
let rows = this.anyToDBMs(dbms, opt);
|
|
661
|
+
if (opt.ensureUniqueId)
|
|
662
|
+
throw new js_lib_1.AppError('ensureUniqueId is not supported in saveBatch');
|
|
675
663
|
if (this.cfg.immutable && !opt.allowMutability && !opt.saveMethod) {
|
|
676
664
|
opt = { ...opt, saveMethod: 'insert' };
|
|
677
665
|
}
|
|
@@ -842,9 +830,15 @@ class CommonDao {
|
|
|
842
830
|
dbm = this.cfg.hooks.anonymize(dbm);
|
|
843
831
|
}
|
|
844
832
|
// DBM > BM
|
|
845
|
-
|
|
833
|
+
let bm;
|
|
834
|
+
if (this.cfg.hooks.beforeDBMToBM) {
|
|
835
|
+
bm = await this.cfg.hooks.beforeDBMToBM(dbm);
|
|
836
|
+
}
|
|
837
|
+
else {
|
|
838
|
+
bm = dbm;
|
|
839
|
+
}
|
|
846
840
|
// Validate/convert BM
|
|
847
|
-
return this.validateAndConvert(bm, this.cfg.bmSchema,
|
|
841
|
+
return this.validateAndConvert(bm, this.cfg.bmSchema, opt);
|
|
848
842
|
}
|
|
849
843
|
async dbmsToBM(dbms, opt = {}) {
|
|
850
844
|
return await (0, js_lib_1.pMap)(dbms, async (dbm) => await this.dbmToBM(dbm, opt));
|
|
@@ -852,16 +846,21 @@ class CommonDao {
|
|
|
852
846
|
async bmToDBM(bm, opt) {
|
|
853
847
|
if (bm === undefined)
|
|
854
848
|
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
849
|
// should not do it on load, but only on save!
|
|
860
850
|
// this.assignIdCreatedUpdated(bm, opt)
|
|
851
|
+
// bm gets assigned to the new reference
|
|
852
|
+
bm = this.validateAndConvert(bm, this.cfg.bmSchema, opt);
|
|
861
853
|
// BM > DBM
|
|
862
|
-
|
|
854
|
+
let dbm;
|
|
855
|
+
if (this.cfg.hooks.beforeBMToDBM) {
|
|
856
|
+
dbm = { ...(await this.cfg.hooks.beforeBMToDBM(bm)) };
|
|
857
|
+
}
|
|
858
|
+
else {
|
|
859
|
+
dbm = bm;
|
|
860
|
+
}
|
|
863
861
|
// Validate/convert DBM
|
|
864
|
-
return this.validateAndConvert(dbm, this.cfg.dbmSchema,
|
|
862
|
+
// return this.validateAndConvert(dbm, this.cfg.dbmSchema, DBModelType.DBM, opt)
|
|
863
|
+
return dbm;
|
|
865
864
|
}
|
|
866
865
|
async bmsToDBM(bms, opt = {}) {
|
|
867
866
|
// try/catch?
|
|
@@ -873,11 +872,14 @@ class CommonDao {
|
|
|
873
872
|
// this shouldn't be happening on load! but should on save!
|
|
874
873
|
// this.assignIdCreatedUpdated(dbm, opt)
|
|
875
874
|
dbm = { ...dbm, ...this.cfg.hooks.parseNaturalId(dbm.id) };
|
|
875
|
+
// todo: is this the right place?
|
|
876
|
+
// todo: is anyToDBM even needed?
|
|
876
877
|
if (opt.anonymize) {
|
|
877
878
|
dbm = this.cfg.hooks.anonymize(dbm);
|
|
878
879
|
}
|
|
879
880
|
// Validate/convert DBM
|
|
880
|
-
return this.validateAndConvert(dbm, this.cfg.dbmSchema,
|
|
881
|
+
// return this.validateAndConvert(dbm, this.cfg.dbmSchema, DBModelType.DBM, opt)
|
|
882
|
+
return dbm;
|
|
881
883
|
}
|
|
882
884
|
anyToDBMs(entities, opt = {}) {
|
|
883
885
|
return entities.map(entity => this.anyToDBM(entity, opt));
|
|
@@ -888,10 +890,7 @@ class CommonDao {
|
|
|
888
890
|
*
|
|
889
891
|
* Does NOT mutate the object.
|
|
890
892
|
*/
|
|
891
|
-
validateAndConvert(obj, schema,
|
|
892
|
-
// `raw` option completely bypasses any processing
|
|
893
|
-
if (opt.raw)
|
|
894
|
-
return obj;
|
|
893
|
+
validateAndConvert(obj, schema, opt = {}) {
|
|
895
894
|
// Kirill 2021-10-18: I realized that there's little reason to keep removing null values
|
|
896
895
|
// So, from now on we'll preserve them
|
|
897
896
|
// "undefined" values, I believe, are/were not saved to/from DB anyway (due to e.g JSON.stringify removing them)
|
|
@@ -901,23 +900,14 @@ class CommonDao {
|
|
|
901
900
|
// obj = _filterNullishValues(obj as any)
|
|
902
901
|
// We still filter `undefined` values here, because `beforeDBMToBM` can return undefined values
|
|
903
902
|
// 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
|
-
}
|
|
903
|
+
obj = (0, js_lib_1._filterUndefinedValues)(obj);
|
|
914
904
|
// Return as is if no schema is passed or if `skipConversion` is set
|
|
915
905
|
if (!schema || opt.skipConversion) {
|
|
916
906
|
return obj;
|
|
917
907
|
}
|
|
918
908
|
// This will Convert and Validate
|
|
919
909
|
const table = opt.table || this.cfg.table;
|
|
920
|
-
const objectName = table
|
|
910
|
+
const objectName = table;
|
|
921
911
|
let error;
|
|
922
912
|
let convertedValue;
|
|
923
913
|
if (schema instanceof js_lib_1.ZodSchema) {
|
|
@@ -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}`,
|
package/package.json
CHANGED
|
@@ -47,17 +47,6 @@ export interface CommonDaoHooks<BM extends BaseDBEntity, DBM extends BaseDBEntit
|
|
|
47
47
|
*/
|
|
48
48
|
beforeCreate: (bm: Partial<BM>) => Partial<BM>
|
|
49
49
|
|
|
50
|
-
/**
|
|
51
|
-
* Called when loading things "as DBM" and validation is not skipped.
|
|
52
|
-
* When loading things as BM/TM - other hooks get involved instead:
|
|
53
|
-
* - beforeDBMToBM
|
|
54
|
-
* - beforeBMToTM
|
|
55
|
-
*
|
|
56
|
-
* TODO: maybe rename those to `validateAs(model)`
|
|
57
|
-
* as it only validates "final state", not intermediate
|
|
58
|
-
*/
|
|
59
|
-
beforeDBMValidate: (dbm: Partial<DBM>) => Partial<DBM>
|
|
60
|
-
|
|
61
50
|
beforeDBMToBM: (dbm: DBM) => Partial<BM> | Promise<Partial<BM>>
|
|
62
51
|
beforeBMToDBM: (bm: BM) => Partial<DBM> | Promise<Partial<DBM>>
|
|
63
52
|
|
|
@@ -136,7 +125,6 @@ export interface CommonDaoCfg<BM extends BaseDBEntity, DBM extends BaseDBEntity
|
|
|
136
125
|
/**
|
|
137
126
|
* Joi, AjvSchema or ZodSchema is supported.
|
|
138
127
|
*/
|
|
139
|
-
dbmSchema?: ObjectSchema<DBM> | AjvSchema<DBM> | ZodSchema<DBM>
|
|
140
128
|
bmSchema?: ObjectSchema<BM> | AjvSchema<BM> | ZodSchema<BM>
|
|
141
129
|
|
|
142
130
|
excludeFromIndexes?: (keyof DBM)[]
|
|
@@ -201,17 +189,6 @@ export interface CommonDaoCfg<BM extends BaseDBEntity, DBM extends BaseDBEntity
|
|
|
201
189
|
*/
|
|
202
190
|
useUpdatedProperty?: boolean
|
|
203
191
|
|
|
204
|
-
/**
|
|
205
|
-
* Default is false.
|
|
206
|
-
* If true - will run `_filterNullishValues` inside `validateAndConvert` function
|
|
207
|
-
* (instead of `_filterUndefinedValues`).
|
|
208
|
-
* This was the old db-lib behavior.
|
|
209
|
-
* This option allows to keep backwards-compatible behavior.
|
|
210
|
-
*
|
|
211
|
-
* @deprecated
|
|
212
|
-
*/
|
|
213
|
-
filterNullishValues?: boolean
|
|
214
|
-
|
|
215
192
|
/**
|
|
216
193
|
* Defaults to false.
|
|
217
194
|
* If true - run patch operations (patch, patchById) in a Transaction.
|
|
@@ -242,16 +219,6 @@ export interface CommonDaoOptions extends CommonDBOptions {
|
|
|
242
219
|
*/
|
|
243
220
|
skipConversion?: boolean
|
|
244
221
|
|
|
245
|
-
/**
|
|
246
|
-
* If true - will SKIP ANY transformation/processing, will return DB objects as they are. Will also skip created/updated/id
|
|
247
|
-
* generation.
|
|
248
|
-
*
|
|
249
|
-
* Useful for performance/streaming/pipelines.
|
|
250
|
-
*
|
|
251
|
-
* @default false
|
|
252
|
-
*/
|
|
253
|
-
raw?: boolean
|
|
254
|
-
|
|
255
222
|
/**
|
|
256
223
|
* @default false
|
|
257
224
|
*/
|
|
@@ -2,7 +2,6 @@ import { Transform } from 'node:stream'
|
|
|
2
2
|
import {
|
|
3
3
|
_assert,
|
|
4
4
|
_deepJsonEquals,
|
|
5
|
-
_filterNullishValues,
|
|
6
5
|
_filterUndefinedValues,
|
|
7
6
|
_isTruthy,
|
|
8
7
|
_objectAssignExact,
|
|
@@ -43,13 +42,7 @@ import {
|
|
|
43
42
|
writableVoid,
|
|
44
43
|
} from '@naturalcycles/nodejs-lib'
|
|
45
44
|
import { DBLibError } from '../cnst'
|
|
46
|
-
import {
|
|
47
|
-
CommonDBTransactionOptions,
|
|
48
|
-
DBModelType,
|
|
49
|
-
DBPatch,
|
|
50
|
-
DBTransaction,
|
|
51
|
-
RunQueryResult,
|
|
52
|
-
} from '../db.model'
|
|
45
|
+
import { CommonDBTransactionOptions, DBPatch, DBTransaction, RunQueryResult } from '../db.model'
|
|
53
46
|
import { DBQuery, RunnableDBQuery } from '../query/dbQuery'
|
|
54
47
|
import {
|
|
55
48
|
CommonDaoCfg,
|
|
@@ -91,9 +84,6 @@ export class CommonDao<BM extends BaseDBEntity, DBM extends BaseDBEntity = BM> {
|
|
|
91
84
|
hooks: {
|
|
92
85
|
parseNaturalId: () => ({}),
|
|
93
86
|
beforeCreate: bm => bm as BM,
|
|
94
|
-
beforeDBMValidate: dbm => dbm,
|
|
95
|
-
beforeDBMToBM: dbm => dbm as any,
|
|
96
|
-
beforeBMToDBM: bm => bm as any,
|
|
97
87
|
anonymize: dbm => dbm,
|
|
98
88
|
onValidationError: err => err,
|
|
99
89
|
...cfg.hooks,
|
|
@@ -112,7 +102,7 @@ export class CommonDao<BM extends BaseDBEntity, DBM extends BaseDBEntity = BM> {
|
|
|
112
102
|
const bm = this.cfg.hooks!.beforeCreate!(part)
|
|
113
103
|
// First assignIdCreatedUpdated, then validate!
|
|
114
104
|
this.assignIdCreatedUpdated(bm, opt)
|
|
115
|
-
return this.validateAndConvert(bm, this.cfg.bmSchema,
|
|
105
|
+
return this.validateAndConvert(bm, this.cfg.bmSchema, opt)
|
|
116
106
|
}
|
|
117
107
|
|
|
118
108
|
// GET
|
|
@@ -125,11 +115,11 @@ export class CommonDao<BM extends BaseDBEntity, DBM extends BaseDBEntity = BM> {
|
|
|
125
115
|
const started = this.logStarted(op, table)
|
|
126
116
|
|
|
127
117
|
let dbm = (await (opt.tx || this.cfg.db).getByIds<DBM>(table, [id]))[0]
|
|
128
|
-
if (dbm &&
|
|
118
|
+
if (dbm && this.cfg.hooks!.afterLoad) {
|
|
129
119
|
dbm = (await this.cfg.hooks!.afterLoad(dbm)) || undefined
|
|
130
120
|
}
|
|
131
121
|
|
|
132
|
-
const bm =
|
|
122
|
+
const bm = await this.dbmToBM(dbm, opt)
|
|
133
123
|
this.logResult(started, op, bm, table)
|
|
134
124
|
return bm || null
|
|
135
125
|
}
|
|
@@ -161,13 +151,11 @@ export class CommonDao<BM extends BaseDBEntity, DBM extends BaseDBEntity = BM> {
|
|
|
161
151
|
const table = opt.table || this.cfg.table
|
|
162
152
|
const started = this.logStarted(op, table)
|
|
163
153
|
let [dbm] = await (opt.tx || this.cfg.db).getByIds<DBM>(table, [id])
|
|
164
|
-
if (dbm &&
|
|
154
|
+
if (dbm && this.cfg.hooks!.afterLoad) {
|
|
165
155
|
dbm = (await this.cfg.hooks!.afterLoad(dbm)) || undefined
|
|
166
156
|
}
|
|
167
157
|
|
|
168
|
-
|
|
169
|
-
dbm = this.anyToDBM(dbm!, opt)
|
|
170
|
-
}
|
|
158
|
+
dbm = this.anyToDBM(dbm!, opt)
|
|
171
159
|
this.logResult(started, op, dbm, table)
|
|
172
160
|
return dbm || null
|
|
173
161
|
}
|
|
@@ -178,13 +166,13 @@ export class CommonDao<BM extends BaseDBEntity, DBM extends BaseDBEntity = BM> {
|
|
|
178
166
|
const table = opt.table || this.cfg.table
|
|
179
167
|
const started = this.logStarted(op, table)
|
|
180
168
|
let dbms = await (opt.tx || this.cfg.db).getByIds<DBM>(table, ids)
|
|
181
|
-
if (
|
|
169
|
+
if (this.cfg.hooks!.afterLoad && dbms.length) {
|
|
182
170
|
dbms = (await pMap(dbms, async dbm => await this.cfg.hooks!.afterLoad!(dbm))).filter(
|
|
183
171
|
_isTruthy,
|
|
184
172
|
)
|
|
185
173
|
}
|
|
186
174
|
|
|
187
|
-
const bms =
|
|
175
|
+
const bms = await this.dbmsToBM(dbms, opt)
|
|
188
176
|
this.logResult(started, op, bms, table)
|
|
189
177
|
return bms
|
|
190
178
|
}
|
|
@@ -195,7 +183,7 @@ export class CommonDao<BM extends BaseDBEntity, DBM extends BaseDBEntity = BM> {
|
|
|
195
183
|
const table = opt.table || this.cfg.table
|
|
196
184
|
const started = this.logStarted(op, table)
|
|
197
185
|
let dbms = await (opt.tx || this.cfg.db).getByIds<DBM>(table, ids)
|
|
198
|
-
if (
|
|
186
|
+
if (this.cfg.hooks!.afterLoad && dbms.length) {
|
|
199
187
|
dbms = (await pMap(dbms, async dbm => await this.cfg.hooks!.afterLoad!(dbm))).filter(
|
|
200
188
|
_isTruthy,
|
|
201
189
|
)
|
|
@@ -318,13 +306,13 @@ export class CommonDao<BM extends BaseDBEntity, DBM extends BaseDBEntity = BM> {
|
|
|
318
306
|
const started = this.logStarted(op, q.table)
|
|
319
307
|
let { rows, ...queryResult } = await this.cfg.db.runQuery<DBM>(q, opt)
|
|
320
308
|
const partialQuery = !!q._selectedFieldNames
|
|
321
|
-
if (
|
|
309
|
+
if (this.cfg.hooks!.afterLoad && rows.length) {
|
|
322
310
|
rows = (await pMap(rows, async dbm => await this.cfg.hooks!.afterLoad!(dbm))).filter(
|
|
323
311
|
_isTruthy,
|
|
324
312
|
)
|
|
325
313
|
}
|
|
326
314
|
|
|
327
|
-
const bms = partialQuery
|
|
315
|
+
const bms = partialQuery ? (rows as any[]) : await this.dbmsToBM(rows, opt)
|
|
328
316
|
this.logResult(started, op, bms, q.table)
|
|
329
317
|
return {
|
|
330
318
|
rows: bms,
|
|
@@ -345,14 +333,14 @@ export class CommonDao<BM extends BaseDBEntity, DBM extends BaseDBEntity = BM> {
|
|
|
345
333
|
const op = `runQueryAsDBM(${q.pretty()})`
|
|
346
334
|
const started = this.logStarted(op, q.table)
|
|
347
335
|
let { rows, ...queryResult } = await this.cfg.db.runQuery<DBM>(q, opt)
|
|
348
|
-
if (
|
|
336
|
+
if (this.cfg.hooks!.afterLoad && rows.length) {
|
|
349
337
|
rows = (await pMap(rows, async dbm => await this.cfg.hooks!.afterLoad!(dbm))).filter(
|
|
350
338
|
_isTruthy,
|
|
351
339
|
)
|
|
352
340
|
}
|
|
353
341
|
|
|
354
342
|
const partialQuery = !!q._selectedFieldNames
|
|
355
|
-
const dbms = partialQuery
|
|
343
|
+
const dbms = partialQuery ? rows : this.anyToDBMs(rows, opt)
|
|
356
344
|
this.logResult(started, op, dbms, q.table)
|
|
357
345
|
return { rows: dbms, ...queryResult }
|
|
358
346
|
}
|
|
@@ -388,7 +376,7 @@ export class CommonDao<BM extends BaseDBEntity, DBM extends BaseDBEntity = BM> {
|
|
|
388
376
|
transformMap<DBM, BM>(
|
|
389
377
|
async dbm => {
|
|
390
378
|
count++
|
|
391
|
-
if (partialQuery
|
|
379
|
+
if (partialQuery) return dbm as any
|
|
392
380
|
|
|
393
381
|
if (this.cfg.hooks!.afterLoad) {
|
|
394
382
|
dbm = (await this.cfg.hooks!.afterLoad(dbm))!
|
|
@@ -438,7 +426,7 @@ export class CommonDao<BM extends BaseDBEntity, DBM extends BaseDBEntity = BM> {
|
|
|
438
426
|
transformMap<any, DBM>(
|
|
439
427
|
async dbm => {
|
|
440
428
|
count++
|
|
441
|
-
if (partialQuery
|
|
429
|
+
if (partialQuery) return dbm
|
|
442
430
|
|
|
443
431
|
if (this.cfg.hooks!.afterLoad) {
|
|
444
432
|
dbm = (await this.cfg.hooks!.afterLoad(dbm))!
|
|
@@ -480,7 +468,7 @@ export class CommonDao<BM extends BaseDBEntity, DBM extends BaseDBEntity = BM> {
|
|
|
480
468
|
const partialQuery = !!q._selectedFieldNames
|
|
481
469
|
|
|
482
470
|
const stream = this.cfg.db.streamQuery<DBM>(q, opt)
|
|
483
|
-
if (partialQuery
|
|
471
|
+
if (partialQuery) return stream
|
|
484
472
|
|
|
485
473
|
return stream
|
|
486
474
|
.on('error', err => stream.emit('error', err))
|
|
@@ -518,7 +506,7 @@ export class CommonDao<BM extends BaseDBEntity, DBM extends BaseDBEntity = BM> {
|
|
|
518
506
|
|
|
519
507
|
const stream = this.cfg.db.streamQuery<DBM>(q, opt)
|
|
520
508
|
const partialQuery = !!q._selectedFieldNames
|
|
521
|
-
if (partialQuery
|
|
509
|
+
if (partialQuery) return stream
|
|
522
510
|
|
|
523
511
|
return (
|
|
524
512
|
stream
|
|
@@ -641,7 +629,7 @@ export class CommonDao<BM extends BaseDBEntity, DBM extends BaseDBEntity = BM> {
|
|
|
641
629
|
const idWasGenerated = !bm.id && this.cfg.generateId
|
|
642
630
|
this.assignIdCreatedUpdated(bm, opt) // mutates
|
|
643
631
|
_typeCast<BM>(bm)
|
|
644
|
-
let dbm = await this.bmToDBM(bm, opt)
|
|
632
|
+
let dbm = await this.bmToDBM(bm, opt) // validates BM
|
|
645
633
|
|
|
646
634
|
if (this.cfg.hooks!.beforeSave) {
|
|
647
635
|
dbm = (await this.cfg.hooks!.beforeSave(dbm))!
|
|
@@ -800,13 +788,11 @@ export class CommonDao<BM extends BaseDBEntity, DBM extends BaseDBEntity = BM> {
|
|
|
800
788
|
|
|
801
789
|
// assigning id in case it misses the id
|
|
802
790
|
// will override/set `updated` field, unless opts.preserveUpdated is set
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
if (opt.ensureUniqueId && idWasGenerated) await this.ensureUniqueId(table, row)
|
|
809
|
-
}
|
|
791
|
+
const idWasGenerated = !dbm.id && this.cfg.generateId
|
|
792
|
+
this.assignIdCreatedUpdated(dbm, opt) // mutates
|
|
793
|
+
let row = this.anyToDBM(dbm, opt)
|
|
794
|
+
if (opt.ensureUniqueId && idWasGenerated) await this.ensureUniqueId(table, row)
|
|
795
|
+
|
|
810
796
|
if (this.cfg.immutable && !opt.allowMutability && !opt.saveMethod) {
|
|
811
797
|
opt = { ...opt, saveMethod: 'insert' }
|
|
812
798
|
}
|
|
@@ -885,12 +871,10 @@ export class CommonDao<BM extends BaseDBEntity, DBM extends BaseDBEntity = BM> {
|
|
|
885
871
|
if (!dbms.length) return []
|
|
886
872
|
this.requireWriteAccess()
|
|
887
873
|
const table = opt.table || this.cfg.table
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
if (opt.ensureUniqueId) throw new AppError('ensureUniqueId is not supported in saveBatch')
|
|
893
|
-
}
|
|
874
|
+
dbms.forEach(dbm => this.assignIdCreatedUpdated(dbm, opt)) // mutates
|
|
875
|
+
let rows = this.anyToDBMs(dbms as DBM[], opt)
|
|
876
|
+
if (opt.ensureUniqueId) throw new AppError('ensureUniqueId is not supported in saveBatch')
|
|
877
|
+
|
|
894
878
|
if (this.cfg.immutable && !opt.allowMutability && !opt.saveMethod) {
|
|
895
879
|
opt = { ...opt, saveMethod: 'insert' }
|
|
896
880
|
}
|
|
@@ -1119,11 +1103,16 @@ export class CommonDao<BM extends BaseDBEntity, DBM extends BaseDBEntity = BM> {
|
|
|
1119
1103
|
}
|
|
1120
1104
|
|
|
1121
1105
|
// DBM > BM
|
|
1122
|
-
|
|
1106
|
+
let bm: Partial<BM>
|
|
1107
|
+
if (this.cfg.hooks!.beforeDBMToBM) {
|
|
1108
|
+
bm = await this.cfg.hooks!.beforeDBMToBM(dbm)
|
|
1109
|
+
} else {
|
|
1110
|
+
bm = dbm as any
|
|
1111
|
+
}
|
|
1123
1112
|
|
|
1124
1113
|
// Validate/convert BM
|
|
1125
1114
|
|
|
1126
|
-
return this.validateAndConvert(bm, this.cfg.bmSchema,
|
|
1115
|
+
return this.validateAndConvert(bm, this.cfg.bmSchema, opt)
|
|
1127
1116
|
}
|
|
1128
1117
|
|
|
1129
1118
|
async dbmsToBM(dbms: DBM[], opt: CommonDaoOptions = {}): Promise<BM[]> {
|
|
@@ -1139,20 +1128,23 @@ export class CommonDao<BM extends BaseDBEntity, DBM extends BaseDBEntity = BM> {
|
|
|
1139
1128
|
async bmToDBM(bm?: BM, opt?: CommonDaoOptions): Promise<DBM | undefined> {
|
|
1140
1129
|
if (bm === undefined) return
|
|
1141
1130
|
|
|
1142
|
-
// optimization: no need to run the BM validation, since DBM will be validated anyway
|
|
1143
|
-
// Validate/convert BM
|
|
1144
|
-
// bm gets assigned to the new reference
|
|
1145
|
-
// bm = this.validateAndConvert(bm, this.cfg.bmSchema, DBModelType.BM, opt)
|
|
1146
|
-
|
|
1147
1131
|
// should not do it on load, but only on save!
|
|
1148
1132
|
// this.assignIdCreatedUpdated(bm, opt)
|
|
1149
1133
|
|
|
1134
|
+
// bm gets assigned to the new reference
|
|
1135
|
+
bm = this.validateAndConvert(bm, this.cfg.bmSchema, opt)
|
|
1136
|
+
|
|
1150
1137
|
// BM > DBM
|
|
1151
|
-
|
|
1138
|
+
let dbm: DBM
|
|
1139
|
+
if (this.cfg.hooks!.beforeBMToDBM) {
|
|
1140
|
+
dbm = { ...((await this.cfg.hooks!.beforeBMToDBM(bm!)) as DBM) }
|
|
1141
|
+
} else {
|
|
1142
|
+
dbm = bm as any
|
|
1143
|
+
}
|
|
1152
1144
|
|
|
1153
1145
|
// Validate/convert DBM
|
|
1154
|
-
|
|
1155
|
-
return
|
|
1146
|
+
// return this.validateAndConvert(dbm, this.cfg.dbmSchema, DBModelType.DBM, opt)
|
|
1147
|
+
return dbm
|
|
1156
1148
|
}
|
|
1157
1149
|
|
|
1158
1150
|
async bmsToDBM(bms: BM[], opt: CommonDaoOptions = {}): Promise<DBM[]> {
|
|
@@ -1170,12 +1162,15 @@ export class CommonDao<BM extends BaseDBEntity, DBM extends BaseDBEntity = BM> {
|
|
|
1170
1162
|
|
|
1171
1163
|
dbm = { ...dbm, ...this.cfg.hooks!.parseNaturalId!(dbm.id) }
|
|
1172
1164
|
|
|
1165
|
+
// todo: is this the right place?
|
|
1166
|
+
// todo: is anyToDBM even needed?
|
|
1173
1167
|
if (opt.anonymize) {
|
|
1174
1168
|
dbm = this.cfg.hooks!.anonymize!(dbm)
|
|
1175
1169
|
}
|
|
1176
1170
|
|
|
1177
1171
|
// Validate/convert DBM
|
|
1178
|
-
return this.validateAndConvert(dbm, this.cfg.dbmSchema, DBModelType.DBM, opt)
|
|
1172
|
+
// return this.validateAndConvert(dbm, this.cfg.dbmSchema, DBModelType.DBM, opt)
|
|
1173
|
+
return dbm
|
|
1179
1174
|
}
|
|
1180
1175
|
|
|
1181
1176
|
anyToDBMs(entities: DBM[], opt: CommonDaoOptions = {}): DBM[] {
|
|
@@ -1191,12 +1186,8 @@ export class CommonDao<BM extends BaseDBEntity, DBM extends BaseDBEntity = BM> {
|
|
|
1191
1186
|
validateAndConvert<T>(
|
|
1192
1187
|
obj: Partial<T>,
|
|
1193
1188
|
schema: ObjectSchema<T> | AjvSchema<T> | ZodSchema<T> | undefined,
|
|
1194
|
-
modelType?: DBModelType,
|
|
1195
1189
|
opt: CommonDaoOptions = {},
|
|
1196
1190
|
): any {
|
|
1197
|
-
// `raw` option completely bypasses any processing
|
|
1198
|
-
if (opt.raw) return obj as any
|
|
1199
|
-
|
|
1200
1191
|
// Kirill 2021-10-18: I realized that there's little reason to keep removing null values
|
|
1201
1192
|
// So, from now on we'll preserve them
|
|
1202
1193
|
// "undefined" values, I believe, are/were not saved to/from DB anyway (due to e.g JSON.stringify removing them)
|
|
@@ -1206,16 +1197,7 @@ export class CommonDao<BM extends BaseDBEntity, DBM extends BaseDBEntity = BM> {
|
|
|
1206
1197
|
// obj = _filterNullishValues(obj as any)
|
|
1207
1198
|
// We still filter `undefined` values here, because `beforeDBMToBM` can return undefined values
|
|
1208
1199
|
// and they can be annoying with snapshot tests
|
|
1209
|
-
|
|
1210
|
-
obj = _filterNullishValues(obj)
|
|
1211
|
-
} else {
|
|
1212
|
-
obj = _filterUndefinedValues(obj)
|
|
1213
|
-
}
|
|
1214
|
-
|
|
1215
|
-
// Pre-validation hooks
|
|
1216
|
-
if (modelType === DBModelType.DBM) {
|
|
1217
|
-
obj = this.cfg.hooks!.beforeDBMValidate!(obj as any) as T
|
|
1218
|
-
}
|
|
1200
|
+
obj = _filterUndefinedValues(obj)
|
|
1219
1201
|
|
|
1220
1202
|
// Return as is if no schema is passed or if `skipConversion` is set
|
|
1221
1203
|
if (!schema || opt.skipConversion) {
|
|
@@ -1224,7 +1206,7 @@ export class CommonDao<BM extends BaseDBEntity, DBM extends BaseDBEntity = BM> {
|
|
|
1224
1206
|
|
|
1225
1207
|
// This will Convert and Validate
|
|
1226
1208
|
const table = opt.table || this.cfg.table
|
|
1227
|
-
const objectName = table
|
|
1209
|
+
const objectName = table
|
|
1228
1210
|
|
|
1229
1211
|
let error: JoiValidationError | AjvValidationError | ZodValidationError<T> | undefined
|
|
1230
1212
|
let convertedValue: any
|
package/src/testing/daoTest.ts
CHANGED
|
@@ -8,10 +8,9 @@ import { CommonDBImplementationQuirks, expectMatch } from './dbTest'
|
|
|
8
8
|
import {
|
|
9
9
|
createTestItemsBM,
|
|
10
10
|
testItemBMSchema,
|
|
11
|
-
testItemDBMSchema,
|
|
12
11
|
TEST_TABLE,
|
|
13
12
|
createTestItemBM,
|
|
14
|
-
|
|
13
|
+
testItemBMJsonSchema,
|
|
15
14
|
} from './test.model'
|
|
16
15
|
import { TestItemBM } from '.'
|
|
17
16
|
|
|
@@ -20,7 +19,6 @@ export function runCommonDaoTest(db: CommonDB, quirks: CommonDBImplementationQui
|
|
|
20
19
|
const dao = new CommonDao({
|
|
21
20
|
table: TEST_TABLE,
|
|
22
21
|
db,
|
|
23
|
-
dbmSchema: testItemDBMSchema,
|
|
24
22
|
bmSchema: testItemBMSchema,
|
|
25
23
|
logStarted: true,
|
|
26
24
|
logLevel: CommonDaoLogLevel.DATA_FULL,
|
|
@@ -43,7 +41,7 @@ export function runCommonDaoTest(db: CommonDB, quirks: CommonDBImplementationQui
|
|
|
43
41
|
// CREATE TABLE, DROP
|
|
44
42
|
if (support.createTable) {
|
|
45
43
|
test('createTable, dropIfExists=true', async () => {
|
|
46
|
-
await dao.createTable(
|
|
44
|
+
await dao.createTable(testItemBMJsonSchema, { dropIfExists: true })
|
|
47
45
|
})
|
|
48
46
|
}
|
|
49
47
|
|
package/src/testing/dbTest.ts
CHANGED
|
@@ -7,8 +7,8 @@ import {
|
|
|
7
7
|
createTestItemDBM,
|
|
8
8
|
createTestItemsDBM,
|
|
9
9
|
TEST_TABLE,
|
|
10
|
+
testItemBMJsonSchema,
|
|
10
11
|
TestItemDBM,
|
|
11
|
-
testItemDBMJsonSchema,
|
|
12
12
|
} from './test.model'
|
|
13
13
|
import { deepFreeze } from './test.util'
|
|
14
14
|
|
|
@@ -42,7 +42,7 @@ export function runCommonDBTest(db: CommonDB, quirks: CommonDBImplementationQuir
|
|
|
42
42
|
// CREATE TABLE, DROP
|
|
43
43
|
if (support.createTable) {
|
|
44
44
|
test('createTable, dropIfExists=true', async () => {
|
|
45
|
-
await db.createTable(TEST_TABLE,
|
|
45
|
+
await db.createTable(TEST_TABLE, testItemBMJsonSchema, { dropIfExists: true })
|
|
46
46
|
})
|
|
47
47
|
}
|
|
48
48
|
|
package/src/testing/index.ts
CHANGED
|
@@ -10,8 +10,6 @@ import {
|
|
|
10
10
|
testItemBMJsonSchema,
|
|
11
11
|
testItemBMSchema,
|
|
12
12
|
TestItemDBM,
|
|
13
|
-
testItemDBMJsonSchema,
|
|
14
|
-
testItemDBMSchema,
|
|
15
13
|
TestItemTM,
|
|
16
14
|
testItemTMSchema,
|
|
17
15
|
TEST_TABLE,
|
|
@@ -25,11 +23,9 @@ export {
|
|
|
25
23
|
createTestItemBM,
|
|
26
24
|
createTestItemsDBM,
|
|
27
25
|
createTestItemsBM,
|
|
28
|
-
testItemDBMSchema,
|
|
29
26
|
testItemBMSchema,
|
|
30
27
|
testItemTMSchema,
|
|
31
28
|
testItemBMJsonSchema,
|
|
32
|
-
testItemDBMJsonSchema,
|
|
33
29
|
runCommonDBTest,
|
|
34
30
|
runCommonDaoTest,
|
|
35
31
|
runCommonKeyValueDBTest,
|
|
@@ -35,14 +35,6 @@ export const testItemBMSchema = objectSchema<TestItemBM>({
|
|
|
35
35
|
b1: binarySchema.optional(),
|
|
36
36
|
}).concat(baseDBEntitySchema as any)
|
|
37
37
|
|
|
38
|
-
export const testItemDBMSchema = objectSchema<TestItemDBM>({
|
|
39
|
-
k1: stringSchema,
|
|
40
|
-
k2: stringSchema.allow(null).optional(),
|
|
41
|
-
k3: numberSchema.optional(),
|
|
42
|
-
even: booleanSchema.optional(),
|
|
43
|
-
b1: binarySchema.optional(),
|
|
44
|
-
}).concat(baseDBEntitySchema as any)
|
|
45
|
-
|
|
46
38
|
export const testItemTMSchema = objectSchema<TestItemTM>({
|
|
47
39
|
k1: stringSchema,
|
|
48
40
|
even: booleanSchema.optional(),
|
|
@@ -63,20 +55,6 @@ export const testItemBMJsonSchema: JsonSchemaObject<TestItemBM> = jsonSchema
|
|
|
63
55
|
.baseDBEntity()
|
|
64
56
|
.build()
|
|
65
57
|
|
|
66
|
-
export const testItemDBMJsonSchema: JsonSchemaObject<TestItemDBM> = jsonSchema
|
|
67
|
-
.rootObject<TestItemDBM>({
|
|
68
|
-
// todo: figure out how to not copy-paste these 3 fields
|
|
69
|
-
id: jsonSchema.string(),
|
|
70
|
-
created: jsonSchema.unixTimestamp(),
|
|
71
|
-
updated: jsonSchema.unixTimestamp(),
|
|
72
|
-
k1: jsonSchema.string(),
|
|
73
|
-
k2: jsonSchema.string().optional(),
|
|
74
|
-
k3: jsonSchema.number().optional(),
|
|
75
|
-
even: jsonSchema.boolean().optional(),
|
|
76
|
-
b1: jsonSchema.buffer().optional(),
|
|
77
|
-
})
|
|
78
|
-
.build()
|
|
79
|
-
|
|
80
58
|
export function createTestItemDBM(num = 1): TestItemDBM {
|
|
81
59
|
return {
|
|
82
60
|
id: `id${num}`,
|