@naturalcycles/db-lib 8.35.0 → 8.37.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.
Files changed (37) hide show
  1. package/dist/adapter/cachedb/cache.db.d.ts +9 -9
  2. package/dist/adapter/cachedb/cache.db.js +3 -1
  3. package/dist/adapter/cachedb/cache.db.model.d.ts +5 -3
  4. package/dist/adapter/file/file.db.d.ts +3 -3
  5. package/dist/adapter/file/file.db.js +1 -0
  6. package/dist/adapter/inmemory/inMemory.db.d.ts +3 -3
  7. package/dist/adapter/inmemory/inMemory.db.js +14 -11
  8. package/dist/base.common.db.d.ts +3 -3
  9. package/dist/common.db.d.ts +7 -4
  10. package/dist/commondao/common.dao.d.ts +24 -23
  11. package/dist/commondao/common.dao.js +13 -9
  12. package/dist/commondao/common.dao.model.d.ts +23 -23
  13. package/dist/db.model.d.ts +16 -18
  14. package/dist/index.d.ts +3 -3
  15. package/dist/model.util.d.ts +2 -3
  16. package/dist/model.util.js +1 -7
  17. package/dist/query/dbQuery.d.ts +6 -6
  18. package/dist/testing/dbTest.d.ts +2 -0
  19. package/dist/testing/dbTest.js +16 -1
  20. package/dist/validation/index.d.ts +3 -3
  21. package/package.json +1 -1
  22. package/src/adapter/cachedb/cache.db.model.ts +8 -7
  23. package/src/adapter/cachedb/cache.db.ts +21 -18
  24. package/src/adapter/file/file.db.ts +8 -5
  25. package/src/adapter/inmemory/inMemory.db.ts +22 -15
  26. package/src/base.common.db.ts +3 -3
  27. package/src/common.db.ts +11 -4
  28. package/src/commondao/common.dao.model.ts +32 -25
  29. package/src/commondao/common.dao.ts +58 -65
  30. package/src/db.model.ts +18 -19
  31. package/src/index.ts +4 -20
  32. package/src/model.util.ts +3 -9
  33. package/src/query/dbQuery.ts +8 -7
  34. package/src/testing/dbTest.ts +22 -0
  35. package/dist/adapter/inmemory/index.d.ts +0 -3
  36. package/dist/adapter/inmemory/index.js +0 -8
  37. package/src/adapter/inmemory/index.ts +0 -9
@@ -15,6 +15,7 @@ import {
15
15
  pMap,
16
16
  pTimeout,
17
17
  Saved,
18
+ Unsaved,
18
19
  } from '@naturalcycles/js-lib'
19
20
  import {
20
21
  _pipeline,
@@ -59,49 +60,60 @@ const isCI = !!process.env['CI']
59
60
  * TM = Transport model (optimized to be sent over the wire)
60
61
  */
61
62
  export class CommonDao<
62
- BM extends Partial<ObjectWithId>,
63
- DBM extends ObjectWithId = Saved<BM>,
63
+ BM extends Partial<ObjectWithId<ID>>,
64
+ DBM extends ObjectWithId<ID> = Saved<BM>,
64
65
  TM = BM,
66
+ ID extends string | number = DBM['id'],
65
67
  > {
66
- constructor(public cfg: CommonDaoCfg<BM, DBM, TM>) {
68
+ constructor(public cfg: CommonDaoCfg<BM, DBM, TM, ID>) {
67
69
  this.cfg = {
68
70
  // Default is to NOT log in AppEngine and in CI,
69
71
  // otherwise to log Operations
70
72
  // e.g in Dev (local machine), Test - it will log operations (useful for debugging)
71
73
  logLevel: isGAE || isCI ? CommonDaoLogLevel.NONE : CommonDaoLogLevel.OPERATIONS,
74
+ idType: 'string',
75
+ createId: true,
72
76
  created: true,
73
77
  updated: true,
74
78
  logger: console,
75
79
  ...cfg,
76
80
  hooks: {
77
- createId: () => stringId(),
78
81
  parseNaturalId: () => ({}),
79
82
  beforeCreate: bm => bm as BM,
80
83
  beforeDBMValidate: dbm => dbm,
81
84
  beforeDBMToBM: dbm => dbm as any,
82
85
  beforeBMToDBM: bm => bm as any,
83
- beforeTMToBM: tm => tm as any,
86
+ beforeTMToBM: tm => tm,
84
87
  beforeBMToTM: bm => bm as any,
85
88
  anonymize: dbm => dbm,
86
89
  onValidationError: err => err,
87
90
  ...cfg.hooks,
88
91
  },
89
92
  }
93
+
94
+ if (this.cfg.createId) {
95
+ _assert(
96
+ this.cfg.idType === 'string',
97
+ 'db-lib: automatic generation of non-string ids is not supported',
98
+ )
99
+
100
+ this.cfg.hooks!.createId ||= () => stringId() as ID
101
+ } else {
102
+ delete this.cfg.hooks!.createId
103
+ }
90
104
  }
91
105
 
92
106
  // CREATE
93
107
  create(part: Partial<BM> = {}, opt: CommonDaoOptions = {}): Saved<BM> {
94
108
  let bm = this.cfg.hooks!.beforeCreate!(part) as BM
95
109
  bm = this.validateAndConvert(bm, this.cfg.bmSchema, DBModelType.BM, opt)
96
-
97
- // If no SCHEMA - return as is
98
110
  return this.assignIdCreatedUpdated(bm, opt)
99
111
  }
100
112
 
101
113
  // GET
102
114
  async getById(id: undefined, opt?: CommonDaoOptions): Promise<null>
103
- async getById(id?: string, opt?: CommonDaoOptions): Promise<Saved<BM> | null>
104
- async getById(id?: string, opt: CommonDaoOptions = {}): Promise<Saved<BM> | null> {
115
+ async getById(id?: ID, opt?: CommonDaoOptions): Promise<Saved<BM> | null>
116
+ async getById(id?: ID, opt: CommonDaoOptions = {}): Promise<Saved<BM> | null> {
105
117
  if (!id) return null
106
118
  const op = `getById(${id})`
107
119
  const table = opt.table || this.cfg.table
@@ -126,22 +138,14 @@ export class CommonDao<
126
138
  return bm || null
127
139
  }
128
140
 
129
- async getByIdOrEmpty(
130
- id: string,
131
- part: Partial<BM> = {},
132
- opt?: CommonDaoOptions,
133
- ): Promise<Saved<BM>> {
141
+ async getByIdOrEmpty(id: ID, part: Partial<BM> = {}, opt?: CommonDaoOptions): Promise<Saved<BM>> {
134
142
  const bm = await this.getById(id, opt)
135
143
  if (bm) return bm
136
144
 
137
145
  return this.create({ ...part, id }, opt)
138
146
  }
139
147
 
140
- async getByIdAsDBMOrEmpty(
141
- id: string,
142
- part: Partial<BM> = {},
143
- opt?: CommonDaoOptions,
144
- ): Promise<DBM> {
148
+ async getByIdAsDBMOrEmpty(id: ID, part: Partial<BM> = {}, opt?: CommonDaoOptions): Promise<DBM> {
145
149
  const dbm = await this.getByIdAsDBM(id, opt)
146
150
  if (dbm) return dbm
147
151
 
@@ -150,8 +154,8 @@ export class CommonDao<
150
154
  }
151
155
 
152
156
  async getByIdAsDBM(id: undefined, opt?: CommonDaoOptions): Promise<null>
153
- async getByIdAsDBM(id?: string, opt?: CommonDaoOptions): Promise<DBM | null>
154
- async getByIdAsDBM(id?: string, opt: CommonDaoOptions = {}): Promise<DBM | null> {
157
+ async getByIdAsDBM(id?: ID, opt?: CommonDaoOptions): Promise<DBM | null>
158
+ async getByIdAsDBM(id?: ID, opt: CommonDaoOptions = {}): Promise<DBM | null> {
155
159
  if (!id) return null
156
160
  const op = `getByIdAsDBM(${id})`
157
161
  const table = opt.table || this.cfg.table
@@ -165,8 +169,8 @@ export class CommonDao<
165
169
  }
166
170
 
167
171
  async getByIdAsTM(id: undefined, opt?: CommonDaoOptions): Promise<null>
168
- async getByIdAsTM(id?: string, opt?: CommonDaoOptions): Promise<TM | null>
169
- async getByIdAsTM(id?: string, opt: CommonDaoOptions = {}): Promise<TM | null> {
172
+ async getByIdAsTM(id?: ID, opt?: CommonDaoOptions): Promise<TM | null>
173
+ async getByIdAsTM(id?: ID, opt: CommonDaoOptions = {}): Promise<TM | null> {
170
174
  if (!id) return null
171
175
  const op = `getByIdAsTM(${id})`
172
176
  const table = opt.table || this.cfg.table
@@ -182,7 +186,7 @@ export class CommonDao<
182
186
  return tm || null
183
187
  }
184
188
 
185
- async getByIds(ids: string[], opt: CommonDaoOptions = {}): Promise<Saved<BM>[]> {
189
+ async getByIds(ids: ID[], opt: CommonDaoOptions = {}): Promise<Saved<BM>[]> {
186
190
  const op = `getByIds ${ids.length} id(s) (${_truncate(ids.slice(0, 10).join(', '), 50)})`
187
191
  const table = opt.table || this.cfg.table
188
192
  const started = this.logStarted(op, table)
@@ -192,7 +196,7 @@ export class CommonDao<
192
196
  return bms
193
197
  }
194
198
 
195
- async getByIdsAsDBM(ids: string[], opt: CommonDaoOptions = {}): Promise<DBM[]> {
199
+ async getByIdsAsDBM(ids: ID[], opt: CommonDaoOptions = {}): Promise<DBM[]> {
196
200
  const op = `getByIdsAsDBM ${ids.length} id(s) (${_truncate(ids.slice(0, 10).join(', '), 50)})`
197
201
  const table = opt.table || this.cfg.table
198
202
  const started = this.logStarted(op, table)
@@ -201,7 +205,7 @@ export class CommonDao<
201
205
  return dbms
202
206
  }
203
207
 
204
- async requireById(id: string, opt: CommonDaoOptions = {}): Promise<Saved<BM>> {
208
+ async requireById(id: ID, opt: CommonDaoOptions = {}): Promise<Saved<BM>> {
205
209
  const r = await this.getById(id, opt)
206
210
  if (!r) {
207
211
  this.throwRequiredError(id, opt)
@@ -209,7 +213,7 @@ export class CommonDao<
209
213
  return r
210
214
  }
211
215
 
212
- async requireByIdAsDBM(id: string, opt: CommonDaoOptions = {}): Promise<DBM> {
216
+ async requireByIdAsDBM(id: ID, opt: CommonDaoOptions = {}): Promise<DBM> {
213
217
  const r = await this.getByIdAsDBM(id, opt)
214
218
  if (!r) {
215
219
  this.throwRequiredError(id, opt)
@@ -217,7 +221,7 @@ export class CommonDao<
217
221
  return r
218
222
  }
219
223
 
220
- private throwRequiredError(id: string, opt: CommonDaoOptions): never {
224
+ private throwRequiredError(id: ID, opt: CommonDaoOptions): never {
221
225
  const table = opt.table || this.cfg.table
222
226
  throw new AppError(`DB row required, but not found: ${table}.${id}`, {
223
227
  code: DBLibError.DB_ROW_REQUIRED,
@@ -267,8 +271,8 @@ export class CommonDao<
267
271
  /**
268
272
  * Pass `table` to override table
269
273
  */
270
- query(table?: string): RunnableDBQuery<BM, DBM, TM> {
271
- return new RunnableDBQuery<BM, DBM, TM>(this, table)
274
+ query(table?: string): RunnableDBQuery<BM, DBM, TM, ID> {
275
+ return new RunnableDBQuery<BM, DBM, TM, ID>(this, table)
272
276
  }
273
277
 
274
278
  async runQuery(q: DBQuery<DBM>, opt?: CommonDaoOptions): Promise<Saved<BM>[]> {
@@ -514,18 +518,18 @@ export class CommonDao<
514
518
  )
515
519
  }
516
520
 
517
- async queryIds(q: DBQuery<DBM>, opt: CommonDaoOptions = {}): Promise<string[]> {
521
+ async queryIds(q: DBQuery<DBM>, opt: CommonDaoOptions = {}): Promise<ID[]> {
518
522
  q.table = opt.table || q.table
519
523
  const { rows } = await this.cfg.db.runQuery(q.select(['id']), opt)
520
524
  return rows.map(r => r.id)
521
525
  }
522
526
 
523
- streamQueryIds(q: DBQuery<DBM>, opt: CommonDaoStreamOptions = {}): ReadableTyped<string> {
527
+ streamQueryIds(q: DBQuery<DBM>, opt: CommonDaoStreamOptions = {}): ReadableTyped<ID> {
524
528
  q.table = opt.table || q.table
525
529
  opt.errorMode ||= ErrorMode.SUPPRESS
526
530
 
527
531
  return this.cfg.db.streamQuery<DBM>(q.select(['id']), opt).pipe(
528
- transformMapSimple<ObjectWithId, string>(objectWithId => objectWithId.id, {
532
+ transformMapSimple<DBM, ID>(objectWithId => objectWithId.id, {
529
533
  errorMode: ErrorMode.SUPPRESS, // cause .pipe() cannot propagate errors
530
534
  }),
531
535
  )
@@ -533,8 +537,8 @@ export class CommonDao<
533
537
 
534
538
  async streamQueryIdsForEach(
535
539
  q: DBQuery<DBM>,
536
- mapper: AsyncMapper<string, void>,
537
- opt: CommonDaoStreamForEachOptions<string> = {},
540
+ mapper: AsyncMapper<ID, void>,
541
+ opt: CommonDaoStreamForEachOptions<ID> = {},
538
542
  ): Promise<void> {
539
543
  q.table = opt.table || q.table
540
544
  opt.errorMode = opt.errorMode || ErrorMode.SUPPRESS
@@ -545,9 +549,9 @@ export class CommonDao<
545
549
 
546
550
  await _pipeline([
547
551
  this.cfg.db.streamQuery<DBM>(q.select(['id']), opt),
548
- transformMapSimple<ObjectWithId, string>(objectWithId => objectWithId.id),
552
+ transformMapSimple<DBM, ID>(objectWithId => objectWithId.id),
549
553
  transformTap(() => count++),
550
- transformMap<string, void>(mapper, {
554
+ transformMap<ID, void>(mapper, {
551
555
  ...opt,
552
556
  predicate: _passthroughPredicate,
553
557
  }),
@@ -570,21 +574,18 @@ export class CommonDao<
570
574
  */
571
575
  assignIdCreatedUpdated(obj: DBM, opt?: CommonDaoOptions): DBM
572
576
  assignIdCreatedUpdated(obj: BM, opt?: CommonDaoOptions): Saved<BM>
573
- assignIdCreatedUpdated(obj: DBM | BM, opt: CommonDaoOptions = {}): DBM | Saved<BM> {
577
+ assignIdCreatedUpdated(obj: Unsaved<BM>, opt?: CommonDaoOptions): Saved<BM>
578
+ assignIdCreatedUpdated(obj: DBM | BM | Unsaved<BM>, opt: CommonDaoOptions = {}): DBM | Saved<BM> {
574
579
  const now = Math.floor(Date.now() / 1000)
575
580
 
576
- obj.id = obj.id || this.cfg.hooks!.createId!(obj)
581
+ obj.id ||= this.cfg.hooks!.createId?.(obj as BM)
577
582
 
578
583
  if (this.cfg.created) {
579
- Object.assign(obj, {
580
- created: (obj as any).created || (obj as any).updated || now,
581
- })
584
+ obj['created'] ||= obj['updated'] || now
582
585
  }
583
586
 
584
587
  if (this.cfg.updated) {
585
- Object.assign(obj, {
586
- updated: opt.preserveUpdatedCreated && (obj as any).updated ? (obj as any).updated : now,
587
- })
588
+ obj['updated'] = opt.preserveUpdatedCreated && obj['updated'] ? obj['updated'] : now
588
589
  }
589
590
 
590
591
  return obj as any
@@ -594,11 +595,11 @@ export class CommonDao<
594
595
  /**
595
596
  * Mutates with id, created, updated
596
597
  */
597
- async save(bm: BM, opt: CommonDaoSaveOptions<DBM> = {}): Promise<Saved<BM>> {
598
+ async save(bm: Unsaved<BM>, opt: CommonDaoSaveOptions<DBM> = {}): Promise<Saved<BM>> {
598
599
  this.requireWriteAccess()
599
600
  const idWasGenerated = !bm.id
600
601
  this.assignIdCreatedUpdated(bm, opt) // mutates
601
- const dbm = await this.bmToDBM(bm, opt)
602
+ const dbm = await this.bmToDBM(bm as BM, opt)
602
603
  const table = opt.table || this.cfg.table
603
604
  if (opt.ensureUniqueId && idWasGenerated) await this.ensureUniqueId(table, dbm)
604
605
  if (this.cfg.immutable) await this.ensureImmutableDontExist(table, [dbm.id])
@@ -613,7 +614,7 @@ export class CommonDao<
613
614
  return bm as any
614
615
  }
615
616
 
616
- private async ensureImmutableDontExist(table: string, ids: string[]): Promise<void> {
617
+ private async ensureImmutableDontExist(table: string, ids: ID[]): Promise<void> {
617
618
  await this.throwIfObjectExists(table, ids, [
618
619
  DBLibError.OBJECT_IS_IMMUTABLE,
619
620
  {
@@ -640,7 +641,7 @@ export class CommonDao<
640
641
 
641
642
  private async throwIfObjectExists(
642
643
  table: string,
643
- ids: string[],
644
+ ids: ID[],
644
645
  errorMeta: [DBLibError, any],
645
646
  ): Promise<void> {
646
647
  const existing = await this.cfg.db.getByIds<DBM>(table, ids)
@@ -656,11 +657,7 @@ export class CommonDao<
656
657
  *
657
658
  * Convenience method to replace 3 operations (loading+patching+saving) with one.
658
659
  */
659
- async patch(
660
- id: string,
661
- patch: Partial<BM>,
662
- opt: CommonDaoSaveOptions<DBM> = {},
663
- ): Promise<Saved<BM>> {
660
+ async patch(id: ID, patch: Partial<BM>, opt: CommonDaoSaveOptions<DBM> = {}): Promise<Saved<BM>> {
664
661
  return await this.save(
665
662
  {
666
663
  ...(await this.getByIdOrEmpty(id, patch, opt)),
@@ -670,11 +667,7 @@ export class CommonDao<
670
667
  )
671
668
  }
672
669
 
673
- async patchAsDBM(
674
- id: string,
675
- patch: Partial<DBM>,
676
- opt: CommonDaoSaveOptions<DBM> = {},
677
- ): Promise<DBM> {
670
+ async patchAsDBM(id: ID, patch: Partial<DBM>, opt: CommonDaoSaveOptions<DBM> = {}): Promise<DBM> {
678
671
  const dbm =
679
672
  (await this.getByIdAsDBM(id, opt)) ||
680
673
  (this.create({ ...patch, id } as Partial<BM>, opt) as any as DBM)
@@ -711,11 +704,11 @@ export class CommonDao<
711
704
  return dbm
712
705
  }
713
706
 
714
- async saveBatch(bms: BM[], opt: CommonDaoSaveOptions<DBM> = {}): Promise<Saved<BM>[]> {
707
+ async saveBatch(bms: Unsaved<BM>[], opt: CommonDaoSaveOptions<DBM> = {}): Promise<Saved<BM>[]> {
715
708
  this.requireWriteAccess()
716
709
  const table = opt.table || this.cfg.table
717
710
  bms.forEach(bm => this.assignIdCreatedUpdated(bm, opt))
718
- const dbms = await this.bmsToDBM(bms, opt)
711
+ const dbms = await this.bmsToDBM(bms as BM[], opt)
719
712
  if (opt.ensureUniqueId) throw new AppError('ensureUniqueId is not supported in saveBatch')
720
713
  if (this.cfg.immutable)
721
714
  await this.ensureImmutableDontExist(
@@ -778,8 +771,8 @@ export class CommonDao<
778
771
  * @returns number of deleted items
779
772
  */
780
773
  async deleteById(id: undefined, opt?: CommonDaoOptions): Promise<0>
781
- async deleteById(id?: string, opt?: CommonDaoOptions): Promise<number>
782
- async deleteById(id?: string, opt: CommonDaoOptions = {}): Promise<number> {
774
+ async deleteById(id?: ID, opt?: CommonDaoOptions): Promise<number>
775
+ async deleteById(id?: ID, opt: CommonDaoOptions = {}): Promise<number> {
783
776
  if (!id) return 0
784
777
  this.requireWriteAccess()
785
778
  if (!opt.allowMutability) this.requireObjectMutability()
@@ -791,7 +784,7 @@ export class CommonDao<
791
784
  return ids
792
785
  }
793
786
 
794
- async deleteByIds(ids: string[], opt: CommonDaoOptions = {}): Promise<number> {
787
+ async deleteByIds(ids: ID[], opt: CommonDaoOptions = {}): Promise<number> {
795
788
  this.requireWriteAccess()
796
789
  if (!opt.allowMutability) this.requireObjectMutability()
797
790
  const op = `deleteByIds(${ids.join(', ')})`
@@ -823,7 +816,7 @@ export class CommonDao<
823
816
 
824
817
  await _pipeline([
825
818
  this.cfg.db.streamQuery<DBM>(q.select(['id']), opt),
826
- transformMapSimple<ObjectWithId, string>(objectWithId => objectWithId.id, {
819
+ transformMapSimple<DBM, ID>(objectWithId => objectWithId.id, {
827
820
  errorMode: ErrorMode.SUPPRESS,
828
821
  }),
829
822
  transformBuffer<string>({ batchSize }),
package/src/db.model.ts CHANGED
@@ -1,5 +1,14 @@
1
1
  import { AnyObjectWithId, ObjectWithId } from '@naturalcycles/js-lib'
2
- import { CommonDB } from './common.db'
2
+
3
+ /**
4
+ * Similar to SQL INSERT, UPDATE.
5
+ * Insert will fail if row already exists.
6
+ * Update will fail if row is missing.
7
+ * Upsert will auto-detect and use Insert or Update to not fail.
8
+ *
9
+ * Default is Upsert.
10
+ */
11
+ export type CommonDBSaveMethod = 'upsert' | 'insert' | 'update'
3
12
 
4
13
  // eslint-disable-next-line @typescript-eslint/no-empty-interface
5
14
  export interface CommonDBOptions {}
@@ -7,17 +16,23 @@ export interface CommonDBOptions {}
7
16
  /**
8
17
  * All properties default to undefined.
9
18
  */
10
- export interface CommonDBSaveOptions<ROW extends ObjectWithId = AnyObjectWithId>
19
+ export interface CommonDBSaveOptions<ROW extends Partial<ObjectWithId> = AnyObjectWithId>
11
20
  extends CommonDBOptions {
12
21
  excludeFromIndexes?: (keyof ROW)[]
22
+
23
+ /**
24
+ * Default is `upsert`
25
+ */
26
+ saveMethod?: CommonDBSaveMethod
13
27
  }
14
28
 
15
29
  export type CommonDBStreamOptions = CommonDBOptions
16
30
 
17
31
  export interface CommonDBCreateOptions extends CommonDBOptions {
18
32
  /**
19
- * @default false
20
33
  * Caution! If set to true - will actually DROP the table!
34
+ *
35
+ * @default false
21
36
  */
22
37
  dropIfExists?: boolean
23
38
  }
@@ -51,19 +66,3 @@ export enum DBModelType {
51
66
  BM = 'BM',
52
67
  TM = 'TM',
53
68
  }
54
-
55
- /**
56
- * Interface for a module (lib) that implements CommonDB.
57
- *
58
- * Example:
59
- *
60
- * const lib: CommonDBModule = require('mysql-lib')
61
- * const db = lib.getDB()
62
- */
63
- export interface CommonDBAdapter {
64
- /**
65
- * @param cfg was read from SECRET_DB${i} by secret('SECRET_DB${i}') method and passed there.
66
- * It's a string that can contain e.g JSON.stringified configuration object (depends on the adapter).
67
- */
68
- getDBAdapter(cfg?: string): CommonDB
69
- }
package/src/index.ts CHANGED
@@ -6,27 +6,19 @@ import { DBLibError } from './cnst'
6
6
  import { CommonDB } from './common.db'
7
7
  import { CommonDao } from './commondao/common.dao'
8
8
  import {
9
- CommonDaoAnonymizeHook,
10
- CommonDaoBeforeBMToDBMHook,
11
- CommonDaoBeforeBMToTMHook,
12
- CommonDaoBeforeCreateHook,
13
- CommonDaoBeforeDBMToBMHook,
14
- CommonDaoBeforeDBMValidateHook,
15
- CommonDaoBeforeTMToBMHook,
16
9
  CommonDaoCfg,
17
- CommonDaoCreateIdHook,
18
10
  CommonDaoCreateOptions,
19
11
  CommonDaoLogLevel,
20
12
  CommonDaoOptions,
21
- CommonDaoParseNaturalIdHook,
22
13
  CommonDaoSaveOptions,
23
14
  CommonDaoStreamForEachOptions,
24
15
  CommonDaoStreamOptions,
16
+ CommonDaoHooks,
25
17
  } from './commondao/common.dao.model'
26
18
  import {
27
- CommonDBAdapter,
28
19
  CommonDBCreateOptions,
29
20
  CommonDBOptions,
21
+ CommonDBSaveMethod,
30
22
  CommonDBSaveOptions,
31
23
  CommonDBStreamOptions,
32
24
  DBDeleteByIdsOperation,
@@ -68,28 +60,20 @@ export type {
68
60
  CommonDaoSaveOptions,
69
61
  CommonDaoStreamForEachOptions,
70
62
  CommonDaoStreamOptions,
63
+ CommonDaoHooks,
71
64
  CommonDBOptions,
72
65
  CommonDBSaveOptions,
66
+ CommonDBSaveMethod,
73
67
  CommonDBStreamOptions,
74
68
  CommonDBCreateOptions,
75
69
  CommonDB,
76
70
  RunQueryResult,
77
71
  CommonDaoCfg,
78
- CommonDaoCreateIdHook,
79
- CommonDaoParseNaturalIdHook,
80
- CommonDaoBeforeCreateHook,
81
- CommonDaoBeforeDBMValidateHook,
82
- CommonDaoBeforeDBMToBMHook,
83
- CommonDaoBeforeBMToDBMHook,
84
- CommonDaoBeforeTMToBMHook,
85
- CommonDaoBeforeBMToTMHook,
86
- CommonDaoAnonymizeHook,
87
72
  InMemoryDBCfg,
88
73
  InMemoryKeyValueDBCfg,
89
74
  DBPipelineBackupOptions,
90
75
  DBPipelineRestoreOptions,
91
76
  DBPipelineCopyOptions,
92
- CommonDBAdapter,
93
77
  DBOperation,
94
78
  DBSaveBatchOperation,
95
79
  DBDeleteByIdsOperation,
package/src/model.util.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { stringId } from '@naturalcycles/nodejs-lib'
2
- import { CreatedUpdated, CreatedUpdatedId, ObjectWithId } from '@naturalcycles/js-lib'
2
+ import { CreatedUpdated, CreatedUpdatedId } from '@naturalcycles/js-lib'
3
3
 
4
4
  export function createdUpdatedFields(
5
5
  existingObject?: Partial<CreatedUpdated> | null,
@@ -12,8 +12,8 @@ export function createdUpdatedFields(
12
12
  }
13
13
 
14
14
  export function createdUpdatedIdFields(
15
- existingObject?: Partial<CreatedUpdatedId> | null,
16
- ): CreatedUpdatedId {
15
+ existingObject?: Partial<CreatedUpdatedId<string>> | null,
16
+ ): CreatedUpdatedId<string> {
17
17
  const now = Math.floor(Date.now() / 1000)
18
18
  return {
19
19
  created: existingObject?.created || now,
@@ -22,12 +22,6 @@ export function createdUpdatedIdFields(
22
22
  }
23
23
  }
24
24
 
25
- export function idField(existingObject?: Partial<CreatedUpdatedId> | null): ObjectWithId {
26
- return {
27
- id: existingObject?.id || stringId(),
28
- }
29
- }
30
-
31
25
  export function deserializeJsonField<T = any>(f?: string): T {
32
26
  return JSON.parse(f || '{}')
33
27
  }
@@ -216,14 +216,15 @@ export class DBQuery<ROW extends ObjectWithId = AnyObjectWithId> {
216
216
  * DBQuery that has additional method to support Fluent API style.
217
217
  */
218
218
  export class RunnableDBQuery<
219
- BM extends Partial<ObjectWithId>,
220
- DBM extends ObjectWithId,
219
+ BM extends Partial<ObjectWithId<ID>>,
220
+ DBM extends ObjectWithId<ID>,
221
221
  TM,
222
+ ID extends string | number,
222
223
  > extends DBQuery<DBM> {
223
224
  /**
224
225
  * Pass `table` to override table.
225
226
  */
226
- constructor(public dao: CommonDao<BM, DBM, TM>, table?: string) {
227
+ constructor(public dao: CommonDao<BM, DBM, TM, ID>, table?: string) {
227
228
  super(table || dao.cfg.table)
228
229
  }
229
230
 
@@ -281,17 +282,17 @@ export class RunnableDBQuery<
281
282
  return this.dao.streamQueryAsDBM(this, opt)
282
283
  }
283
284
 
284
- async queryIds(opt?: CommonDaoOptions): Promise<string[]> {
285
+ async queryIds(opt?: CommonDaoOptions): Promise<ID[]> {
285
286
  return await this.dao.queryIds(this, opt)
286
287
  }
287
288
 
288
- streamQueryIds(opt?: CommonDaoStreamOptions): ReadableTyped<string> {
289
+ streamQueryIds(opt?: CommonDaoStreamOptions): ReadableTyped<ID> {
289
290
  return this.dao.streamQueryIds(this, opt)
290
291
  }
291
292
 
292
293
  async streamQueryIdsForEach(
293
- mapper: AsyncMapper<string, void>,
294
- opt?: CommonDaoStreamForEachOptions<string>,
294
+ mapper: AsyncMapper<ID, void>,
295
+ opt?: CommonDaoStreamForEachOptions<ID>,
295
296
  ): Promise<void> {
296
297
  await this.dao.streamQueryIdsForEach(this, mapper, opt)
297
298
  }
@@ -21,6 +21,8 @@ export interface CommonDBImplementationFeatures {
21
21
  dbQueryFilterIn?: boolean
22
22
  dbQueryOrder?: boolean
23
23
  dbQuerySelectFields?: boolean
24
+ insert?: boolean
25
+ update?: boolean
24
26
 
25
27
  createTable?: boolean
26
28
  tableSchemas?: boolean
@@ -80,6 +82,8 @@ export function runCommonDBTest(
80
82
  // dbQueryFilterIn = true,
81
83
  dbQueryOrder = true,
82
84
  dbQuerySelectFields = true,
85
+ insert = true,
86
+ update = true,
83
87
  streaming = true,
84
88
  strongConsistency = true,
85
89
  bufferSupport = true,
@@ -176,10 +180,28 @@ export function runCommonDBTest(
176
180
  })
177
181
  }
178
182
 
183
+ if (update) {
184
+ test('saveBatch UPDATE method should throw', async () => {
185
+ await expect(db.saveBatch(TEST_TABLE, items, { saveMethod: 'update' })).rejects.toThrow()
186
+ })
187
+ }
188
+
179
189
  test('saveBatch test items', async () => {
180
190
  await db.saveBatch(TEST_TABLE, items)
181
191
  })
182
192
 
193
+ if (insert) {
194
+ test('saveBatch INSERT method should throw', async () => {
195
+ await expect(db.saveBatch(TEST_TABLE, items, { saveMethod: 'insert' })).rejects.toThrow()
196
+ })
197
+ }
198
+
199
+ if (update) {
200
+ test('saveBatch UPDATE method should pass', async () => {
201
+ await db.saveBatch(TEST_TABLE, items, { saveMethod: 'update' })
202
+ })
203
+ }
204
+
183
205
  // GET not empty
184
206
  test('getByIds all items', async () => {
185
207
  const rows = await db.getByIds<TestItemDBM>(TEST_TABLE, items.map(i => i.id).concat('abcd'))
@@ -1,3 +0,0 @@
1
- import { CommonDB } from '../../common.db';
2
- export declare function getDBAdapter(): CommonDB;
3
- export {};
@@ -1,8 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.getDBAdapter = void 0;
4
- const inMemory_db_1 = require("./inMemory.db");
5
- function getDBAdapter() {
6
- return new inMemory_db_1.InMemoryDB();
7
- }
8
- exports.getDBAdapter = getDBAdapter;
@@ -1,9 +0,0 @@
1
- import { CommonDB } from '../../common.db'
2
- import { InMemoryDB } from './inMemory.db'
3
-
4
- export function getDBAdapter(): CommonDB {
5
- return new InMemoryDB()
6
- }
7
-
8
- export // InMemoryDB, // no, otherwise it's double-exported, which can confuse IDEs
9
- {}