@naturalcycles/db-lib 9.11.0 → 9.12.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.
@@ -448,7 +448,7 @@ class CommonDao {
448
448
  * "Returns", just to have a type of "Saved"
449
449
  */
450
450
  assignIdCreatedUpdated(obj, opt = {}) {
451
- const now = Math.floor(Date.now() / 1000);
451
+ const now = (0, js_lib_1.nowUnix)();
452
452
  if (this.cfg.useCreatedProperty) {
453
453
  obj.created ||= obj.updated || now;
454
454
  }
@@ -3,7 +3,7 @@ import { CommonLogger, KeyValueTuple } from '@naturalcycles/js-lib';
3
3
  import { ReadableTyped } from '@naturalcycles/nodejs-lib';
4
4
  import { CommonDaoLogLevel } from '../commondao/common.dao.model';
5
5
  import { CommonDBCreateOptions } from '../db.model';
6
- import { CommonKeyValueDB, KeyValueDBTuple } from './commonKeyValueDB';
6
+ import { CommonKeyValueDB, CommonKeyValueDBSaveBatchOptions, KeyValueDBTuple } from './commonKeyValueDB';
7
7
  export interface CommonKeyValueDaoCfg<T> {
8
8
  db: CommonKeyValueDB;
9
9
  table: string;
@@ -36,6 +36,7 @@ export interface CommonKeyValueDaoCfg<T> {
36
36
  */
37
37
  deflatedJsonValue?: boolean;
38
38
  }
39
+ export type CommonKeyValueDaoSaveOptions = CommonKeyValueDBSaveBatchOptions;
39
40
  export declare class CommonKeyValueDao<T> {
40
41
  constructor(cfg: CommonKeyValueDaoCfg<T>);
41
42
  cfg: CommonKeyValueDaoCfg<T> & {
@@ -50,13 +51,13 @@ export declare class CommonKeyValueDao<T> {
50
51
  requireById(id: string): Promise<T>;
51
52
  requireByIdAsBuffer(id: string): Promise<Buffer>;
52
53
  getByIdOrEmpty(id: string, part?: Partial<T>): Promise<T>;
53
- patch(id: string, patch: Partial<T>): Promise<T>;
54
+ patch(id: string, patch: Partial<T>, opt?: CommonKeyValueDaoSaveOptions): Promise<T>;
54
55
  getByIds(ids: string[]): Promise<KeyValueTuple<string, T>[]>;
55
56
  getByIdsAsBuffer(ids: string[]): Promise<KeyValueTuple<string, Buffer>[]>;
56
- save(id: string, value: T): Promise<void>;
57
- saveAsBuffer(id: string, value: Buffer): Promise<void>;
58
- saveBatch(entries: KeyValueTuple<string, T>[]): Promise<void>;
59
- saveBatchAsBuffer(entries: KeyValueDBTuple[]): Promise<void>;
57
+ save(id: string, value: T, opt?: CommonKeyValueDaoSaveOptions): Promise<void>;
58
+ saveAsBuffer(id: string, value: Buffer, opt?: CommonKeyValueDaoSaveOptions): Promise<void>;
59
+ saveBatch(entries: KeyValueTuple<string, T>[], opt?: CommonKeyValueDaoSaveOptions): Promise<void>;
60
+ saveBatchAsBuffer(entries: KeyValueDBTuple[], opt?: CommonKeyValueDaoSaveOptions): Promise<void>;
60
61
  deleteByIds(ids: string[]): Promise<void>;
61
62
  deleteById(id: string): Promise<void>;
62
63
  streamIds(limit?: number): ReadableTyped<string>;
@@ -74,12 +74,12 @@ class CommonKeyValueDao {
74
74
  ...part,
75
75
  };
76
76
  }
77
- async patch(id, patch) {
77
+ async patch(id, patch, opt) {
78
78
  const v = {
79
79
  ...(await this.getByIdOrEmpty(id)),
80
80
  ...patch,
81
81
  };
82
- await this.save(id, v);
82
+ await this.save(id, v, opt);
83
83
  return v;
84
84
  }
85
85
  async getByIds(ids) {
@@ -94,27 +94,25 @@ class CommonKeyValueDao {
94
94
  async getByIdsAsBuffer(ids) {
95
95
  return await this.cfg.db.getByIds(this.cfg.table, ids);
96
96
  }
97
- async save(id, value) {
98
- await this.saveBatch([[id, value]]);
97
+ async save(id, value, opt) {
98
+ await this.saveBatch([[id, value]], opt);
99
99
  }
100
- async saveAsBuffer(id, value) {
101
- await this.cfg.db.saveBatch(this.cfg.table, [[id, value]]);
100
+ async saveAsBuffer(id, value, opt) {
101
+ await this.cfg.db.saveBatch(this.cfg.table, [[id, value]], opt);
102
102
  }
103
- async saveBatch(entries) {
103
+ async saveBatch(entries, opt) {
104
+ const { mapValueToBuffer } = this.cfg.hooks;
104
105
  let bufferEntries;
105
- if (!this.cfg.hooks.mapValueToBuffer) {
106
+ if (!mapValueToBuffer) {
106
107
  bufferEntries = entries;
107
108
  }
108
109
  else {
109
- bufferEntries = await (0, js_lib_1.pMap)(entries, async ([id, v]) => [
110
- id,
111
- await this.cfg.hooks.mapValueToBuffer(v),
112
- ]);
110
+ bufferEntries = await (0, js_lib_1.pMap)(entries, async ([id, v]) => [id, await mapValueToBuffer(v)]);
113
111
  }
114
- await this.cfg.db.saveBatch(this.cfg.table, bufferEntries);
112
+ await this.cfg.db.saveBatch(this.cfg.table, bufferEntries, opt);
115
113
  }
116
- async saveBatchAsBuffer(entries) {
117
- await this.cfg.db.saveBatch(this.cfg.table, entries);
114
+ async saveBatchAsBuffer(entries, opt) {
115
+ await this.cfg.db.saveBatch(this.cfg.table, entries, opt);
118
116
  }
119
117
  async deleteByIds(ids) {
120
118
  await this.cfg.db.deleteByIds(this.cfg.table, ids);
@@ -130,10 +128,7 @@ class CommonKeyValueDao {
130
128
  if (!mapBufferToValue) {
131
129
  return this.cfg.db.streamValues(this.cfg.table, limit);
132
130
  }
133
- const stream = this.cfg.db
134
- .streamValues(this.cfg.table, limit)
135
- // .on('error', err => stream.emit('error', err))
136
- .flatMap(async (buf) => {
131
+ return this.cfg.db.streamValues(this.cfg.table, limit).flatMap(async (buf) => {
137
132
  try {
138
133
  return [await mapBufferToValue(buf)];
139
134
  }
@@ -141,18 +136,16 @@ class CommonKeyValueDao {
141
136
  this.cfg.logger.error(err);
142
137
  return []; // SKIP
143
138
  }
139
+ }, {
140
+ concurrency: 16,
144
141
  });
145
- return stream;
146
142
  }
147
143
  streamEntries(limit) {
148
144
  const { mapBufferToValue } = this.cfg.hooks;
149
145
  if (!mapBufferToValue) {
150
146
  return this.cfg.db.streamEntries(this.cfg.table, limit);
151
147
  }
152
- const stream = this.cfg.db
153
- .streamEntries(this.cfg.table, limit)
154
- // .on('error', err => stream.emit('error', err))
155
- .flatMap(async ([id, buf]) => {
148
+ return this.cfg.db.streamEntries(this.cfg.table, limit).flatMap(async ([id, buf]) => {
156
149
  try {
157
150
  return [[id, await mapBufferToValue(buf)]];
158
151
  }
@@ -160,8 +153,9 @@ class CommonKeyValueDao {
160
153
  this.cfg.logger.error(err);
161
154
  return []; // SKIP
162
155
  }
156
+ }, {
157
+ concurrency: 16,
163
158
  });
164
- return stream;
165
159
  }
166
160
  }
167
161
  exports.CommonKeyValueDao = CommonKeyValueDao;
@@ -1,5 +1,12 @@
1
- import { AsyncMemoCache, MISS } from '@naturalcycles/js-lib';
1
+ import { AsyncMemoCache, MISS, NumberOfSeconds } from '@naturalcycles/js-lib';
2
2
  import { CommonKeyValueDao } from './commonKeyValueDao';
3
+ export interface CommonKeyValueDaoMemoCacheCfg<VALUE> {
4
+ dao: CommonKeyValueDao<VALUE>;
5
+ /**
6
+ * If set, every `set()` will set `expireAt` (TTL) option.
7
+ */
8
+ ttl?: NumberOfSeconds;
9
+ }
3
10
  /**
4
11
  * AsyncMemoCache implementation, backed by CommonKeyValueDao.
5
12
  *
@@ -9,8 +16,8 @@ import { CommonKeyValueDao } from './commonKeyValueDao';
9
16
  * clear the whole table/cache.
10
17
  */
11
18
  export declare class CommonKeyValueDaoMemoCache<VALUE = any> implements AsyncMemoCache<string, VALUE> {
12
- private dao;
13
- constructor(dao: CommonKeyValueDao<VALUE>);
19
+ private cfg;
20
+ constructor(cfg: CommonKeyValueDaoMemoCacheCfg<VALUE>);
14
21
  get(k: string): Promise<VALUE | typeof MISS>;
15
22
  set(k: string, v: VALUE): Promise<void>;
16
23
  clear(): Promise<void>;
@@ -11,14 +11,15 @@ const js_lib_1 = require("@naturalcycles/js-lib");
11
11
  * clear the whole table/cache.
12
12
  */
13
13
  class CommonKeyValueDaoMemoCache {
14
- constructor(dao) {
15
- this.dao = dao;
14
+ constructor(cfg) {
15
+ this.cfg = cfg;
16
16
  }
17
17
  async get(k) {
18
- return (await this.dao.getById(k)) || js_lib_1.MISS;
18
+ return (await this.cfg.dao.getById(k)) || js_lib_1.MISS;
19
19
  }
20
20
  async set(k, v) {
21
- await this.dao.save(k, v);
21
+ const opt = this.cfg.ttl ? { expireAt: (0, js_lib_1.nowUnix)() + this.cfg.ttl } : undefined;
22
+ await this.cfg.dao.save(k, v, opt);
22
23
  }
23
24
  async clear() {
24
25
  throw new Error('CommonKeyValueDaoMemoCache.clear is not supported, because cache is expected to be persistent');
@@ -1,9 +1,10 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.serializeJsonField = exports.deserializeJsonField = exports.createdUpdatedIdFields = exports.createdUpdatedFields = void 0;
4
+ const js_lib_1 = require("@naturalcycles/js-lib");
4
5
  const nodejs_lib_1 = require("@naturalcycles/nodejs-lib");
5
6
  function createdUpdatedFields(existingObject) {
6
- const now = Math.floor(Date.now() / 1000);
7
+ const now = (0, js_lib_1.nowUnix)();
7
8
  return {
8
9
  created: existingObject?.created || now,
9
10
  updated: now,
@@ -11,7 +12,7 @@ function createdUpdatedFields(existingObject) {
11
12
  }
12
13
  exports.createdUpdatedFields = createdUpdatedFields;
13
14
  function createdUpdatedIdFields(existingObject) {
14
- const now = Math.floor(Date.now() / 1000);
15
+ const now = (0, js_lib_1.nowUnix)();
15
16
  return {
16
17
  created: existingObject?.created || now,
17
18
  id: existingObject?.id || (0, nodejs_lib_1.stringId)(),
package/package.json CHANGED
@@ -40,7 +40,7 @@
40
40
  "engines": {
41
41
  "node": ">=18.12"
42
42
  },
43
- "version": "9.11.0",
43
+ "version": "9.12.0",
44
44
  "description": "Lowest Common Denominator API to supported Databases",
45
45
  "keywords": [
46
46
  "db",
@@ -18,6 +18,7 @@ import {
18
18
  ErrorMode,
19
19
  JsonSchemaObject,
20
20
  JsonSchemaRootObject,
21
+ nowUnix,
21
22
  ObjectWithId,
22
23
  pMap,
23
24
  SKIP,
@@ -606,7 +607,7 @@ export class CommonDao<BM extends BaseDBEntity, DBM extends BaseDBEntity = BM> {
606
607
  * "Returns", just to have a type of "Saved"
607
608
  */
608
609
  assignIdCreatedUpdated<T extends BaseDBEntity>(obj: Partial<T>, opt: CommonDaoOptions = {}): T {
609
- const now = Math.floor(Date.now() / 1000)
610
+ const now = nowUnix()
610
611
 
611
612
  if (this.cfg.useCreatedProperty) {
612
613
  obj.created ||= obj.updated || now
@@ -2,7 +2,11 @@ import { AppError, CommonLogger, KeyValueTuple, pMap } from '@naturalcycles/js-l
2
2
  import { deflateString, inflateToString, ReadableTyped } from '@naturalcycles/nodejs-lib'
3
3
  import { CommonDaoLogLevel } from '../commondao/common.dao.model'
4
4
  import { CommonDBCreateOptions } from '../db.model'
5
- import { CommonKeyValueDB, KeyValueDBTuple } from './commonKeyValueDB'
5
+ import {
6
+ CommonKeyValueDB,
7
+ CommonKeyValueDBSaveBatchOptions,
8
+ KeyValueDBTuple,
9
+ } from './commonKeyValueDB'
6
10
 
7
11
  export interface CommonKeyValueDaoCfg<T> {
8
12
  db: CommonKeyValueDB
@@ -44,6 +48,8 @@ export interface CommonKeyValueDaoCfg<T> {
44
48
  deflatedJsonValue?: boolean
45
49
  }
46
50
 
51
+ export type CommonKeyValueDaoSaveOptions = CommonKeyValueDBSaveBatchOptions
52
+
47
53
  // todo: logging
48
54
  // todo: readonly
49
55
 
@@ -133,13 +139,13 @@ export class CommonKeyValueDao<T> {
133
139
  } as T
134
140
  }
135
141
 
136
- async patch(id: string, patch: Partial<T>): Promise<T> {
142
+ async patch(id: string, patch: Partial<T>, opt?: CommonKeyValueDaoSaveOptions): Promise<T> {
137
143
  const v: T = {
138
144
  ...(await this.getByIdOrEmpty(id)),
139
145
  ...patch,
140
146
  }
141
147
 
142
- await this.save(id, v)
148
+ await this.save(id, v, opt)
143
149
 
144
150
  return v
145
151
  }
@@ -158,31 +164,35 @@ export class CommonKeyValueDao<T> {
158
164
  return await this.cfg.db.getByIds(this.cfg.table, ids)
159
165
  }
160
166
 
161
- async save(id: string, value: T): Promise<void> {
162
- await this.saveBatch([[id, value]])
167
+ async save(id: string, value: T, opt?: CommonKeyValueDaoSaveOptions): Promise<void> {
168
+ await this.saveBatch([[id, value]], opt)
163
169
  }
164
170
 
165
- async saveAsBuffer(id: string, value: Buffer): Promise<void> {
166
- await this.cfg.db.saveBatch(this.cfg.table, [[id, value]])
171
+ async saveAsBuffer(id: string, value: Buffer, opt?: CommonKeyValueDaoSaveOptions): Promise<void> {
172
+ await this.cfg.db.saveBatch(this.cfg.table, [[id, value]], opt)
167
173
  }
168
174
 
169
- async saveBatch(entries: KeyValueTuple<string, T>[]): Promise<void> {
175
+ async saveBatch(
176
+ entries: KeyValueTuple<string, T>[],
177
+ opt?: CommonKeyValueDaoSaveOptions,
178
+ ): Promise<void> {
179
+ const { mapValueToBuffer } = this.cfg.hooks
170
180
  let bufferEntries: KeyValueDBTuple[]
171
181
 
172
- if (!this.cfg.hooks.mapValueToBuffer) {
182
+ if (!mapValueToBuffer) {
173
183
  bufferEntries = entries as any
174
184
  } else {
175
- bufferEntries = await pMap(entries, async ([id, v]) => [
176
- id,
177
- await this.cfg.hooks.mapValueToBuffer!(v),
178
- ])
185
+ bufferEntries = await pMap(entries, async ([id, v]) => [id, await mapValueToBuffer(v)])
179
186
  }
180
187
 
181
- await this.cfg.db.saveBatch(this.cfg.table, bufferEntries)
188
+ await this.cfg.db.saveBatch(this.cfg.table, bufferEntries, opt)
182
189
  }
183
190
 
184
- async saveBatchAsBuffer(entries: KeyValueDBTuple[]): Promise<void> {
185
- await this.cfg.db.saveBatch(this.cfg.table, entries)
191
+ async saveBatchAsBuffer(
192
+ entries: KeyValueDBTuple[],
193
+ opt?: CommonKeyValueDaoSaveOptions,
194
+ ): Promise<void> {
195
+ await this.cfg.db.saveBatch(this.cfg.table, entries, opt)
186
196
  }
187
197
 
188
198
  async deleteByIds(ids: string[]): Promise<void> {
@@ -204,19 +214,19 @@ export class CommonKeyValueDao<T> {
204
214
  return this.cfg.db.streamValues(this.cfg.table, limit) as ReadableTyped<T>
205
215
  }
206
216
 
207
- const stream: ReadableTyped<T> = this.cfg.db
208
- .streamValues(this.cfg.table, limit)
209
- // .on('error', err => stream.emit('error', err))
210
- .flatMap(async buf => {
217
+ return this.cfg.db.streamValues(this.cfg.table, limit).flatMap(
218
+ async buf => {
211
219
  try {
212
220
  return [await mapBufferToValue(buf)]
213
221
  } catch (err) {
214
222
  this.cfg.logger.error(err)
215
223
  return [] // SKIP
216
224
  }
217
- })
218
-
219
- return stream
225
+ },
226
+ {
227
+ concurrency: 16,
228
+ },
229
+ )
220
230
  }
221
231
 
222
232
  streamEntries(limit?: number): ReadableTyped<KeyValueTuple<string, T>> {
@@ -228,18 +238,18 @@ export class CommonKeyValueDao<T> {
228
238
  >
229
239
  }
230
240
 
231
- const stream: ReadableTyped<KeyValueTuple<string, T>> = this.cfg.db
232
- .streamEntries(this.cfg.table, limit)
233
- // .on('error', err => stream.emit('error', err))
234
- .flatMap(async ([id, buf]) => {
241
+ return this.cfg.db.streamEntries(this.cfg.table, limit).flatMap(
242
+ async ([id, buf]) => {
235
243
  try {
236
244
  return [[id, await mapBufferToValue(buf)]]
237
245
  } catch (err) {
238
246
  this.cfg.logger.error(err)
239
247
  return [] // SKIP
240
248
  }
241
- })
242
-
243
- return stream
249
+ },
250
+ {
251
+ concurrency: 16,
252
+ },
253
+ )
244
254
  }
245
255
  }
@@ -1,6 +1,15 @@
1
- import { AsyncMemoCache, MISS } from '@naturalcycles/js-lib'
1
+ import { AsyncMemoCache, MISS, nowUnix, NumberOfSeconds } from '@naturalcycles/js-lib'
2
2
  import { CommonKeyValueDao } from './commonKeyValueDao'
3
3
 
4
+ export interface CommonKeyValueDaoMemoCacheCfg<VALUE> {
5
+ dao: CommonKeyValueDao<VALUE>
6
+
7
+ /**
8
+ * If set, every `set()` will set `expireAt` (TTL) option.
9
+ */
10
+ ttl?: NumberOfSeconds
11
+ }
12
+
4
13
  /**
5
14
  * AsyncMemoCache implementation, backed by CommonKeyValueDao.
6
15
  *
@@ -10,14 +19,16 @@ import { CommonKeyValueDao } from './commonKeyValueDao'
10
19
  * clear the whole table/cache.
11
20
  */
12
21
  export class CommonKeyValueDaoMemoCache<VALUE = any> implements AsyncMemoCache<string, VALUE> {
13
- constructor(private dao: CommonKeyValueDao<VALUE>) {}
22
+ constructor(private cfg: CommonKeyValueDaoMemoCacheCfg<VALUE>) {}
14
23
 
15
24
  async get(k: string): Promise<VALUE | typeof MISS> {
16
- return (await this.dao.getById(k)) || MISS
25
+ return (await this.cfg.dao.getById(k)) || MISS
17
26
  }
18
27
 
19
28
  async set(k: string, v: VALUE): Promise<void> {
20
- await this.dao.save(k, v)
29
+ const opt = this.cfg.ttl ? { expireAt: nowUnix() + this.cfg.ttl } : undefined
30
+
31
+ await this.cfg.dao.save(k, v, opt)
21
32
  }
22
33
 
23
34
  async clear(): Promise<void> {
package/src/model.util.ts CHANGED
@@ -1,10 +1,10 @@
1
- import { CreatedUpdated, CreatedUpdatedId } from '@naturalcycles/js-lib'
1
+ import { CreatedUpdated, CreatedUpdatedId, nowUnix } from '@naturalcycles/js-lib'
2
2
  import { stringId } from '@naturalcycles/nodejs-lib'
3
3
 
4
4
  export function createdUpdatedFields(
5
5
  existingObject?: Partial<CreatedUpdated> | null,
6
6
  ): CreatedUpdated {
7
- const now = Math.floor(Date.now() / 1000)
7
+ const now = nowUnix()
8
8
  return {
9
9
  created: existingObject?.created || now,
10
10
  updated: now,
@@ -14,7 +14,7 @@ export function createdUpdatedFields(
14
14
  export function createdUpdatedIdFields(
15
15
  existingObject?: Partial<CreatedUpdatedId> | null,
16
16
  ): CreatedUpdatedId {
17
- const now = Math.floor(Date.now() / 1000)
17
+ const now = nowUnix()
18
18
  return {
19
19
  created: existingObject?.created || now,
20
20
  id: existingObject?.id || stringId(),