Skip to content
This repository was archived by the owner on May 25, 2025. It is now read-only.

Commit d0c0ddd

Browse files
feat: CommonKeyValueDaoMemoCacheCfg.ttl
1 parent 5eaf601 commit d0c0ddd

File tree

5 files changed

+69
-47
lines changed

5 files changed

+69
-47
lines changed

src/commondao/common.dao.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import {
1818
ErrorMode,
1919
JsonSchemaObject,
2020
JsonSchemaRootObject,
21+
nowUnix,
2122
ObjectWithId,
2223
pMap,
2324
SKIP,
@@ -606,7 +607,7 @@ export class CommonDao<BM extends BaseDBEntity, DBM extends BaseDBEntity = BM> {
606607
* "Returns", just to have a type of "Saved"
607608
*/
608609
assignIdCreatedUpdated<T extends BaseDBEntity>(obj: Partial<T>, opt: CommonDaoOptions = {}): T {
609-
const now = Math.floor(Date.now() / 1000)
610+
const now = nowUnix()
610611

611612
if (this.cfg.useCreatedProperty) {
612613
obj.created ||= obj.updated || now

src/kv/commonKeyValueDao.ts

Lines changed: 40 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,11 @@ import { AppError, CommonLogger, KeyValueTuple, pMap } from '@naturalcycles/js-l
22
import { deflateString, inflateToString, ReadableTyped } from '@naturalcycles/nodejs-lib'
33
import { CommonDaoLogLevel } from '../commondao/common.dao.model'
44
import { CommonDBCreateOptions } from '../db.model'
5-
import { CommonKeyValueDB, KeyValueDBTuple } from './commonKeyValueDB'
5+
import {
6+
CommonKeyValueDB,
7+
CommonKeyValueDBSaveBatchOptions,
8+
KeyValueDBTuple,
9+
} from './commonKeyValueDB'
610

711
export interface CommonKeyValueDaoCfg<T> {
812
db: CommonKeyValueDB
@@ -44,6 +48,8 @@ export interface CommonKeyValueDaoCfg<T> {
4448
deflatedJsonValue?: boolean
4549
}
4650

51+
export type CommonKeyValueDaoSaveOptions = CommonKeyValueDBSaveBatchOptions
52+
4753
// todo: logging
4854
// todo: readonly
4955

@@ -133,13 +139,13 @@ export class CommonKeyValueDao<T> {
133139
} as T
134140
}
135141

136-
async patch(id: string, patch: Partial<T>): Promise<T> {
142+
async patch(id: string, patch: Partial<T>, opt?: CommonKeyValueDaoSaveOptions): Promise<T> {
137143
const v: T = {
138144
...(await this.getByIdOrEmpty(id)),
139145
...patch,
140146
}
141147

142-
await this.save(id, v)
148+
await this.save(id, v, opt)
143149

144150
return v
145151
}
@@ -158,31 +164,35 @@ export class CommonKeyValueDao<T> {
158164
return await this.cfg.db.getByIds(this.cfg.table, ids)
159165
}
160166

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)
163169
}
164170

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)
167173
}
168174

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
170180
let bufferEntries: KeyValueDBTuple[]
171181

172-
if (!this.cfg.hooks.mapValueToBuffer) {
182+
if (!mapValueToBuffer) {
173183
bufferEntries = entries as any
174184
} 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)])
179186
}
180187

181-
await this.cfg.db.saveBatch(this.cfg.table, bufferEntries)
188+
await this.cfg.db.saveBatch(this.cfg.table, bufferEntries, opt)
182189
}
183190

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)
186196
}
187197

188198
async deleteByIds(ids: string[]): Promise<void> {
@@ -204,19 +214,19 @@ export class CommonKeyValueDao<T> {
204214
return this.cfg.db.streamValues(this.cfg.table, limit) as ReadableTyped<T>
205215
}
206216

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 => {
211219
try {
212220
return [await mapBufferToValue(buf)]
213221
} catch (err) {
214222
this.cfg.logger.error(err)
215223
return [] // SKIP
216224
}
217-
})
218-
219-
return stream
225+
},
226+
{
227+
concurrency: 16,
228+
},
229+
)
220230
}
221231

222232
streamEntries(limit?: number): ReadableTyped<KeyValueTuple<string, T>> {
@@ -228,18 +238,18 @@ export class CommonKeyValueDao<T> {
228238
>
229239
}
230240

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]) => {
235243
try {
236244
return [[id, await mapBufferToValue(buf)]]
237245
} catch (err) {
238246
this.cfg.logger.error(err)
239247
return [] // SKIP
240248
}
241-
})
242-
243-
return stream
249+
},
250+
{
251+
concurrency: 16,
252+
},
253+
)
244254
}
245255
}

src/kv/commonKeyValueDaoMemoCache.ts

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,15 @@
1-
import { AsyncMemoCache, MISS } from '@naturalcycles/js-lib'
1+
import { AsyncMemoCache, MISS, nowUnix, NumberOfSeconds } from '@naturalcycles/js-lib'
22
import { CommonKeyValueDao } from './commonKeyValueDao'
33

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+
413
/**
514
* AsyncMemoCache implementation, backed by CommonKeyValueDao.
615
*
@@ -10,14 +19,16 @@ import { CommonKeyValueDao } from './commonKeyValueDao'
1019
* clear the whole table/cache.
1120
*/
1221
export class CommonKeyValueDaoMemoCache<VALUE = any> implements AsyncMemoCache<string, VALUE> {
13-
constructor(private dao: CommonKeyValueDao<VALUE>) {}
22+
constructor(private cfg: CommonKeyValueDaoMemoCacheCfg<VALUE>) {}
1423

1524
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
1726
}
1827

1928
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)
2132
}
2233

2334
async clear(): Promise<void> {

src/model.util.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
import { CreatedUpdated, CreatedUpdatedId } from '@naturalcycles/js-lib'
1+
import { CreatedUpdated, CreatedUpdatedId, nowUnix } from '@naturalcycles/js-lib'
22
import { stringId } from '@naturalcycles/nodejs-lib'
33

44
export function createdUpdatedFields(
55
existingObject?: Partial<CreatedUpdated> | null,
66
): CreatedUpdated {
7-
const now = Math.floor(Date.now() / 1000)
7+
const now = nowUnix()
88
return {
99
created: existingObject?.created || now,
1010
updated: now,
@@ -14,7 +14,7 @@ export function createdUpdatedFields(
1414
export function createdUpdatedIdFields(
1515
existingObject?: Partial<CreatedUpdatedId> | null,
1616
): CreatedUpdatedId {
17-
const now = Math.floor(Date.now() / 1000)
17+
const now = nowUnix()
1818
return {
1919
created: existingObject?.created || now,
2020
id: existingObject?.id || stringId(),

yarn.lock

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -836,9 +836,9 @@
836836
typescript "^5.0.2"
837837

838838
"@naturalcycles/dev-lib@^13.0.0":
839-
version "13.51.1"
840-
resolved "https://registry.yarnpkg.com/@naturalcycles/dev-lib/-/dev-lib-13.51.1.tgz#0b96023d5cdccff5f844296ed03edbd0c7eb3d14"
841-
integrity sha512-kKul83X8hysRzeyx9KbjmoStYYFG7+zbBebEyb1WEFTdFRjx6W509pVCrqxmXSS7z7Zit0O6dVT1u5EmqQwTvA==
839+
version "13.51.2"
840+
resolved "https://registry.yarnpkg.com/@naturalcycles/dev-lib/-/dev-lib-13.51.2.tgz#7f8ea46a936849051527a958a6b17d3e970287b0"
841+
integrity sha512-N1TUk/F7iFlrtHqlNdABD0bJ3j2D9+EutH1jb7xFKg6b0R2SOEGmUr+OKG8GL75FwkJ2DEBtPXfdIbxwfRqnBw==
842842
dependencies:
843843
"@commitlint/cli" "^19.0.0"
844844
"@commitlint/config-conventional" "^19.0.0"
@@ -871,9 +871,9 @@
871871
yargs "^17.0.0"
872872

873873
"@naturalcycles/js-lib@^14.0.0", "@naturalcycles/js-lib@^14.116.0":
874-
version "14.219.2"
875-
resolved "https://registry.yarnpkg.com/@naturalcycles/js-lib/-/js-lib-14.219.2.tgz#95cc0e875e3befba83f541856ecb84b0d94667a5"
876-
integrity sha512-m68SFGyDT6s/j9kOxLsQs/5kfy4xWdJyyw/RIdR8m2svstA0bkZsgS4xYCaIX+onXDQWyEPKKH8EgqfUXPhHIA==
874+
version "14.221.0"
875+
resolved "https://registry.yarnpkg.com/@naturalcycles/js-lib/-/js-lib-14.221.0.tgz#cfd70eec1c2678f202f0982da18ff34bf7abaf6e"
876+
integrity sha512-jF00+CgTxIjwgQNGFjoZKsjrnhs5sz4CTsH0RTQfODRWfvHwld7XqY1Tzc7Rf/Patb4hTH2IwtHvGGczhPj6Zw==
877877
dependencies:
878878
tslib "^2.0.0"
879879
zod "^3.20.2"
@@ -2377,9 +2377,9 @@ eslint-plugin-import@^2.22.1:
23772377
tsconfig-paths "^3.15.0"
23782378

23792379
eslint-plugin-jest@^28.0.0:
2380-
version "28.0.0"
2381-
resolved "https://registry.yarnpkg.com/eslint-plugin-jest/-/eslint-plugin-jest-28.0.0.tgz#b18f22977c3c216de928eeae6643c231c5b47316"
2382-
integrity sha512-FHiVI/nMYy48juLJKIt34MWPemvZyl0XT8JC3HTiUu/jgKJzoGgrNTCsyq4DzMlEjPZfmXKc0ogIzfrm6DJEuQ==
2380+
version "28.2.0"
2381+
resolved "https://registry.yarnpkg.com/eslint-plugin-jest/-/eslint-plugin-jest-28.2.0.tgz#863e2b2bda95eb41981ba9bcf4c44f57dce40a73"
2382+
integrity sha512-yRDti/a+f+SMSmNTiT9/M/MzXGkitl8CfzUxnpoQcTyfq8gUrXMriVcWU36W1X6BZSUoyUCJrDAWWUA2N4hE5g==
23832383
dependencies:
23842384
"@typescript-eslint/utils" "^6.0.0"
23852385

0 commit comments

Comments
 (0)