@naturalcycles/db-lib 9.8.0 → 9.9.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.
@@ -149,7 +149,8 @@ export declare class CommonDao<BM extends BaseDBEntity, DBM extends BaseDBEntity
149
149
  * Does NOT mutate the object.
150
150
  * Validates (unless `skipValidation=true` passed).
151
151
  */
152
- validateAndConvert<T>(obj: Partial<T>, schema: ObjectSchema<T> | AjvSchema<T> | ZodSchema<T> | undefined, opt?: CommonDaoOptions): any;
152
+ validateAndConvert<T>(obj: Partial<T>, schema: ObjectSchema<T> | AjvSchema<T> | ZodSchema<T> | undefined, op?: 'load' | 'save', // this is to skip validation if validateOnLoad/Save is false
153
+ opt?: CommonDaoOptions): any;
153
154
  getTableSchema(): Promise<JsonSchemaRootObject<DBM>>;
154
155
  createTable(schema: JsonSchemaObject<DBM>, opt?: CommonDaoCreateOptions): Promise<void>;
155
156
  /**
@@ -27,6 +27,8 @@ class CommonDao {
27
27
  assignGeneratedIds: false,
28
28
  useCreatedProperty: true,
29
29
  useUpdatedProperty: true,
30
+ validateOnLoad: true,
31
+ validateOnSave: true,
30
32
  logger: console,
31
33
  ...cfg,
32
34
  hooks: {
@@ -49,7 +51,7 @@ class CommonDao {
49
51
  const bm = this.cfg.hooks.beforeCreate(part);
50
52
  // First assignIdCreatedUpdated, then validate!
51
53
  this.assignIdCreatedUpdated(bm, opt);
52
- return this.validateAndConvert(bm, this.cfg.bmSchema, opt);
54
+ return this.validateAndConvert(bm, this.cfg.bmSchema, undefined, opt);
53
55
  }
54
56
  async getById(id, opt = {}) {
55
57
  if (!id)
@@ -245,7 +247,6 @@ class CommonDao {
245
247
  async streamQueryForEach(q, mapper, opt = {}) {
246
248
  q.table = opt.table || q.table;
247
249
  opt.skipValidation = opt.skipValidation !== false; // default true
248
- opt.skipConversion = opt.skipConversion !== false; // default true
249
250
  opt.errorMode ||= js_lib_1.ErrorMode.SUPPRESS;
250
251
  const partialQuery = !!q._selectedFieldNames;
251
252
  const op = `streamQueryForEach(${q.pretty()})`;
@@ -284,7 +285,6 @@ class CommonDao {
284
285
  async streamQueryAsDBMForEach(q, mapper, opt = {}) {
285
286
  q.table = opt.table || q.table;
286
287
  opt.skipValidation = opt.skipValidation !== false; // default true
287
- opt.skipConversion = opt.skipConversion !== false; // default true
288
288
  opt.errorMode ||= js_lib_1.ErrorMode.SUPPRESS;
289
289
  const partialQuery = !!q._selectedFieldNames;
290
290
  const op = `streamQueryAsDBMForEach(${q.pretty()})`;
@@ -326,7 +326,6 @@ class CommonDao {
326
326
  streamQueryAsDBM(q, opt = {}) {
327
327
  q.table = opt.table || q.table;
328
328
  opt.skipValidation = opt.skipValidation !== false; // default true
329
- opt.skipConversion = opt.skipConversion !== false; // default true
330
329
  opt.errorMode ||= js_lib_1.ErrorMode.SUPPRESS;
331
330
  const partialQuery = !!q._selectedFieldNames;
332
331
  const stream = this.cfg.db.streamQuery(q, opt);
@@ -357,7 +356,6 @@ class CommonDao {
357
356
  streamQuery(q, opt = {}) {
358
357
  q.table = opt.table || q.table;
359
358
  opt.skipValidation = opt.skipValidation !== false; // default true
360
- opt.skipConversion = opt.skipConversion !== false; // default true
361
359
  opt.errorMode ||= js_lib_1.ErrorMode.SUPPRESS;
362
360
  const stream = this.cfg.db.streamQuery(q, opt);
363
361
  const partialQuery = !!q._selectedFieldNames;
@@ -537,7 +535,7 @@ class CommonDao {
537
535
  // We compare with convertedBM, to account for cases when some extra property is assigned to bm,
538
536
  // which should be removed post-validation, but it breaks the "equality check"
539
537
  // Post-validation the equality check should work as intended
540
- const convertedBM = this.validateAndConvert(bm, this.cfg.bmSchema, opt);
538
+ const convertedBM = this.validateAndConvert(bm, this.cfg.bmSchema, 'save', opt);
541
539
  if ((0, js_lib_1._deepJsonEquals)(convertedBM, opt.skipIfEquals)) {
542
540
  // Skipping the save operation
543
541
  return bm;
@@ -682,7 +680,6 @@ class CommonDao {
682
680
  this.requireWriteAccess();
683
681
  const table = opt.table || this.cfg.table;
684
682
  opt.skipValidation ??= true;
685
- opt.skipConversion ??= true;
686
683
  opt.errorMode ||= js_lib_1.ErrorMode.SUPPRESS;
687
684
  if (this.cfg.immutable && !opt.allowMutability && !opt.saveMethod) {
688
685
  opt = { ...opt, saveMethod: 'insert' };
@@ -817,7 +814,7 @@ class CommonDao {
817
814
  // DBM > BM
818
815
  const bm = ((await this.cfg.hooks.beforeDBMToBM?.(dbm)) || dbm);
819
816
  // Validate/convert BM
820
- return this.validateAndConvert(bm, this.cfg.bmSchema, opt);
817
+ return this.validateAndConvert(bm, this.cfg.bmSchema, 'load', opt);
821
818
  }
822
819
  async dbmsToBM(dbms, opt = {}) {
823
820
  return await (0, js_lib_1.pMap)(dbms, async (dbm) => await this.dbmToBM(dbm, opt));
@@ -826,7 +823,7 @@ class CommonDao {
826
823
  if (bm === undefined)
827
824
  return;
828
825
  // bm gets assigned to the new reference
829
- bm = this.validateAndConvert(bm, this.cfg.bmSchema, opt);
826
+ bm = this.validateAndConvert(bm, this.cfg.bmSchema, 'save', opt);
830
827
  // BM > DBM
831
828
  return ((await this.cfg.hooks.beforeBMToDBM?.(bm)) || bm);
832
829
  }
@@ -857,7 +854,8 @@ class CommonDao {
857
854
  * Does NOT mutate the object.
858
855
  * Validates (unless `skipValidation=true` passed).
859
856
  */
860
- validateAndConvert(obj, schema, opt = {}) {
857
+ validateAndConvert(obj, schema, op, // this is to skip validation if validateOnLoad/Save is false
858
+ opt = {}) {
861
859
  // Kirill 2021-10-18: I realized that there's little reason to keep removing null values
862
860
  // So, from now on we'll preserve them
863
861
  // "undefined" values, I believe, are/were not saved to/from DB anyway (due to e.g JSON.stringify removing them)
@@ -869,7 +867,10 @@ class CommonDao {
869
867
  // and they can be annoying with snapshot tests
870
868
  obj = (0, js_lib_1._filterUndefinedValues)(obj);
871
869
  // Return as is if no schema is passed or if `skipConversion` is set
872
- if (!schema || opt.skipConversion) {
870
+ if (!schema ||
871
+ opt.skipValidation ||
872
+ (op === 'load' && !this.cfg.validateOnLoad) ||
873
+ (op === 'save' && !this.cfg.validateOnSave)) {
873
874
  return obj;
874
875
  }
875
876
  // This will Convert and Validate
@@ -897,7 +898,7 @@ class CommonDao {
897
898
  convertedValue = vr.value;
898
899
  }
899
900
  // If we care about validation and there's an error
900
- if (error && !opt.skipValidation) {
901
+ if (error) {
901
902
  const processedError = this.cfg.hooks.onValidationError(error);
902
903
  if (processedError)
903
904
  throw processedError;
@@ -101,6 +101,16 @@ export interface CommonDaoCfg<BM extends BaseDBEntity, DBM extends BaseDBEntity
101
101
  */
102
102
  bmSchema?: ObjectSchema<BM> | AjvSchema<BM> | ZodSchema<BM>;
103
103
  excludeFromIndexes?: (keyof DBM)[];
104
+ /**
105
+ * Defaults to true.
106
+ * If set to false - load (read) operations will skip validation (and conversion).
107
+ */
108
+ validateOnLoad?: boolean;
109
+ /**
110
+ * Defaults to true.
111
+ * If set to false - save (write) operations will skip validation (and conversion).
112
+ */
113
+ validateOnSave?: boolean;
104
114
  /**
105
115
  * Defaults to false.
106
116
  * Setting it to true will set saveMethod to `insert` for save/saveBatch, which will
@@ -163,20 +173,12 @@ export interface CommonDaoCfg<BM extends BaseDBEntity, DBM extends BaseDBEntity
163
173
  */
164
174
  export interface CommonDaoOptions extends CommonDBOptions {
165
175
  /**
166
- * If true - will ignore the validation result, but will STILL DO the validation step, which will DO conversion
167
- * (according to Joi schema).
168
- *
169
- * Set skipConversion=true (or raw=true) to bypass conversion step as well (e.g for performance reasons).
176
+ * Defaults to false.
170
177
  *
171
- * @default false
178
+ * If set to true - will disable validation (and conversion).
179
+ * One possible use case of doing this is - performance (as validation/conversion takes time, especially with Joi).
172
180
  */
173
181
  skipValidation?: boolean;
174
- /**
175
- * If true - will SKIP the joi validation AND conversion steps alltogether. To improve performance of DAO.
176
- *
177
- * @default false
178
- */
179
- skipConversion?: boolean;
180
182
  /**
181
183
  * @default false
182
184
  */
@@ -241,10 +243,6 @@ export interface CommonDaoStreamOptions<IN> extends CommonDaoOptions, TransformL
241
243
  * @default true (for streams)
242
244
  */
243
245
  skipValidation?: boolean;
244
- /**
245
- * @default true (for streams)
246
- */
247
- skipConversion?: boolean;
248
246
  /**
249
247
  * @default ErrorMode.SUPPRESS for returning ReadableStream, because .pipe() has no concept of "error propagation"
250
248
  * @default ErrorMode.SUPPRESS for .forEach() streams as well, but overridable
package/package.json CHANGED
@@ -40,7 +40,7 @@
40
40
  "engines": {
41
41
  "node": ">=18.12"
42
42
  },
43
- "version": "9.8.0",
43
+ "version": "9.9.0",
44
44
  "description": "Lowest Common Denominator API to supported Databases",
45
45
  "keywords": [
46
46
  "db",
@@ -129,6 +129,18 @@ export interface CommonDaoCfg<BM extends BaseDBEntity, DBM extends BaseDBEntity
129
129
 
130
130
  excludeFromIndexes?: (keyof DBM)[]
131
131
 
132
+ /**
133
+ * Defaults to true.
134
+ * If set to false - load (read) operations will skip validation (and conversion).
135
+ */
136
+ validateOnLoad?: boolean
137
+
138
+ /**
139
+ * Defaults to true.
140
+ * If set to false - save (write) operations will skip validation (and conversion).
141
+ */
142
+ validateOnSave?: boolean
143
+
132
144
  /**
133
145
  * Defaults to false.
134
146
  * Setting it to true will set saveMethod to `insert` for save/saveBatch, which will
@@ -203,22 +215,13 @@ export interface CommonDaoCfg<BM extends BaseDBEntity, DBM extends BaseDBEntity
203
215
  */
204
216
  export interface CommonDaoOptions extends CommonDBOptions {
205
217
  /**
206
- * If true - will ignore the validation result, but will STILL DO the validation step, which will DO conversion
207
- * (according to Joi schema).
208
- *
209
- * Set skipConversion=true (or raw=true) to bypass conversion step as well (e.g for performance reasons).
218
+ * Defaults to false.
210
219
  *
211
- * @default false
220
+ * If set to true - will disable validation (and conversion).
221
+ * One possible use case of doing this is - performance (as validation/conversion takes time, especially with Joi).
212
222
  */
213
223
  skipValidation?: boolean
214
224
 
215
- /**
216
- * If true - will SKIP the joi validation AND conversion steps alltogether. To improve performance of DAO.
217
- *
218
- * @default false
219
- */
220
- skipConversion?: boolean
221
-
222
225
  /**
223
226
  * @default false
224
227
  */
@@ -302,11 +305,6 @@ export interface CommonDaoStreamOptions<IN>
302
305
  */
303
306
  skipValidation?: boolean
304
307
 
305
- /**
306
- * @default true (for streams)
307
- */
308
- skipConversion?: boolean
309
-
310
308
  /**
311
309
  * @default ErrorMode.SUPPRESS for returning ReadableStream, because .pipe() has no concept of "error propagation"
312
310
  * @default ErrorMode.SUPPRESS for .forEach() streams as well, but overridable
@@ -81,6 +81,8 @@ export class CommonDao<BM extends BaseDBEntity, DBM extends BaseDBEntity = BM> {
81
81
  assignGeneratedIds: false,
82
82
  useCreatedProperty: true,
83
83
  useUpdatedProperty: true,
84
+ validateOnLoad: true,
85
+ validateOnSave: true,
84
86
  logger: console,
85
87
  ...cfg,
86
88
  hooks: {
@@ -104,7 +106,7 @@ export class CommonDao<BM extends BaseDBEntity, DBM extends BaseDBEntity = BM> {
104
106
  const bm = this.cfg.hooks!.beforeCreate!(part)
105
107
  // First assignIdCreatedUpdated, then validate!
106
108
  this.assignIdCreatedUpdated(bm, opt)
107
- return this.validateAndConvert(bm, this.cfg.bmSchema, opt)
109
+ return this.validateAndConvert(bm, this.cfg.bmSchema, undefined, opt)
108
110
  }
109
111
 
110
112
  // GET
@@ -353,7 +355,6 @@ export class CommonDao<BM extends BaseDBEntity, DBM extends BaseDBEntity = BM> {
353
355
  ): Promise<void> {
354
356
  q.table = opt.table || q.table
355
357
  opt.skipValidation = opt.skipValidation !== false // default true
356
- opt.skipConversion = opt.skipConversion !== false // default true
357
358
  opt.errorMode ||= ErrorMode.SUPPRESS
358
359
 
359
360
  const partialQuery = !!q._selectedFieldNames
@@ -403,7 +404,6 @@ export class CommonDao<BM extends BaseDBEntity, DBM extends BaseDBEntity = BM> {
403
404
  ): Promise<void> {
404
405
  q.table = opt.table || q.table
405
406
  opt.skipValidation = opt.skipValidation !== false // default true
406
- opt.skipConversion = opt.skipConversion !== false // default true
407
407
  opt.errorMode ||= ErrorMode.SUPPRESS
408
408
 
409
409
  const partialQuery = !!q._selectedFieldNames
@@ -452,7 +452,6 @@ export class CommonDao<BM extends BaseDBEntity, DBM extends BaseDBEntity = BM> {
452
452
  streamQueryAsDBM(q: DBQuery<DBM>, opt: CommonDaoStreamOptions<DBM> = {}): ReadableTyped<DBM> {
453
453
  q.table = opt.table || q.table
454
454
  opt.skipValidation = opt.skipValidation !== false // default true
455
- opt.skipConversion = opt.skipConversion !== false // default true
456
455
  opt.errorMode ||= ErrorMode.SUPPRESS
457
456
 
458
457
  const partialQuery = !!q._selectedFieldNames
@@ -491,7 +490,6 @@ export class CommonDao<BM extends BaseDBEntity, DBM extends BaseDBEntity = BM> {
491
490
  streamQuery(q: DBQuery<DBM>, opt: CommonDaoStreamOptions<BM> = {}): ReadableTyped<BM> {
492
491
  q.table = opt.table || q.table
493
492
  opt.skipValidation = opt.skipValidation !== false // default true
494
- opt.skipConversion = opt.skipConversion !== false // default true
495
493
  opt.errorMode ||= ErrorMode.SUPPRESS
496
494
 
497
495
  const stream = this.cfg.db.streamQuery<DBM>(q, opt)
@@ -721,7 +719,7 @@ export class CommonDao<BM extends BaseDBEntity, DBM extends BaseDBEntity = BM> {
721
719
  // We compare with convertedBM, to account for cases when some extra property is assigned to bm,
722
720
  // which should be removed post-validation, but it breaks the "equality check"
723
721
  // Post-validation the equality check should work as intended
724
- const convertedBM = this.validateAndConvert(bm as Partial<BM>, this.cfg.bmSchema, opt)
722
+ const convertedBM = this.validateAndConvert(bm as Partial<BM>, this.cfg.bmSchema, 'save', opt)
725
723
  if (_deepJsonEquals(convertedBM, opt.skipIfEquals)) {
726
724
  // Skipping the save operation
727
725
  return bm as BM
@@ -900,7 +898,6 @@ export class CommonDao<BM extends BaseDBEntity, DBM extends BaseDBEntity = BM> {
900
898
 
901
899
  const table = opt.table || this.cfg.table
902
900
  opt.skipValidation ??= true
903
- opt.skipConversion ??= true
904
901
  opt.errorMode ||= ErrorMode.SUPPRESS
905
902
 
906
903
  if (this.cfg.immutable && !opt.allowMutability && !opt.saveMethod) {
@@ -1077,7 +1074,7 @@ export class CommonDao<BM extends BaseDBEntity, DBM extends BaseDBEntity = BM> {
1077
1074
  const bm = ((await this.cfg.hooks!.beforeDBMToBM?.(dbm)) || dbm) as Partial<BM>
1078
1075
 
1079
1076
  // Validate/convert BM
1080
- return this.validateAndConvert(bm, this.cfg.bmSchema, opt)
1077
+ return this.validateAndConvert(bm, this.cfg.bmSchema, 'load', opt)
1081
1078
  }
1082
1079
 
1083
1080
  async dbmsToBM(dbms: DBM[], opt: CommonDaoOptions = {}): Promise<BM[]> {
@@ -1094,7 +1091,7 @@ export class CommonDao<BM extends BaseDBEntity, DBM extends BaseDBEntity = BM> {
1094
1091
  if (bm === undefined) return
1095
1092
 
1096
1093
  // bm gets assigned to the new reference
1097
- bm = this.validateAndConvert(bm, this.cfg.bmSchema, opt)
1094
+ bm = this.validateAndConvert(bm, this.cfg.bmSchema, 'save', opt)
1098
1095
 
1099
1096
  // BM > DBM
1100
1097
  return ((await this.cfg.hooks!.beforeBMToDBM?.(bm!)) || bm) as DBM
@@ -1138,6 +1135,7 @@ export class CommonDao<BM extends BaseDBEntity, DBM extends BaseDBEntity = BM> {
1138
1135
  validateAndConvert<T>(
1139
1136
  obj: Partial<T>,
1140
1137
  schema: ObjectSchema<T> | AjvSchema<T> | ZodSchema<T> | undefined,
1138
+ op?: 'load' | 'save', // this is to skip validation if validateOnLoad/Save is false
1141
1139
  opt: CommonDaoOptions = {},
1142
1140
  ): any {
1143
1141
  // Kirill 2021-10-18: I realized that there's little reason to keep removing null values
@@ -1152,7 +1150,12 @@ export class CommonDao<BM extends BaseDBEntity, DBM extends BaseDBEntity = BM> {
1152
1150
  obj = _filterUndefinedValues(obj)
1153
1151
 
1154
1152
  // Return as is if no schema is passed or if `skipConversion` is set
1155
- if (!schema || opt.skipConversion) {
1153
+ if (
1154
+ !schema ||
1155
+ opt.skipValidation ||
1156
+ (op === 'load' && !this.cfg.validateOnLoad) ||
1157
+ (op === 'save' && !this.cfg.validateOnSave)
1158
+ ) {
1156
1159
  return obj
1157
1160
  }
1158
1161
 
@@ -1183,7 +1186,7 @@ export class CommonDao<BM extends BaseDBEntity, DBM extends BaseDBEntity = BM> {
1183
1186
  }
1184
1187
 
1185
1188
  // If we care about validation and there's an error
1186
- if (error && !opt.skipValidation) {
1189
+ if (error) {
1187
1190
  const processedError = this.cfg.hooks!.onValidationError!(error)
1188
1191
 
1189
1192
  if (processedError) throw processedError