@naturalcycles/db-lib 9.2.1 → 9.3.1

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 (36) hide show
  1. package/dist/adapter/cachedb/cache.db.d.ts +11 -12
  2. package/dist/adapter/cachedb/cache.db.model.d.ts +2 -2
  3. package/dist/adapter/file/file.db.d.ts +12 -12
  4. package/dist/adapter/file/file.db.model.d.ts +2 -2
  5. package/dist/adapter/file/localFile.persistence.plugin.d.ts +3 -3
  6. package/dist/adapter/file/noop.persistence.plugin.d.ts +2 -2
  7. package/dist/adapter/inmemory/inMemory.db.d.ts +12 -12
  8. package/dist/adapter/inmemory/queryInMemory.d.ts +2 -2
  9. package/dist/base.common.db.d.ts +10 -10
  10. package/dist/common.db.d.ts +10 -10
  11. package/dist/commondao/common.dao.d.ts +23 -25
  12. package/dist/commondao/common.dao.js +16 -15
  13. package/dist/commondao/common.dao.model.d.ts +13 -13
  14. package/dist/db.model.d.ts +4 -4
  15. package/dist/query/dbQuery.d.ts +9 -9
  16. package/dist/testing/test.model.d.ts +3 -4
  17. package/dist/testing/test.model.js +1 -1
  18. package/dist/transaction/dbTransaction.util.d.ts +3 -3
  19. package/dist/validation/index.d.ts +2 -2
  20. package/package.json +1 -1
  21. package/src/adapter/cachedb/cache.db.model.ts +2 -2
  22. package/src/adapter/cachedb/cache.db.ts +18 -16
  23. package/src/adapter/file/file.db.model.ts +2 -2
  24. package/src/adapter/file/file.db.ts +17 -15
  25. package/src/adapter/file/localFile.persistence.plugin.ts +4 -4
  26. package/src/adapter/file/noop.persistence.plugin.ts +2 -2
  27. package/src/adapter/inmemory/inMemory.db.ts +20 -18
  28. package/src/adapter/inmemory/queryInMemory.ts +5 -2
  29. package/src/base.common.db.ts +20 -10
  30. package/src/common.db.ts +20 -13
  31. package/src/commondao/common.dao.model.ts +23 -16
  32. package/src/commondao/common.dao.ts +68 -71
  33. package/src/db.model.ts +4 -4
  34. package/src/query/dbQuery.ts +13 -11
  35. package/src/testing/test.model.ts +4 -6
  36. package/src/transaction/dbTransaction.util.ts +3 -3
package/src/common.db.ts CHANGED
@@ -1,4 +1,9 @@
1
- import { JsonSchemaObject, JsonSchemaRootObject, ObjectWithId } from '@naturalcycles/js-lib'
1
+ import {
2
+ JsonSchemaObject,
3
+ JsonSchemaRootObject,
4
+ PartialObjectWithId,
5
+ Saved,
6
+ } from '@naturalcycles/js-lib'
2
7
  import type { ReadableTyped } from '@naturalcycles/nodejs-lib'
3
8
  import {
4
9
  CommonDBCreateOptions,
@@ -64,13 +69,15 @@ export interface CommonDB {
64
69
  *
65
70
  * This is important for the code to rely on it, and it's verified by dbTest
66
71
  */
67
- getTableSchema: <ROW extends ObjectWithId>(table: string) => Promise<JsonSchemaRootObject<ROW>>
72
+ getTableSchema: <ROW extends PartialObjectWithId>(
73
+ table: string,
74
+ ) => Promise<JsonSchemaRootObject<ROW>>
68
75
 
69
76
  /**
70
77
  * Will do like `create table ...` for mysql.
71
78
  * Caution! dropIfExists defaults to false. If set to true - will actually DROP the table!
72
79
  */
73
- createTable: <ROW extends ObjectWithId>(
80
+ createTable: <ROW extends PartialObjectWithId>(
74
81
  table: string,
75
82
  schema: JsonSchemaObject<ROW>,
76
83
  opt?: CommonDBCreateOptions,
@@ -81,36 +88,36 @@ export interface CommonDB {
81
88
  * Order of items returned is not guaranteed to match order of ids.
82
89
  * (Such limitation exists because Datastore doesn't support it).
83
90
  */
84
- getByIds: <ROW extends ObjectWithId>(
91
+ getByIds: <ROW extends PartialObjectWithId>(
85
92
  table: string,
86
93
  ids: string[],
87
94
  opt?: CommonDBOptions,
88
- ) => Promise<ROW[]>
95
+ ) => Promise<Saved<ROW>[]>
89
96
 
90
97
  // QUERY
91
98
  /**
92
99
  * Order by 'id' is not supported by all implementations (for example, Datastore doesn't support it).
93
100
  */
94
- runQuery: <ROW extends ObjectWithId>(
101
+ runQuery: <ROW extends PartialObjectWithId>(
95
102
  q: DBQuery<ROW>,
96
103
  opt?: CommonDBOptions,
97
- ) => Promise<RunQueryResult<ROW>>
104
+ ) => Promise<RunQueryResult<Saved<ROW>>>
98
105
 
99
- runQueryCount: <ROW extends ObjectWithId>(
106
+ runQueryCount: <ROW extends PartialObjectWithId>(
100
107
  q: DBQuery<ROW>,
101
108
  opt?: CommonDBOptions,
102
109
  ) => Promise<number>
103
110
 
104
- streamQuery: <ROW extends ObjectWithId>(
111
+ streamQuery: <ROW extends PartialObjectWithId>(
105
112
  q: DBQuery<ROW>,
106
113
  opt?: CommonDBStreamOptions,
107
- ) => ReadableTyped<ROW>
114
+ ) => ReadableTyped<Saved<ROW>>
108
115
 
109
116
  // SAVE
110
117
  /**
111
118
  * rows can have missing ids only if DB supports auto-generating them (like mysql auto_increment).
112
119
  */
113
- saveBatch: <ROW extends Partial<ObjectWithId>>(
120
+ saveBatch: <ROW extends PartialObjectWithId>(
114
121
  table: string,
115
122
  rows: ROW[],
116
123
  opt?: CommonDBSaveOptions<ROW>,
@@ -127,7 +134,7 @@ export interface CommonDB {
127
134
  * Returns number of deleted items.
128
135
  * Not supported by all implementations (e.g Datastore will always return same number as number of ids).
129
136
  */
130
- deleteByQuery: <ROW extends ObjectWithId>(
137
+ deleteByQuery: <ROW extends PartialObjectWithId>(
131
138
  q: DBQuery<ROW>,
132
139
  opt?: CommonDBOptions,
133
140
  ) => Promise<number>
@@ -150,7 +157,7 @@ export interface CommonDB {
150
157
  *
151
158
  * Returns number of rows affected.
152
159
  */
153
- updateByQuery: <ROW extends ObjectWithId>(
160
+ updateByQuery: <ROW extends PartialObjectWithId>(
154
161
  q: DBQuery<ROW>,
155
162
  patch: DBPatch<ROW>,
156
163
  opt?: CommonDBOptions,
@@ -1,7 +1,8 @@
1
1
  import {
2
+ AnyObject,
2
3
  CommonLogger,
3
4
  ErrorMode,
4
- ObjectWithId,
5
+ PartialObjectWithId,
5
6
  Promisable,
6
7
  Saved,
7
8
  ZodError,
@@ -18,7 +19,11 @@ import {
18
19
  import { CommonDB } from '../common.db'
19
20
  import { CommonDBCreateOptions, CommonDBOptions, CommonDBSaveOptions } from '../db.model'
20
21
 
21
- export interface CommonDaoHooks<BM extends Partial<ObjectWithId>, DBM extends ObjectWithId, TM> {
22
+ export interface CommonDaoHooks<
23
+ BM extends PartialObjectWithId,
24
+ DBM extends PartialObjectWithId,
25
+ TM,
26
+ > {
22
27
  /**
23
28
  * Allows to override the id generation function.
24
29
  * By default it uses `stringId` from nodejs-lib
@@ -59,7 +64,7 @@ export interface CommonDaoHooks<BM extends Partial<ObjectWithId>, DBM extends Ob
59
64
  */
60
65
  beforeDBMValidate: (dbm: Partial<DBM>) => Partial<DBM>
61
66
 
62
- beforeDBMToBM: (dbm: DBM) => Partial<BM> | Promise<Partial<BM>>
67
+ beforeDBMToBM: (dbm: Saved<DBM>) => Partial<BM> | Promise<Partial<BM>>
63
68
  beforeBMToDBM: (bm: BM) => Partial<DBM> | Promise<Partial<DBM>>
64
69
  beforeBMToTM: (bm: BM) => Partial<TM>
65
70
 
@@ -75,7 +80,7 @@ export interface CommonDaoHooks<BM extends Partial<ObjectWithId>, DBM extends Ob
75
80
  *
76
81
  * You can do validations as needed here and throw errors, they will be propagated.
77
82
  */
78
- afterLoad?: (dbm: DBM) => Promisable<DBM | null>
83
+ afterLoad?: (dbm: Saved<DBM>) => Promisable<Saved<DBM> | null>
79
84
 
80
85
  /**
81
86
  * Allows to access the DBM just before it's supposed to be saved to the DB.
@@ -90,7 +95,7 @@ export interface CommonDaoHooks<BM extends Partial<ObjectWithId>, DBM extends Ob
90
95
  *
91
96
  * You can do validations as needed here and throw errors, they will be propagated.
92
97
  */
93
- beforeSave?: (dbm: DBM) => Promisable<DBM | null>
98
+ beforeSave?: (dbm: Saved<DBM>) => Promisable<Saved<DBM> | null>
94
99
 
95
100
  /**
96
101
  * Called in:
@@ -101,7 +106,7 @@ export interface CommonDaoHooks<BM extends Partial<ObjectWithId>, DBM extends Ob
101
106
  * It still applies to BM "transitively", during dbmToBM
102
107
  * (e.g after loaded from the Database).
103
108
  */
104
- anonymize: (dbm: DBM) => DBM
109
+ anonymize: (dbm: Saved<DBM>) => Saved<DBM>
105
110
 
106
111
  /**
107
112
  * If hook is defined - allows to prevent or modify the error thrown.
@@ -132,9 +137,9 @@ export enum CommonDaoLogLevel {
132
137
  }
133
138
 
134
139
  export interface CommonDaoCfg<
135
- BM extends Partial<ObjectWithId>,
136
- DBM extends ObjectWithId = Saved<BM>,
137
- TM = BM,
140
+ BM extends PartialObjectWithId,
141
+ DBM extends PartialObjectWithId = BM,
142
+ TM extends AnyObject = BM,
138
143
  > {
139
144
  db: CommonDB
140
145
  table: string
@@ -200,13 +205,13 @@ export interface CommonDaoCfg<
200
205
  * Defaults to true
201
206
  * Set to false to disable `created` field management.
202
207
  */
203
- created?: boolean
208
+ useCreatedProperty?: boolean
204
209
 
205
210
  /**
206
211
  * Defaults to true
207
212
  * Set to false to disable `updated` field management.
208
213
  */
209
- updated?: boolean
214
+ useUpdatedProperty?: boolean
210
215
 
211
216
  /**
212
217
  * Default is false.
@@ -276,8 +281,10 @@ export interface CommonDaoOptions extends CommonDBOptions {
276
281
  table?: string
277
282
  }
278
283
 
279
- export interface CommonDaoSaveOptions<BM extends Partial<ObjectWithId>, DBM extends ObjectWithId>
280
- extends CommonDaoSaveBatchOptions<DBM> {
284
+ export interface CommonDaoSaveOptions<
285
+ BM extends PartialObjectWithId,
286
+ DBM extends PartialObjectWithId,
287
+ > extends CommonDaoSaveBatchOptions<DBM> {
281
288
  /**
282
289
  * If provided - a check will be made.
283
290
  * If the object for saving equals to the object passed to `skipIfEquals` - save operation will be skipped.
@@ -292,7 +299,7 @@ export interface CommonDaoSaveOptions<BM extends Partial<ObjectWithId>, DBM exte
292
299
  /**
293
300
  * All properties default to undefined.
294
301
  */
295
- export interface CommonDaoSaveBatchOptions<DBM extends ObjectWithId>
302
+ export interface CommonDaoSaveBatchOptions<DBM extends PartialObjectWithId>
296
303
  extends CommonDaoOptions,
297
304
  CommonDBSaveOptions<DBM> {
298
305
  /**
@@ -307,10 +314,10 @@ export interface CommonDaoSaveBatchOptions<DBM extends ObjectWithId>
307
314
  ensureUniqueId?: boolean
308
315
  }
309
316
 
310
- export interface CommonDaoStreamDeleteOptions<DBM extends ObjectWithId>
317
+ export interface CommonDaoStreamDeleteOptions<DBM extends PartialObjectWithId>
311
318
  extends CommonDaoStreamOptions<DBM> {}
312
319
 
313
- export interface CommonDaoStreamSaveOptions<DBM extends ObjectWithId>
320
+ export interface CommonDaoStreamSaveOptions<DBM extends PartialObjectWithId>
314
321
  extends CommonDaoSaveBatchOptions<DBM>,
315
322
  CommonDaoStreamOptions<DBM> {}
316
323
 
@@ -13,16 +13,17 @@ import {
13
13
  AnyObject,
14
14
  AppError,
15
15
  AsyncMapper,
16
+ BaseDBEntity,
16
17
  CommonLogger,
17
18
  ErrorMode,
18
19
  JsonSchemaObject,
19
20
  JsonSchemaRootObject,
20
21
  ObjectWithId,
22
+ PartialObjectWithId,
21
23
  pMap,
22
24
  Saved,
23
25
  SKIP,
24
26
  UnixTimestampMillisNumber,
25
- Unsaved,
26
27
  ZodSchema,
27
28
  ZodValidationError,
28
29
  zSafeValidate,
@@ -76,8 +77,8 @@ const isCI = !!process.env['CI']
76
77
  * TM = Transport model (optimized to be sent over the wire)
77
78
  */
78
79
  export class CommonDao<
79
- BM extends Partial<ObjectWithId>,
80
- DBM extends ObjectWithId = Saved<BM>,
80
+ BM extends PartialObjectWithId,
81
+ DBM extends PartialObjectWithId = BM,
81
82
  TM extends AnyObject = BM,
82
83
  > {
83
84
  constructor(public cfg: CommonDaoCfg<BM, DBM, TM>) {
@@ -88,8 +89,8 @@ export class CommonDao<
88
89
  logLevel: isGAE || isCI ? CommonDaoLogLevel.NONE : CommonDaoLogLevel.OPERATIONS,
89
90
  createId: true,
90
91
  assignGeneratedIds: false,
91
- created: true,
92
- updated: true,
92
+ useCreatedProperty: true,
93
+ useUpdatedProperty: true,
93
94
  logger: console,
94
95
  ...cfg,
95
96
  hooks: {
@@ -116,7 +117,7 @@ export class CommonDao<
116
117
  create(part: Partial<BM> = {}, opt: CommonDaoOptions = {}): Saved<BM> {
117
118
  const bm = this.cfg.hooks!.beforeCreate!(part)
118
119
  // First assignIdCreatedUpdated, then validate!
119
- this.assignIdCreatedUpdated(bm as any, opt)
120
+ this.assignIdCreatedUpdated(bm, opt)
120
121
  return this.validateAndConvert(bm, this.cfg.bmSchema, DBModelType.BM, opt)
121
122
  }
122
123
 
@@ -154,17 +155,17 @@ export class CommonDao<
154
155
  id: string,
155
156
  part: Partial<BM> = {},
156
157
  opt?: CommonDaoOptions,
157
- ): Promise<DBM> {
158
+ ): Promise<Saved<DBM>> {
158
159
  const dbm = await this.getByIdAsDBM(id, opt)
159
160
  if (dbm) return dbm
160
161
 
161
- const bm: BM = this.create({ ...part, id }, opt) as any
162
+ const bm = this.create({ ...part, id }, opt)
162
163
  return await this.bmToDBM(bm, opt)
163
164
  }
164
165
 
165
166
  async getByIdAsDBM(id: undefined | null, opt?: CommonDaoOptions): Promise<null>
166
- async getByIdAsDBM(id?: string | null, opt?: CommonDaoOptions): Promise<DBM | null>
167
- async getByIdAsDBM(id?: string | null, opt: CommonDaoOptions = {}): Promise<DBM | null> {
167
+ async getByIdAsDBM(id?: string | null, opt?: CommonDaoOptions): Promise<Saved<DBM> | null>
168
+ async getByIdAsDBM(id?: string | null, opt: CommonDaoOptions = {}): Promise<Saved<DBM> | null> {
168
169
  if (!id) return null
169
170
  const op = `getByIdAsDBM(${id})`
170
171
  const table = opt.table || this.cfg.table
@@ -220,7 +221,7 @@ export class CommonDao<
220
221
  return bms
221
222
  }
222
223
 
223
- async getByIdsAsDBM(ids: string[], opt: CommonDaoOptions = {}): Promise<DBM[]> {
224
+ async getByIdsAsDBM(ids: string[], opt: CommonDaoOptions = {}): Promise<Saved<DBM>[]> {
224
225
  if (!ids.length) return []
225
226
  const op = `getByIdsAsDBM ${ids.length} id(s) (${_truncate(ids.slice(0, 10).join(', '), 50)})`
226
227
  const table = opt.table || this.cfg.table
@@ -244,7 +245,7 @@ export class CommonDao<
244
245
  return r
245
246
  }
246
247
 
247
- async requireByIdAsDBM(id: string, opt: CommonDaoOptions = {}): Promise<DBM> {
248
+ async requireByIdAsDBM(id: string, opt: CommonDaoOptions = {}): Promise<Saved<DBM>> {
248
249
  const r = await this.getByIdAsDBM(id, opt)
249
250
  if (!r) {
250
251
  this.throwRequiredError(id, opt)
@@ -282,7 +283,7 @@ export class CommonDao<
282
283
  }
283
284
  }
284
285
 
285
- private async ensureUniqueId(table: string, dbm: DBM): Promise<void> {
286
+ private async ensureUniqueId(table: string, dbm: Saved<DBM>): Promise<void> {
286
287
  // todo: retry N times
287
288
  const existing = await this.cfg.db.getByIds<DBM>(table, [dbm.id])
288
289
  if (existing.length) {
@@ -366,7 +367,7 @@ export class CommonDao<
366
367
  }
367
368
  }
368
369
 
369
- async runQueryAsDBM(q: DBQuery<DBM>, opt?: CommonDaoOptions): Promise<DBM[]> {
370
+ async runQueryAsDBM(q: DBQuery<DBM>, opt?: CommonDaoOptions): Promise<Saved<DBM>[]> {
370
371
  const { rows } = await this.runQueryExtendedAsDBM(q, opt)
371
372
  return rows
372
373
  }
@@ -374,7 +375,7 @@ export class CommonDao<
374
375
  async runQueryExtendedAsDBM(
375
376
  q: DBQuery<DBM>,
376
377
  opt: CommonDaoOptions = {},
377
- ): Promise<RunQueryResult<DBM>> {
378
+ ): Promise<RunQueryResult<Saved<DBM>>> {
378
379
  q.table = opt.table || q.table
379
380
  const op = `runQueryAsDBM(${q.pretty()})`
380
381
  const started = this.logStarted(op, q.table)
@@ -448,7 +449,7 @@ export class CommonDao<
448
449
 
449
450
  await _pipeline([
450
451
  this.cfg.db.streamQuery<DBM>(q, opt),
451
- transformMap<DBM, Saved<BM>>(
452
+ transformMap<Saved<DBM>, Saved<BM>>(
452
453
  async dbm => {
453
454
  count++
454
455
  if (partialQuery || opt.raw) return dbm as any
@@ -548,7 +549,7 @@ export class CommonDao<
548
549
  return stream
549
550
  .on('error', err => stream.emit('error', err))
550
551
  .pipe(
551
- transformMap<any, DBM>(
552
+ transformMap<any, Saved<DBM>>(
552
553
  async dbm => {
553
554
  if (this.cfg.hooks!.afterLoad) {
554
555
  dbm = (await this.cfg.hooks!.afterLoad(dbm))!
@@ -593,7 +594,7 @@ export class CommonDao<
593
594
  // .pipe(transformMap<DBM, Saved<BM>>(dbm => this.dbmToBM(dbm, opt), safeOpt))
594
595
  .on('error', err => stream.emit('error', err))
595
596
  .pipe(
596
- transformMap<DBM, Saved<BM>>(
597
+ transformMap<Saved<DBM>, Saved<BM>>(
597
598
  async dbm => {
598
599
  if (this.cfg.hooks!.afterLoad) {
599
600
  dbm = (await this.cfg.hooks!.afterLoad(dbm))!
@@ -627,7 +628,7 @@ export class CommonDao<
627
628
  .streamQuery<DBM>(q.select(['id']), opt)
628
629
  .on('error', err => stream.emit('error', err))
629
630
  .pipe(
630
- transformMapSimple<DBM, string>(objectWithId => objectWithId.id, {
631
+ transformMapSimple<Saved<DBM>, string>(r => r.id, {
631
632
  errorMode: ErrorMode.SUPPRESS, // cause .pipe() cannot propagate errors
632
633
  }),
633
634
  )
@@ -649,9 +650,9 @@ export class CommonDao<
649
650
 
650
651
  await _pipeline([
651
652
  this.cfg.db.streamQuery<DBM>(q.select(['id']), opt),
652
- transformMapSimple<DBM, string>(objectWithId => {
653
+ transformMapSimple<Saved<DBM>, string>(r => {
653
654
  count++
654
- return objectWithId.id
655
+ return r.id
655
656
  }),
656
657
  transformMap<string, void>(mapper, {
657
658
  ...opt,
@@ -674,33 +675,29 @@ export class CommonDao<
674
675
  * Mutates!
675
676
  * "Returns", just to have a type of "Saved"
676
677
  */
677
- assignIdCreatedUpdated(obj: DBM, opt?: CommonDaoOptions): DBM
678
- assignIdCreatedUpdated(obj: BM, opt?: CommonDaoOptions): Saved<BM>
679
- assignIdCreatedUpdated(obj: Unsaved<BM>, opt?: CommonDaoOptions): Saved<BM>
680
- assignIdCreatedUpdated(obj: DBM | BM | Unsaved<BM>, opt: CommonDaoOptions = {}): DBM | Saved<BM> {
678
+ assignIdCreatedUpdated<T extends BaseDBEntity>(obj: T, opt: CommonDaoOptions = {}): Saved<T> {
681
679
  const now = Math.floor(Date.now() / 1000)
682
680
 
683
- if (this.cfg.created) {
684
- ;(obj as any)['created'] ||= (obj as any)['updated'] || now
681
+ if (this.cfg.useCreatedProperty) {
682
+ obj.created ||= obj.updated || now
685
683
  }
686
684
 
687
- if (this.cfg.updated) {
688
- ;(obj as any)['updated'] =
689
- opt.preserveUpdatedCreated && (obj as any)['updated'] ? (obj as any)['updated'] : now
685
+ if (this.cfg.useUpdatedProperty) {
686
+ obj.updated = opt.preserveUpdatedCreated && obj.updated ? obj.updated : now
690
687
  }
691
688
 
692
689
  if (this.cfg.createId) {
693
- obj.id ||= this.cfg.hooks!.createNaturalId?.(obj as BM) || this.cfg.hooks!.createRandomId!()
690
+ obj.id ||= this.cfg.hooks!.createNaturalId?.(obj as any) || this.cfg.hooks!.createRandomId!()
694
691
  }
695
692
 
696
- return obj as any
693
+ return obj as Saved<T>
697
694
  }
698
695
 
699
696
  // SAVE
700
697
  /**
701
698
  * Mutates with id, created, updated
702
699
  */
703
- async save(bm: Unsaved<BM>, opt: CommonDaoSaveOptions<BM, DBM> = {}): Promise<Saved<BM>> {
700
+ async save(bm: BM, opt: CommonDaoSaveOptions<BM, DBM> = {}): Promise<Saved<BM>> {
704
701
  this.requireWriteAccess()
705
702
 
706
703
  if (opt.skipIfEquals && _deepJsonEquals(bm, opt.skipIfEquals)) {
@@ -710,7 +707,7 @@ export class CommonDao<
710
707
 
711
708
  const idWasGenerated = !bm.id && this.cfg.createId
712
709
  this.assignIdCreatedUpdated(bm, opt) // mutates
713
- let dbm = await this.bmToDBM(bm as BM, opt)
710
+ let dbm = await this.bmToDBM(bm, opt)
714
711
 
715
712
  if (this.cfg.hooks!.beforeSave) {
716
713
  dbm = (await this.cfg.hooks!.beforeSave(dbm))!
@@ -734,11 +731,11 @@ export class CommonDao<
734
731
  })
735
732
 
736
733
  if (assignGeneratedIds) {
737
- bm.id = dbm.id as any
734
+ bm.id = dbm.id
738
735
  }
739
736
 
740
737
  this.logSaveResult(started, op, table)
741
- return bm as any
738
+ return bm as Saved<BM>
742
739
  }
743
740
 
744
741
  /**
@@ -835,13 +832,13 @@ export class CommonDao<
835
832
  return await this.save(bm, opt)
836
833
  }
837
834
 
838
- async saveAsDBM(dbm: DBM, opt: CommonDaoSaveBatchOptions<DBM> = {}): Promise<DBM> {
835
+ async saveAsDBM(dbm: DBM, opt: CommonDaoSaveBatchOptions<DBM> = {}): Promise<Saved<DBM>> {
839
836
  this.requireWriteAccess()
840
837
  const table = opt.table || this.cfg.table
841
838
 
842
839
  // assigning id in case it misses the id
843
840
  // will override/set `updated` field, unless opts.preserveUpdated is set
844
- let row = dbm
841
+ let row = dbm as Saved<DBM>
845
842
  if (!opt.raw) {
846
843
  const idWasGenerated = !dbm.id && this.cfg.createId
847
844
  this.assignIdCreatedUpdated(dbm, opt) // mutates
@@ -858,7 +855,7 @@ export class CommonDao<
858
855
 
859
856
  if (this.cfg.hooks!.beforeSave) {
860
857
  row = (await this.cfg.hooks!.beforeSave(row))!
861
- if (row === null) return dbm
858
+ if (row === null) return dbm as Saved<DBM>
862
859
  }
863
860
 
864
861
  await this.cfg.db.saveBatch(table, [row], {
@@ -875,15 +872,12 @@ export class CommonDao<
875
872
  return row
876
873
  }
877
874
 
878
- async saveBatch(
879
- bms: Unsaved<BM>[],
880
- opt: CommonDaoSaveBatchOptions<DBM> = {},
881
- ): Promise<Saved<BM>[]> {
875
+ async saveBatch(bms: BM[], opt: CommonDaoSaveBatchOptions<DBM> = {}): Promise<Saved<BM>[]> {
882
876
  if (!bms.length) return []
883
877
  this.requireWriteAccess()
884
878
  const table = opt.table || this.cfg.table
885
879
  bms.forEach(bm => this.assignIdCreatedUpdated(bm, opt))
886
- let dbms = await this.bmsToDBM(bms as BM[], opt)
880
+ let dbms = await this.bmsToDBM(bms, opt)
887
881
 
888
882
  if (this.cfg.hooks!.beforeSave && dbms.length) {
889
883
  dbms = (await pMap(dbms, async dbm => await this.cfg.hooks!.beforeSave!(dbm))).filter(
@@ -914,22 +908,25 @@ export class CommonDao<
914
908
  })
915
909
 
916
910
  if (assignGeneratedIds) {
917
- dbms.forEach((dbm, i) => (bms[i]!.id = dbm.id as any))
911
+ dbms.forEach((dbm, i) => (bms[i]!.id = dbm.id))
918
912
  }
919
913
 
920
914
  this.logSaveResult(started, op, table)
921
915
 
922
- return bms as any[]
916
+ return bms as Saved<BM>[]
923
917
  }
924
918
 
925
- async saveBatchAsDBM(dbms: DBM[], opt: CommonDaoSaveBatchOptions<DBM> = {}): Promise<DBM[]> {
919
+ async saveBatchAsDBM(
920
+ dbms: DBM[],
921
+ opt: CommonDaoSaveBatchOptions<DBM> = {},
922
+ ): Promise<Saved<DBM>[]> {
926
923
  if (!dbms.length) return []
927
924
  this.requireWriteAccess()
928
925
  const table = opt.table || this.cfg.table
929
- let rows = dbms
926
+ let rows = dbms as Saved<DBM>[]
930
927
  if (!opt.raw) {
931
928
  dbms.forEach(dbm => this.assignIdCreatedUpdated(dbm, opt)) // mutates
932
- rows = this.anyToDBMs(dbms, opt)
929
+ rows = this.anyToDBMs(dbms as Saved<DBM>[], opt)
933
930
  if (opt.ensureUniqueId) throw new AppError('ensureUniqueId is not supported in saveBatch')
934
931
  }
935
932
  if (this.cfg.immutable && !opt.allowMutability && !opt.saveMethod) {
@@ -990,7 +987,7 @@ export class CommonDao<
990
987
  const { batchSize = 500, batchConcurrency = 16, errorMode } = opt
991
988
 
992
989
  return [
993
- transformMap<BM, DBM>(
990
+ transformMap<BM, Saved<DBM>>(
994
991
  async bm => {
995
992
  this.assignIdCreatedUpdated(bm, opt) // mutates
996
993
 
@@ -1083,7 +1080,7 @@ export class CommonDao<
1083
1080
 
1084
1081
  await _pipeline([
1085
1082
  this.cfg.db.streamQuery<DBM>(q.select(['id']), opt),
1086
- transformMapSimple<DBM, string>(objectWithId => objectWithId.id, {
1083
+ transformMapSimple<ObjectWithId, string>(r => r.id, {
1087
1084
  errorMode: ErrorMode.SUPPRESS,
1088
1085
  }),
1089
1086
  transformBuffer<string>({ batchSize }),
@@ -1147,13 +1144,13 @@ export class CommonDao<
1147
1144
  // CONVERSIONS
1148
1145
 
1149
1146
  async dbmToBM(_dbm: undefined, opt?: CommonDaoOptions): Promise<undefined>
1150
- async dbmToBM(_dbm?: DBM, opt?: CommonDaoOptions): Promise<Saved<BM>>
1151
- async dbmToBM(_dbm?: DBM, opt: CommonDaoOptions = {}): Promise<Saved<BM> | undefined> {
1147
+ async dbmToBM(_dbm?: Saved<DBM>, opt?: CommonDaoOptions): Promise<Saved<BM>>
1148
+ async dbmToBM(_dbm?: Saved<DBM>, opt: CommonDaoOptions = {}): Promise<Saved<BM> | undefined> {
1152
1149
  if (!_dbm) return
1153
1150
 
1154
1151
  // optimization: no need to run full joi DBM validation, cause BM validation will be run
1155
1152
  // const dbm = this.anyToDBM(_dbm, opt)
1156
- let dbm: DBM = { ..._dbm, ...this.cfg.hooks!.parseNaturalId!(_dbm.id) }
1153
+ let dbm: Saved<DBM> = { ..._dbm, ...this.cfg.hooks!.parseNaturalId!(_dbm.id) }
1157
1154
 
1158
1155
  if (opt.anonymize) {
1159
1156
  dbm = this.cfg.hooks!.anonymize!(dbm)
@@ -1167,7 +1164,7 @@ export class CommonDao<
1167
1164
  return this.validateAndConvert(bm, this.cfg.bmSchema, DBModelType.BM, opt)
1168
1165
  }
1169
1166
 
1170
- async dbmsToBM(dbms: DBM[], opt: CommonDaoOptions = {}): Promise<Saved<BM>[]> {
1167
+ async dbmsToBM(dbms: Saved<DBM>[], opt: CommonDaoOptions = {}): Promise<Saved<BM>[]> {
1171
1168
  return await pMap(dbms, async dbm => await this.dbmToBM(dbm, opt))
1172
1169
  }
1173
1170
 
@@ -1176,8 +1173,8 @@ export class CommonDao<
1176
1173
  * Returns DBM (new reference).
1177
1174
  */
1178
1175
  async bmToDBM(bm: undefined, opt?: CommonDaoOptions): Promise<undefined>
1179
- async bmToDBM(bm?: BM, opt?: CommonDaoOptions): Promise<DBM>
1180
- async bmToDBM(bm?: BM, opt?: CommonDaoOptions): Promise<DBM | undefined> {
1176
+ async bmToDBM(bm?: BM, opt?: CommonDaoOptions): Promise<Saved<DBM>>
1177
+ async bmToDBM(bm?: BM, opt?: CommonDaoOptions): Promise<Saved<DBM> | undefined> {
1181
1178
  if (bm === undefined) return
1182
1179
 
1183
1180
  // optimization: no need to run the BM validation, since DBM will be validated anyway
@@ -1196,14 +1193,14 @@ export class CommonDao<
1196
1193
  return this.validateAndConvert(dbm, this.cfg.dbmSchema, DBModelType.DBM, opt)
1197
1194
  }
1198
1195
 
1199
- async bmsToDBM(bms: BM[], opt: CommonDaoOptions = {}): Promise<DBM[]> {
1196
+ async bmsToDBM(bms: BM[], opt: CommonDaoOptions = {}): Promise<Saved<DBM>[]> {
1200
1197
  // try/catch?
1201
1198
  return await pMap(bms, async bm => await this.bmToDBM(bm, opt))
1202
1199
  }
1203
1200
 
1204
1201
  anyToDBM(dbm: undefined, opt?: CommonDaoOptions): undefined
1205
- anyToDBM(dbm?: any, opt?: CommonDaoOptions): DBM
1206
- anyToDBM(dbm?: DBM, opt: CommonDaoOptions = {}): DBM | undefined {
1202
+ anyToDBM(dbm?: any, opt?: CommonDaoOptions): Saved<DBM>
1203
+ anyToDBM(dbm?: Saved<DBM>, opt: CommonDaoOptions = {}): Saved<DBM> | undefined {
1207
1204
  if (!dbm) return
1208
1205
 
1209
1206
  // this shouldn't be happening on load! but should on save!
@@ -1219,7 +1216,7 @@ export class CommonDao<
1219
1216
  return this.validateAndConvert(dbm, this.cfg.dbmSchema, DBModelType.DBM, opt)
1220
1217
  }
1221
1218
 
1222
- anyToDBMs(entities: DBM[], opt: CommonDaoOptions = {}): DBM[] {
1219
+ anyToDBMs(entities: Saved<DBM>[], opt: CommonDaoOptions = {}): Saved<DBM>[] {
1223
1220
  return entities.map(entity => this.anyToDBM(entity, opt))
1224
1221
  }
1225
1222
 
@@ -1234,7 +1231,7 @@ export class CommonDao<
1234
1231
  // bm = this.validateAndConvert(bm, this.cfg.bmSchema, DBModelType.BM, opt)
1235
1232
 
1236
1233
  // BM > TM
1237
- const tm = this.cfg.hooks!.beforeBMToTM!(bm as any)
1234
+ const tm = this.cfg.hooks!.beforeBMToTM!(bm)
1238
1235
 
1239
1236
  // Validate/convert DBM
1240
1237
  return this.validateAndConvert(tm, this.cfg.tmSchema, DBModelType.TM, opt)
@@ -1327,7 +1324,7 @@ export class CommonDao<
1327
1324
 
1328
1325
  async createTable(schema: JsonSchemaObject<DBM>, opt?: CommonDaoCreateOptions): Promise<void> {
1329
1326
  this.requireWriteAccess()
1330
- await this.cfg.db.createTable(this.cfg.table, schema as any, opt)
1327
+ await this.cfg.db.createTable(this.cfg.table, schema, opt)
1331
1328
  }
1332
1329
 
1333
1330
  /**
@@ -1347,7 +1344,7 @@ export class CommonDao<
1347
1344
  try {
1348
1345
  await fn(daoTx)
1349
1346
  } catch (err) {
1350
- await daoTx.rollback()
1347
+ await daoTx.rollback() // graceful rollback that "never throws"
1351
1348
  throw err
1352
1349
  }
1353
1350
  }, opt)
@@ -1439,7 +1436,7 @@ export class CommonDaoTransaction {
1439
1436
  }
1440
1437
  }
1441
1438
 
1442
- async getById<BM extends Partial<ObjectWithId>, DBM extends ObjectWithId>(
1439
+ async getById<BM extends PartialObjectWithId, DBM extends PartialObjectWithId>(
1443
1440
  dao: CommonDao<BM, DBM, any>,
1444
1441
  id?: string | null,
1445
1442
  opt?: CommonDaoOptions,
@@ -1448,7 +1445,7 @@ export class CommonDaoTransaction {
1448
1445
  return (await this.getByIds(dao, [id], opt))[0] || null
1449
1446
  }
1450
1447
 
1451
- async getByIds<BM extends Partial<ObjectWithId>, DBM extends ObjectWithId>(
1448
+ async getByIds<BM extends PartialObjectWithId, DBM extends PartialObjectWithId>(
1452
1449
  dao: CommonDao<BM, DBM, any>,
1453
1450
  ids: string[],
1454
1451
  opt?: CommonDaoOptions,
@@ -1457,7 +1454,7 @@ export class CommonDaoTransaction {
1457
1454
  }
1458
1455
 
1459
1456
  // todo: Queries inside Transaction are not supported yet
1460
- // async runQuery<BM extends Partial<ObjectWithId>, DBM extends ObjectWithId>(
1457
+ // async runQuery<BM extends PartialObjectWithId, DBM extends ObjectWithId>(
1461
1458
  // dao: CommonDao<BM, DBM, any>,
1462
1459
  // q: DBQuery<DBM>,
1463
1460
  // opt?: CommonDaoOptions,
@@ -1470,17 +1467,17 @@ export class CommonDaoTransaction {
1470
1467
  // }
1471
1468
  // }
1472
1469
 
1473
- async save<BM extends Partial<ObjectWithId>, DBM extends ObjectWithId>(
1470
+ async save<BM extends PartialObjectWithId, DBM extends PartialObjectWithId>(
1474
1471
  dao: CommonDao<BM, DBM, any>,
1475
- bm: Unsaved<BM>,
1472
+ bm: BM,
1476
1473
  opt?: CommonDaoSaveBatchOptions<DBM>,
1477
1474
  ): Promise<Saved<BM>> {
1478
1475
  return (await this.saveBatch(dao, [bm], opt))[0]!
1479
1476
  }
1480
1477
 
1481
- async saveBatch<BM extends Partial<ObjectWithId>, DBM extends ObjectWithId>(
1478
+ async saveBatch<BM extends PartialObjectWithId, DBM extends PartialObjectWithId>(
1482
1479
  dao: CommonDao<BM, DBM, any>,
1483
- bms: Unsaved<BM>[],
1480
+ bms: BM[],
1484
1481
  opt?: CommonDaoSaveBatchOptions<DBM>,
1485
1482
  ): Promise<Saved<BM>[]> {
1486
1483
  return await dao.saveBatch(bms, { ...opt, tx: this.tx })