@naturalcycles/redis-lib 3.1.1 → 3.2.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.
@@ -47,11 +47,13 @@ export declare class RedisClient implements CommonClient {
47
47
  hmget(key: string, fields: string[]): Promise<NullableString[]>;
48
48
  hmgetBuffer(key: string, fields: string[]): Promise<NullableBuffer[]>;
49
49
  hincr(key: string, field: string, increment?: number): Promise<number>;
50
+ hincrBatch(key: string, incrementTuples: [string, number][]): Promise<[string, number][]>;
50
51
  setWithTTL(key: string, value: string | number | Buffer, expireAt: UnixTimestampNumber): Promise<void>;
51
- hsetWithTTL(key: string, value: AnyObject, expireAt: UnixTimestampNumber): Promise<void>;
52
+ hsetWithTTL(_key: string, _value: AnyObject, _expireAt: UnixTimestampNumber): Promise<void>;
52
53
  mset(obj: Record<string, string | number>): Promise<void>;
53
54
  msetBuffer(obj: Record<string, Buffer>): Promise<void>;
54
55
  incr(key: string, by?: number): Promise<number>;
56
+ incrBatch(incrementTuples: [string, number][]): Promise<[string, number][]>;
55
57
  ttl(key: string): Promise<number>;
56
58
  dropTable(table: string): Promise<void>;
57
59
  clearAll(): Promise<void>;
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.RedisClient = void 0;
4
+ const js_lib_1 = require("@naturalcycles/js-lib");
4
5
  /**
5
6
  Wraps the redis sdk with unified interface.
6
7
  Features:
@@ -98,17 +99,30 @@ class RedisClient {
98
99
  async hincr(key, field, increment = 1) {
99
100
  return await this.redis().hincrby(key, field, increment);
100
101
  }
102
+ async hincrBatch(key, incrementTuples) {
103
+ const results = {};
104
+ await this.withPipeline(async (pipeline) => {
105
+ for (const [field, increment] of incrementTuples) {
106
+ pipeline.hincrby(key, field, increment, (_err, newValue) => {
107
+ results[field] = newValue;
108
+ });
109
+ }
110
+ });
111
+ const validResults = (0, js_lib_1._stringMapEntries)(results).filter(([_, v]) => v !== undefined);
112
+ return validResults;
113
+ }
101
114
  async setWithTTL(key, value, expireAt) {
102
115
  await this.redis().set(key, value, 'EXAT', expireAt);
103
116
  }
104
- async hsetWithTTL(key, value, expireAt) {
105
- const valueKeys = Object.keys(value);
106
- const numberOfKeys = valueKeys.length;
107
- const keyList = valueKeys.join(' ');
108
- const commandString = `HEXPIREAT ${key} ${expireAt} FIELDS ${numberOfKeys} ${keyList}`;
109
- const [command, ...args] = commandString.split(' ');
110
- await this.redis().hset(key, value);
111
- await this.redis().call(command, args);
117
+ async hsetWithTTL(_key, _value, _expireAt) {
118
+ throw new Error('Not supported until Redis 7.4.0');
119
+ // const valueKeys = Object.keys(value)
120
+ // const numberOfKeys = valueKeys.length
121
+ // const keyList = valueKeys.join(' ')
122
+ // const commandString = `HEXPIREAT ${key} ${expireAt} FIELDS ${numberOfKeys} ${keyList}`
123
+ // const [command, ...args] = commandString.split(' ')
124
+ // await this.redis().hset(key, value)
125
+ // await this.redis().call(command!, args)
112
126
  }
113
127
  async mset(obj) {
114
128
  await this.redis().mset(obj);
@@ -119,6 +133,18 @@ class RedisClient {
119
133
  async incr(key, by = 1) {
120
134
  return await this.redis().incrby(key, by);
121
135
  }
136
+ async incrBatch(incrementTuples) {
137
+ const results = {};
138
+ await this.withPipeline(async (pipeline) => {
139
+ for (const [key, increment] of incrementTuples) {
140
+ pipeline.incrby(key, increment, (_err, newValue) => {
141
+ results[key] = newValue;
142
+ });
143
+ }
144
+ });
145
+ const validResults = (0, js_lib_1._stringMapEntries)(results).filter(([_, v]) => v !== undefined);
146
+ return validResults;
147
+ }
122
148
  async ttl(key) {
123
149
  return await this.redis().ttl(key);
124
150
  }
@@ -1,5 +1,4 @@
1
- import { CommonDBCreateOptions, CommonKeyValueDB, CommonKeyValueDBSaveBatchOptions, KeyValueDBTuple } from '@naturalcycles/db-lib';
2
- import { StringMap } from '@naturalcycles/js-lib';
1
+ import { CommonDBCreateOptions, CommonKeyValueDB, CommonKeyValueDBSaveBatchOptions, IncrementTuple, KeyValueDBTuple } from '@naturalcycles/db-lib';
3
2
  import { ReadableTyped } from '@naturalcycles/nodejs-lib';
4
3
  import { RedisClient } from './redisClient';
5
4
  import { RedisKeyValueDBCfg } from './redisKeyValueDB';
@@ -23,8 +22,7 @@ export declare class RedisHashKeyValueDB implements CommonKeyValueDB, AsyncDispo
23
22
  streamValues(table: string, limit?: number): ReadableTyped<Buffer>;
24
23
  streamEntries(table: string, limit?: number): ReadableTyped<KeyValueDBTuple>;
25
24
  count(table: string): Promise<number>;
26
- increment(table: string, id: string, by?: number): Promise<number>;
27
- incrementBatch(_table: string, _incrementMap: StringMap<number>): Promise<StringMap<number>>;
25
+ incrementBatch(table: string, increments: IncrementTuple[]): Promise<IncrementTuple[]>;
28
26
  createTable(table: string, opt?: CommonDBCreateOptions): Promise<void>;
29
27
  private idsToKeys;
30
28
  private idToKey;
@@ -94,11 +94,11 @@ class RedisHashKeyValueDB {
94
94
  match: `${table}:*`,
95
95
  });
96
96
  }
97
- async increment(table, id, by = 1) {
98
- return await this.client.hincr(this.keyOfHashField, this.idToKey(table, id), by);
99
- }
100
- async incrementBatch(_table, _incrementMap) {
101
- throw new Error('Not implemented');
97
+ async incrementBatch(table, increments) {
98
+ const incrementTuplesWithInternalKeys = increments.map(([id, v]) => [this.idToKey(table, id), v]);
99
+ const resultsWithInternalKeys = await this.client.hincrBatch(this.keyOfHashField, incrementTuplesWithInternalKeys);
100
+ const results = resultsWithInternalKeys.map(([k, v]) => [this.keyToId(table, k), v]);
101
+ return results;
102
102
  }
103
103
  async createTable(table, opt) {
104
104
  if (!opt?.dropIfExists)
@@ -1,5 +1,4 @@
1
- import { CommonDBCreateOptions, CommonKeyValueDB, CommonKeyValueDBSaveBatchOptions, KeyValueDBTuple } from '@naturalcycles/db-lib';
2
- import { StringMap } from '@naturalcycles/js-lib';
1
+ import { CommonDBCreateOptions, CommonKeyValueDB, CommonKeyValueDBSaveBatchOptions, IncrementTuple, KeyValueDBTuple } from '@naturalcycles/db-lib';
3
2
  import { ReadableTyped } from '@naturalcycles/nodejs-lib';
4
3
  import { RedisClient } from './redisClient';
5
4
  export interface RedisKeyValueDBCfg {
@@ -21,8 +20,7 @@ export declare class RedisKeyValueDB implements CommonKeyValueDB, AsyncDisposabl
21
20
  streamValues(table: string, limit?: number): ReadableTyped<Buffer>;
22
21
  streamEntries(table: string, limit?: number): ReadableTyped<KeyValueDBTuple>;
23
22
  count(table: string): Promise<number>;
24
- increment(table: string, id: string, by?: number): Promise<number>;
25
- incrementBatch(_table: string, _incrementMap: StringMap<number>): Promise<StringMap<number>>;
23
+ incrementBatch(table: string, increments: IncrementTuple[]): Promise<IncrementTuple[]>;
26
24
  createTable(table: string, opt?: CommonDBCreateOptions): Promise<void>;
27
25
  private idsToKeys;
28
26
  private idToKey;
@@ -89,11 +89,11 @@ class RedisKeyValueDB {
89
89
  match: `${table}:*`,
90
90
  });
91
91
  }
92
- async increment(table, id, by = 1) {
93
- return await this.client.incr(this.idToKey(table, id), by);
94
- }
95
- async incrementBatch(_table, _incrementMap) {
96
- throw new Error('Not implemented');
92
+ async incrementBatch(table, increments) {
93
+ const incrementTuplesWithInternalKeys = increments.map(([id, v]) => [this.idToKey(table, id), v]);
94
+ const resultsWithInternalKeys = await this.client.incrBatch(incrementTuplesWithInternalKeys);
95
+ const results = resultsWithInternalKeys.map(([k, v]) => [this.keyToId(table, k), v]);
96
+ return results;
97
97
  }
98
98
  async createTable(table, opt) {
99
99
  if (!opt?.dropIfExists)
package/package.json CHANGED
@@ -40,7 +40,7 @@
40
40
  "engines": {
41
41
  "node": ">=20.13"
42
42
  },
43
- "version": "3.1.1",
43
+ "version": "3.2.0",
44
44
  "description": "Redis implementation of CommonKeyValueDB interface",
45
45
  "author": "Natural Cycles Team",
46
46
  "license": "MIT"
@@ -1,9 +1,11 @@
1
1
  import {
2
+ _stringMapEntries,
2
3
  AnyObject,
3
4
  CommonLogger,
4
5
  NullableBuffer,
5
6
  NullableString,
6
7
  Promisable,
8
+ StringMap,
7
9
  UnixTimestampNumber,
8
10
  } from '@naturalcycles/js-lib'
9
11
  import { ReadableTyped } from '@naturalcycles/nodejs-lib'
@@ -157,6 +159,25 @@ export class RedisClient implements CommonClient {
157
159
  return await this.redis().hincrby(key, field, increment)
158
160
  }
159
161
 
162
+ async hincrBatch(key: string, incrementTuples: [string, number][]): Promise<[string, number][]> {
163
+ const results: StringMap<number | undefined> = {}
164
+
165
+ await this.withPipeline(async pipeline => {
166
+ for (const [field, increment] of incrementTuples) {
167
+ pipeline.hincrby(key, field, increment, (_err, newValue) => {
168
+ results[field] = newValue
169
+ })
170
+ }
171
+ })
172
+
173
+ const validResults = _stringMapEntries(results).filter(([_, v]) => v !== undefined) as [
174
+ string,
175
+ number,
176
+ ][]
177
+
178
+ return validResults
179
+ }
180
+
160
181
  async setWithTTL(
161
182
  key: string,
162
183
  value: string | number | Buffer,
@@ -165,14 +186,19 @@ export class RedisClient implements CommonClient {
165
186
  await this.redis().set(key, value, 'EXAT', expireAt)
166
187
  }
167
188
 
168
- async hsetWithTTL(key: string, value: AnyObject, expireAt: UnixTimestampNumber): Promise<void> {
169
- const valueKeys = Object.keys(value)
170
- const numberOfKeys = valueKeys.length
171
- const keyList = valueKeys.join(' ')
172
- const commandString = `HEXPIREAT ${key} ${expireAt} FIELDS ${numberOfKeys} ${keyList}`
173
- const [command, ...args] = commandString.split(' ')
174
- await this.redis().hset(key, value)
175
- await this.redis().call(command!, args)
189
+ async hsetWithTTL(
190
+ _key: string,
191
+ _value: AnyObject,
192
+ _expireAt: UnixTimestampNumber,
193
+ ): Promise<void> {
194
+ throw new Error('Not supported until Redis 7.4.0')
195
+ // const valueKeys = Object.keys(value)
196
+ // const numberOfKeys = valueKeys.length
197
+ // const keyList = valueKeys.join(' ')
198
+ // const commandString = `HEXPIREAT ${key} ${expireAt} FIELDS ${numberOfKeys} ${keyList}`
199
+ // const [command, ...args] = commandString.split(' ')
200
+ // await this.redis().hset(key, value)
201
+ // await this.redis().call(command!, args)
176
202
  }
177
203
 
178
204
  async mset(obj: Record<string, string | number>): Promise<void> {
@@ -187,6 +213,25 @@ export class RedisClient implements CommonClient {
187
213
  return await this.redis().incrby(key, by)
188
214
  }
189
215
 
216
+ async incrBatch(incrementTuples: [string, number][]): Promise<[string, number][]> {
217
+ const results: StringMap<number | undefined> = {}
218
+
219
+ await this.withPipeline(async pipeline => {
220
+ for (const [key, increment] of incrementTuples) {
221
+ pipeline.incrby(key, increment, (_err, newValue) => {
222
+ results[key] = newValue
223
+ })
224
+ }
225
+ })
226
+
227
+ const validResults = _stringMapEntries(results).filter(([_, v]) => v !== undefined) as [
228
+ string,
229
+ number,
230
+ ][]
231
+
232
+ return validResults
233
+ }
234
+
190
235
  async ttl(key: string): Promise<number> {
191
236
  return await this.redis().ttl(key)
192
237
  }
@@ -3,6 +3,7 @@ import {
3
3
  CommonKeyValueDB,
4
4
  commonKeyValueDBFullSupport,
5
5
  CommonKeyValueDBSaveBatchOptions,
6
+ IncrementTuple,
6
7
  KeyValueDBTuple,
7
8
  } from '@naturalcycles/db-lib'
8
9
  import { _chunk, StringMap } from '@naturalcycles/js-lib'
@@ -121,15 +122,18 @@ export class RedisHashKeyValueDB implements CommonKeyValueDB, AsyncDisposable {
121
122
  })
122
123
  }
123
124
 
124
- async increment(table: string, id: string, by = 1): Promise<number> {
125
- return await this.client.hincr(this.keyOfHashField, this.idToKey(table, id), by)
126
- }
127
-
128
- async incrementBatch(
129
- _table: string,
130
- _incrementMap: StringMap<number>,
131
- ): Promise<StringMap<number>> {
132
- throw new Error('Not implemented')
125
+ async incrementBatch(table: string, increments: IncrementTuple[]): Promise<IncrementTuple[]> {
126
+ const incrementTuplesWithInternalKeys = increments.map(
127
+ ([id, v]) => [this.idToKey(table, id), v] as [string, number],
128
+ )
129
+ const resultsWithInternalKeys = await this.client.hincrBatch(
130
+ this.keyOfHashField,
131
+ incrementTuplesWithInternalKeys,
132
+ )
133
+ const results = resultsWithInternalKeys.map(
134
+ ([k, v]) => [this.keyToId(table, k), v] as IncrementTuple,
135
+ )
136
+ return results
133
137
  }
134
138
 
135
139
  async createTable(table: string, opt?: CommonDBCreateOptions): Promise<void> {
@@ -3,9 +3,10 @@ import {
3
3
  CommonKeyValueDB,
4
4
  commonKeyValueDBFullSupport,
5
5
  CommonKeyValueDBSaveBatchOptions,
6
+ IncrementTuple,
6
7
  KeyValueDBTuple,
7
8
  } from '@naturalcycles/db-lib'
8
- import { _isTruthy, _zip, StringMap } from '@naturalcycles/js-lib'
9
+ import { _isTruthy, _zip } from '@naturalcycles/js-lib'
9
10
  import { ReadableTyped } from '@naturalcycles/nodejs-lib'
10
11
  import { RedisClient } from './redisClient'
11
12
 
@@ -123,15 +124,15 @@ export class RedisKeyValueDB implements CommonKeyValueDB, AsyncDisposable {
123
124
  })
124
125
  }
125
126
 
126
- async increment(table: string, id: string, by = 1): Promise<number> {
127
- return await this.client.incr(this.idToKey(table, id), by)
128
- }
129
-
130
- async incrementBatch(
131
- _table: string,
132
- _incrementMap: StringMap<number>,
133
- ): Promise<StringMap<number>> {
134
- throw new Error('Not implemented')
127
+ async incrementBatch(table: string, increments: IncrementTuple[]): Promise<IncrementTuple[]> {
128
+ const incrementTuplesWithInternalKeys = increments.map(
129
+ ([id, v]) => [this.idToKey(table, id), v] as [string, number],
130
+ )
131
+ const resultsWithInternalKeys = await this.client.incrBatch(incrementTuplesWithInternalKeys)
132
+ const results = resultsWithInternalKeys.map(
133
+ ([k, v]) => [this.keyToId(table, k), v] as IncrementTuple,
134
+ )
135
+ return results
135
136
  }
136
137
 
137
138
  async createTable(table: string, opt?: CommonDBCreateOptions): Promise<void> {