@naturalcycles/redis-lib 4.3.1 → 4.4.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/redisClient.d.ts +4 -4
- package/dist/redisClient.js +7 -25
- package/dist/redisHashKeyValueDB.d.ts +4 -4
- package/dist/redisHashKeyValueDB.js +10 -8
- package/dist/redisKeyValueDB.d.ts +4 -4
- package/dist/redisKeyValueDB.js +12 -16
- package/package.json +2 -2
- package/src/redisClient.ts +10 -33
- package/src/redisHashKeyValueDB.ts +14 -13
- package/src/redisKeyValueDB.ts +16 -22
package/dist/redisClient.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { CommonLogger } from '@naturalcycles/js-lib/log';
|
|
2
2
|
import type { AnyObject, NullableBuffer, NullableString, Promisable, UnixTimestamp } from '@naturalcycles/js-lib/types';
|
|
3
|
-
import
|
|
3
|
+
import { Pipeline } from '@naturalcycles/nodejs-lib/stream';
|
|
4
4
|
import type { Redis, RedisOptions } from 'ioredis';
|
|
5
5
|
import type { ScanStreamOptions } from 'ioredis/built/types.js';
|
|
6
6
|
import type { ChainableCommander } from 'ioredis/built/utils/RedisCommander.js';
|
|
@@ -62,13 +62,13 @@ export declare class RedisClient implements CommonClient {
|
|
|
62
62
|
Convenient type-safe wrapper.
|
|
63
63
|
Returns BATCHES of keys in each iteration (as-is).
|
|
64
64
|
*/
|
|
65
|
-
scanStream(opt?: ScanStreamOptions):
|
|
65
|
+
scanStream(opt?: ScanStreamOptions): Pipeline<string[]>;
|
|
66
66
|
/**
|
|
67
67
|
* Like scanStream, but flattens the stream of keys.
|
|
68
68
|
*/
|
|
69
|
-
scanStreamFlat(opt: ScanStreamOptions):
|
|
69
|
+
scanStreamFlat(opt: ScanStreamOptions): Pipeline<string>;
|
|
70
70
|
scanCount(opt: ScanStreamOptions): Promise<number>;
|
|
71
|
-
hscanStream(key: string, opt?: ScanStreamOptions):
|
|
71
|
+
hscanStream(key: string, opt?: ScanStreamOptions): Pipeline<string[]>;
|
|
72
72
|
hscanCount(key: string, opt?: ScanStreamOptions): Promise<number>;
|
|
73
73
|
withPipeline(fn: (pipeline: ChainableCommander) => Promisable<void>): Promise<void>;
|
|
74
74
|
private log;
|
package/dist/redisClient.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { Transform } from 'node:stream';
|
|
2
1
|
import { _stringMapEntries } from '@naturalcycles/js-lib/types';
|
|
2
|
+
import { Pipeline } from '@naturalcycles/nodejs-lib/stream';
|
|
3
3
|
/**
|
|
4
4
|
Wraps the redis sdk with unified interface.
|
|
5
5
|
Features:
|
|
@@ -174,7 +174,7 @@ export class RedisClient {
|
|
|
174
174
|
await this.withPipeline(async (pipeline) => {
|
|
175
175
|
await this.scanStream({
|
|
176
176
|
match: `${table}:*`,
|
|
177
|
-
}).
|
|
177
|
+
}).forEachSync(keys => {
|
|
178
178
|
pipeline.del(keys);
|
|
179
179
|
count += keys.length;
|
|
180
180
|
});
|
|
@@ -187,7 +187,7 @@ export class RedisClient {
|
|
|
187
187
|
await this.withPipeline(async (pipeline) => {
|
|
188
188
|
await this.scanStream({
|
|
189
189
|
match: `*`,
|
|
190
|
-
}).
|
|
190
|
+
}).forEachSync(keys => {
|
|
191
191
|
pipeline.del(keys);
|
|
192
192
|
count += keys.length;
|
|
193
193
|
});
|
|
@@ -199,7 +199,7 @@ export class RedisClient {
|
|
|
199
199
|
Returns BATCHES of keys in each iteration (as-is).
|
|
200
200
|
*/
|
|
201
201
|
scanStream(opt) {
|
|
202
|
-
return
|
|
202
|
+
return Pipeline.fromAsyncReadable(async () => {
|
|
203
203
|
const redis = await this.redis();
|
|
204
204
|
return redis.scanStream(opt);
|
|
205
205
|
});
|
|
@@ -208,20 +208,19 @@ export class RedisClient {
|
|
|
208
208
|
* Like scanStream, but flattens the stream of keys.
|
|
209
209
|
*/
|
|
210
210
|
scanStreamFlat(opt) {
|
|
211
|
-
|
|
212
|
-
return this.scanStream(opt).flatMap(keys => keys);
|
|
211
|
+
return this.scanStream(opt).flatten();
|
|
213
212
|
}
|
|
214
213
|
async scanCount(opt) {
|
|
215
214
|
const redis = await this.redis();
|
|
216
215
|
// todo: implement more efficiently, e.g via LUA?
|
|
217
216
|
let count = 0;
|
|
218
|
-
await redis.scanStream(opt).forEach(keys => {
|
|
217
|
+
await redis.scanStream(opt).forEach((keys) => {
|
|
219
218
|
count += keys.length;
|
|
220
219
|
});
|
|
221
220
|
return count;
|
|
222
221
|
}
|
|
223
222
|
hscanStream(key, opt) {
|
|
224
|
-
return
|
|
223
|
+
return Pipeline.fromAsyncReadable(async () => {
|
|
225
224
|
const redis = await this.redis();
|
|
226
225
|
return redis.hscanStream(key, opt);
|
|
227
226
|
});
|
|
@@ -245,20 +244,3 @@ export class RedisClient {
|
|
|
245
244
|
this.cfg.logger.log(...args);
|
|
246
245
|
}
|
|
247
246
|
}
|
|
248
|
-
/**
|
|
249
|
-
* Turn async function into Readable.
|
|
250
|
-
*/
|
|
251
|
-
function createReadableFromAsync(fn) {
|
|
252
|
-
const transform = new Transform({
|
|
253
|
-
objectMode: true,
|
|
254
|
-
transform: (chunk, _encoding, cb) => {
|
|
255
|
-
cb(null, chunk);
|
|
256
|
-
},
|
|
257
|
-
});
|
|
258
|
-
void fn()
|
|
259
|
-
.then(readable => {
|
|
260
|
-
readable.on('error', err => transform.destroy(err)).pipe(transform);
|
|
261
|
-
})
|
|
262
|
-
.catch(err => transform.destroy(err));
|
|
263
|
-
return transform;
|
|
264
|
-
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { CommonDBCreateOptions } from '@naturalcycles/db-lib';
|
|
2
2
|
import type { CommonKeyValueDB, CommonKeyValueDBSaveBatchOptions, IncrementTuple, KeyValueDBTuple } from '@naturalcycles/db-lib/kv';
|
|
3
|
-
import type {
|
|
3
|
+
import type { Pipeline } from '@naturalcycles/nodejs-lib/stream';
|
|
4
4
|
import type { RedisKeyValueDBCfg } from './redisKeyValueDB.js';
|
|
5
5
|
/**
|
|
6
6
|
* RedisHashKeyValueDB is a KeyValueDB implementation that uses hash fields to simulate tables.
|
|
@@ -23,9 +23,9 @@ export declare class RedisHashKeyValueDB implements CommonKeyValueDB, AsyncDispo
|
|
|
23
23
|
getByIds(table: string, ids: string[]): Promise<KeyValueDBTuple[]>;
|
|
24
24
|
deleteByIds(table: string, ids: string[]): Promise<void>;
|
|
25
25
|
saveBatch(table: string, entries: KeyValueDBTuple[], opt?: CommonKeyValueDBSaveBatchOptions): Promise<void>;
|
|
26
|
-
streamIds(table: string, limit?: number):
|
|
27
|
-
streamValues(table: string, limit?: number):
|
|
28
|
-
streamEntries(table: string, limit?: number):
|
|
26
|
+
streamIds(table: string, limit?: number): Pipeline<string>;
|
|
27
|
+
streamValues(table: string, limit?: number): Pipeline<Buffer>;
|
|
28
|
+
streamEntries(table: string, limit?: number): Pipeline<KeyValueDBTuple>;
|
|
29
29
|
count(table: string): Promise<number>;
|
|
30
30
|
incrementBatch(table: string, increments: IncrementTuple[]): Promise<IncrementTuple[]>;
|
|
31
31
|
createTable(table: string, opt?: CommonDBCreateOptions): Promise<void>;
|
|
@@ -49,22 +49,22 @@ export class RedisHashKeyValueDB {
|
|
|
49
49
|
}
|
|
50
50
|
}
|
|
51
51
|
streamIds(table, limit) {
|
|
52
|
-
|
|
52
|
+
return this.cfg.client
|
|
53
53
|
.hscanStream(table)
|
|
54
|
-
.
|
|
54
|
+
.mapSync(keyValueList => {
|
|
55
55
|
const keys = [];
|
|
56
56
|
for (let i = 0; i < keyValueList.length; i += 2) {
|
|
57
57
|
keys.push(keyValueList[i]);
|
|
58
58
|
}
|
|
59
59
|
return keys;
|
|
60
60
|
})
|
|
61
|
-
.
|
|
62
|
-
|
|
61
|
+
.flatten()
|
|
62
|
+
.limit(limit);
|
|
63
63
|
}
|
|
64
64
|
streamValues(table, limit) {
|
|
65
65
|
return this.cfg.client
|
|
66
66
|
.hscanStream(table)
|
|
67
|
-
.
|
|
67
|
+
.mapSync(keyValueList => {
|
|
68
68
|
const values = [];
|
|
69
69
|
for (let i = 0; i < keyValueList.length; i += 2) {
|
|
70
70
|
const value = Buffer.from(keyValueList[i + 1]);
|
|
@@ -72,12 +72,13 @@ export class RedisHashKeyValueDB {
|
|
|
72
72
|
}
|
|
73
73
|
return values;
|
|
74
74
|
})
|
|
75
|
-
.
|
|
75
|
+
.flatten()
|
|
76
|
+
.limit(limit);
|
|
76
77
|
}
|
|
77
78
|
streamEntries(table, limit) {
|
|
78
79
|
return this.cfg.client
|
|
79
80
|
.hscanStream(table)
|
|
80
|
-
.
|
|
81
|
+
.mapSync(keyValueList => {
|
|
81
82
|
const entries = [];
|
|
82
83
|
for (let i = 0; i < keyValueList.length; i += 2) {
|
|
83
84
|
const key = keyValueList[i];
|
|
@@ -86,7 +87,8 @@ export class RedisHashKeyValueDB {
|
|
|
86
87
|
}
|
|
87
88
|
return entries;
|
|
88
89
|
})
|
|
89
|
-
.
|
|
90
|
+
.flatten()
|
|
91
|
+
.limit(limit);
|
|
90
92
|
}
|
|
91
93
|
async count(table) {
|
|
92
94
|
return await this.cfg.client.hscanCount(table);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { CommonDBCreateOptions } from '@naturalcycles/db-lib';
|
|
2
2
|
import type { CommonKeyValueDB, CommonKeyValueDBSaveBatchOptions, IncrementTuple, KeyValueDBTuple } from '@naturalcycles/db-lib/kv';
|
|
3
|
-
import type {
|
|
3
|
+
import type { Pipeline } from '@naturalcycles/nodejs-lib/stream';
|
|
4
4
|
import type { RedisClient } from './redisClient.js';
|
|
5
5
|
export interface RedisKeyValueDBCfg {
|
|
6
6
|
client: RedisClient;
|
|
@@ -14,9 +14,9 @@ export declare class RedisKeyValueDB implements CommonKeyValueDB, AsyncDisposabl
|
|
|
14
14
|
getByIds(table: string, ids: string[]): Promise<KeyValueDBTuple[]>;
|
|
15
15
|
deleteByIds(table: string, ids: string[]): Promise<void>;
|
|
16
16
|
saveBatch(table: string, entries: KeyValueDBTuple[], opt?: CommonKeyValueDBSaveBatchOptions): Promise<void>;
|
|
17
|
-
streamIds(table: string, limit?: number):
|
|
18
|
-
streamValues(table: string, limit?: number):
|
|
19
|
-
streamEntries(table: string, limit?: number):
|
|
17
|
+
streamIds(table: string, limit?: number): Pipeline<string>;
|
|
18
|
+
streamValues(table: string, limit?: number): Pipeline<Buffer>;
|
|
19
|
+
streamEntries(table: string, limit?: number): Pipeline<KeyValueDBTuple>;
|
|
20
20
|
count(table: string): Promise<number>;
|
|
21
21
|
incrementBatch(table: string, increments: IncrementTuple[]): Promise<IncrementTuple[]>;
|
|
22
22
|
createTable(table: string, opt?: CommonDBCreateOptions): Promise<void>;
|
package/dist/redisKeyValueDB.js
CHANGED
|
@@ -45,42 +45,38 @@ export class RedisKeyValueDB {
|
|
|
45
45
|
}
|
|
46
46
|
}
|
|
47
47
|
streamIds(table, limit) {
|
|
48
|
-
|
|
48
|
+
return this.cfg.client
|
|
49
49
|
.scanStream({
|
|
50
50
|
match: `${table}:*`,
|
|
51
51
|
// count: limit, // count is actually a "batchSize", not a limit
|
|
52
52
|
})
|
|
53
|
-
.
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
}
|
|
57
|
-
return stream;
|
|
53
|
+
.mapSync(keys => this.keysToIds(table, keys))
|
|
54
|
+
.flatten()
|
|
55
|
+
.limit(limit);
|
|
58
56
|
}
|
|
59
57
|
streamValues(table, limit) {
|
|
60
58
|
return this.cfg.client
|
|
61
59
|
.scanStream({
|
|
62
60
|
match: `${table}:*`,
|
|
63
61
|
})
|
|
64
|
-
.
|
|
62
|
+
.map(async (keys) => {
|
|
65
63
|
return (await this.cfg.client.mgetBuffer(keys)).filter(_isTruthy);
|
|
66
|
-
}, {
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
.take(limit || Infinity);
|
|
64
|
+
}, { concurrency: 16 })
|
|
65
|
+
.flatten()
|
|
66
|
+
.limit(limit);
|
|
70
67
|
}
|
|
71
68
|
streamEntries(table, limit) {
|
|
72
69
|
return this.cfg.client
|
|
73
70
|
.scanStream({
|
|
74
71
|
match: `${table}:*`,
|
|
75
72
|
})
|
|
76
|
-
.
|
|
73
|
+
.map(async (keys) => {
|
|
77
74
|
// casting as Buffer[], because values are expected to exist for given keys
|
|
78
75
|
const bufs = (await this.cfg.client.mgetBuffer(keys));
|
|
79
76
|
return _zip(this.keysToIds(table, keys), bufs);
|
|
80
|
-
}, {
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
.take(limit || Infinity);
|
|
77
|
+
}, { concurrency: 16 })
|
|
78
|
+
.flatten()
|
|
79
|
+
.limit(limit);
|
|
84
80
|
}
|
|
85
81
|
async count(table) {
|
|
86
82
|
// todo: implement more efficiently, e.g via LUA?
|
package/package.json
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
},
|
|
11
11
|
"devDependencies": {
|
|
12
12
|
"@types/node": "^24",
|
|
13
|
-
"@naturalcycles/dev-lib": "
|
|
13
|
+
"@naturalcycles/dev-lib": "19.37.0"
|
|
14
14
|
},
|
|
15
15
|
"exports": {
|
|
16
16
|
".": "./dist/index.js"
|
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
"engines": {
|
|
38
38
|
"node": ">=22.12.0"
|
|
39
39
|
},
|
|
40
|
-
"version": "4.
|
|
40
|
+
"version": "4.4.0",
|
|
41
41
|
"description": "Redis implementation of CommonKeyValueDB interface",
|
|
42
42
|
"author": "Natural Cycles Team",
|
|
43
43
|
"license": "MIT",
|
package/src/redisClient.ts
CHANGED
|
@@ -1,8 +1,6 @@
|
|
|
1
|
-
import { Transform } from 'node:stream'
|
|
2
1
|
import type { CommonLogger } from '@naturalcycles/js-lib/log'
|
|
3
2
|
import type {
|
|
4
3
|
AnyObject,
|
|
5
|
-
AsyncFunction,
|
|
6
4
|
NullableBuffer,
|
|
7
5
|
NullableString,
|
|
8
6
|
Promisable,
|
|
@@ -10,7 +8,7 @@ import type {
|
|
|
10
8
|
UnixTimestamp,
|
|
11
9
|
} from '@naturalcycles/js-lib/types'
|
|
12
10
|
import { _stringMapEntries } from '@naturalcycles/js-lib/types'
|
|
13
|
-
import
|
|
11
|
+
import { Pipeline } from '@naturalcycles/nodejs-lib/stream'
|
|
14
12
|
import type { Redis, RedisOptions } from 'ioredis'
|
|
15
13
|
import type { ScanStreamOptions } from 'ioredis/built/types.js'
|
|
16
14
|
import type { ChainableCommander } from 'ioredis/built/utils/RedisCommander.js'
|
|
@@ -258,7 +256,7 @@ export class RedisClient implements CommonClient {
|
|
|
258
256
|
await this.withPipeline(async pipeline => {
|
|
259
257
|
await this.scanStream({
|
|
260
258
|
match: `${table}:*`,
|
|
261
|
-
}).
|
|
259
|
+
}).forEachSync(keys => {
|
|
262
260
|
pipeline.del(keys)
|
|
263
261
|
count += keys.length
|
|
264
262
|
})
|
|
@@ -274,7 +272,7 @@ export class RedisClient implements CommonClient {
|
|
|
274
272
|
await this.withPipeline(async pipeline => {
|
|
275
273
|
await this.scanStream({
|
|
276
274
|
match: `*`,
|
|
277
|
-
}).
|
|
275
|
+
}).forEachSync(keys => {
|
|
278
276
|
pipeline.del(keys)
|
|
279
277
|
count += keys.length
|
|
280
278
|
})
|
|
@@ -287,8 +285,8 @@ export class RedisClient implements CommonClient {
|
|
|
287
285
|
Convenient type-safe wrapper.
|
|
288
286
|
Returns BATCHES of keys in each iteration (as-is).
|
|
289
287
|
*/
|
|
290
|
-
scanStream(opt?: ScanStreamOptions):
|
|
291
|
-
return
|
|
288
|
+
scanStream(opt?: ScanStreamOptions): Pipeline<string[]> {
|
|
289
|
+
return Pipeline.fromAsyncReadable(async () => {
|
|
292
290
|
const redis = await this.redis()
|
|
293
291
|
return redis.scanStream(opt)
|
|
294
292
|
})
|
|
@@ -297,9 +295,8 @@ export class RedisClient implements CommonClient {
|
|
|
297
295
|
/**
|
|
298
296
|
* Like scanStream, but flattens the stream of keys.
|
|
299
297
|
*/
|
|
300
|
-
scanStreamFlat(opt: ScanStreamOptions):
|
|
301
|
-
|
|
302
|
-
return this.scanStream(opt).flatMap(keys => keys)
|
|
298
|
+
scanStreamFlat(opt: ScanStreamOptions): Pipeline<string> {
|
|
299
|
+
return this.scanStream(opt).flatten()
|
|
303
300
|
}
|
|
304
301
|
|
|
305
302
|
async scanCount(opt: ScanStreamOptions): Promise<number> {
|
|
@@ -307,15 +304,15 @@ export class RedisClient implements CommonClient {
|
|
|
307
304
|
// todo: implement more efficiently, e.g via LUA?
|
|
308
305
|
let count = 0
|
|
309
306
|
|
|
310
|
-
await
|
|
307
|
+
await redis.scanStream(opt).forEach((keys: string[]) => {
|
|
311
308
|
count += keys.length
|
|
312
309
|
})
|
|
313
310
|
|
|
314
311
|
return count
|
|
315
312
|
}
|
|
316
313
|
|
|
317
|
-
hscanStream(key: string, opt?: ScanStreamOptions):
|
|
318
|
-
return
|
|
314
|
+
hscanStream(key: string, opt?: ScanStreamOptions): Pipeline<string[]> {
|
|
315
|
+
return Pipeline.fromAsyncReadable(async () => {
|
|
319
316
|
const redis = await this.redis()
|
|
320
317
|
return redis.hscanStream(key, opt)
|
|
321
318
|
})
|
|
@@ -345,23 +342,3 @@ export class RedisClient implements CommonClient {
|
|
|
345
342
|
this.cfg.logger.log(...args)
|
|
346
343
|
}
|
|
347
344
|
}
|
|
348
|
-
|
|
349
|
-
/**
|
|
350
|
-
* Turn async function into Readable.
|
|
351
|
-
*/
|
|
352
|
-
function createReadableFromAsync<T>(fn: AsyncFunction<ReadableTyped<T>>): ReadableTyped<T> {
|
|
353
|
-
const transform = new Transform({
|
|
354
|
-
objectMode: true,
|
|
355
|
-
transform: (chunk, _encoding, cb) => {
|
|
356
|
-
cb(null, chunk)
|
|
357
|
-
},
|
|
358
|
-
})
|
|
359
|
-
|
|
360
|
-
void fn()
|
|
361
|
-
.then(readable => {
|
|
362
|
-
readable.on('error', err => transform.destroy(err)).pipe(transform)
|
|
363
|
-
})
|
|
364
|
-
.catch(err => transform.destroy(err))
|
|
365
|
-
|
|
366
|
-
return transform
|
|
367
|
-
}
|
|
@@ -6,7 +6,7 @@ import type {
|
|
|
6
6
|
KeyValueDBTuple,
|
|
7
7
|
} from '@naturalcycles/db-lib/kv'
|
|
8
8
|
import { commonKeyValueDBFullSupport } from '@naturalcycles/db-lib/kv'
|
|
9
|
-
import type {
|
|
9
|
+
import type { Pipeline } from '@naturalcycles/nodejs-lib/stream'
|
|
10
10
|
import type { RedisKeyValueDBCfg } from './redisKeyValueDB.js'
|
|
11
11
|
|
|
12
12
|
/**
|
|
@@ -64,25 +64,24 @@ export class RedisHashKeyValueDB implements CommonKeyValueDB, AsyncDisposable {
|
|
|
64
64
|
}
|
|
65
65
|
}
|
|
66
66
|
|
|
67
|
-
streamIds(table: string, limit?: number):
|
|
68
|
-
|
|
67
|
+
streamIds(table: string, limit?: number): Pipeline<string> {
|
|
68
|
+
return this.cfg.client
|
|
69
69
|
.hscanStream(table)
|
|
70
|
-
.
|
|
70
|
+
.mapSync(keyValueList => {
|
|
71
71
|
const keys: string[] = []
|
|
72
72
|
for (let i = 0; i < keyValueList.length; i += 2) {
|
|
73
73
|
keys.push(keyValueList[i]!)
|
|
74
74
|
}
|
|
75
75
|
return keys
|
|
76
76
|
})
|
|
77
|
-
.
|
|
78
|
-
|
|
79
|
-
return stream
|
|
77
|
+
.flatten()
|
|
78
|
+
.limit(limit)
|
|
80
79
|
}
|
|
81
80
|
|
|
82
|
-
streamValues(table: string, limit?: number):
|
|
81
|
+
streamValues(table: string, limit?: number): Pipeline<Buffer> {
|
|
83
82
|
return this.cfg.client
|
|
84
83
|
.hscanStream(table)
|
|
85
|
-
.
|
|
84
|
+
.mapSync(keyValueList => {
|
|
86
85
|
const values: Buffer[] = []
|
|
87
86
|
for (let i = 0; i < keyValueList.length; i += 2) {
|
|
88
87
|
const value = Buffer.from(keyValueList[i + 1]!)
|
|
@@ -90,13 +89,14 @@ export class RedisHashKeyValueDB implements CommonKeyValueDB, AsyncDisposable {
|
|
|
90
89
|
}
|
|
91
90
|
return values
|
|
92
91
|
})
|
|
93
|
-
.
|
|
92
|
+
.flatten()
|
|
93
|
+
.limit(limit)
|
|
94
94
|
}
|
|
95
95
|
|
|
96
|
-
streamEntries(table: string, limit?: number):
|
|
96
|
+
streamEntries(table: string, limit?: number): Pipeline<KeyValueDBTuple> {
|
|
97
97
|
return this.cfg.client
|
|
98
98
|
.hscanStream(table)
|
|
99
|
-
.
|
|
99
|
+
.mapSync(keyValueList => {
|
|
100
100
|
const entries: [string, Buffer][] = []
|
|
101
101
|
for (let i = 0; i < keyValueList.length; i += 2) {
|
|
102
102
|
const key = keyValueList[i]!
|
|
@@ -105,7 +105,8 @@ export class RedisHashKeyValueDB implements CommonKeyValueDB, AsyncDisposable {
|
|
|
105
105
|
}
|
|
106
106
|
return entries
|
|
107
107
|
})
|
|
108
|
-
.
|
|
108
|
+
.flatten()
|
|
109
|
+
.limit(limit)
|
|
109
110
|
}
|
|
110
111
|
|
|
111
112
|
async count(table: string): Promise<number> {
|
package/src/redisKeyValueDB.ts
CHANGED
|
@@ -8,7 +8,7 @@ import type {
|
|
|
8
8
|
import { commonKeyValueDBFullSupport } from '@naturalcycles/db-lib/kv'
|
|
9
9
|
import { _isTruthy } from '@naturalcycles/js-lib'
|
|
10
10
|
import { _zip } from '@naturalcycles/js-lib/array/array.util.js'
|
|
11
|
-
import type {
|
|
11
|
+
import type { Pipeline } from '@naturalcycles/nodejs-lib/stream'
|
|
12
12
|
import type { RedisClient } from './redisClient.js'
|
|
13
13
|
|
|
14
14
|
export interface RedisKeyValueDBCfg {
|
|
@@ -65,53 +65,47 @@ export class RedisKeyValueDB implements CommonKeyValueDB, AsyncDisposable {
|
|
|
65
65
|
}
|
|
66
66
|
}
|
|
67
67
|
|
|
68
|
-
streamIds(table: string, limit?: number):
|
|
69
|
-
|
|
68
|
+
streamIds(table: string, limit?: number): Pipeline<string> {
|
|
69
|
+
return this.cfg.client
|
|
70
70
|
.scanStream({
|
|
71
71
|
match: `${table}:*`,
|
|
72
72
|
// count: limit, // count is actually a "batchSize", not a limit
|
|
73
73
|
})
|
|
74
|
-
.
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
stream = stream.take(limit)
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
return stream
|
|
74
|
+
.mapSync(keys => this.keysToIds(table, keys))
|
|
75
|
+
.flatten()
|
|
76
|
+
.limit(limit)
|
|
81
77
|
}
|
|
82
78
|
|
|
83
|
-
streamValues(table: string, limit?: number):
|
|
79
|
+
streamValues(table: string, limit?: number): Pipeline<Buffer> {
|
|
84
80
|
return this.cfg.client
|
|
85
81
|
.scanStream({
|
|
86
82
|
match: `${table}:*`,
|
|
87
83
|
})
|
|
88
|
-
.
|
|
84
|
+
.map(
|
|
89
85
|
async keys => {
|
|
90
86
|
return (await this.cfg.client.mgetBuffer(keys)).filter(_isTruthy)
|
|
91
87
|
},
|
|
92
|
-
{
|
|
93
|
-
concurrency: 16,
|
|
94
|
-
},
|
|
88
|
+
{ concurrency: 16 },
|
|
95
89
|
)
|
|
96
|
-
.
|
|
90
|
+
.flatten()
|
|
91
|
+
.limit(limit)
|
|
97
92
|
}
|
|
98
93
|
|
|
99
|
-
streamEntries(table: string, limit?: number):
|
|
94
|
+
streamEntries(table: string, limit?: number): Pipeline<KeyValueDBTuple> {
|
|
100
95
|
return this.cfg.client
|
|
101
96
|
.scanStream({
|
|
102
97
|
match: `${table}:*`,
|
|
103
98
|
})
|
|
104
|
-
.
|
|
99
|
+
.map(
|
|
105
100
|
async keys => {
|
|
106
101
|
// casting as Buffer[], because values are expected to exist for given keys
|
|
107
102
|
const bufs = (await this.cfg.client.mgetBuffer(keys)) as Buffer[]
|
|
108
103
|
return _zip(this.keysToIds(table, keys), bufs)
|
|
109
104
|
},
|
|
110
|
-
{
|
|
111
|
-
concurrency: 16,
|
|
112
|
-
},
|
|
105
|
+
{ concurrency: 16 },
|
|
113
106
|
)
|
|
114
|
-
.
|
|
107
|
+
.flatten()
|
|
108
|
+
.limit(limit)
|
|
115
109
|
}
|
|
116
110
|
|
|
117
111
|
async count(table: string): Promise<number> {
|