@naturalcycles/db-lib 9.19.0 → 9.21.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.
- package/dist/adapter/inmemory/inMemoryKeyValueDB.d.ts +4 -0
- package/dist/adapter/inmemory/inMemoryKeyValueDB.js +4 -0
- package/dist/common.db.d.ts +0 -15
- package/dist/kv/commonKeyValueDB.d.ts +20 -8
- package/dist/kv/commonKeyValueDB.js +5 -0
- package/dist/kv/commonKeyValueDao.d.ts +29 -26
- package/dist/kv/commonKeyValueDao.js +10 -1
- package/dist/testing/keyValueDBTest.js +20 -15
- package/dist/testing/keyValueDaoTest.js +15 -12
- package/package.json +1 -1
- package/src/adapter/inmemory/inMemoryKeyValueDB.ts +9 -1
- package/src/common.db.ts +0 -17
- package/src/kv/commonKeyValueDB.ts +28 -10
- package/src/kv/commonKeyValueDao.ts +48 -36
- package/src/testing/keyValueDBTest.ts +21 -15
- package/src/testing/keyValueDaoTest.ts +16 -12
|
@@ -7,6 +7,10 @@ export interface InMemoryKeyValueDBCfg {
|
|
|
7
7
|
export declare class InMemoryKeyValueDB implements CommonKeyValueDB {
|
|
8
8
|
cfg: InMemoryKeyValueDBCfg;
|
|
9
9
|
constructor(cfg?: InMemoryKeyValueDBCfg);
|
|
10
|
+
support: {
|
|
11
|
+
count?: boolean;
|
|
12
|
+
increment?: boolean;
|
|
13
|
+
};
|
|
10
14
|
data: StringMap<StringMap<Buffer>>;
|
|
11
15
|
ping(): Promise<void>;
|
|
12
16
|
createTable(_table: string, _opt?: CommonDBCreateOptions): Promise<void>;
|
|
@@ -2,9 +2,13 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.InMemoryKeyValueDB = void 0;
|
|
4
4
|
const node_stream_1 = require("node:stream");
|
|
5
|
+
const commonKeyValueDB_1 = require("../../kv/commonKeyValueDB");
|
|
5
6
|
class InMemoryKeyValueDB {
|
|
6
7
|
constructor(cfg = {}) {
|
|
7
8
|
this.cfg = cfg;
|
|
9
|
+
this.support = {
|
|
10
|
+
...commonKeyValueDB_1.commonKeyValueDBFullSupport,
|
|
11
|
+
};
|
|
8
12
|
// data[table][id] > Buffer
|
|
9
13
|
this.data = {};
|
|
10
14
|
}
|
package/dist/common.db.d.ts
CHANGED
|
@@ -15,21 +15,6 @@ export interface CommonDB {
|
|
|
15
15
|
* Manifest of supported features.
|
|
16
16
|
*/
|
|
17
17
|
support: CommonDBSupport;
|
|
18
|
-
supportsQueries?: boolean;
|
|
19
|
-
supportsDBQueryFilter?: boolean;
|
|
20
|
-
supportsDBQueryFilterIn?: boolean;
|
|
21
|
-
supportsDBQueryOrder?: boolean;
|
|
22
|
-
supportsDBQuerySelectFields?: boolean;
|
|
23
|
-
supportsInsertSaveMethod?: boolean;
|
|
24
|
-
supportsUpdateSaveMethod?: boolean;
|
|
25
|
-
supportsUpdateByQuery?: boolean;
|
|
26
|
-
supportsDBIncrement?: boolean;
|
|
27
|
-
supportsCreateTable?: boolean;
|
|
28
|
-
supportsTableSchemas?: boolean;
|
|
29
|
-
supportsStreaming?: boolean;
|
|
30
|
-
supportsBufferValues?: boolean;
|
|
31
|
-
supportsNullValues?: boolean;
|
|
32
|
-
supportsTransactions?: boolean;
|
|
33
18
|
/**
|
|
34
19
|
* Checks that connection/credentials/etc is ok.
|
|
35
20
|
* Also acts as a "warmup request" for a DB.
|
|
@@ -1,20 +1,16 @@
|
|
|
1
1
|
import { UnixTimestampNumber } from '@naturalcycles/js-lib';
|
|
2
2
|
import { ReadableTyped } from '@naturalcycles/nodejs-lib';
|
|
3
3
|
import { CommonDBCreateOptions } from '../db.model';
|
|
4
|
-
export type KeyValueDBTuple = [key: string, value: Buffer];
|
|
5
|
-
export interface CommonKeyValueDBSaveBatchOptions {
|
|
6
|
-
/**
|
|
7
|
-
* If set (and if it's implemented by the driver) - will set expiry TTL for each key of the batch.
|
|
8
|
-
* E.g EXAT in Redis.
|
|
9
|
-
*/
|
|
10
|
-
expireAt?: UnixTimestampNumber;
|
|
11
|
-
}
|
|
12
4
|
/**
|
|
13
5
|
* Common interface for Key-Value database implementations.
|
|
14
6
|
*
|
|
15
7
|
* @experimental
|
|
16
8
|
*/
|
|
17
9
|
export interface CommonKeyValueDB {
|
|
10
|
+
/**
|
|
11
|
+
* Manifest of supported features.
|
|
12
|
+
*/
|
|
13
|
+
support: CommonKeyValueDBSupport;
|
|
18
14
|
/**
|
|
19
15
|
* Check that DB connection is working properly.
|
|
20
16
|
*/
|
|
@@ -45,3 +41,19 @@ export interface CommonKeyValueDB {
|
|
|
45
41
|
*/
|
|
46
42
|
increment: (table: string, id: string, by?: number) => Promise<number>;
|
|
47
43
|
}
|
|
44
|
+
export type KeyValueDBTuple = [key: string, value: Buffer];
|
|
45
|
+
export interface CommonKeyValueDBSaveBatchOptions {
|
|
46
|
+
/**
|
|
47
|
+
* If set (and if it's implemented by the driver) - will set expiry TTL for each key of the batch.
|
|
48
|
+
* E.g EXAT in Redis.
|
|
49
|
+
*/
|
|
50
|
+
expireAt?: UnixTimestampNumber;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Manifest of supported features.
|
|
54
|
+
*/
|
|
55
|
+
export interface CommonKeyValueDBSupport {
|
|
56
|
+
count?: boolean;
|
|
57
|
+
increment?: boolean;
|
|
58
|
+
}
|
|
59
|
+
export declare const commonKeyValueDBFullSupport: CommonKeyValueDBSupport;
|
|
@@ -3,7 +3,7 @@ import { ReadableTyped } from '@naturalcycles/nodejs-lib';
|
|
|
3
3
|
import { CommonDaoLogLevel } from '../commondao/common.dao.model';
|
|
4
4
|
import { CommonDBCreateOptions } from '../db.model';
|
|
5
5
|
import { CommonKeyValueDB, CommonKeyValueDBSaveBatchOptions, KeyValueDBTuple } from './commonKeyValueDB';
|
|
6
|
-
export interface CommonKeyValueDaoCfg<
|
|
6
|
+
export interface CommonKeyValueDaoCfg<V> {
|
|
7
7
|
db: CommonKeyValueDB;
|
|
8
8
|
table: string;
|
|
9
9
|
/**
|
|
@@ -24,9 +24,9 @@ export interface CommonKeyValueDaoCfg<T> {
|
|
|
24
24
|
*/
|
|
25
25
|
logStarted?: boolean;
|
|
26
26
|
hooks?: {
|
|
27
|
-
mapValueToBuffer?: (v:
|
|
28
|
-
mapBufferToValue?: (b: Buffer) => Promise<
|
|
29
|
-
beforeCreate?: (v: Partial<
|
|
27
|
+
mapValueToBuffer?: (v: V) => Promise<Buffer>;
|
|
28
|
+
mapBufferToValue?: (b: Buffer) => Promise<V>;
|
|
29
|
+
beforeCreate?: (v: Partial<V>) => Partial<V>;
|
|
30
30
|
};
|
|
31
31
|
/**
|
|
32
32
|
* Set to `true` to conveniently enable zipping+JSON.stringify
|
|
@@ -36,37 +36,40 @@ export interface CommonKeyValueDaoCfg<T> {
|
|
|
36
36
|
deflatedJsonValue?: boolean;
|
|
37
37
|
}
|
|
38
38
|
export type CommonKeyValueDaoSaveOptions = CommonKeyValueDBSaveBatchOptions;
|
|
39
|
-
export declare class CommonKeyValueDao<
|
|
40
|
-
constructor(cfg: CommonKeyValueDaoCfg<
|
|
41
|
-
cfg: CommonKeyValueDaoCfg<
|
|
42
|
-
hooks: NonNullable<CommonKeyValueDaoCfg<
|
|
39
|
+
export declare class CommonKeyValueDao<V, K extends string = string> {
|
|
40
|
+
constructor(cfg: CommonKeyValueDaoCfg<V>);
|
|
41
|
+
cfg: CommonKeyValueDaoCfg<V> & {
|
|
42
|
+
hooks: NonNullable<CommonKeyValueDaoCfg<V>['hooks']>;
|
|
43
43
|
logger: CommonLogger;
|
|
44
44
|
};
|
|
45
45
|
ping(): Promise<void>;
|
|
46
46
|
createTable(opt?: CommonDBCreateOptions): Promise<void>;
|
|
47
|
-
create(input?: Partial<
|
|
48
|
-
getById(id?:
|
|
49
|
-
getByIdAsBuffer(id?:
|
|
50
|
-
requireById(id:
|
|
51
|
-
requireByIdAsBuffer(id:
|
|
52
|
-
getByIdOrEmpty(id:
|
|
53
|
-
patch(id:
|
|
54
|
-
getByIds(ids:
|
|
55
|
-
getByIdsAsBuffer(ids:
|
|
56
|
-
save(id:
|
|
57
|
-
saveAsBuffer(id:
|
|
58
|
-
saveBatch(entries: KeyValueTuple<
|
|
47
|
+
create(input?: Partial<V>): V;
|
|
48
|
+
getById(id?: K): Promise<V | null>;
|
|
49
|
+
getByIdAsBuffer(id?: K): Promise<Buffer | null>;
|
|
50
|
+
requireById(id: K): Promise<V>;
|
|
51
|
+
requireByIdAsBuffer(id: K): Promise<Buffer>;
|
|
52
|
+
getByIdOrEmpty(id: K, part?: Partial<V>): Promise<V>;
|
|
53
|
+
patch(id: K, patch: Partial<V>, opt?: CommonKeyValueDaoSaveOptions): Promise<V>;
|
|
54
|
+
getByIds(ids: K[]): Promise<KeyValueTuple<string, V>[]>;
|
|
55
|
+
getByIdsAsBuffer(ids: K[]): Promise<KeyValueTuple<K, Buffer>[]>;
|
|
56
|
+
save(id: K, value: V, opt?: CommonKeyValueDaoSaveOptions): Promise<void>;
|
|
57
|
+
saveAsBuffer(id: K, value: Buffer, opt?: CommonKeyValueDaoSaveOptions): Promise<void>;
|
|
58
|
+
saveBatch(entries: KeyValueTuple<K, V>[], opt?: CommonKeyValueDaoSaveOptions): Promise<void>;
|
|
59
59
|
saveBatchAsBuffer(entries: KeyValueDBTuple[], opt?: CommonKeyValueDaoSaveOptions): Promise<void>;
|
|
60
|
-
deleteByIds(ids:
|
|
61
|
-
deleteById(id:
|
|
62
|
-
streamIds(limit?: number): ReadableTyped<
|
|
63
|
-
streamValues(limit?: number): ReadableTyped<
|
|
64
|
-
streamEntries(limit?: number): ReadableTyped<KeyValueTuple<
|
|
60
|
+
deleteByIds(ids: K[]): Promise<void>;
|
|
61
|
+
deleteById(id: K): Promise<void>;
|
|
62
|
+
streamIds(limit?: number): ReadableTyped<K>;
|
|
63
|
+
streamValues(limit?: number): ReadableTyped<V>;
|
|
64
|
+
streamEntries(limit?: number): ReadableTyped<KeyValueTuple<K, V>>;
|
|
65
|
+
getAllKeys(limit?: number): Promise<K[]>;
|
|
66
|
+
getAllValues(limit?: number): Promise<V[]>;
|
|
67
|
+
getAllEntries(limit?: number): Promise<KeyValueTuple<K, V>[]>;
|
|
65
68
|
/**
|
|
66
69
|
* Increments the `id` field by the amount specified in `by`,
|
|
67
70
|
* or by 1 if `by` is not specified.
|
|
68
71
|
*
|
|
69
72
|
* Returns the new value of the field.
|
|
70
73
|
*/
|
|
71
|
-
increment(id:
|
|
74
|
+
increment(id: K, by?: number): Promise<number>;
|
|
72
75
|
}
|
|
@@ -92,7 +92,7 @@ class CommonKeyValueDao {
|
|
|
92
92
|
]);
|
|
93
93
|
}
|
|
94
94
|
async getByIdsAsBuffer(ids) {
|
|
95
|
-
return await this.cfg.db.getByIds(this.cfg.table, ids);
|
|
95
|
+
return (await this.cfg.db.getByIds(this.cfg.table, ids));
|
|
96
96
|
}
|
|
97
97
|
async save(id, value, opt) {
|
|
98
98
|
await this.saveBatch([[id, value]], opt);
|
|
@@ -157,6 +157,15 @@ class CommonKeyValueDao {
|
|
|
157
157
|
concurrency: 32,
|
|
158
158
|
});
|
|
159
159
|
}
|
|
160
|
+
async getAllKeys(limit) {
|
|
161
|
+
return await this.streamIds(limit).toArray();
|
|
162
|
+
}
|
|
163
|
+
async getAllValues(limit) {
|
|
164
|
+
return await this.streamValues(limit).toArray();
|
|
165
|
+
}
|
|
166
|
+
async getAllEntries(limit) {
|
|
167
|
+
return await this.streamEntries(limit).toArray();
|
|
168
|
+
}
|
|
160
169
|
/**
|
|
161
170
|
* Increments the `id` field by the amount specified in `by`,
|
|
162
171
|
* or by 1 if `by` is not specified.
|
|
@@ -18,6 +18,7 @@ function runCommonKeyValueDBTest(db) {
|
|
|
18
18
|
const ids = await db.streamIds(test_model_1.TEST_TABLE).toArray();
|
|
19
19
|
await db.deleteByIds(test_model_1.TEST_TABLE, ids);
|
|
20
20
|
});
|
|
21
|
+
const { support } = db;
|
|
21
22
|
test('ping', async () => {
|
|
22
23
|
await db.ping();
|
|
23
24
|
});
|
|
@@ -40,9 +41,11 @@ function runCommonKeyValueDBTest(db) {
|
|
|
40
41
|
(0, js_lib_1._sortBy)(entries, e => e[0], true);
|
|
41
42
|
expect(entries).toEqual(testEntries);
|
|
42
43
|
});
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
44
|
+
if (support.count) {
|
|
45
|
+
test('count should be 3', async () => {
|
|
46
|
+
expect(await db.count(test_model_1.TEST_TABLE)).toBe(3);
|
|
47
|
+
});
|
|
48
|
+
}
|
|
46
49
|
test('streamIds', async () => {
|
|
47
50
|
const ids = await db.streamIds(test_model_1.TEST_TABLE).toArray();
|
|
48
51
|
ids.sort();
|
|
@@ -82,16 +85,18 @@ function runCommonKeyValueDBTest(db) {
|
|
|
82
85
|
const results = await db.getByIds(test_model_1.TEST_TABLE, testIds);
|
|
83
86
|
expect(results).toEqual([]);
|
|
84
87
|
});
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
88
|
+
if (support.increment) {
|
|
89
|
+
test('increment on a non-existing field should set the value to 1', async () => {
|
|
90
|
+
const result = await db.increment(test_model_1.TEST_TABLE, 'nonExistingField');
|
|
91
|
+
expect(result).toBe(1);
|
|
92
|
+
});
|
|
93
|
+
test('increment on a existing field should increase the value by one', async () => {
|
|
94
|
+
const result = await db.increment(test_model_1.TEST_TABLE, 'nonExistingField');
|
|
95
|
+
expect(result).toBe(2);
|
|
96
|
+
});
|
|
97
|
+
test('increment should increase the value by the specified amount', async () => {
|
|
98
|
+
const result = await db.increment(test_model_1.TEST_TABLE, 'nonExistingField', 2);
|
|
99
|
+
expect(result).toBe(4);
|
|
100
|
+
});
|
|
101
|
+
}
|
|
97
102
|
}
|
|
@@ -17,6 +17,7 @@ function runCommonKeyValueDaoTest(dao) {
|
|
|
17
17
|
const ids = await dao.streamIds().toArray();
|
|
18
18
|
await dao.deleteByIds(ids);
|
|
19
19
|
});
|
|
20
|
+
const { support } = dao.cfg.db;
|
|
20
21
|
test('ping', async () => {
|
|
21
22
|
await dao.ping();
|
|
22
23
|
});
|
|
@@ -75,16 +76,18 @@ function runCommonKeyValueDaoTest(dao) {
|
|
|
75
76
|
const results = await dao.getByIds(testIds);
|
|
76
77
|
expect(results).toEqual([]);
|
|
77
78
|
});
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
79
|
+
if (support.increment) {
|
|
80
|
+
test('increment on a non-existing field should set the value to 1', async () => {
|
|
81
|
+
const result = await dao.increment('nonExistingField');
|
|
82
|
+
expect(result).toBe(1);
|
|
83
|
+
});
|
|
84
|
+
test('increment on a existing field should increase the value by one', async () => {
|
|
85
|
+
const result = await dao.increment('nonExistingField');
|
|
86
|
+
expect(result).toBe(2);
|
|
87
|
+
});
|
|
88
|
+
test('increment should increase the value by the specified amount', async () => {
|
|
89
|
+
const result = await dao.increment('nonExistingField', 2);
|
|
90
|
+
expect(result).toBe(4);
|
|
91
|
+
});
|
|
92
|
+
}
|
|
90
93
|
}
|
package/package.json
CHANGED
|
@@ -2,13 +2,21 @@ import { Readable } from 'node:stream'
|
|
|
2
2
|
import { StringMap } from '@naturalcycles/js-lib'
|
|
3
3
|
import { ReadableTyped } from '@naturalcycles/nodejs-lib'
|
|
4
4
|
import { CommonDBCreateOptions } from '../../db.model'
|
|
5
|
-
import {
|
|
5
|
+
import {
|
|
6
|
+
CommonKeyValueDB,
|
|
7
|
+
commonKeyValueDBFullSupport,
|
|
8
|
+
KeyValueDBTuple,
|
|
9
|
+
} from '../../kv/commonKeyValueDB'
|
|
6
10
|
|
|
7
11
|
export interface InMemoryKeyValueDBCfg {}
|
|
8
12
|
|
|
9
13
|
export class InMemoryKeyValueDB implements CommonKeyValueDB {
|
|
10
14
|
constructor(public cfg: InMemoryKeyValueDBCfg = {}) {}
|
|
11
15
|
|
|
16
|
+
support = {
|
|
17
|
+
...commonKeyValueDBFullSupport,
|
|
18
|
+
}
|
|
19
|
+
|
|
12
20
|
// data[table][id] > Buffer
|
|
13
21
|
data: StringMap<StringMap<Buffer>> = {}
|
|
14
22
|
|
package/src/common.db.ts
CHANGED
|
@@ -28,23 +28,6 @@ export interface CommonDB {
|
|
|
28
28
|
*/
|
|
29
29
|
support: CommonDBSupport
|
|
30
30
|
|
|
31
|
-
// Support flags indicate which of the CommonDB features are supported by this implementation.
|
|
32
|
-
supportsQueries?: boolean
|
|
33
|
-
supportsDBQueryFilter?: boolean
|
|
34
|
-
supportsDBQueryFilterIn?: boolean
|
|
35
|
-
supportsDBQueryOrder?: boolean
|
|
36
|
-
supportsDBQuerySelectFields?: boolean
|
|
37
|
-
supportsInsertSaveMethod?: boolean
|
|
38
|
-
supportsUpdateSaveMethod?: boolean
|
|
39
|
-
supportsUpdateByQuery?: boolean
|
|
40
|
-
supportsDBIncrement?: boolean
|
|
41
|
-
supportsCreateTable?: boolean
|
|
42
|
-
supportsTableSchemas?: boolean
|
|
43
|
-
supportsStreaming?: boolean
|
|
44
|
-
supportsBufferValues?: boolean
|
|
45
|
-
supportsNullValues?: boolean
|
|
46
|
-
supportsTransactions?: boolean
|
|
47
|
-
|
|
48
31
|
/**
|
|
49
32
|
* Checks that connection/credentials/etc is ok.
|
|
50
33
|
* Also acts as a "warmup request" for a DB.
|
|
@@ -2,22 +2,17 @@ import { UnixTimestampNumber } from '@naturalcycles/js-lib'
|
|
|
2
2
|
import { ReadableTyped } from '@naturalcycles/nodejs-lib'
|
|
3
3
|
import { CommonDBCreateOptions } from '../db.model'
|
|
4
4
|
|
|
5
|
-
export type KeyValueDBTuple = [key: string, value: Buffer]
|
|
6
|
-
|
|
7
|
-
export interface CommonKeyValueDBSaveBatchOptions {
|
|
8
|
-
/**
|
|
9
|
-
* If set (and if it's implemented by the driver) - will set expiry TTL for each key of the batch.
|
|
10
|
-
* E.g EXAT in Redis.
|
|
11
|
-
*/
|
|
12
|
-
expireAt?: UnixTimestampNumber
|
|
13
|
-
}
|
|
14
|
-
|
|
15
5
|
/**
|
|
16
6
|
* Common interface for Key-Value database implementations.
|
|
17
7
|
*
|
|
18
8
|
* @experimental
|
|
19
9
|
*/
|
|
20
10
|
export interface CommonKeyValueDB {
|
|
11
|
+
/**
|
|
12
|
+
* Manifest of supported features.
|
|
13
|
+
*/
|
|
14
|
+
support: CommonKeyValueDBSupport
|
|
15
|
+
|
|
21
16
|
/**
|
|
22
17
|
* Check that DB connection is working properly.
|
|
23
18
|
*/
|
|
@@ -59,3 +54,26 @@ export interface CommonKeyValueDB {
|
|
|
59
54
|
*/
|
|
60
55
|
increment: (table: string, id: string, by?: number) => Promise<number>
|
|
61
56
|
}
|
|
57
|
+
|
|
58
|
+
export type KeyValueDBTuple = [key: string, value: Buffer]
|
|
59
|
+
|
|
60
|
+
export interface CommonKeyValueDBSaveBatchOptions {
|
|
61
|
+
/**
|
|
62
|
+
* If set (and if it's implemented by the driver) - will set expiry TTL for each key of the batch.
|
|
63
|
+
* E.g EXAT in Redis.
|
|
64
|
+
*/
|
|
65
|
+
expireAt?: UnixTimestampNumber
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Manifest of supported features.
|
|
70
|
+
*/
|
|
71
|
+
export interface CommonKeyValueDBSupport {
|
|
72
|
+
count?: boolean
|
|
73
|
+
increment?: boolean
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export const commonKeyValueDBFullSupport: CommonKeyValueDBSupport = {
|
|
77
|
+
count: true,
|
|
78
|
+
increment: true,
|
|
79
|
+
}
|
|
@@ -8,7 +8,7 @@ import {
|
|
|
8
8
|
KeyValueDBTuple,
|
|
9
9
|
} from './commonKeyValueDB'
|
|
10
10
|
|
|
11
|
-
export interface CommonKeyValueDaoCfg<
|
|
11
|
+
export interface CommonKeyValueDaoCfg<V> {
|
|
12
12
|
db: CommonKeyValueDB
|
|
13
13
|
|
|
14
14
|
table: string
|
|
@@ -35,9 +35,9 @@ export interface CommonKeyValueDaoCfg<T> {
|
|
|
35
35
|
logStarted?: boolean
|
|
36
36
|
|
|
37
37
|
hooks?: {
|
|
38
|
-
mapValueToBuffer?: (v:
|
|
39
|
-
mapBufferToValue?: (b: Buffer) => Promise<
|
|
40
|
-
beforeCreate?: (v: Partial<
|
|
38
|
+
mapValueToBuffer?: (v: V) => Promise<Buffer>
|
|
39
|
+
mapBufferToValue?: (b: Buffer) => Promise<V>
|
|
40
|
+
beforeCreate?: (v: Partial<V>) => Partial<V>
|
|
41
41
|
}
|
|
42
42
|
|
|
43
43
|
/**
|
|
@@ -53,8 +53,8 @@ export type CommonKeyValueDaoSaveOptions = CommonKeyValueDBSaveBatchOptions
|
|
|
53
53
|
// todo: logging
|
|
54
54
|
// todo: readonly
|
|
55
55
|
|
|
56
|
-
export class CommonKeyValueDao<
|
|
57
|
-
constructor(cfg: CommonKeyValueDaoCfg<
|
|
56
|
+
export class CommonKeyValueDao<V, K extends string = string> {
|
|
57
|
+
constructor(cfg: CommonKeyValueDaoCfg<V>) {
|
|
58
58
|
this.cfg = {
|
|
59
59
|
hooks: {},
|
|
60
60
|
logger: console,
|
|
@@ -70,8 +70,8 @@ export class CommonKeyValueDao<T> {
|
|
|
70
70
|
}
|
|
71
71
|
}
|
|
72
72
|
|
|
73
|
-
cfg: CommonKeyValueDaoCfg<
|
|
74
|
-
hooks: NonNullable<CommonKeyValueDaoCfg<
|
|
73
|
+
cfg: CommonKeyValueDaoCfg<V> & {
|
|
74
|
+
hooks: NonNullable<CommonKeyValueDaoCfg<V>['hooks']>
|
|
75
75
|
logger: CommonLogger
|
|
76
76
|
}
|
|
77
77
|
|
|
@@ -83,25 +83,25 @@ export class CommonKeyValueDao<T> {
|
|
|
83
83
|
await this.cfg.db.createTable(this.cfg.table, opt)
|
|
84
84
|
}
|
|
85
85
|
|
|
86
|
-
create(input: Partial<
|
|
86
|
+
create(input: Partial<V> = {}): V {
|
|
87
87
|
return {
|
|
88
88
|
...this.cfg.hooks.beforeCreate?.(input),
|
|
89
|
-
} as
|
|
89
|
+
} as V
|
|
90
90
|
}
|
|
91
91
|
|
|
92
|
-
async getById(id?:
|
|
92
|
+
async getById(id?: K): Promise<V | null> {
|
|
93
93
|
if (!id) return null
|
|
94
94
|
const [r] = await this.getByIds([id])
|
|
95
95
|
return r?.[1] || null
|
|
96
96
|
}
|
|
97
97
|
|
|
98
|
-
async getByIdAsBuffer(id?:
|
|
98
|
+
async getByIdAsBuffer(id?: K): Promise<Buffer | null> {
|
|
99
99
|
if (!id) return null
|
|
100
100
|
const [r] = await this.cfg.db.getByIds(this.cfg.table, [id])
|
|
101
101
|
return r?.[1] || null
|
|
102
102
|
}
|
|
103
103
|
|
|
104
|
-
async requireById(id:
|
|
104
|
+
async requireById(id: K): Promise<V> {
|
|
105
105
|
const [r] = await this.getByIds([id])
|
|
106
106
|
|
|
107
107
|
if (!r) {
|
|
@@ -115,7 +115,7 @@ export class CommonKeyValueDao<T> {
|
|
|
115
115
|
return r[1]
|
|
116
116
|
}
|
|
117
117
|
|
|
118
|
-
async requireByIdAsBuffer(id:
|
|
118
|
+
async requireByIdAsBuffer(id: K): Promise<Buffer> {
|
|
119
119
|
const [r] = await this.cfg.db.getByIds(this.cfg.table, [id])
|
|
120
120
|
|
|
121
121
|
if (!r) {
|
|
@@ -129,18 +129,18 @@ export class CommonKeyValueDao<T> {
|
|
|
129
129
|
return r[1]
|
|
130
130
|
}
|
|
131
131
|
|
|
132
|
-
async getByIdOrEmpty(id:
|
|
132
|
+
async getByIdOrEmpty(id: K, part: Partial<V> = {}): Promise<V> {
|
|
133
133
|
const [r] = await this.getByIds([id])
|
|
134
134
|
if (r) return r[1]
|
|
135
135
|
|
|
136
136
|
return {
|
|
137
137
|
...this.cfg.hooks.beforeCreate?.({}),
|
|
138
138
|
...part,
|
|
139
|
-
} as
|
|
139
|
+
} as V
|
|
140
140
|
}
|
|
141
141
|
|
|
142
|
-
async patch(id:
|
|
143
|
-
const v:
|
|
142
|
+
async patch(id: K, patch: Partial<V>, opt?: CommonKeyValueDaoSaveOptions): Promise<V> {
|
|
143
|
+
const v: V = {
|
|
144
144
|
...(await this.getByIdOrEmpty(id)),
|
|
145
145
|
...patch,
|
|
146
146
|
}
|
|
@@ -150,7 +150,7 @@ export class CommonKeyValueDao<T> {
|
|
|
150
150
|
return v
|
|
151
151
|
}
|
|
152
152
|
|
|
153
|
-
async getByIds(ids:
|
|
153
|
+
async getByIds(ids: K[]): Promise<KeyValueTuple<string, V>[]> {
|
|
154
154
|
const entries = await this.cfg.db.getByIds(this.cfg.table, ids)
|
|
155
155
|
if (!this.cfg.hooks.mapBufferToValue) return entries as any
|
|
156
156
|
|
|
@@ -160,20 +160,20 @@ export class CommonKeyValueDao<T> {
|
|
|
160
160
|
])
|
|
161
161
|
}
|
|
162
162
|
|
|
163
|
-
async getByIdsAsBuffer(ids:
|
|
164
|
-
return await this.cfg.db.getByIds(this.cfg.table, ids)
|
|
163
|
+
async getByIdsAsBuffer(ids: K[]): Promise<KeyValueTuple<K, Buffer>[]> {
|
|
164
|
+
return (await this.cfg.db.getByIds(this.cfg.table, ids)) as KeyValueTuple<K, Buffer>[]
|
|
165
165
|
}
|
|
166
166
|
|
|
167
|
-
async save(id:
|
|
167
|
+
async save(id: K, value: V, opt?: CommonKeyValueDaoSaveOptions): Promise<void> {
|
|
168
168
|
await this.saveBatch([[id, value]], opt)
|
|
169
169
|
}
|
|
170
170
|
|
|
171
|
-
async saveAsBuffer(id:
|
|
171
|
+
async saveAsBuffer(id: K, value: Buffer, opt?: CommonKeyValueDaoSaveOptions): Promise<void> {
|
|
172
172
|
await this.cfg.db.saveBatch(this.cfg.table, [[id, value]], opt)
|
|
173
173
|
}
|
|
174
174
|
|
|
175
175
|
async saveBatch(
|
|
176
|
-
entries: KeyValueTuple<
|
|
176
|
+
entries: KeyValueTuple<K, V>[],
|
|
177
177
|
opt?: CommonKeyValueDaoSaveOptions,
|
|
178
178
|
): Promise<void> {
|
|
179
179
|
const { mapValueToBuffer } = this.cfg.hooks
|
|
@@ -195,23 +195,23 @@ export class CommonKeyValueDao<T> {
|
|
|
195
195
|
await this.cfg.db.saveBatch(this.cfg.table, entries, opt)
|
|
196
196
|
}
|
|
197
197
|
|
|
198
|
-
async deleteByIds(ids:
|
|
198
|
+
async deleteByIds(ids: K[]): Promise<void> {
|
|
199
199
|
await this.cfg.db.deleteByIds(this.cfg.table, ids)
|
|
200
200
|
}
|
|
201
201
|
|
|
202
|
-
async deleteById(id:
|
|
202
|
+
async deleteById(id: K): Promise<void> {
|
|
203
203
|
await this.cfg.db.deleteByIds(this.cfg.table, [id])
|
|
204
204
|
}
|
|
205
205
|
|
|
206
|
-
streamIds(limit?: number): ReadableTyped<
|
|
207
|
-
return this.cfg.db.streamIds(this.cfg.table, limit)
|
|
206
|
+
streamIds(limit?: number): ReadableTyped<K> {
|
|
207
|
+
return this.cfg.db.streamIds(this.cfg.table, limit) as ReadableTyped<K>
|
|
208
208
|
}
|
|
209
209
|
|
|
210
|
-
streamValues(limit?: number): ReadableTyped<
|
|
210
|
+
streamValues(limit?: number): ReadableTyped<V> {
|
|
211
211
|
const { mapBufferToValue } = this.cfg.hooks
|
|
212
212
|
|
|
213
213
|
if (!mapBufferToValue) {
|
|
214
|
-
return this.cfg.db.streamValues(this.cfg.table, limit) as ReadableTyped<
|
|
214
|
+
return this.cfg.db.streamValues(this.cfg.table, limit) as ReadableTyped<V>
|
|
215
215
|
}
|
|
216
216
|
|
|
217
217
|
return this.cfg.db.streamValues(this.cfg.table, limit).flatMap(
|
|
@@ -229,16 +229,16 @@ export class CommonKeyValueDao<T> {
|
|
|
229
229
|
)
|
|
230
230
|
}
|
|
231
231
|
|
|
232
|
-
streamEntries(limit?: number): ReadableTyped<KeyValueTuple<
|
|
232
|
+
streamEntries(limit?: number): ReadableTyped<KeyValueTuple<K, V>> {
|
|
233
233
|
const { mapBufferToValue } = this.cfg.hooks
|
|
234
234
|
|
|
235
235
|
if (!mapBufferToValue) {
|
|
236
|
-
return this.cfg.db.streamEntries(this.cfg.table, limit) as ReadableTyped<
|
|
237
|
-
KeyValueTuple<string, T>
|
|
238
|
-
>
|
|
236
|
+
return this.cfg.db.streamEntries(this.cfg.table, limit) as ReadableTyped<KeyValueTuple<K, V>>
|
|
239
237
|
}
|
|
240
238
|
|
|
241
|
-
return
|
|
239
|
+
return (
|
|
240
|
+
this.cfg.db.streamEntries(this.cfg.table, limit) as ReadableTyped<KeyValueTuple<K, Buffer>>
|
|
241
|
+
).flatMap(
|
|
242
242
|
async ([id, buf]) => {
|
|
243
243
|
try {
|
|
244
244
|
return [[id, await mapBufferToValue(buf)]]
|
|
@@ -253,13 +253,25 @@ export class CommonKeyValueDao<T> {
|
|
|
253
253
|
)
|
|
254
254
|
}
|
|
255
255
|
|
|
256
|
+
async getAllKeys(limit?: number): Promise<K[]> {
|
|
257
|
+
return await this.streamIds(limit).toArray()
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
async getAllValues(limit?: number): Promise<V[]> {
|
|
261
|
+
return await this.streamValues(limit).toArray()
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
async getAllEntries(limit?: number): Promise<KeyValueTuple<K, V>[]> {
|
|
265
|
+
return await this.streamEntries(limit).toArray()
|
|
266
|
+
}
|
|
267
|
+
|
|
256
268
|
/**
|
|
257
269
|
* Increments the `id` field by the amount specified in `by`,
|
|
258
270
|
* or by 1 if `by` is not specified.
|
|
259
271
|
*
|
|
260
272
|
* Returns the new value of the field.
|
|
261
273
|
*/
|
|
262
|
-
async increment(id:
|
|
274
|
+
async increment(id: K, by = 1): Promise<number> {
|
|
263
275
|
return await this.cfg.db.increment(this.cfg.table, id, by)
|
|
264
276
|
}
|
|
265
277
|
}
|
|
@@ -21,6 +21,8 @@ export function runCommonKeyValueDBTest(db: CommonKeyValueDB): void {
|
|
|
21
21
|
await db.deleteByIds(TEST_TABLE, ids)
|
|
22
22
|
})
|
|
23
23
|
|
|
24
|
+
const { support } = db
|
|
25
|
+
|
|
24
26
|
test('ping', async () => {
|
|
25
27
|
await db.ping()
|
|
26
28
|
})
|
|
@@ -50,9 +52,11 @@ export function runCommonKeyValueDBTest(db: CommonKeyValueDB): void {
|
|
|
50
52
|
expect(entries).toEqual(testEntries)
|
|
51
53
|
})
|
|
52
54
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
55
|
+
if (support.count) {
|
|
56
|
+
test('count should be 3', async () => {
|
|
57
|
+
expect(await db.count(TEST_TABLE)).toBe(3)
|
|
58
|
+
})
|
|
59
|
+
}
|
|
56
60
|
|
|
57
61
|
test('streamIds', async () => {
|
|
58
62
|
const ids = await db.streamIds(TEST_TABLE).toArray()
|
|
@@ -100,18 +104,20 @@ export function runCommonKeyValueDBTest(db: CommonKeyValueDB): void {
|
|
|
100
104
|
expect(results).toEqual([])
|
|
101
105
|
})
|
|
102
106
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
+
if (support.increment) {
|
|
108
|
+
test('increment on a non-existing field should set the value to 1', async () => {
|
|
109
|
+
const result = await db.increment(TEST_TABLE, 'nonExistingField')
|
|
110
|
+
expect(result).toBe(1)
|
|
111
|
+
})
|
|
107
112
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
113
|
+
test('increment on a existing field should increase the value by one', async () => {
|
|
114
|
+
const result = await db.increment(TEST_TABLE, 'nonExistingField')
|
|
115
|
+
expect(result).toBe(2)
|
|
116
|
+
})
|
|
112
117
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
118
|
+
test('increment should increase the value by the specified amount', async () => {
|
|
119
|
+
const result = await db.increment(TEST_TABLE, 'nonExistingField', 2)
|
|
120
|
+
expect(result).toBe(4)
|
|
121
|
+
})
|
|
122
|
+
}
|
|
117
123
|
}
|
|
@@ -20,6 +20,8 @@ export function runCommonKeyValueDaoTest(dao: CommonKeyValueDao<Buffer>): void {
|
|
|
20
20
|
await dao.deleteByIds(ids)
|
|
21
21
|
})
|
|
22
22
|
|
|
23
|
+
const { support } = dao.cfg.db
|
|
24
|
+
|
|
23
25
|
test('ping', async () => {
|
|
24
26
|
await dao.ping()
|
|
25
27
|
})
|
|
@@ -91,18 +93,20 @@ export function runCommonKeyValueDaoTest(dao: CommonKeyValueDao<Buffer>): void {
|
|
|
91
93
|
expect(results).toEqual([])
|
|
92
94
|
})
|
|
93
95
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
96
|
+
if (support.increment) {
|
|
97
|
+
test('increment on a non-existing field should set the value to 1', async () => {
|
|
98
|
+
const result = await dao.increment('nonExistingField')
|
|
99
|
+
expect(result).toBe(1)
|
|
100
|
+
})
|
|
98
101
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
102
|
+
test('increment on a existing field should increase the value by one', async () => {
|
|
103
|
+
const result = await dao.increment('nonExistingField')
|
|
104
|
+
expect(result).toBe(2)
|
|
105
|
+
})
|
|
103
106
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
107
|
+
test('increment should increase the value by the specified amount', async () => {
|
|
108
|
+
const result = await dao.increment('nonExistingField', 2)
|
|
109
|
+
expect(result).toBe(4)
|
|
110
|
+
})
|
|
111
|
+
}
|
|
108
112
|
}
|