@naturalcycles/db-lib 8.37.1 → 8.38.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.
@@ -35,6 +35,7 @@ export declare class CommonDao<BM extends Partial<ObjectWithId<ID>>, DBM extends
35
35
  * Throws if readOnly is true
36
36
  */
37
37
  private requireObjectMutability;
38
+ private ensureUniqueId;
38
39
  getBy(by: keyof DBM, value: any, limit?: number, opt?: CommonDaoOptions): Promise<Saved<BM>[]>;
39
40
  getOneBy(by: keyof DBM, value: any, opt?: CommonDaoOptions): Promise<Saved<BM> | null>;
40
41
  getAll(opt?: CommonDaoOptions): Promise<Saved<BM>[]>;
@@ -86,9 +87,6 @@ export declare class CommonDao<BM extends Partial<ObjectWithId<ID>>, DBM extends
86
87
  * Mutates with id, created, updated
87
88
  */
88
89
  save(bm: Unsaved<BM>, opt?: CommonDaoSaveOptions<DBM>): Promise<Saved<BM>>;
89
- private ensureImmutableDontExist;
90
- private ensureUniqueId;
91
- private throwIfObjectExists;
92
90
  /**
93
91
  * Loads the row by id.
94
92
  * Creates the row (via this.create()) if it doesn't exist
@@ -175,14 +175,25 @@ class CommonDao {
175
175
  /**
176
176
  * Throws if readOnly is true
177
177
  */
178
- requireObjectMutability() {
179
- if (this.cfg.immutable) {
178
+ requireObjectMutability(opt) {
179
+ if (this.cfg.immutable && !opt.allowMutability) {
180
180
  throw new js_lib_1.AppError(cnst_1.DBLibError.OBJECT_IS_IMMUTABLE, {
181
181
  code: cnst_1.DBLibError.OBJECT_IS_IMMUTABLE,
182
182
  table: this.cfg.table,
183
183
  });
184
184
  }
185
185
  }
186
+ async ensureUniqueId(table, dbm) {
187
+ // todo: retry N times
188
+ const existing = await this.cfg.db.getByIds(table, [dbm.id]);
189
+ if (existing.length) {
190
+ throw new js_lib_1.AppError(cnst_1.DBLibError.NON_UNIQUE_ID, {
191
+ table,
192
+ code: cnst_1.DBLibError.NON_UNIQUE_ID,
193
+ ids: existing.map(i => i.id),
194
+ });
195
+ }
196
+ }
186
197
  async getBy(by, value, limit = 0, opt) {
187
198
  return await this.query().filterEq(by, value).limit(limit).runQuery(opt);
188
199
  }
@@ -445,8 +456,9 @@ class CommonDao {
445
456
  const table = opt.table || this.cfg.table;
446
457
  if (opt.ensureUniqueId && idWasGenerated)
447
458
  await this.ensureUniqueId(table, dbm);
448
- if (this.cfg.immutable)
449
- await this.ensureImmutableDontExist(table, [dbm.id]);
459
+ if (this.cfg.immutable && !opt.allowMutability) {
460
+ opt.saveMethod || (opt.saveMethod = 'insert');
461
+ }
450
462
  const op = `save(${dbm.id})`;
451
463
  const started = this.logSaveStarted(op, bm, table);
452
464
  await this.cfg.db.saveBatch(table, [dbm], {
@@ -456,30 +468,6 @@ class CommonDao {
456
468
  this.logSaveResult(started, op, table);
457
469
  return bm;
458
470
  }
459
- async ensureImmutableDontExist(table, ids) {
460
- await this.throwIfObjectExists(table, ids, [
461
- cnst_1.DBLibError.OBJECT_IS_IMMUTABLE,
462
- {
463
- code: cnst_1.DBLibError.OBJECT_IS_IMMUTABLE,
464
- table,
465
- },
466
- ]);
467
- }
468
- async ensureUniqueId(table, dbm) {
469
- // todo: retry N times
470
- await this.throwIfObjectExists(table, [dbm.id], [
471
- cnst_1.DBLibError.OBJECT_IS_IMMUTABLE,
472
- {
473
- code: cnst_1.DBLibError.OBJECT_IS_IMMUTABLE,
474
- table,
475
- },
476
- ]);
477
- }
478
- async throwIfObjectExists(table, ids, errorMeta) {
479
- const existing = await this.cfg.db.getByIds(table, ids);
480
- if (existing.length > 0)
481
- throw new js_lib_1.AppError(errorMeta[0], { ...errorMeta[1], ids: existing.map(i => i.id) });
482
- }
483
471
  /**
484
472
  * Loads the row by id.
485
473
  * Creates the row (via this.create()) if it doesn't exist
@@ -513,8 +501,9 @@ class CommonDao {
513
501
  dbm = this.anyToDBM(dbm, opt);
514
502
  if (opt.ensureUniqueId && idWasGenerated)
515
503
  await this.ensureUniqueId(table, dbm);
516
- if (this.cfg.immutable)
517
- await this.ensureImmutableDontExist(table, [dbm.id]);
504
+ }
505
+ if (this.cfg.immutable && !opt.allowMutability) {
506
+ opt.saveMethod || (opt.saveMethod = 'insert');
518
507
  }
519
508
  const op = `saveAsDBM(${dbm.id})`;
520
509
  const started = this.logSaveStarted(op, dbm, table);
@@ -532,8 +521,9 @@ class CommonDao {
532
521
  const dbms = await this.bmsToDBM(bms, opt);
533
522
  if (opt.ensureUniqueId)
534
523
  throw new js_lib_1.AppError('ensureUniqueId is not supported in saveBatch');
535
- if (this.cfg.immutable)
536
- await this.ensureImmutableDontExist(table, dbms.map(dbm => dbm.id));
524
+ if (this.cfg.immutable && !opt.allowMutability) {
525
+ opt.saveMethod || (opt.saveMethod = 'insert');
526
+ }
537
527
  const op = `saveBatch ${dbms.length} row(s) (${(0, js_lib_1._truncate)(dbms
538
528
  .slice(0, 10)
539
529
  .map(bm => bm.id)
@@ -554,8 +544,9 @@ class CommonDao {
554
544
  dbms = this.anyToDBMs(dbms, opt);
555
545
  if (opt.ensureUniqueId)
556
546
  throw new js_lib_1.AppError('ensureUniqueId is not supported in saveBatch');
557
- if (this.cfg.immutable)
558
- await this.ensureImmutableDontExist(table, dbms.map(dbm => dbm.id));
547
+ }
548
+ if (this.cfg.immutable && !opt.allowMutability) {
549
+ opt.saveMethod || (opt.saveMethod = 'insert');
559
550
  }
560
551
  const op = `saveBatchAsDBM ${dbms.length} row(s) (${(0, js_lib_1._truncate)(dbms
561
552
  .slice(0, 10)
@@ -573,8 +564,7 @@ class CommonDao {
573
564
  if (!id)
574
565
  return 0;
575
566
  this.requireWriteAccess();
576
- if (!opt.allowMutability)
577
- this.requireObjectMutability();
567
+ this.requireObjectMutability(opt);
578
568
  const op = `deleteById(${id})`;
579
569
  const table = opt.table || this.cfg.table;
580
570
  const started = this.logStarted(op, table);
@@ -584,8 +574,7 @@ class CommonDao {
584
574
  }
585
575
  async deleteByIds(ids, opt = {}) {
586
576
  this.requireWriteAccess();
587
- if (!opt.allowMutability)
588
- this.requireObjectMutability();
577
+ this.requireObjectMutability(opt);
589
578
  const op = `deleteByIds(${ids.join(', ')})`;
590
579
  const table = opt.table || this.cfg.table;
591
580
  const started = this.logStarted(op, table);
@@ -600,8 +589,7 @@ class CommonDao {
600
589
  */
601
590
  async deleteByQuery(q, opt = {}) {
602
591
  this.requireWriteAccess();
603
- if (!opt.allowMutability)
604
- this.requireObjectMutability();
592
+ this.requireObjectMutability(opt);
605
593
  q.table = opt.table || q.table;
606
594
  const op = `deleteByQuery(${q.pretty()})`;
607
595
  const started = this.logStarted(op, q.table);
@@ -49,17 +49,18 @@ export interface CommonDaoCfg<BM extends Partial<ObjectWithId<ID>>, DBM extends
49
49
  tmSchema?: ObjectSchemaTyped<TM> | AjvSchema<TM>;
50
50
  excludeFromIndexes?: (keyof DBM)[];
51
51
  /**
52
- * @default to false
53
- * Set to true to limit DB writing:
54
- * * Will throw an error if an object with matching ID already exists during save().
55
- * * saveBatch, delete*() and patch() will throw.
52
+ * Defaults to false.
53
+ * Setting it to true will set saveMethod to `insert` for save/saveBatch, which will
54
+ * fail for rows that already exist in the DB (if CommonDB implementation supports it).
56
55
  *
57
- * Although deletion is possible by passing (opt.overrideImmutability === true)
56
+ * `delete*` and `patch` will throw.
57
+ *
58
+ * You can still override saveMethod, or set opt.allowMutability to allow deletion.
58
59
  */
59
60
  immutable?: boolean;
60
61
  /**
61
- * @default to false
62
- * Set to true to limit DB writing (will throw an error is such case).
62
+ * Defaults to false.
63
+ * Set to true to limit DB writing (will throw an error in such case).
63
64
  */
64
65
  readOnly?: boolean;
65
66
  /**
package/package.json CHANGED
@@ -42,7 +42,7 @@
42
42
  "engines": {
43
43
  "node": ">=14.15"
44
44
  },
45
- "version": "8.37.1",
45
+ "version": "8.38.0",
46
46
  "description": "Lowest Common Denominator API to supported Databases",
47
47
  "keywords": [
48
48
  "db",
@@ -73,18 +73,19 @@ export interface CommonDaoCfg<
73
73
  excludeFromIndexes?: (keyof DBM)[]
74
74
 
75
75
  /**
76
- * @default to false
77
- * Set to true to limit DB writing:
78
- * * Will throw an error if an object with matching ID already exists during save().
79
- * * saveBatch, delete*() and patch() will throw.
76
+ * Defaults to false.
77
+ * Setting it to true will set saveMethod to `insert` for save/saveBatch, which will
78
+ * fail for rows that already exist in the DB (if CommonDB implementation supports it).
80
79
  *
81
- * Although deletion is possible by passing (opt.overrideImmutability === true)
80
+ * `delete*` and `patch` will throw.
81
+ *
82
+ * You can still override saveMethod, or set opt.allowMutability to allow deletion.
82
83
  */
83
84
  immutable?: boolean
84
85
 
85
86
  /**
86
- * @default to false
87
- * Set to true to limit DB writing (will throw an error is such case).
87
+ * Defaults to false.
88
+ * Set to true to limit DB writing (will throw an error in such case).
88
89
  */
89
90
  readOnly?: boolean
90
91
 
@@ -245,8 +245,8 @@ export class CommonDao<
245
245
  /**
246
246
  * Throws if readOnly is true
247
247
  */
248
- private requireObjectMutability(): void {
249
- if (this.cfg.immutable) {
248
+ private requireObjectMutability(opt: CommonDaoOptions): void {
249
+ if (this.cfg.immutable && !opt.allowMutability) {
250
250
  throw new AppError(DBLibError.OBJECT_IS_IMMUTABLE, {
251
251
  code: DBLibError.OBJECT_IS_IMMUTABLE,
252
252
  table: this.cfg.table,
@@ -254,6 +254,18 @@ export class CommonDao<
254
254
  }
255
255
  }
256
256
 
257
+ private async ensureUniqueId(table: string, dbm: DBM): Promise<void> {
258
+ // todo: retry N times
259
+ const existing = await this.cfg.db.getByIds<DBM>(table, [dbm.id])
260
+ if (existing.length) {
261
+ throw new AppError(DBLibError.NON_UNIQUE_ID, {
262
+ table,
263
+ code: DBLibError.NON_UNIQUE_ID,
264
+ ids: existing.map(i => i.id),
265
+ })
266
+ }
267
+ }
268
+
257
269
  async getBy(by: keyof DBM, value: any, limit = 0, opt?: CommonDaoOptions): Promise<Saved<BM>[]> {
258
270
  return await this.query().filterEq(by, value).limit(limit).runQuery(opt)
259
271
  }
@@ -602,7 +614,9 @@ export class CommonDao<
602
614
  const dbm = await this.bmToDBM(bm as BM, opt)
603
615
  const table = opt.table || this.cfg.table
604
616
  if (opt.ensureUniqueId && idWasGenerated) await this.ensureUniqueId(table, dbm)
605
- if (this.cfg.immutable) await this.ensureImmutableDontExist(table, [dbm.id])
617
+ if (this.cfg.immutable && !opt.allowMutability) {
618
+ opt.saveMethod ||= 'insert'
619
+ }
606
620
  const op = `save(${dbm.id})`
607
621
  const started = this.logSaveStarted(op, bm, table)
608
622
  await this.cfg.db.saveBatch(table, [dbm], {
@@ -614,41 +628,6 @@ export class CommonDao<
614
628
  return bm as any
615
629
  }
616
630
 
617
- private async ensureImmutableDontExist(table: string, ids: ID[]): Promise<void> {
618
- await this.throwIfObjectExists(table, ids, [
619
- DBLibError.OBJECT_IS_IMMUTABLE,
620
- {
621
- code: DBLibError.OBJECT_IS_IMMUTABLE,
622
- table,
623
- },
624
- ])
625
- }
626
-
627
- private async ensureUniqueId(table: string, dbm: DBM): Promise<void> {
628
- // todo: retry N times
629
- await this.throwIfObjectExists(
630
- table,
631
- [dbm.id],
632
- [
633
- DBLibError.OBJECT_IS_IMMUTABLE,
634
- {
635
- code: DBLibError.OBJECT_IS_IMMUTABLE,
636
- table,
637
- },
638
- ],
639
- )
640
- }
641
-
642
- private async throwIfObjectExists(
643
- table: string,
644
- ids: ID[],
645
- errorMeta: [DBLibError, any],
646
- ): Promise<void> {
647
- const existing = await this.cfg.db.getByIds<DBM>(table, ids)
648
- if (existing.length > 0)
649
- throw new AppError(errorMeta[0], { ...errorMeta[1], ids: existing.map(i => i.id) })
650
- }
651
-
652
631
  /**
653
632
  * Loads the row by id.
654
633
  * Creates the row (via this.create()) if it doesn't exist
@@ -692,7 +671,9 @@ export class CommonDao<
692
671
  this.assignIdCreatedUpdated(dbm, opt) // mutates
693
672
  dbm = this.anyToDBM(dbm, opt)
694
673
  if (opt.ensureUniqueId && idWasGenerated) await this.ensureUniqueId(table, dbm)
695
- if (this.cfg.immutable) await this.ensureImmutableDontExist(table, [dbm.id])
674
+ }
675
+ if (this.cfg.immutable && !opt.allowMutability) {
676
+ opt.saveMethod ||= 'insert'
696
677
  }
697
678
  const op = `saveAsDBM(${dbm.id})`
698
679
  const started = this.logSaveStarted(op, dbm, table)
@@ -710,11 +691,9 @@ export class CommonDao<
710
691
  bms.forEach(bm => this.assignIdCreatedUpdated(bm, opt))
711
692
  const dbms = await this.bmsToDBM(bms as BM[], opt)
712
693
  if (opt.ensureUniqueId) throw new AppError('ensureUniqueId is not supported in saveBatch')
713
- if (this.cfg.immutable)
714
- await this.ensureImmutableDontExist(
715
- table,
716
- dbms.map(dbm => dbm.id),
717
- )
694
+ if (this.cfg.immutable && !opt.allowMutability) {
695
+ opt.saveMethod ||= 'insert'
696
+ }
718
697
 
719
698
  const op = `saveBatch ${dbms.length} row(s) (${_truncate(
720
699
  dbms
@@ -742,11 +721,9 @@ export class CommonDao<
742
721
  dbms.forEach(dbm => this.assignIdCreatedUpdated(dbm, opt)) // mutates
743
722
  dbms = this.anyToDBMs(dbms, opt)
744
723
  if (opt.ensureUniqueId) throw new AppError('ensureUniqueId is not supported in saveBatch')
745
- if (this.cfg.immutable)
746
- await this.ensureImmutableDontExist(
747
- table,
748
- dbms.map(dbm => dbm.id),
749
- )
724
+ }
725
+ if (this.cfg.immutable && !opt.allowMutability) {
726
+ opt.saveMethod ||= 'insert'
750
727
  }
751
728
  const op = `saveBatchAsDBM ${dbms.length} row(s) (${_truncate(
752
729
  dbms
@@ -775,7 +752,7 @@ export class CommonDao<
775
752
  async deleteById(id?: ID, opt: CommonDaoOptions = {}): Promise<number> {
776
753
  if (!id) return 0
777
754
  this.requireWriteAccess()
778
- if (!opt.allowMutability) this.requireObjectMutability()
755
+ this.requireObjectMutability(opt)
779
756
  const op = `deleteById(${id})`
780
757
  const table = opt.table || this.cfg.table
781
758
  const started = this.logStarted(op, table)
@@ -786,7 +763,7 @@ export class CommonDao<
786
763
 
787
764
  async deleteByIds(ids: ID[], opt: CommonDaoOptions = {}): Promise<number> {
788
765
  this.requireWriteAccess()
789
- if (!opt.allowMutability) this.requireObjectMutability()
766
+ this.requireObjectMutability(opt)
790
767
  const op = `deleteByIds(${ids.join(', ')})`
791
768
  const table = opt.table || this.cfg.table
792
769
  const started = this.logStarted(op, table)
@@ -805,7 +782,7 @@ export class CommonDao<
805
782
  opt: CommonDaoStreamForEachOptions<DBM> & { stream?: boolean } = {},
806
783
  ): Promise<number> {
807
784
  this.requireWriteAccess()
808
- if (!opt.allowMutability) this.requireObjectMutability()
785
+ this.requireObjectMutability(opt)
809
786
  q.table = opt.table || q.table
810
787
  const op = `deleteByQuery(${q.pretty()})`
811
788
  const started = this.logStarted(op, q.table)