@naturalcycles/db-lib 10.11.0 → 10.12.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.
@@ -2,9 +2,6 @@ import type { Transform } from 'node:stream';
2
2
  import type { JsonSchemaObject, JsonSchemaRootObject } from '@naturalcycles/js-lib/json-schema';
3
3
  import type { CommonLogger } from '@naturalcycles/js-lib/log';
4
4
  import type { AsyncIndexedMapper, BaseDBEntity, StringMap, UnixTimestampMillis, Unsaved } from '@naturalcycles/js-lib/types';
5
- import { ZodType } from '@naturalcycles/js-lib/zod';
6
- import { AjvSchema } from '@naturalcycles/nodejs-lib/ajv';
7
- import { type ObjectSchema } from '@naturalcycles/nodejs-lib/joi';
8
5
  import type { ReadableTyped } from '@naturalcycles/nodejs-lib/stream';
9
6
  import type { CommonDBTransactionOptions, DBTransaction, RunQueryResult } from '../db.model.js';
10
7
  import type { DBQuery } from '../query/dbQuery.js';
@@ -163,8 +160,7 @@ export declare class CommonDao<BM extends BaseDBEntity, DBM extends BaseDBEntity
163
160
  * Does NOT mutate the object.
164
161
  * Validates (unless `skipValidation=true` passed).
165
162
  */
166
- validateAndConvert<T>(obj: Partial<T>, schema: ObjectSchema<T> | AjvSchema<T> | ZodType<T> | undefined, op?: 'load' | 'save', // this is to skip validation if validateOnLoad/Save is false
167
- opt?: CommonDaoOptions): any;
163
+ private validateAndConvert;
168
164
  getTableSchema(): Promise<JsonSchemaRootObject<DBM>>;
169
165
  createTable(schema: JsonSchemaObject<DBM>, opt?: CommonDaoCreateOptions): Promise<void>;
170
166
  /**
@@ -8,10 +8,7 @@ import { _deepCopy, _filterUndefinedValues, _objectAssignExact, } from '@natural
8
8
  import { pMap } from '@naturalcycles/js-lib/promise/pMap.js';
9
9
  import { _truncate } from '@naturalcycles/js-lib/string/string.util.js';
10
10
  import { _passthroughPredicate, _typeCast, SKIP } from '@naturalcycles/js-lib/types';
11
- import { ZodType, zSafeValidate } from '@naturalcycles/js-lib/zod';
12
11
  import { stringId } from '@naturalcycles/nodejs-lib';
13
- import { AjvSchema } from '@naturalcycles/nodejs-lib/ajv';
14
- import { getValidationResult, } from '@naturalcycles/nodejs-lib/joi';
15
12
  import { _pipeline, transformChunk, transformLogProgress, transformMap, transformNoOp, writableVoid, } from '@naturalcycles/nodejs-lib/stream';
16
13
  import { DBLibError } from '../cnst.js';
17
14
  import { RunnableDBQuery } from '../query/dbQuery.js';
@@ -57,7 +54,7 @@ export class CommonDao {
57
54
  const bm = this.cfg.hooks.beforeCreate(part);
58
55
  // First assignIdCreatedUpdated, then validate!
59
56
  this.assignIdCreatedUpdated(bm, opt);
60
- return this.validateAndConvert(bm, this.cfg.bmSchema, undefined, opt);
57
+ return this.validateAndConvert(bm, undefined, opt);
61
58
  }
62
59
  // GET
63
60
  // overrides are disabled now, as they obfuscate errors when ID branded type is used
@@ -592,7 +589,7 @@ export class CommonDao {
592
589
  // We compare with convertedBM, to account for cases when some extra property is assigned to bm,
593
590
  // which should be removed post-validation, but it breaks the "equality check"
594
591
  // Post-validation the equality check should work as intended
595
- const convertedBM = this.validateAndConvert(bm, this.cfg.bmSchema, 'save', opt);
592
+ const convertedBM = this.validateAndConvert(bm, 'save', opt);
596
593
  if (_deepJsonEquals(convertedBM, opt.skipIfEquals)) {
597
594
  // Skipping the save operation
598
595
  return bm;
@@ -901,7 +898,7 @@ export class CommonDao {
901
898
  // DBM > BM
902
899
  const bm = ((await this.cfg.hooks.beforeDBMToBM?.(dbm)) || dbm);
903
900
  // Validate/convert BM
904
- return this.validateAndConvert(bm, this.cfg.bmSchema, 'load', opt);
901
+ return this.validateAndConvert(bm, 'load', opt);
905
902
  }
906
903
  async dbmsToBM(dbms, opt = {}) {
907
904
  return await pMap(dbms, async (dbm) => await this.dbmToBM(dbm, opt));
@@ -910,7 +907,7 @@ export class CommonDao {
910
907
  if (bm === undefined)
911
908
  return;
912
909
  // bm gets assigned to the new reference
913
- bm = this.validateAndConvert(bm, this.cfg.bmSchema, 'save', opt);
910
+ bm = this.validateAndConvert(bm, 'save', opt);
914
911
  // BM > DBM
915
912
  return ((await this.cfg.hooks.beforeBMToDBM?.(bm)) || bm);
916
913
  }
@@ -941,60 +938,26 @@ export class CommonDao {
941
938
  * Does NOT mutate the object.
942
939
  * Validates (unless `skipValidation=true` passed).
943
940
  */
944
- validateAndConvert(obj, schema, op, // this is to skip validation if validateOnLoad/Save is false
941
+ validateAndConvert(input, op, // this is to skip validation if validateOnLoad/Save is false
945
942
  opt = {}) {
946
- // Kirill 2021-10-18: I realized that there's little reason to keep removing null values
947
- // So, from now on we'll preserve them
948
- // "undefined" values, I believe, are/were not saved to/from DB anyway (due to e.g JSON.stringify removing them)
949
- // But let's keep watching it!
950
- //
951
- // Filter null and undefined values
952
- // obj = _filterNullishValues(obj as any)
953
943
  // We still filter `undefined` values here, because `beforeDBMToBM` can return undefined values
954
944
  // and they can be annoying with snapshot tests
955
- obj = _filterUndefinedValues(obj);
945
+ input = _filterUndefinedValues(input);
956
946
  // Return as is if no schema is passed or if `skipConversion` is set
957
- if ((!schema && !this.cfg.validateBM) ||
947
+ if (!this.cfg.validateBM ||
958
948
  opt.skipValidation ||
959
949
  (op === 'load' && !this.cfg.validateOnLoad) ||
960
950
  (op === 'save' && !this.cfg.validateOnSave)) {
961
- return obj;
951
+ return input;
962
952
  }
963
953
  const inputName = opt.table || this.cfg.table;
964
- let error;
965
- let convertedValue;
966
- if (this.cfg.validateBM) {
967
- const [err, value] = this.cfg.validateBM(obj, {
968
- // Passing `mutateInput` through allows to do opt-in mutation
969
- // for individual operations, e.g `someDao.save(myObj, { mutateInput: true })`,
970
- // while still keeping safe non-mutating behavior by default
971
- mutateInput: opt.mutateInput,
972
- inputName,
973
- });
974
- error = err;
975
- convertedValue = value;
976
- }
977
- else if (schema instanceof ZodType) {
978
- // Zod schema
979
- const [err, value] = zSafeValidate(obj, schema);
980
- error = err;
981
- convertedValue = value;
982
- }
983
- else if (schema instanceof AjvSchema) {
984
- // Ajv schema
985
- const [err, value] = schema.getValidationResult(obj, {
986
- inputName,
987
- });
988
- error = err;
989
- convertedValue = value;
990
- }
991
- else {
992
- // Joi
993
- const [err, value] = getValidationResult(obj, schema, inputName);
994
- error = err;
995
- convertedValue = value;
996
- }
997
- // If we care about validation and there's an error
954
+ const [error, convertedValue] = this.cfg.validateBM(input, {
955
+ // Passing `mutateInput` through allows to do opt-in mutation
956
+ // for individual operations, e.g `someDao.save(myObj, { mutateInput: true })`,
957
+ // while still keeping safe non-mutating behavior by default
958
+ mutateInput: opt.mutateInput,
959
+ inputName,
960
+ });
998
961
  if (error) {
999
962
  const processedError = this.cfg.hooks.onValidationError(error);
1000
963
  if (processedError)
@@ -1,10 +1,7 @@
1
1
  import type { ValidationFunction } from '@naturalcycles/js-lib';
2
- import type { ErrorMode } from '@naturalcycles/js-lib/error';
2
+ import type { AppError, ErrorMode } from '@naturalcycles/js-lib/error';
3
3
  import type { CommonLogger } from '@naturalcycles/js-lib/log';
4
4
  import type { BaseDBEntity, NumberOfMilliseconds, Promisable, UnixTimestamp } from '@naturalcycles/js-lib/types';
5
- import type { ZodType, ZodValidationError } from '@naturalcycles/js-lib/zod';
6
- import type { AjvSchema, AjvValidationError } from '@naturalcycles/nodejs-lib/ajv';
7
- import type { JoiValidationError, ObjectSchema } from '@naturalcycles/nodejs-lib/joi';
8
5
  import type { TransformLogProgressOptions, TransformMapOptions } from '@naturalcycles/nodejs-lib/stream';
9
6
  import type { CommonDB } from '../commondb/common.db.js';
10
7
  import type { CommonDBCreateOptions, CommonDBOptions, CommonDBSaveOptions } from '../db.model.js';
@@ -79,7 +76,7 @@ export interface CommonDaoHooks<BM extends BaseDBEntity, DBM extends BaseDBEntit
79
76
  * Return original `err` to pass the error through (will be thrown in CommonDao).
80
77
  * Return modified/new `Error` if needed.
81
78
  */
82
- onValidationError: (err: JoiValidationError | AjvValidationError | ZodValidationError) => Error | false;
79
+ onValidationError: (err: AppError) => Error | false;
83
80
  }
84
81
  export declare enum CommonDaoLogLevel {
85
82
  /**
@@ -102,19 +99,11 @@ export declare enum CommonDaoLogLevel {
102
99
  export interface CommonDaoCfg<BM extends BaseDBEntity, DBM extends BaseDBEntity = BM, ID = BM['id']> {
103
100
  db: CommonDB;
104
101
  table: string;
105
- /**
106
- * Joi, AjvSchema or ZodSchema is supported.
107
- *
108
- * @deprecated - use `validateBM` instead.
109
- */
110
- bmSchema?: ObjectSchema<BM> | AjvSchema<BM> | ZodType<BM>;
111
102
  /**
112
103
  * Experimental alternative to bmSchema.
113
104
  * "Bring your own validation function".
114
105
  * It removes the knowledge from CommonDao about the validation library used
115
106
  * and abstracts it away.
116
- *
117
- * @experimental
118
107
  */
119
108
  validateBM?: ValidationFunction<BM, any>;
120
109
  excludeFromIndexes?: (keyof DBM)[];
@@ -2,6 +2,7 @@ import { Readable } from 'node:stream';
2
2
  import { _sortBy } from '@naturalcycles/js-lib/array/array.util.js';
3
3
  import { localTime } from '@naturalcycles/js-lib/datetime/localTime.js';
4
4
  import { _deepCopy, _filterObject, _omit, _pick } from '@naturalcycles/js-lib/object';
5
+ import { getJoiValidationFunction } from '@naturalcycles/nodejs-lib/joi';
5
6
  import { _pipeline } from '@naturalcycles/nodejs-lib/stream';
6
7
  import { CommonDao } from '../commondao/common.dao.js';
7
8
  import { CommonDaoLogLevel } from '../commondao/common.dao.model.js';
@@ -14,7 +15,7 @@ export async function runCommonDaoTest(db, quirks = {}) {
14
15
  const dao = new CommonDao({
15
16
  table: TEST_TABLE,
16
17
  db,
17
- bmSchema: testItemBMSchema,
18
+ validateBM: getJoiValidationFunction(testItemBMSchema),
18
19
  logStarted: true,
19
20
  logLevel: CommonDaoLogLevel.DATA_FULL,
20
21
  });
package/package.json CHANGED
@@ -1,13 +1,13 @@
1
1
  {
2
2
  "name": "@naturalcycles/db-lib",
3
3
  "type": "module",
4
- "version": "10.11.0",
4
+ "version": "10.12.0",
5
5
  "dependencies": {
6
6
  "@naturalcycles/js-lib": "^15",
7
7
  "@naturalcycles/nodejs-lib": "^15"
8
8
  },
9
9
  "devDependencies": {
10
- "@naturalcycles/dev-lib": "19.22.0"
10
+ "@naturalcycles/dev-lib": "18.4.2"
11
11
  },
12
12
  "files": [
13
13
  "dist",
@@ -1,5 +1,5 @@
1
1
  import type { ValidationFunction } from '@naturalcycles/js-lib'
2
- import type { ErrorMode } from '@naturalcycles/js-lib/error'
2
+ import type { AppError, ErrorMode } from '@naturalcycles/js-lib/error'
3
3
  import type { CommonLogger } from '@naturalcycles/js-lib/log'
4
4
  import type {
5
5
  BaseDBEntity,
@@ -7,9 +7,6 @@ import type {
7
7
  Promisable,
8
8
  UnixTimestamp,
9
9
  } from '@naturalcycles/js-lib/types'
10
- import type { ZodType, ZodValidationError } from '@naturalcycles/js-lib/zod'
11
- import type { AjvSchema, AjvValidationError } from '@naturalcycles/nodejs-lib/ajv'
12
- import type { JoiValidationError, ObjectSchema } from '@naturalcycles/nodejs-lib/joi'
13
10
  import type {
14
11
  TransformLogProgressOptions,
15
12
  TransformMapOptions,
@@ -96,9 +93,7 @@ export interface CommonDaoHooks<BM extends BaseDBEntity, DBM extends BaseDBEntit
96
93
  * Return original `err` to pass the error through (will be thrown in CommonDao).
97
94
  * Return modified/new `Error` if needed.
98
95
  */
99
- onValidationError: (
100
- err: JoiValidationError | AjvValidationError | ZodValidationError,
101
- ) => Error | false
96
+ onValidationError: (err: AppError) => Error | false
102
97
  }
103
98
 
104
99
  export enum CommonDaoLogLevel {
@@ -128,20 +123,11 @@ export interface CommonDaoCfg<
128
123
  db: CommonDB
129
124
  table: string
130
125
 
131
- /**
132
- * Joi, AjvSchema or ZodSchema is supported.
133
- *
134
- * @deprecated - use `validateBM` instead.
135
- */
136
- bmSchema?: ObjectSchema<BM> | AjvSchema<BM> | ZodType<BM>
137
-
138
126
  /**
139
127
  * Experimental alternative to bmSchema.
140
128
  * "Bring your own validation function".
141
129
  * It removes the knowledge from CommonDao about the validation library used
142
130
  * and abstracts it away.
143
- *
144
- * @experimental
145
131
  */
146
132
  validateBM?: ValidationFunction<BM, any>
147
133
 
@@ -23,15 +23,7 @@ import type {
23
23
  Unsaved,
24
24
  } from '@naturalcycles/js-lib/types'
25
25
  import { _passthroughPredicate, _typeCast, SKIP } from '@naturalcycles/js-lib/types'
26
- import type { ZodValidationError } from '@naturalcycles/js-lib/zod'
27
- import { ZodType, zSafeValidate } from '@naturalcycles/js-lib/zod'
28
26
  import { stringId } from '@naturalcycles/nodejs-lib'
29
- import { AjvSchema, type AjvValidationError } from '@naturalcycles/nodejs-lib/ajv'
30
- import {
31
- getValidationResult,
32
- type JoiValidationError,
33
- type ObjectSchema,
34
- } from '@naturalcycles/nodejs-lib/joi'
35
27
  import type { ReadableTyped } from '@naturalcycles/nodejs-lib/stream'
36
28
  import {
37
29
  _pipeline,
@@ -102,7 +94,7 @@ export class CommonDao<BM extends BaseDBEntity, DBM extends BaseDBEntity = BM, I
102
94
  const bm = this.cfg.hooks!.beforeCreate!(part)
103
95
  // First assignIdCreatedUpdated, then validate!
104
96
  this.assignIdCreatedUpdated(bm, opt)
105
- return this.validateAndConvert(bm, this.cfg.bmSchema, undefined, opt)
97
+ return this.validateAndConvert(bm, undefined, opt)
106
98
  }
107
99
 
108
100
  // GET
@@ -767,7 +759,7 @@ export class CommonDao<BM extends BaseDBEntity, DBM extends BaseDBEntity = BM, I
767
759
  // We compare with convertedBM, to account for cases when some extra property is assigned to bm,
768
760
  // which should be removed post-validation, but it breaks the "equality check"
769
761
  // Post-validation the equality check should work as intended
770
- const convertedBM = this.validateAndConvert(bm as Partial<BM>, this.cfg.bmSchema, 'save', opt)
762
+ const convertedBM = this.validateAndConvert(bm as Partial<BM>, 'save', opt)
771
763
  if (_deepJsonEquals(convertedBM, opt.skipIfEquals)) {
772
764
  // Skipping the save operation
773
765
  return bm as BM
@@ -1150,7 +1142,7 @@ export class CommonDao<BM extends BaseDBEntity, DBM extends BaseDBEntity = BM, I
1150
1142
  const bm = ((await this.cfg.hooks!.beforeDBMToBM?.(dbm)) || dbm) as Partial<BM>
1151
1143
 
1152
1144
  // Validate/convert BM
1153
- return this.validateAndConvert(bm, this.cfg.bmSchema, 'load', opt)
1145
+ return this.validateAndConvert(bm, 'load', opt)
1154
1146
  }
1155
1147
 
1156
1148
  async dbmsToBM(dbms: DBM[], opt: CommonDaoOptions = {}): Promise<BM[]> {
@@ -1167,10 +1159,10 @@ export class CommonDao<BM extends BaseDBEntity, DBM extends BaseDBEntity = BM, I
1167
1159
  if (bm === undefined) return
1168
1160
 
1169
1161
  // bm gets assigned to the new reference
1170
- bm = this.validateAndConvert(bm, this.cfg.bmSchema, 'save', opt)
1162
+ bm = this.validateAndConvert(bm, 'save', opt)
1171
1163
 
1172
1164
  // BM > DBM
1173
- return ((await this.cfg.hooks!.beforeBMToDBM?.(bm!)) || bm) as DBM
1165
+ return ((await this.cfg.hooks!.beforeBMToDBM?.(bm)) || bm) as DBM
1174
1166
  }
1175
1167
 
1176
1168
  async bmsToDBM(bms: BM[], opt: CommonDaoOptions = {}): Promise<DBM[]> {
@@ -1208,70 +1200,37 @@ export class CommonDao<BM extends BaseDBEntity, DBM extends BaseDBEntity = BM, I
1208
1200
  * Does NOT mutate the object.
1209
1201
  * Validates (unless `skipValidation=true` passed).
1210
1202
  */
1211
- validateAndConvert<T>(
1212
- obj: Partial<T>,
1213
- schema: ObjectSchema<T> | AjvSchema<T> | ZodType<T> | undefined,
1203
+ private validateAndConvert(
1204
+ input: Partial<BM>,
1214
1205
  op?: 'load' | 'save', // this is to skip validation if validateOnLoad/Save is false
1215
1206
  opt: CommonDaoOptions = {},
1216
- ): any {
1217
- // Kirill 2021-10-18: I realized that there's little reason to keep removing null values
1218
- // So, from now on we'll preserve them
1219
- // "undefined" values, I believe, are/were not saved to/from DB anyway (due to e.g JSON.stringify removing them)
1220
- // But let's keep watching it!
1221
- //
1222
- // Filter null and undefined values
1223
- // obj = _filterNullishValues(obj as any)
1207
+ ): BM {
1224
1208
  // We still filter `undefined` values here, because `beforeDBMToBM` can return undefined values
1225
1209
  // and they can be annoying with snapshot tests
1226
- obj = _filterUndefinedValues(obj)
1210
+ input = _filterUndefinedValues(input)
1227
1211
 
1228
1212
  // Return as is if no schema is passed or if `skipConversion` is set
1229
1213
  if (
1230
- (!schema && !this.cfg.validateBM) ||
1214
+ !this.cfg.validateBM ||
1231
1215
  opt.skipValidation ||
1232
1216
  (op === 'load' && !this.cfg.validateOnLoad) ||
1233
1217
  (op === 'save' && !this.cfg.validateOnSave)
1234
1218
  ) {
1235
- return obj
1219
+ return input as BM
1236
1220
  }
1237
1221
 
1238
1222
  const inputName = opt.table || this.cfg.table
1239
- let error: JoiValidationError | AjvValidationError | ZodValidationError | null | undefined
1240
- let convertedValue: any
1241
-
1242
- if (this.cfg.validateBM) {
1243
- const [err, value] = this.cfg.validateBM(obj as any as BM, {
1244
- // Passing `mutateInput` through allows to do opt-in mutation
1245
- // for individual operations, e.g `someDao.save(myObj, { mutateInput: true })`,
1246
- // while still keeping safe non-mutating behavior by default
1247
- mutateInput: opt.mutateInput,
1248
- inputName,
1249
- })
1250
- error = err
1251
- convertedValue = value
1252
- } else if (schema instanceof ZodType) {
1253
- // Zod schema
1254
- const [err, value] = zSafeValidate(obj as T, schema)
1255
- error = err
1256
- convertedValue = value
1257
- } else if (schema instanceof AjvSchema) {
1258
- // Ajv schema
1259
- const [err, value] = schema.getValidationResult(obj as T, {
1260
- inputName,
1261
- })
1262
- error = err
1263
- convertedValue = value
1264
- } else {
1265
- // Joi
1266
- const [err, value] = getValidationResult(obj, schema, inputName)
1267
- error = err
1268
- convertedValue = value
1269
- }
1270
1223
 
1271
- // If we care about validation and there's an error
1224
+ const [error, convertedValue] = this.cfg.validateBM(input as BM, {
1225
+ // Passing `mutateInput` through allows to do opt-in mutation
1226
+ // for individual operations, e.g `someDao.save(myObj, { mutateInput: true })`,
1227
+ // while still keeping safe non-mutating behavior by default
1228
+ mutateInput: opt.mutateInput,
1229
+ inputName,
1230
+ })
1231
+
1272
1232
  if (error) {
1273
1233
  const processedError = this.cfg.hooks!.onValidationError!(error)
1274
-
1275
1234
  if (processedError) throw processedError
1276
1235
  }
1277
1236
 
@@ -2,6 +2,7 @@ import { Readable } from 'node:stream'
2
2
  import { _sortBy } from '@naturalcycles/js-lib/array/array.util.js'
3
3
  import { localTime } from '@naturalcycles/js-lib/datetime/localTime.js'
4
4
  import { _deepCopy, _filterObject, _omit, _pick } from '@naturalcycles/js-lib/object'
5
+ import { getJoiValidationFunction } from '@naturalcycles/nodejs-lib/joi'
5
6
  import { _pipeline } from '@naturalcycles/nodejs-lib/stream'
6
7
  import { CommonDao } from '../commondao/common.dao.js'
7
8
  import { CommonDaoLogLevel } from '../commondao/common.dao.model.js'
@@ -28,7 +29,7 @@ export async function runCommonDaoTest(
28
29
  const dao = new CommonDao({
29
30
  table: TEST_TABLE,
30
31
  db,
31
- bmSchema: testItemBMSchema,
32
+ validateBM: getJoiValidationFunction(testItemBMSchema),
32
33
  logStarted: true,
33
34
  logLevel: CommonDaoLogLevel.DATA_FULL,
34
35
  })