@naturalcycles/db-lib 9.7.2 → 9.8.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.
@@ -4,7 +4,7 @@ import { AsyncMapper, BaseDBEntity, CommonLogger, JsonSchemaObject, JsonSchemaRo
4
4
  import { AjvSchema, ObjectSchema, ReadableTyped } from '@naturalcycles/nodejs-lib';
5
5
  import { CommonDBTransactionOptions, DBPatch, DBTransaction, RunQueryResult } from '../db.model';
6
6
  import { DBQuery, RunnableDBQuery } from '../query/dbQuery';
7
- import { CommonDaoCfg, CommonDaoCreateOptions, CommonDaoOptions, CommonDaoSaveBatchOptions, CommonDaoSaveOptions, CommonDaoStreamDeleteOptions, CommonDaoStreamForEachOptions, CommonDaoStreamOptions, CommonDaoStreamSaveOptions } from './common.dao.model';
7
+ import { CommonDaoCfg, CommonDaoCreateOptions, CommonDaoOptions, CommonDaoPatchOptions, CommonDaoSaveBatchOptions, CommonDaoSaveOptions, CommonDaoStreamDeleteOptions, CommonDaoStreamForEachOptions, CommonDaoStreamOptions, CommonDaoStreamSaveOptions } from './common.dao.model';
8
8
  /**
9
9
  * Lowest common denominator API between supported Databases.
10
10
  *
@@ -78,15 +78,6 @@ export declare class CommonDao<BM extends BaseDBEntity, DBM extends BaseDBEntity
78
78
  * "Returns", just to have a type of "Saved"
79
79
  */
80
80
  assignIdCreatedUpdated<T extends BaseDBEntity>(obj: Partial<T>, opt?: CommonDaoOptions): T;
81
- /**
82
- * 1. Applies the patch
83
- * 2. If object is the same after patching - skips saving it
84
- * 3. Otherwise - saves the patched object and returns it
85
- *
86
- * Similar to `save` with skipIfEquals.
87
- * Similar to `patch`, but doesn't load the object from the Database.
88
- */
89
- savePatch(bm: BM, patch: Partial<BM>, opt?: CommonDaoSaveBatchOptions<DBM>): Promise<BM>;
90
81
  /**
91
82
  * Convenience method to replace 3 operations (loading+patching+saving) with one:
92
83
  *
@@ -107,7 +98,7 @@ export declare class CommonDao<BM extends BaseDBEntity, DBM extends BaseDBEntity
107
98
  * Otherwise, similar behavior as patchById.
108
99
  * It still loads the row from the DB.
109
100
  */
110
- patch(bm: BM, patch: Partial<BM>, opt?: CommonDaoSaveBatchOptions<DBM>): Promise<BM>;
101
+ patch(bm: BM, patch: Partial<BM>, opt?: CommonDaoPatchOptions<DBM>): Promise<BM>;
111
102
  /**
112
103
  * Like patch, but runs all operations within a Transaction.
113
104
  */
@@ -444,27 +444,6 @@ class CommonDao {
444
444
  return obj;
445
445
  }
446
446
  // SAVE
447
- /**
448
- * 1. Applies the patch
449
- * 2. If object is the same after patching - skips saving it
450
- * 3. Otherwise - saves the patched object and returns it
451
- *
452
- * Similar to `save` with skipIfEquals.
453
- * Similar to `patch`, but doesn't load the object from the Database.
454
- */
455
- async savePatch(bm, patch, opt) {
456
- const patched = {
457
- ...bm,
458
- ...patch,
459
- };
460
- if ((0, js_lib_1._deepJsonEquals)(bm, patched)) {
461
- // Skipping the save operation, as data is the same
462
- return bm;
463
- }
464
- // Actually apply the patch by mutating the original object (by design)
465
- Object.assign(bm, patch);
466
- return await this.save(bm, opt);
467
- }
468
447
  /**
469
448
  * Convenience method to replace 3 operations (loading+patching+saving) with one:
470
449
  *
@@ -516,18 +495,28 @@ class CommonDao {
516
495
  // and should just continue as-is
517
496
  return await this.patchInTransaction(bm, patch, opt);
518
497
  }
519
- const loaded = await this.getById(bm.id, opt);
520
- if (loaded) {
521
- Object.assign(loaded, patch);
522
- if ((0, js_lib_1._deepJsonEquals)(loaded, bm)) {
498
+ if (opt.skipDBRead) {
499
+ const bmBefore = (0, js_lib_1._deepCopy)(bm);
500
+ Object.assign(bm, patch);
501
+ if ((0, js_lib_1._deepJsonEquals)(bm, bmBefore)) {
523
502
  // Skipping the save operation, as data is the same
524
503
  return bm;
525
504
  }
526
- // Make `bm` exactly the same as `loaded`
527
- (0, js_lib_1._objectAssignExact)(bm, loaded);
528
505
  }
529
506
  else {
530
- Object.assign(bm, patch);
507
+ const loaded = await this.getById(bm.id, opt);
508
+ if (loaded) {
509
+ Object.assign(loaded, patch);
510
+ if ((0, js_lib_1._deepJsonEquals)(loaded, bm)) {
511
+ // Skipping the save operation, as data is the same
512
+ return bm;
513
+ }
514
+ // Make `bm` exactly the same as `loaded`
515
+ (0, js_lib_1._objectAssignExact)(bm, loaded);
516
+ }
517
+ else {
518
+ Object.assign(bm, patch);
519
+ }
531
520
  }
532
521
  return await this.save(bm, opt);
533
522
  }
@@ -209,6 +209,12 @@ export interface CommonDaoSaveOptions<BM extends BaseDBEntity, DBM extends BaseD
209
209
  */
210
210
  skipIfEquals?: BM;
211
211
  }
212
+ export interface CommonDaoPatchOptions<DBM extends BaseDBEntity> extends CommonDaoSaveBatchOptions<DBM> {
213
+ /**
214
+ * If true - patch will skip loading from DB, and will just optimistically patch passed object.
215
+ */
216
+ skipDBRead?: boolean;
217
+ }
212
218
  /**
213
219
  * All properties default to undefined.
214
220
  */
@@ -4,6 +4,6 @@ exports.createTestTimeSeries = void 0;
4
4
  const js_lib_1 = require("@naturalcycles/js-lib");
5
5
  function createTestTimeSeries(count = 10) {
6
6
  const ts = Date.now();
7
- return (0, js_lib_1._range)(1, count + 1).map(i => [ts - i * 60000, (0, js_lib_1._randomInt)(10, 20)]);
7
+ return (0, js_lib_1._range)(1, count + 1).map(i => [ts - i * 60_000, (0, js_lib_1._randomInt)(10, 20)]);
8
8
  }
9
9
  exports.createTestTimeSeries = createTestTimeSeries;
package/package.json CHANGED
@@ -8,7 +8,7 @@
8
8
  "@naturalcycles/nodejs-lib": "^13.1.1"
9
9
  },
10
10
  "devDependencies": {
11
- "@naturalcycles/bench-lib": "^1.0.0",
11
+ "@naturalcycles/bench-lib": "^2.0.0",
12
12
  "@naturalcycles/dev-lib": "^13.0.0",
13
13
  "@types/node": "^20.2.1",
14
14
  "jest": "^29.0.0"
@@ -40,7 +40,7 @@
40
40
  "engines": {
41
41
  "node": ">=18.12"
42
42
  },
43
- "version": "9.7.2",
43
+ "version": "9.8.0",
44
44
  "description": "Lowest Common Denominator API to supported Databases",
45
45
  "keywords": [
46
46
  "db",
@@ -257,6 +257,14 @@ export interface CommonDaoSaveOptions<BM extends BaseDBEntity, DBM extends BaseD
257
257
  skipIfEquals?: BM
258
258
  }
259
259
 
260
+ export interface CommonDaoPatchOptions<DBM extends BaseDBEntity>
261
+ extends CommonDaoSaveBatchOptions<DBM> {
262
+ /**
263
+ * If true - patch will skip loading from DB, and will just optimistically patch passed object.
264
+ */
265
+ skipDBRead?: boolean
266
+ }
267
+
260
268
  /**
261
269
  * All properties default to undefined.
262
270
  */
@@ -51,6 +51,7 @@ import {
51
51
  CommonDaoHooks,
52
52
  CommonDaoLogLevel,
53
53
  CommonDaoOptions,
54
+ CommonDaoPatchOptions,
54
55
  CommonDaoSaveBatchOptions,
55
56
  CommonDaoSaveOptions,
56
57
  CommonDaoStreamDeleteOptions,
@@ -604,31 +605,6 @@ export class CommonDao<BM extends BaseDBEntity, DBM extends BaseDBEntity = BM> {
604
605
  }
605
606
 
606
607
  // SAVE
607
- /**
608
- * 1. Applies the patch
609
- * 2. If object is the same after patching - skips saving it
610
- * 3. Otherwise - saves the patched object and returns it
611
- *
612
- * Similar to `save` with skipIfEquals.
613
- * Similar to `patch`, but doesn't load the object from the Database.
614
- */
615
- async savePatch(bm: BM, patch: Partial<BM>, opt?: CommonDaoSaveBatchOptions<DBM>): Promise<BM> {
616
- const patched: BM = {
617
- ...bm,
618
- ...patch,
619
- }
620
-
621
- if (_deepJsonEquals(bm, patched)) {
622
- // Skipping the save operation, as data is the same
623
- return bm
624
- }
625
-
626
- // Actually apply the patch by mutating the original object (by design)
627
- Object.assign(bm, patch)
628
-
629
- return await this.save(bm, opt)
630
- }
631
-
632
608
  /**
633
609
  * Convenience method to replace 3 operations (loading+patching+saving) with one:
634
610
  *
@@ -686,7 +662,7 @@ export class CommonDao<BM extends BaseDBEntity, DBM extends BaseDBEntity = BM> {
686
662
  * Otherwise, similar behavior as patchById.
687
663
  * It still loads the row from the DB.
688
664
  */
689
- async patch(bm: BM, patch: Partial<BM>, opt: CommonDaoSaveBatchOptions<DBM> = {}): Promise<BM> {
665
+ async patch(bm: BM, patch: Partial<BM>, opt: CommonDaoPatchOptions<DBM> = {}): Promise<BM> {
690
666
  if (this.cfg.patchInTransaction && !opt.tx) {
691
667
  // patchInTransaction means that we should run this op in Transaction
692
668
  // But if opt.tx is passed - means that we are already in a Transaction,
@@ -694,20 +670,29 @@ export class CommonDao<BM extends BaseDBEntity, DBM extends BaseDBEntity = BM> {
694
670
  return await this.patchInTransaction(bm, patch, opt)
695
671
  }
696
672
 
697
- const loaded = await this.getById(bm.id, opt)
698
-
699
- if (loaded) {
700
- Object.assign(loaded, patch)
701
-
702
- if (_deepJsonEquals(loaded, bm)) {
673
+ if (opt.skipDBRead) {
674
+ const bmBefore = _deepCopy(bm)
675
+ Object.assign(bm, patch)
676
+ if (_deepJsonEquals(bm, bmBefore)) {
703
677
  // Skipping the save operation, as data is the same
704
678
  return bm
705
679
  }
706
-
707
- // Make `bm` exactly the same as `loaded`
708
- _objectAssignExact(bm, loaded)
709
680
  } else {
710
- Object.assign(bm, patch)
681
+ const loaded = await this.getById(bm.id, opt)
682
+
683
+ if (loaded) {
684
+ Object.assign(loaded, patch)
685
+
686
+ if (_deepJsonEquals(loaded, bm)) {
687
+ // Skipping the save operation, as data is the same
688
+ return bm
689
+ }
690
+
691
+ // Make `bm` exactly the same as `loaded`
692
+ _objectAssignExact(bm, loaded)
693
+ } else {
694
+ Object.assign(bm, patch)
695
+ }
711
696
  }
712
697
 
713
698
  return await this.save(bm, opt)