@naturalcycles/db-lib 9.6.0 → 9.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -19,7 +19,6 @@ export declare class CommonDao<BM extends BaseDBEntity, DBM extends BaseDBEntity
19
19
  getById(id: undefined | null, opt?: CommonDaoOptions): Promise<null>;
20
20
  getById(id?: string | null, opt?: CommonDaoOptions): Promise<BM | null>;
21
21
  getByIdOrEmpty(id: string, part?: Partial<BM>, opt?: CommonDaoOptions): Promise<BM>;
22
- getByIdAsDBMOrEmpty(id: string, part?: Partial<BM>, opt?: CommonDaoOptions): Promise<DBM>;
23
22
  getByIdAsDBM(id: undefined | null, opt?: CommonDaoOptions): Promise<null>;
24
23
  getByIdAsDBM(id?: string | null, opt?: CommonDaoOptions): Promise<DBM | null>;
25
24
  getByIds(ids: string[], opt?: CommonDaoOptions): Promise<BM[]>;
@@ -79,10 +78,6 @@ export declare class CommonDao<BM extends BaseDBEntity, DBM extends BaseDBEntity
79
78
  * "Returns", just to have a type of "Saved"
80
79
  */
81
80
  assignIdCreatedUpdated<T extends BaseDBEntity>(obj: Partial<T>, opt?: CommonDaoOptions): T;
82
- /**
83
- * Mutates with id, created, updated
84
- */
85
- save(bm: Unsaved<BM>, opt?: CommonDaoSaveOptions<BM, DBM>): Promise<BM>;
86
81
  /**
87
82
  * 1. Applies the patch
88
83
  * 2. If object is the same after patching - skips saving it
@@ -117,7 +112,11 @@ export declare class CommonDao<BM extends BaseDBEntity, DBM extends BaseDBEntity
117
112
  * Like patch, but runs all operations within a Transaction.
118
113
  */
119
114
  patchInTransaction(bm: BM, patch: Partial<BM>, opt?: CommonDaoSaveBatchOptions<DBM>): Promise<BM>;
120
- saveAsDBM(dbm: Unsaved<DBM>, opt?: CommonDaoSaveBatchOptions<DBM>): Promise<DBM>;
115
+ /**
116
+ * Mutates with id, created, updated
117
+ */
118
+ save(bm: Unsaved<BM>, opt?: CommonDaoSaveOptions<BM, DBM>): Promise<BM>;
119
+ saveAsDBM(dbm: Unsaved<DBM>, opt?: CommonDaoSaveOptions<BM, DBM>): Promise<DBM>;
121
120
  saveBatch(bms: Unsaved<BM>[], opt?: CommonDaoSaveBatchOptions<DBM>): Promise<BM[]>;
122
121
  saveBatchAsDBM(dbms: Unsaved<DBM>[], opt?: CommonDaoSaveBatchOptions<DBM>): Promise<DBM[]>;
123
122
  /**
@@ -130,7 +129,6 @@ export declare class CommonDao<BM extends BaseDBEntity, DBM extends BaseDBEntity
130
129
  /**
131
130
  * @returns number of deleted items
132
131
  */
133
- deleteById(id: undefined | null, opt?: CommonDaoOptions): Promise<0>;
134
132
  deleteById(id?: string | null, opt?: CommonDaoOptions): Promise<number>;
135
133
  deleteByIds(ids: string[], opt?: CommonDaoOptions): Promise<number>;
136
134
  /**
@@ -194,8 +192,16 @@ export declare class CommonDaoTransaction {
194
192
  rollback(): Promise<void>;
195
193
  getById<BM extends BaseDBEntity, DBM extends BaseDBEntity>(dao: CommonDao<BM, DBM>, id?: string | null, opt?: CommonDaoOptions): Promise<BM | null>;
196
194
  getByIds<BM extends BaseDBEntity, DBM extends BaseDBEntity>(dao: CommonDao<BM, DBM>, ids: string[], opt?: CommonDaoOptions): Promise<BM[]>;
197
- save<BM extends BaseDBEntity, DBM extends BaseDBEntity>(dao: CommonDao<BM, DBM>, bm: Unsaved<BM>, opt?: CommonDaoSaveBatchOptions<DBM>): Promise<BM>;
195
+ save<BM extends BaseDBEntity, DBM extends BaseDBEntity>(dao: CommonDao<BM, DBM>, bm: Unsaved<BM>, opt?: CommonDaoSaveOptions<BM, DBM>): Promise<BM>;
198
196
  saveBatch<BM extends BaseDBEntity, DBM extends BaseDBEntity>(dao: CommonDao<BM, DBM>, bms: Unsaved<BM>[], opt?: CommonDaoSaveBatchOptions<DBM>): Promise<BM[]>;
197
+ /**
198
+ * DaoTransaction.patch does not load from DB.
199
+ * It assumes the bm was previously loaded in the same Transaction, hence could not be
200
+ * concurrently modified. Hence it's safe to not sync with DB.
201
+ *
202
+ * So, this method is a rather simple convenience "Object.assign and then save".
203
+ */
204
+ patch<BM extends BaseDBEntity, DBM extends BaseDBEntity>(dao: CommonDao<BM, DBM>, bm: BM, patch: Partial<BM>, opt?: CommonDaoSaveOptions<BM, DBM>): Promise<BM>;
199
205
  deleteById(dao: CommonDao<any>, id?: string | null, opt?: CommonDaoOptions): Promise<number>;
200
206
  deleteByIds(dao: CommonDao<any>, ids: string[], opt?: CommonDaoOptions): Promise<number>;
201
207
  }
@@ -71,13 +71,6 @@ class CommonDao {
71
71
  return bm;
72
72
  return this.create({ ...part, id }, opt);
73
73
  }
74
- async getByIdAsDBMOrEmpty(id, part = {}, opt) {
75
- const dbm = await this.getByIdAsDBM(id, opt);
76
- if (dbm)
77
- return dbm;
78
- const bm = this.create({ ...part, id }, opt);
79
- return await this.bmToDBM(bm, opt);
80
- }
81
74
  async getByIdAsDBM(id, opt = {}) {
82
75
  if (!id)
83
76
  return null;
@@ -451,45 +444,6 @@ class CommonDao {
451
444
  return obj;
452
445
  }
453
446
  // SAVE
454
- /**
455
- * Mutates with id, created, updated
456
- */
457
- async save(bm, opt = {}) {
458
- this.requireWriteAccess();
459
- if (opt.skipIfEquals && (0, js_lib_1._deepJsonEquals)(bm, opt.skipIfEquals)) {
460
- // Skipping the save operation
461
- return bm;
462
- }
463
- const idWasGenerated = !bm.id && this.cfg.generateId;
464
- this.assignIdCreatedUpdated(bm, opt); // mutates
465
- (0, js_lib_1._typeCast)(bm);
466
- let dbm = await this.bmToDBM(bm, opt); // validates BM
467
- if (this.cfg.hooks.beforeSave) {
468
- dbm = (await this.cfg.hooks.beforeSave(dbm));
469
- if (dbm === null)
470
- return bm;
471
- }
472
- const table = opt.table || this.cfg.table;
473
- if (opt.ensureUniqueId && idWasGenerated)
474
- await this.ensureUniqueId(table, dbm);
475
- if (this.cfg.immutable && !opt.allowMutability && !opt.saveMethod) {
476
- opt = { ...opt, saveMethod: 'insert' };
477
- }
478
- const op = `save(${dbm.id})`;
479
- const started = this.logSaveStarted(op, bm, table);
480
- const { excludeFromIndexes } = this.cfg;
481
- const assignGeneratedIds = opt.assignGeneratedIds || this.cfg.assignGeneratedIds;
482
- await (opt.tx || this.cfg.db).saveBatch(table, [dbm], {
483
- excludeFromIndexes,
484
- assignGeneratedIds,
485
- ...opt,
486
- });
487
- if (assignGeneratedIds) {
488
- bm.id = dbm.id;
489
- }
490
- this.logSaveResult(started, op, table);
491
- return bm;
492
- }
493
447
  /**
494
448
  * 1. Applies the patch
495
449
  * 2. If object is the same after patching - skips saving it
@@ -585,6 +539,45 @@ class CommonDao {
585
539
  return await this.patch(bm, patch, { ...opt, tx: daoTx.tx });
586
540
  });
587
541
  }
542
+ /**
543
+ * Mutates with id, created, updated
544
+ */
545
+ async save(bm, opt = {}) {
546
+ this.requireWriteAccess();
547
+ if (opt.skipIfEquals && (0, js_lib_1._deepJsonEquals)(bm, opt.skipIfEquals)) {
548
+ // Skipping the save operation
549
+ return bm;
550
+ }
551
+ const idWasGenerated = !bm.id && this.cfg.generateId;
552
+ this.assignIdCreatedUpdated(bm, opt); // mutates
553
+ (0, js_lib_1._typeCast)(bm);
554
+ let dbm = await this.bmToDBM(bm, opt); // validates BM
555
+ if (this.cfg.hooks.beforeSave) {
556
+ dbm = (await this.cfg.hooks.beforeSave(dbm));
557
+ if (dbm === null)
558
+ return bm;
559
+ }
560
+ const table = opt.table || this.cfg.table;
561
+ if (opt.ensureUniqueId && idWasGenerated)
562
+ await this.ensureUniqueId(table, dbm);
563
+ if (this.cfg.immutable && !opt.allowMutability && !opt.saveMethod) {
564
+ opt = { ...opt, saveMethod: 'insert' };
565
+ }
566
+ const op = `save(${dbm.id})`;
567
+ const started = this.logSaveStarted(op, bm, table);
568
+ const { excludeFromIndexes } = this.cfg;
569
+ const assignGeneratedIds = opt.assignGeneratedIds || this.cfg.assignGeneratedIds;
570
+ await (opt.tx || this.cfg.db).saveBatch(table, [dbm], {
571
+ excludeFromIndexes,
572
+ assignGeneratedIds,
573
+ ...opt,
574
+ });
575
+ if (assignGeneratedIds) {
576
+ bm.id = dbm.id;
577
+ }
578
+ this.logSaveResult(started, op, table);
579
+ return bm;
580
+ }
588
581
  async saveAsDBM(dbm, opt = {}) {
589
582
  this.requireWriteAccess();
590
583
  const table = opt.table || this.cfg.table;
@@ -736,17 +729,14 @@ class CommonDao {
736
729
  (0, nodejs_lib_1.writableVoid)(),
737
730
  ];
738
731
  }
732
+ // DELETE
733
+ /**
734
+ * @returns number of deleted items
735
+ */
739
736
  async deleteById(id, opt = {}) {
740
737
  if (!id)
741
738
  return 0;
742
- this.requireWriteAccess();
743
- this.requireObjectMutability(opt);
744
- const op = `deleteById(${id})`;
745
- const table = opt.table || this.cfg.table;
746
- const started = this.logStarted(op, table);
747
- const count = await this.cfg.db.deleteByIds(table, [id], opt);
748
- this.logSaveResult(started, op, table);
749
- return count;
739
+ return await this.deleteByIds([id], opt);
750
740
  }
751
741
  async deleteByIds(ids, opt = {}) {
752
742
  if (!ids.length)
@@ -1060,11 +1050,23 @@ class CommonDaoTransaction {
1060
1050
  // }
1061
1051
  // }
1062
1052
  async save(dao, bm, opt) {
1063
- return (await this.saveBatch(dao, [bm], opt))[0];
1053
+ return await dao.save(bm, { ...opt, tx: this.tx });
1064
1054
  }
1065
1055
  async saveBatch(dao, bms, opt) {
1066
1056
  return await dao.saveBatch(bms, { ...opt, tx: this.tx });
1067
1057
  }
1058
+ /**
1059
+ * DaoTransaction.patch does not load from DB.
1060
+ * It assumes the bm was previously loaded in the same Transaction, hence could not be
1061
+ * concurrently modified. Hence it's safe to not sync with DB.
1062
+ *
1063
+ * So, this method is a rather simple convenience "Object.assign and then save".
1064
+ */
1065
+ async patch(dao, bm, patch, opt) {
1066
+ const skipIfEquals = (0, js_lib_1._deepCopy)(bm);
1067
+ Object.assign(bm, patch);
1068
+ return await dao.save(bm, { ...opt, skipIfEquals, tx: this.tx });
1069
+ }
1068
1070
  async deleteById(dao, id, opt) {
1069
1071
  if (!id)
1070
1072
  return 0;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@naturalcycles/db-lib",
3
3
  "scripts": {
4
- "prepare": "husky install"
4
+ "prepare": "husky"
5
5
  },
6
6
  "dependencies": {
7
7
  "@naturalcycles/js-lib": "^14.116.0",
@@ -40,7 +40,7 @@
40
40
  "engines": {
41
41
  "node": ">=18.12"
42
42
  },
43
- "version": "9.6.0",
43
+ "version": "9.7.0",
44
44
  "description": "Lowest Common Denominator API to supported Databases",
45
45
  "keywords": [
46
46
  "db",
@@ -1,6 +1,7 @@
1
1
  import { Transform } from 'node:stream'
2
2
  import {
3
3
  _assert,
4
+ _deepCopy,
4
5
  _deepJsonEquals,
5
6
  _filterUndefinedValues,
6
7
  _isTruthy,
@@ -131,18 +132,6 @@ export class CommonDao<BM extends BaseDBEntity, DBM extends BaseDBEntity = BM> {
131
132
  return this.create({ ...part, id }, opt)
132
133
  }
133
134
 
134
- async getByIdAsDBMOrEmpty(
135
- id: string,
136
- part: Partial<BM> = {},
137
- opt?: CommonDaoOptions,
138
- ): Promise<DBM> {
139
- const dbm = await this.getByIdAsDBM(id, opt)
140
- if (dbm) return dbm
141
-
142
- const bm = this.create({ ...part, id }, opt)
143
- return await this.bmToDBM(bm, opt)
144
- }
145
-
146
135
  async getByIdAsDBM(id: undefined | null, opt?: CommonDaoOptions): Promise<null>
147
136
  async getByIdAsDBM(id?: string | null, opt?: CommonDaoOptions): Promise<DBM | null>
148
137
  async getByIdAsDBM(id?: string | null, opt: CommonDaoOptions = {}): Promise<DBM | null> {
@@ -615,51 +604,6 @@ export class CommonDao<BM extends BaseDBEntity, DBM extends BaseDBEntity = BM> {
615
604
  }
616
605
 
617
606
  // SAVE
618
- /**
619
- * Mutates with id, created, updated
620
- */
621
- async save(bm: Unsaved<BM>, opt: CommonDaoSaveOptions<BM, DBM> = {}): Promise<BM> {
622
- this.requireWriteAccess()
623
-
624
- if (opt.skipIfEquals && _deepJsonEquals(bm, opt.skipIfEquals)) {
625
- // Skipping the save operation
626
- return bm as BM
627
- }
628
-
629
- const idWasGenerated = !bm.id && this.cfg.generateId
630
- this.assignIdCreatedUpdated(bm, opt) // mutates
631
- _typeCast<BM>(bm)
632
- let dbm = await this.bmToDBM(bm, opt) // validates BM
633
-
634
- if (this.cfg.hooks!.beforeSave) {
635
- dbm = (await this.cfg.hooks!.beforeSave(dbm))!
636
- if (dbm === null) return bm
637
- }
638
-
639
- const table = opt.table || this.cfg.table
640
- if (opt.ensureUniqueId && idWasGenerated) await this.ensureUniqueId(table, dbm)
641
- if (this.cfg.immutable && !opt.allowMutability && !opt.saveMethod) {
642
- opt = { ...opt, saveMethod: 'insert' }
643
- }
644
- const op = `save(${dbm.id})`
645
- const started = this.logSaveStarted(op, bm, table)
646
- const { excludeFromIndexes } = this.cfg
647
- const assignGeneratedIds = opt.assignGeneratedIds || this.cfg.assignGeneratedIds
648
-
649
- await (opt.tx || this.cfg.db).saveBatch(table, [dbm], {
650
- excludeFromIndexes,
651
- assignGeneratedIds,
652
- ...opt,
653
- })
654
-
655
- if (assignGeneratedIds) {
656
- bm.id = dbm.id
657
- }
658
-
659
- this.logSaveResult(started, op, table)
660
- return bm
661
- }
662
-
663
607
  /**
664
608
  * 1. Applies the patch
665
609
  * 2. If object is the same after patching - skips saving it
@@ -782,7 +726,52 @@ export class CommonDao<BM extends BaseDBEntity, DBM extends BaseDBEntity = BM> {
782
726
  })
783
727
  }
784
728
 
785
- async saveAsDBM(dbm: Unsaved<DBM>, opt: CommonDaoSaveBatchOptions<DBM> = {}): Promise<DBM> {
729
+ /**
730
+ * Mutates with id, created, updated
731
+ */
732
+ async save(bm: Unsaved<BM>, opt: CommonDaoSaveOptions<BM, DBM> = {}): Promise<BM> {
733
+ this.requireWriteAccess()
734
+
735
+ if (opt.skipIfEquals && _deepJsonEquals(bm, opt.skipIfEquals)) {
736
+ // Skipping the save operation
737
+ return bm as BM
738
+ }
739
+
740
+ const idWasGenerated = !bm.id && this.cfg.generateId
741
+ this.assignIdCreatedUpdated(bm, opt) // mutates
742
+ _typeCast<BM>(bm)
743
+ let dbm = await this.bmToDBM(bm, opt) // validates BM
744
+
745
+ if (this.cfg.hooks!.beforeSave) {
746
+ dbm = (await this.cfg.hooks!.beforeSave(dbm))!
747
+ if (dbm === null) return bm
748
+ }
749
+
750
+ const table = opt.table || this.cfg.table
751
+ if (opt.ensureUniqueId && idWasGenerated) await this.ensureUniqueId(table, dbm)
752
+ if (this.cfg.immutable && !opt.allowMutability && !opt.saveMethod) {
753
+ opt = { ...opt, saveMethod: 'insert' }
754
+ }
755
+ const op = `save(${dbm.id})`
756
+ const started = this.logSaveStarted(op, bm, table)
757
+ const { excludeFromIndexes } = this.cfg
758
+ const assignGeneratedIds = opt.assignGeneratedIds || this.cfg.assignGeneratedIds
759
+
760
+ await (opt.tx || this.cfg.db).saveBatch(table, [dbm], {
761
+ excludeFromIndexes,
762
+ assignGeneratedIds,
763
+ ...opt,
764
+ })
765
+
766
+ if (assignGeneratedIds) {
767
+ bm.id = dbm.id
768
+ }
769
+
770
+ this.logSaveResult(started, op, table)
771
+ return bm
772
+ }
773
+
774
+ async saveAsDBM(dbm: Unsaved<DBM>, opt: CommonDaoSaveOptions<BM, DBM> = {}): Promise<DBM> {
786
775
  this.requireWriteAccess()
787
776
  const table = opt.table || this.cfg.table
788
777
 
@@ -979,18 +968,9 @@ export class CommonDao<BM extends BaseDBEntity, DBM extends BaseDBEntity = BM> {
979
968
  /**
980
969
  * @returns number of deleted items
981
970
  */
982
- async deleteById(id: undefined | null, opt?: CommonDaoOptions): Promise<0>
983
- async deleteById(id?: string | null, opt?: CommonDaoOptions): Promise<number>
984
971
  async deleteById(id?: string | null, opt: CommonDaoOptions = {}): Promise<number> {
985
972
  if (!id) return 0
986
- this.requireWriteAccess()
987
- this.requireObjectMutability(opt)
988
- const op = `deleteById(${id})`
989
- const table = opt.table || this.cfg.table
990
- const started = this.logStarted(op, table)
991
- const count = await this.cfg.db.deleteByIds(table, [id], opt)
992
- this.logSaveResult(started, op, table)
993
- return count
973
+ return await this.deleteByIds([id], opt)
994
974
  }
995
975
 
996
976
  async deleteByIds(ids: string[], opt: CommonDaoOptions = {}): Promise<number> {
@@ -1395,9 +1375,9 @@ export class CommonDaoTransaction {
1395
1375
  async save<BM extends BaseDBEntity, DBM extends BaseDBEntity>(
1396
1376
  dao: CommonDao<BM, DBM>,
1397
1377
  bm: Unsaved<BM>,
1398
- opt?: CommonDaoSaveBatchOptions<DBM>,
1378
+ opt?: CommonDaoSaveOptions<BM, DBM>,
1399
1379
  ): Promise<BM> {
1400
- return (await this.saveBatch(dao, [bm], opt))[0]!
1380
+ return await dao.save(bm, { ...opt, tx: this.tx })
1401
1381
  }
1402
1382
 
1403
1383
  async saveBatch<BM extends BaseDBEntity, DBM extends BaseDBEntity>(
@@ -1408,6 +1388,24 @@ export class CommonDaoTransaction {
1408
1388
  return await dao.saveBatch(bms, { ...opt, tx: this.tx })
1409
1389
  }
1410
1390
 
1391
+ /**
1392
+ * DaoTransaction.patch does not load from DB.
1393
+ * It assumes the bm was previously loaded in the same Transaction, hence could not be
1394
+ * concurrently modified. Hence it's safe to not sync with DB.
1395
+ *
1396
+ * So, this method is a rather simple convenience "Object.assign and then save".
1397
+ */
1398
+ async patch<BM extends BaseDBEntity, DBM extends BaseDBEntity>(
1399
+ dao: CommonDao<BM, DBM>,
1400
+ bm: BM,
1401
+ patch: Partial<BM>,
1402
+ opt?: CommonDaoSaveOptions<BM, DBM>,
1403
+ ): Promise<BM> {
1404
+ const skipIfEquals = _deepCopy(bm)
1405
+ Object.assign(bm, patch)
1406
+ return await dao.save(bm, { ...opt, skipIfEquals, tx: this.tx })
1407
+ }
1408
+
1411
1409
  async deleteById(
1412
1410
  dao: CommonDao<any>,
1413
1411
  id?: string | null,