@naturalcycles/db-lib 10.20.4 → 10.22.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.
@@ -175,10 +175,10 @@ export declare class CommonDao<BM extends BaseDBEntity, DBM extends BaseDBEntity
175
175
  private static multiGetMapByTableById;
176
176
  private static prepareMultiGetOutput;
177
177
  /**
178
- * Very @experimental.
178
+ * @experimental.
179
179
  */
180
- static multiDeleteByIds(inputs: DaoWithIds<any>[], _opt?: CommonDaoOptions): Promise<NonNegativeInteger>;
181
- static multiSave(inputs: (DaoWithRows<any> | DaoWithRow<any>)[], opt?: CommonDaoSaveBatchOptions<any>): Promise<void>;
180
+ static multiDelete(inputs: (DaoWithId<AnyDao> | DaoWithIds<AnyDao>)[], opt?: CommonDaoOptions): Promise<NonNegativeInteger>;
181
+ static multiSave(inputs: (DaoWithRows<AnyDao> | DaoWithRow<AnyDao>)[], opt?: CommonDaoSaveBatchOptions<any>): Promise<void>;
182
182
  createTransaction(opt?: CommonDBTransactionOptions): Promise<CommonDaoTransaction>;
183
183
  runInTransaction<T = void>(fn: CommonDaoTransactionFn<T>, opt?: CommonDBTransactionOptions): Promise<T>;
184
184
  private ensureRequired;
@@ -6,7 +6,7 @@ import { _deepJsonEquals } from '@naturalcycles/js-lib/object/deepEquals.js';
6
6
  import { _filterUndefinedValues, _objectAssignExact, } from '@naturalcycles/js-lib/object/object.util.js';
7
7
  import { pMap } from '@naturalcycles/js-lib/promise/pMap.js';
8
8
  import { _stringMapEntries, _stringMapValues, } from '@naturalcycles/js-lib/types';
9
- import { _passthroughPredicate, _typeCast, SKIP } from '@naturalcycles/js-lib/types';
9
+ import { _passthroughPredicate, _typeCast } from '@naturalcycles/js-lib/types';
10
10
  import { stringId } from '@naturalcycles/nodejs-lib';
11
11
  import { transformFlatten, transformMapSync, } from '@naturalcycles/nodejs-lib/stream';
12
12
  import { _pipeline, transformChunk, transformLogProgress, transformMap, transformNoOp, writableVoid, } from '@naturalcycles/nodejs-lib/stream';
@@ -454,12 +454,8 @@ export class CommonDao {
454
454
  }
455
455
  this.assignIdCreatedUpdated(bm, opt); // mutates
456
456
  _typeCast(bm);
457
- let dbm = await this.bmToDBM(bm, opt); // validates BM
458
- if (this.cfg.hooks.beforeSave) {
459
- dbm = (await this.cfg.hooks.beforeSave(dbm));
460
- if (dbm === null)
461
- return bm;
462
- }
457
+ const dbm = await this.bmToDBM(bm, opt); // validates BM
458
+ this.cfg.hooks.beforeSave?.(dbm);
463
459
  const table = opt.table || this.cfg.table;
464
460
  const saveOptions = this.prepareSaveOptions(opt);
465
461
  await (opt.tx || this.cfg.db).saveBatch(table, [dbm], saveOptions);
@@ -471,12 +467,8 @@ export class CommonDao {
471
467
  async saveAsDBM(dbm, opt = {}) {
472
468
  this.requireWriteAccess();
473
469
  this.assignIdCreatedUpdated(dbm, opt); // mutates
474
- let row = this.anyToDBM(dbm, opt);
475
- if (this.cfg.hooks.beforeSave) {
476
- row = (await this.cfg.hooks.beforeSave(row));
477
- if (row === null)
478
- return dbm;
479
- }
470
+ const row = this.anyToDBM(dbm, opt);
471
+ this.cfg.hooks.beforeSave?.(row);
480
472
  const table = opt.table || this.cfg.table;
481
473
  const saveOptions = this.prepareSaveOptions(opt);
482
474
  await (opt.tx || this.cfg.db).saveBatch(table, [row], saveOptions);
@@ -490,9 +482,9 @@ export class CommonDao {
490
482
  return [];
491
483
  this.requireWriteAccess();
492
484
  bms.forEach(bm => this.assignIdCreatedUpdated(bm, opt));
493
- let dbms = await this.bmsToDBM(bms, opt);
494
- if (this.cfg.hooks.beforeSave && dbms.length) {
495
- dbms = (await pMap(dbms, async (dbm) => await this.cfg.hooks.beforeSave(dbm))).filter(_isTruthy);
485
+ const dbms = await this.bmsToDBM(bms, opt);
486
+ if (this.cfg.hooks.beforeSave) {
487
+ dbms.forEach(dbm => this.cfg.hooks.beforeSave(dbm));
496
488
  }
497
489
  const table = opt.table || this.cfg.table;
498
490
  const saveOptions = this.prepareSaveOptions(opt);
@@ -507,9 +499,9 @@ export class CommonDao {
507
499
  return [];
508
500
  this.requireWriteAccess();
509
501
  dbms.forEach(dbm => this.assignIdCreatedUpdated(dbm, opt));
510
- let rows = this.anyToDBMs(dbms, opt);
511
- if (this.cfg.hooks.beforeSave && rows.length) {
512
- rows = (await pMap(rows, async (row) => await this.cfg.hooks.beforeSave(row))).filter(_isTruthy);
502
+ const rows = this.anyToDBMs(dbms, opt);
503
+ if (this.cfg.hooks.beforeSave) {
504
+ rows.forEach(row => this.cfg.hooks.beforeSave(row));
513
505
  }
514
506
  const table = opt.table || this.cfg.table;
515
507
  const saveOptions = this.prepareSaveOptions(opt);
@@ -550,13 +542,9 @@ export class CommonDao {
550
542
  const { chunkSize = 500, chunkConcurrency = 32, errorMode } = opt;
551
543
  return [
552
544
  transformMap(async (bm) => {
553
- this.assignIdCreatedUpdated(bm, opt); // mutates
554
- let dbm = await this.bmToDBM(bm, opt);
555
- if (beforeSave) {
556
- dbm = (await beforeSave(dbm));
557
- if (dbm === null)
558
- return SKIP;
559
- }
545
+ this.assignIdCreatedUpdated(bm, opt);
546
+ const dbm = await this.bmToDBM(bm, opt);
547
+ beforeSave?.(dbm);
560
548
  return dbm;
561
549
  }, {
562
550
  errorMode,
@@ -866,17 +854,27 @@ export class CommonDao {
866
854
  return bmsByProp;
867
855
  }
868
856
  /**
869
- * Very @experimental.
857
+ * @experimental.
870
858
  */
871
- static async multiDeleteByIds(inputs, _opt = {}) {
859
+ static async multiDelete(inputs, opt = {}) {
872
860
  if (!inputs.length)
873
861
  return 0;
874
862
  const { db } = inputs[0].dao.cfg;
875
863
  const idsByTable = {};
876
- for (const { dao, ids } of inputs) {
877
- idsByTable[dao.cfg.table] = ids;
864
+ for (const input of inputs) {
865
+ const { dao } = input;
866
+ const { table } = dao.cfg;
867
+ dao.requireWriteAccess();
868
+ dao.requireObjectMutability(opt);
869
+ idsByTable[table] ||= [];
870
+ if ('id' in input) {
871
+ idsByTable[table].push(input.id);
872
+ }
873
+ else {
874
+ idsByTable[table].push(...input.ids);
875
+ }
878
876
  }
879
- return await db.multiDelete(idsByTable);
877
+ return await db.multiDelete(idsByTable, opt);
880
878
  }
881
879
  static async multiSave(inputs, opt = {}) {
882
880
  if (!inputs.length)
@@ -901,12 +899,18 @@ export class CommonDao {
901
899
  }
902
900
  }
903
901
  dao.assignIdCreatedUpdated(row, opt);
904
- dbmsByTable[table].push(await dao.bmToDBM(row, opt));
902
+ const dbm = await dao.bmToDBM(row, opt);
903
+ dao.cfg.hooks.beforeSave?.(dbm);
904
+ dbmsByTable[table].push(dbm);
905
905
  }
906
906
  else {
907
907
  // Plural
908
908
  input.rows.forEach(bm => dao.assignIdCreatedUpdated(bm, opt));
909
- dbmsByTable[table].push(...(await dao.bmsToDBM(input.rows, opt)));
909
+ const dbms = await dao.bmsToDBM(input.rows, opt);
910
+ if (dao.cfg.hooks.beforeSave) {
911
+ dbms.forEach(dbm => dao.cfg.hooks.beforeSave(dbm));
912
+ }
913
+ dbmsByTable[table].push(...dbms);
910
914
  }
911
915
  });
912
916
  await db.multiSave(dbmsByTable);
@@ -1,11 +1,11 @@
1
1
  import type { ValidationFunction } from '@naturalcycles/js-lib';
2
2
  import type { AppError, ErrorMode } from '@naturalcycles/js-lib/error';
3
3
  import type { CommonLogger } from '@naturalcycles/js-lib/log';
4
- import type { BaseDBEntity, Promisable, UnixTimestamp } from '@naturalcycles/js-lib/types';
4
+ import type { BaseDBEntity, UnixTimestamp } from '@naturalcycles/js-lib/types';
5
5
  import type { TransformLogProgressOptions, TransformMapOptions } from '@naturalcycles/nodejs-lib/stream';
6
6
  import type { CommonDB } from '../commondb/common.db.js';
7
7
  import type { CommonDBCreateOptions, CommonDBOptions, CommonDBSaveOptions } from '../db.model.js';
8
- export interface CommonDaoHooks<BM extends BaseDBEntity, DBM extends BaseDBEntity, ID = BM['id']> {
8
+ export interface CommonDaoHooks<BM extends BaseDBEntity, DBM extends BaseDBEntity, ID extends string = BM['id']> {
9
9
  /**
10
10
  * Allows to override the id generation function.
11
11
  * By default it uses `stringId` from nodejs-lib
@@ -50,15 +50,10 @@ export interface CommonDaoHooks<BM extends BaseDBEntity, DBM extends BaseDBEntit
50
50
  *
51
51
  * Normally does nothing.
52
52
  *
53
- * You can change the DBM as you want here: ok to mutate or not, but you need to return the DBM
54
- * to pass it further.
55
- *
56
- * You can return `null` to prevent it from being saved, without throwing an error.
57
- * `.save` method will then return the BM/DBM as it has entered the method (it **won't** return the null value!).
58
- *
59
53
  * You can do validations as needed here and throw errors, they will be propagated.
54
+ * Or, you can mutate the DBM if needed.
60
55
  */
61
- beforeSave?: (dbm: DBM) => Promisable<DBM | null>;
56
+ beforeSave?: (dbm: DBM) => void;
62
57
  /**
63
58
  * Called in:
64
59
  * - dbmToBM (applied before DBM becomes BM)
@@ -95,7 +90,7 @@ export declare enum CommonDaoLogLevel {
95
90
  */
96
91
  DATA_FULL = 30
97
92
  }
98
- export interface CommonDaoCfg<BM extends BaseDBEntity, DBM extends BaseDBEntity = BM, ID = BM['id']> {
93
+ export interface CommonDaoCfg<BM extends BaseDBEntity, DBM extends BaseDBEntity = BM, ID extends string = BM['id']> {
99
94
  db: CommonDB;
100
95
  table: string;
101
96
  /**
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@naturalcycles/db-lib",
3
3
  "type": "module",
4
- "version": "10.20.4",
4
+ "version": "10.22.0",
5
5
  "dependencies": {
6
6
  "@naturalcycles/js-lib": "^15",
7
7
  "@naturalcycles/nodejs-lib": "^15"
@@ -1,7 +1,7 @@
1
1
  import type { ValidationFunction } from '@naturalcycles/js-lib'
2
2
  import type { AppError, ErrorMode } from '@naturalcycles/js-lib/error'
3
3
  import type { CommonLogger } from '@naturalcycles/js-lib/log'
4
- import type { BaseDBEntity, Promisable, UnixTimestamp } from '@naturalcycles/js-lib/types'
4
+ import type { BaseDBEntity, UnixTimestamp } from '@naturalcycles/js-lib/types'
5
5
  import type {
6
6
  TransformLogProgressOptions,
7
7
  TransformMapOptions,
@@ -9,7 +9,11 @@ import type {
9
9
  import type { CommonDB } from '../commondb/common.db.js'
10
10
  import type { CommonDBCreateOptions, CommonDBOptions, CommonDBSaveOptions } from '../db.model.js'
11
11
 
12
- export interface CommonDaoHooks<BM extends BaseDBEntity, DBM extends BaseDBEntity, ID = BM['id']> {
12
+ export interface CommonDaoHooks<
13
+ BM extends BaseDBEntity,
14
+ DBM extends BaseDBEntity,
15
+ ID extends string = BM['id'],
16
+ > {
13
17
  /**
14
18
  * Allows to override the id generation function.
15
19
  * By default it uses `stringId` from nodejs-lib
@@ -61,15 +65,10 @@ export interface CommonDaoHooks<BM extends BaseDBEntity, DBM extends BaseDBEntit
61
65
  *
62
66
  * Normally does nothing.
63
67
  *
64
- * You can change the DBM as you want here: ok to mutate or not, but you need to return the DBM
65
- * to pass it further.
66
- *
67
- * You can return `null` to prevent it from being saved, without throwing an error.
68
- * `.save` method will then return the BM/DBM as it has entered the method (it **won't** return the null value!).
69
- *
70
68
  * You can do validations as needed here and throw errors, they will be propagated.
69
+ * Or, you can mutate the DBM if needed.
71
70
  */
72
- beforeSave?: (dbm: DBM) => Promisable<DBM | null>
71
+ beforeSave?: (dbm: DBM) => void
73
72
 
74
73
  /**
75
74
  * Called in:
@@ -113,7 +112,7 @@ export enum CommonDaoLogLevel {
113
112
  export interface CommonDaoCfg<
114
113
  BM extends BaseDBEntity,
115
114
  DBM extends BaseDBEntity = BM,
116
- ID = BM['id'],
115
+ ID extends string = BM['id'],
117
116
  > {
118
117
  db: CommonDB
119
118
  table: string
@@ -20,7 +20,7 @@ import {
20
20
  type StringMap,
21
21
  type Unsaved,
22
22
  } from '@naturalcycles/js-lib/types'
23
- import { _passthroughPredicate, _typeCast, SKIP } from '@naturalcycles/js-lib/types'
23
+ import { _passthroughPredicate, _typeCast } from '@naturalcycles/js-lib/types'
24
24
  import { stringId } from '@naturalcycles/nodejs-lib'
25
25
  import {
26
26
  type ReadableTyped,
@@ -616,13 +616,8 @@ export class CommonDao<
616
616
 
617
617
  this.assignIdCreatedUpdated(bm, opt) // mutates
618
618
  _typeCast<BM>(bm)
619
- let dbm = await this.bmToDBM(bm, opt) // validates BM
620
-
621
- if (this.cfg.hooks!.beforeSave) {
622
- dbm = (await this.cfg.hooks!.beforeSave(dbm))!
623
- if (dbm === null) return bm
624
- }
625
-
619
+ const dbm = await this.bmToDBM(bm, opt) // validates BM
620
+ this.cfg.hooks!.beforeSave?.(dbm)
626
621
  const table = opt.table || this.cfg.table
627
622
  const saveOptions = this.prepareSaveOptions(opt)
628
623
 
@@ -637,15 +632,9 @@ export class CommonDao<
637
632
 
638
633
  async saveAsDBM(dbm: Unsaved<DBM>, opt: CommonDaoSaveOptions<BM, DBM> = {}): Promise<DBM> {
639
634
  this.requireWriteAccess()
640
-
641
635
  this.assignIdCreatedUpdated(dbm, opt) // mutates
642
- let row = this.anyToDBM(dbm, opt)
643
-
644
- if (this.cfg.hooks!.beforeSave) {
645
- row = (await this.cfg.hooks!.beforeSave(row))!
646
- if (row === null) return dbm as DBM
647
- }
648
-
636
+ const row = this.anyToDBM(dbm, opt)
637
+ this.cfg.hooks!.beforeSave?.(row)
649
638
  const table = opt.table || this.cfg.table
650
639
  const saveOptions = this.prepareSaveOptions(opt)
651
640
 
@@ -662,14 +651,10 @@ export class CommonDao<
662
651
  if (!bms.length) return []
663
652
  this.requireWriteAccess()
664
653
  bms.forEach(bm => this.assignIdCreatedUpdated(bm, opt))
665
- let dbms = await this.bmsToDBM(bms as BM[], opt)
666
-
667
- if (this.cfg.hooks!.beforeSave && dbms.length) {
668
- dbms = (await pMap(dbms, async dbm => await this.cfg.hooks!.beforeSave!(dbm))).filter(
669
- _isTruthy,
670
- )
654
+ const dbms = await this.bmsToDBM(bms as BM[], opt)
655
+ if (this.cfg.hooks!.beforeSave) {
656
+ dbms.forEach(dbm => this.cfg.hooks!.beforeSave!(dbm))
671
657
  }
672
-
673
658
  const table = opt.table || this.cfg.table
674
659
  const saveOptions = this.prepareSaveOptions(opt)
675
660
 
@@ -689,14 +674,10 @@ export class CommonDao<
689
674
  if (!dbms.length) return []
690
675
  this.requireWriteAccess()
691
676
  dbms.forEach(dbm => this.assignIdCreatedUpdated(dbm, opt))
692
- let rows = this.anyToDBMs(dbms as DBM[], opt)
693
-
694
- if (this.cfg.hooks!.beforeSave && rows.length) {
695
- rows = (await pMap(rows, async row => await this.cfg.hooks!.beforeSave!(row))).filter(
696
- _isTruthy,
697
- )
677
+ const rows = this.anyToDBMs(dbms as DBM[], opt)
678
+ if (this.cfg.hooks!.beforeSave) {
679
+ rows.forEach(row => this.cfg.hooks!.beforeSave!(row))
698
680
  }
699
-
700
681
  const table = opt.table || this.cfg.table
701
682
  const saveOptions = this.prepareSaveOptions(opt)
702
683
 
@@ -752,15 +733,9 @@ export class CommonDao<
752
733
  return [
753
734
  transformMap<BM, DBM>(
754
735
  async bm => {
755
- this.assignIdCreatedUpdated(bm, opt) // mutates
756
-
757
- let dbm = await this.bmToDBM(bm, opt)
758
-
759
- if (beforeSave) {
760
- dbm = (await beforeSave(dbm))!
761
- if (dbm === null) return SKIP
762
- }
763
-
736
+ this.assignIdCreatedUpdated(bm, opt)
737
+ const dbm = await this.bmToDBM(bm, opt)
738
+ beforeSave?.(dbm)
764
739
  return dbm
765
740
  },
766
741
  {
@@ -1164,24 +1139,34 @@ export class CommonDao<
1164
1139
  }
1165
1140
 
1166
1141
  /**
1167
- * Very @experimental.
1142
+ * @experimental.
1168
1143
  */
1169
- static async multiDeleteByIds(
1170
- inputs: DaoWithIds<any>[],
1171
- _opt: CommonDaoOptions = {},
1144
+ static async multiDelete(
1145
+ inputs: (DaoWithId<AnyDao> | DaoWithIds<AnyDao>)[],
1146
+ opt: CommonDaoOptions = {},
1172
1147
  ): Promise<NonNegativeInteger> {
1173
1148
  if (!inputs.length) return 0
1174
1149
  const { db } = inputs[0]!.dao.cfg
1175
1150
  const idsByTable: StringMap<string[]> = {}
1176
- for (const { dao, ids } of inputs) {
1177
- idsByTable[dao.cfg.table] = ids
1151
+ for (const input of inputs) {
1152
+ const { dao } = input
1153
+ const { table } = dao.cfg
1154
+ dao.requireWriteAccess()
1155
+ dao.requireObjectMutability(opt)
1156
+ idsByTable[table] ||= []
1157
+
1158
+ if ('id' in input) {
1159
+ idsByTable[table].push(input.id)
1160
+ } else {
1161
+ idsByTable[table].push(...input.ids)
1162
+ }
1178
1163
  }
1179
1164
 
1180
- return await db.multiDelete(idsByTable)
1165
+ return await db.multiDelete(idsByTable, opt)
1181
1166
  }
1182
1167
 
1183
1168
  static async multiSave(
1184
- inputs: (DaoWithRows<any> | DaoWithRow<any>)[],
1169
+ inputs: (DaoWithRows<AnyDao> | DaoWithRow<AnyDao>)[],
1185
1170
  opt: CommonDaoSaveBatchOptions<any> = {},
1186
1171
  ): Promise<void> {
1187
1172
  if (!inputs.length) return
@@ -1208,11 +1193,17 @@ export class CommonDao<
1208
1193
  }
1209
1194
 
1210
1195
  dao.assignIdCreatedUpdated(row, opt)
1211
- dbmsByTable[table].push(await dao.bmToDBM(row, opt))
1196
+ const dbm = await dao.bmToDBM(row, opt)
1197
+ dao.cfg.hooks!.beforeSave?.(dbm)
1198
+ dbmsByTable[table].push(dbm)
1212
1199
  } else {
1213
1200
  // Plural
1214
1201
  input.rows.forEach(bm => dao.assignIdCreatedUpdated(bm, opt))
1215
- dbmsByTable[table].push(...(await dao.bmsToDBM(input.rows, opt)))
1202
+ const dbms = await dao.bmsToDBM(input.rows, opt)
1203
+ if (dao.cfg.hooks!.beforeSave) {
1204
+ dbms.forEach(dbm => dao.cfg.hooks!.beforeSave!(dbm))
1205
+ }
1206
+ dbmsByTable[table].push(...dbms)
1216
1207
  }
1217
1208
  })
1218
1209