@keyv/redis 4.1.0 → 4.3.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/README.md CHANGED
@@ -26,11 +26,13 @@ Redis storage adapter for [Keyv](https://github.com/jaredwray/keyv).
26
26
  # Table of Contents
27
27
  * [Usage](#usage)
28
28
  * [Namespaces](#namespaces)
29
+ * [Typescript](#typescript)
29
30
  * [Performance Considerations](#performance-considerations)
30
31
  * [High Memory Usage on Redis Server](#high-memory-usage-on-redis-server)
31
32
  * [Using Cacheable with Redis](#using-cacheable-with-redis)
32
33
  * [Clustering and TLS Support](#clustering-and-tls-support)
33
34
  * [API](#api)
35
+ * [Using Custom Redis Client Events](#using-custom-redis-client-events)
34
36
  * [Migrating from v3 to v4](#migrating-from-v3-to-v4)
35
37
  * [About Redis Sets and its Support in v4](#about-redis-sets-and-its-support-in-v4)
36
38
  * [License](#license)
@@ -110,6 +112,34 @@ keyv.namespace = 'my-namespace';
110
112
 
111
113
  NOTE: If you plan to do many clears or deletes, it is recommended to read the [Performance Considerations](#performance-considerations) section.
112
114
 
115
+ ## Typescript
116
+
117
+ When initializing `KeyvRedis`, you can specify the type of the values you are storing and you can also specify types when calling methods:
118
+
119
+ ```typescript
120
+ import Keyv from 'keyv';
121
+ import KeyvRedis, { createClient } from '@keyv/redis';
122
+
123
+
124
+ interface User {
125
+ id: number
126
+ name: string
127
+ }
128
+
129
+ const redis = createClient('redis://user:pass@localhost:6379');
130
+
131
+ const keyvRedis = new KeyvRedis<User>(redis);
132
+ const keyv = new Keyv({ store: keyvRedis });
133
+
134
+ await keyv.set("user:1", { id: 1, name: "Alice" })
135
+ const user = await keyv.get("user:1")
136
+ console.log(user.name) // 'Alice'
137
+
138
+ // specify types when calling methods
139
+ const user = await keyv.get<User>("user:1")
140
+ console.log(user.name) // 'Alice'
141
+ ```
142
+
113
143
  # Performance Considerations
114
144
 
115
145
  With namespaces being prefix based it is critical to understand some of the performance considerations we have made:
@@ -225,9 +255,34 @@ const keyv = new Keyv({ store: new KeyvRedis(tlsOptions) });
225
255
  * **delete** - Delete a key.
226
256
  * **deleteMany** - Delete multiple keys.
227
257
  * **clear** - Clear all keys in the namespace. If the namespace is not set it will clear all keys that are not prefixed with a namespace unless `noNamespaceAffectsAll` is set to `true`.
228
- * **disconnect** - Disconnect from the Redis server.
258
+ * **disconnect** - Disconnect from the Redis server using `Quit` command. If you set `force` to `true` it will force the disconnect.
229
259
  * **iterator** - Create a new iterator for the keys. If the namespace is not set it will iterate over all keys that are not prefixed with a namespace unless `noNamespaceAffectsAll` is set to `true`.
230
260
 
261
+ # Using Custom Redis Client Events
262
+
263
+ Keyv by default supports the `error` event across all storage adapters. If you want to listen to other events you can do so by accessing the `client` property of the `KeyvRedis` instance. Here is an example of how to do that:
264
+
265
+ ```js
266
+ import {createKeyv} from '@keyv/redis';
267
+
268
+ const keyv = createKeyv('redis://user:pass@localhost:6379');
269
+ const redisClient = keyv.store.client;
270
+
271
+ redisClient.on('connect', () => {
272
+ console.log('Redis client connected');
273
+ });
274
+
275
+ redisClient.on('reconnecting', () => {
276
+ console.log('Redis client reconnecting');
277
+ });
278
+
279
+ redisClient.on('end', () => {
280
+ console.log('Redis client disconnected');
281
+ });
282
+ ```
283
+
284
+ Here are some of the events you can listen to: https://www.npmjs.com/package/redis#events
285
+
231
286
  # Migrating from v3 to v4
232
287
 
233
288
  Overall the API is the same as v3 with additional options and performance improvements. Here are the main changes:
package/dist/index.cjs CHANGED
@@ -28,15 +28,15 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
28
28
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
29
 
30
30
  // src/index.ts
31
- var src_exports = {};
32
- __export(src_exports, {
31
+ var index_exports = {};
32
+ __export(index_exports, {
33
33
  Keyv: () => import_keyv2.Keyv,
34
34
  createClient: () => import_redis2.createClient,
35
35
  createCluster: () => import_redis2.createCluster,
36
36
  createKeyv: () => createKeyv,
37
37
  default: () => KeyvRedis
38
38
  });
39
- module.exports = __toCommonJS(src_exports);
39
+ module.exports = __toCommonJS(index_exports);
40
40
  var import_node_events = __toESM(require("events"), 1);
41
41
  var import_redis = require("redis");
42
42
  var import_keyv = require("keyv");
@@ -199,7 +199,7 @@ var KeyvRedis = class extends import_node_events.default {
199
199
  }
200
200
  /**
201
201
  * Will set many key value pairs in the store. TTL is in milliseconds. This will be done as a single transaction.
202
- * @param {Array<KeyvRedisEntry<string>>} entries - the key value pairs to set with optional ttl
202
+ * @param {KeyvEntry[]} entries - the key value pairs to set with optional ttl
203
203
  */
204
204
  async setMany(entries) {
205
205
  const client = await this.getClient();
@@ -213,6 +213,7 @@ var KeyvRedis = class extends import_node_events.default {
213
213
  }
214
214
  }
215
215
  await multi.exec();
216
+ return entries.map(() => true);
216
217
  }
217
218
  /**
218
219
  * Check if a key exists in the store.
@@ -307,10 +308,12 @@ var KeyvRedis = class extends import_node_events.default {
307
308
  /**
308
309
  * Disconnect from the Redis server.
309
310
  * @returns {Promise<void>}
311
+ * @param {boolean} [force] - it will send a quit command if false, otherwise it will send a disconnect command to forcefully disconnect.
312
+ * @see {@link https://github.com/redis/node-redis/tree/master/packages/redis#disconnecting}
310
313
  */
311
- async disconnect() {
314
+ async disconnect(force) {
312
315
  if (this._client.isOpen) {
313
- await this._client.disconnect();
316
+ await (force ? this._client.disconnect() : this._client.quit());
314
317
  }
315
318
  }
316
319
  /**
@@ -515,6 +518,7 @@ var KeyvRedis = class extends import_node_events.default {
515
518
  }
516
519
  };
517
520
  function createKeyv(connect, options) {
521
+ connect ??= "redis://localhost:6379";
518
522
  const adapter = new KeyvRedis(connect, options);
519
523
  const keyv = new import_keyv.Keyv({ store: adapter, namespace: options?.namespace, useKeyPrefix: false });
520
524
  return keyv;
package/dist/index.d.cts CHANGED
@@ -1,7 +1,7 @@
1
1
  import EventEmitter from 'node:events';
2
2
  import { RedisClientType, RedisClusterType, RedisModules, RedisFunctions, RedisScripts, RedisClientOptions, RedisClusterOptions } from 'redis';
3
3
  export { RedisClientOptions, RedisClientType, RedisClusterOptions, RedisClusterType, createClient, createCluster } from 'redis';
4
- import { KeyvStoreAdapter, Keyv } from 'keyv';
4
+ import { KeyvStoreAdapter, KeyvEntry, Keyv } from 'keyv';
5
5
  export { Keyv } from 'keyv';
6
6
 
7
7
  type KeyvRedisOptions = {
@@ -53,7 +53,7 @@ type KeyvRedisEntry<T> = {
53
53
  ttl?: number;
54
54
  };
55
55
  type RedisClientConnectionType = RedisClientType | RedisClusterType<RedisModules, RedisFunctions, RedisScripts>;
56
- declare class KeyvRedis extends EventEmitter implements KeyvStoreAdapter {
56
+ declare class KeyvRedis<T> extends EventEmitter implements KeyvStoreAdapter {
57
57
  private _client;
58
58
  private _namespace;
59
59
  private _keyPrefixSeparator;
@@ -142,9 +142,9 @@ declare class KeyvRedis extends EventEmitter implements KeyvStoreAdapter {
142
142
  set(key: string, value: string, ttl?: number): Promise<void>;
143
143
  /**
144
144
  * Will set many key value pairs in the store. TTL is in milliseconds. This will be done as a single transaction.
145
- * @param {Array<KeyvRedisEntry<string>>} entries - the key value pairs to set with optional ttl
145
+ * @param {KeyvEntry[]} entries - the key value pairs to set with optional ttl
146
146
  */
147
- setMany(entries: Array<KeyvRedisEntry<string>>): Promise<void>;
147
+ setMany(entries: KeyvEntry[]): Promise<boolean[]>;
148
148
  /**
149
149
  * Check if a key exists in the store.
150
150
  * @param {string} key - the key to check
@@ -162,13 +162,13 @@ declare class KeyvRedis extends EventEmitter implements KeyvStoreAdapter {
162
162
  * @param {string} key - the key to get
163
163
  * @returns {Promise<string | undefined>} - the value or undefined if the key does not exist
164
164
  */
165
- get<T>(key: string): Promise<T | undefined>;
165
+ get<U = T>(key: string): Promise<U | undefined>;
166
166
  /**
167
167
  * Get many values from the store. If a key does not exist, it will return undefined.
168
168
  * @param {Array<string>} keys - the keys to get
169
169
  * @returns {Promise<Array<string | undefined>>} - array of values or undefined if the key does not exist
170
170
  */
171
- getMany<T>(keys: string[]): Promise<Array<T | undefined>>;
171
+ getMany<U = T>(keys: string[]): Promise<Array<U | undefined>>;
172
172
  /**
173
173
  * Delete a key from the store.
174
174
  * @param {string} key - the key to delete
@@ -184,8 +184,10 @@ declare class KeyvRedis extends EventEmitter implements KeyvStoreAdapter {
184
184
  /**
185
185
  * Disconnect from the Redis server.
186
186
  * @returns {Promise<void>}
187
+ * @param {boolean} [force] - it will send a quit command if false, otherwise it will send a disconnect command to forcefully disconnect.
188
+ * @see {@link https://github.com/redis/node-redis/tree/master/packages/redis#disconnecting}
187
189
  */
188
- disconnect(): Promise<void>;
190
+ disconnect(force?: boolean): Promise<void>;
189
191
  /**
190
192
  * Helper function to create a key with a namespace.
191
193
  * @param {string} key - the key to prefix
@@ -216,7 +218,7 @@ declare class KeyvRedis extends EventEmitter implements KeyvStoreAdapter {
216
218
  * @param {string} [namespace] - the namespace to iterate over
217
219
  * @returns {AsyncGenerator<[string, T | undefined], void, unknown>} - async iterator with key value pairs
218
220
  */
219
- iterator<Value>(namespace?: string): AsyncGenerator<[string, Value | undefined], void, unknown>;
221
+ iterator<U = T>(namespace?: string): AsyncGenerator<[string, U | undefined], void, unknown>;
220
222
  /**
221
223
  * Clear all keys in the store.
222
224
  * IMPORTANT: this can cause performance issues if there are a large number of keys in the store and worse with clusters. Use with caution as not recommended for production.
@@ -252,8 +254,8 @@ declare class KeyvRedis extends EventEmitter implements KeyvStoreAdapter {
252
254
  }
253
255
  /**
254
256
  * Will create a Keyv instance with the Redis adapter. This will also set the namespace and useKeyPrefix to false.
255
- * @param connect
256
- * @param options
257
+ * @param connect - How to connect to the Redis server. If string pass in the url, if object pass in the options, if RedisClient pass in the client. If nothing is passed in, it will default to 'redis://localhost:6379'.
258
+ * @param {KeyvRedisOptions} options - Options for the adapter such as namespace, keyPrefixSeparator, and clearBatchSize.
257
259
  * @returns {Keyv} - Keyv instance with the Redis adapter
258
260
  */
259
261
  declare function createKeyv(connect?: string | RedisClientOptions | RedisClientType, options?: KeyvRedisOptions): Keyv;
package/dist/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import EventEmitter from 'node:events';
2
2
  import { RedisClientType, RedisClusterType, RedisModules, RedisFunctions, RedisScripts, RedisClientOptions, RedisClusterOptions } from 'redis';
3
3
  export { RedisClientOptions, RedisClientType, RedisClusterOptions, RedisClusterType, createClient, createCluster } from 'redis';
4
- import { KeyvStoreAdapter, Keyv } from 'keyv';
4
+ import { KeyvStoreAdapter, KeyvEntry, Keyv } from 'keyv';
5
5
  export { Keyv } from 'keyv';
6
6
 
7
7
  type KeyvRedisOptions = {
@@ -53,7 +53,7 @@ type KeyvRedisEntry<T> = {
53
53
  ttl?: number;
54
54
  };
55
55
  type RedisClientConnectionType = RedisClientType | RedisClusterType<RedisModules, RedisFunctions, RedisScripts>;
56
- declare class KeyvRedis extends EventEmitter implements KeyvStoreAdapter {
56
+ declare class KeyvRedis<T> extends EventEmitter implements KeyvStoreAdapter {
57
57
  private _client;
58
58
  private _namespace;
59
59
  private _keyPrefixSeparator;
@@ -142,9 +142,9 @@ declare class KeyvRedis extends EventEmitter implements KeyvStoreAdapter {
142
142
  set(key: string, value: string, ttl?: number): Promise<void>;
143
143
  /**
144
144
  * Will set many key value pairs in the store. TTL is in milliseconds. This will be done as a single transaction.
145
- * @param {Array<KeyvRedisEntry<string>>} entries - the key value pairs to set with optional ttl
145
+ * @param {KeyvEntry[]} entries - the key value pairs to set with optional ttl
146
146
  */
147
- setMany(entries: Array<KeyvRedisEntry<string>>): Promise<void>;
147
+ setMany(entries: KeyvEntry[]): Promise<boolean[]>;
148
148
  /**
149
149
  * Check if a key exists in the store.
150
150
  * @param {string} key - the key to check
@@ -162,13 +162,13 @@ declare class KeyvRedis extends EventEmitter implements KeyvStoreAdapter {
162
162
  * @param {string} key - the key to get
163
163
  * @returns {Promise<string | undefined>} - the value or undefined if the key does not exist
164
164
  */
165
- get<T>(key: string): Promise<T | undefined>;
165
+ get<U = T>(key: string): Promise<U | undefined>;
166
166
  /**
167
167
  * Get many values from the store. If a key does not exist, it will return undefined.
168
168
  * @param {Array<string>} keys - the keys to get
169
169
  * @returns {Promise<Array<string | undefined>>} - array of values or undefined if the key does not exist
170
170
  */
171
- getMany<T>(keys: string[]): Promise<Array<T | undefined>>;
171
+ getMany<U = T>(keys: string[]): Promise<Array<U | undefined>>;
172
172
  /**
173
173
  * Delete a key from the store.
174
174
  * @param {string} key - the key to delete
@@ -184,8 +184,10 @@ declare class KeyvRedis extends EventEmitter implements KeyvStoreAdapter {
184
184
  /**
185
185
  * Disconnect from the Redis server.
186
186
  * @returns {Promise<void>}
187
+ * @param {boolean} [force] - it will send a quit command if false, otherwise it will send a disconnect command to forcefully disconnect.
188
+ * @see {@link https://github.com/redis/node-redis/tree/master/packages/redis#disconnecting}
187
189
  */
188
- disconnect(): Promise<void>;
190
+ disconnect(force?: boolean): Promise<void>;
189
191
  /**
190
192
  * Helper function to create a key with a namespace.
191
193
  * @param {string} key - the key to prefix
@@ -216,7 +218,7 @@ declare class KeyvRedis extends EventEmitter implements KeyvStoreAdapter {
216
218
  * @param {string} [namespace] - the namespace to iterate over
217
219
  * @returns {AsyncGenerator<[string, T | undefined], void, unknown>} - async iterator with key value pairs
218
220
  */
219
- iterator<Value>(namespace?: string): AsyncGenerator<[string, Value | undefined], void, unknown>;
221
+ iterator<U = T>(namespace?: string): AsyncGenerator<[string, U | undefined], void, unknown>;
220
222
  /**
221
223
  * Clear all keys in the store.
222
224
  * IMPORTANT: this can cause performance issues if there are a large number of keys in the store and worse with clusters. Use with caution as not recommended for production.
@@ -252,8 +254,8 @@ declare class KeyvRedis extends EventEmitter implements KeyvStoreAdapter {
252
254
  }
253
255
  /**
254
256
  * Will create a Keyv instance with the Redis adapter. This will also set the namespace and useKeyPrefix to false.
255
- * @param connect
256
- * @param options
257
+ * @param connect - How to connect to the Redis server. If string pass in the url, if object pass in the options, if RedisClient pass in the client. If nothing is passed in, it will default to 'redis://localhost:6379'.
258
+ * @param {KeyvRedisOptions} options - Options for the adapter such as namespace, keyPrefixSeparator, and clearBatchSize.
257
259
  * @returns {Keyv} - Keyv instance with the Redis adapter
258
260
  */
259
261
  declare function createKeyv(connect?: string | RedisClientOptions | RedisClientType, options?: KeyvRedisOptions): Keyv;
package/dist/index.js CHANGED
@@ -169,7 +169,7 @@ var KeyvRedis = class extends EventEmitter {
169
169
  }
170
170
  /**
171
171
  * Will set many key value pairs in the store. TTL is in milliseconds. This will be done as a single transaction.
172
- * @param {Array<KeyvRedisEntry<string>>} entries - the key value pairs to set with optional ttl
172
+ * @param {KeyvEntry[]} entries - the key value pairs to set with optional ttl
173
173
  */
174
174
  async setMany(entries) {
175
175
  const client = await this.getClient();
@@ -183,6 +183,7 @@ var KeyvRedis = class extends EventEmitter {
183
183
  }
184
184
  }
185
185
  await multi.exec();
186
+ return entries.map(() => true);
186
187
  }
187
188
  /**
188
189
  * Check if a key exists in the store.
@@ -277,10 +278,12 @@ var KeyvRedis = class extends EventEmitter {
277
278
  /**
278
279
  * Disconnect from the Redis server.
279
280
  * @returns {Promise<void>}
281
+ * @param {boolean} [force] - it will send a quit command if false, otherwise it will send a disconnect command to forcefully disconnect.
282
+ * @see {@link https://github.com/redis/node-redis/tree/master/packages/redis#disconnecting}
280
283
  */
281
- async disconnect() {
284
+ async disconnect(force) {
282
285
  if (this._client.isOpen) {
283
- await this._client.disconnect();
286
+ await (force ? this._client.disconnect() : this._client.quit());
284
287
  }
285
288
  }
286
289
  /**
@@ -485,6 +488,7 @@ var KeyvRedis = class extends EventEmitter {
485
488
  }
486
489
  };
487
490
  function createKeyv(connect, options) {
491
+ connect ??= "redis://localhost:6379";
488
492
  const adapter = new KeyvRedis(connect, options);
489
493
  const keyv = new Keyv({ store: adapter, namespace: options?.namespace, useKeyPrefix: false });
490
494
  return keyv;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@keyv/redis",
3
- "version": "4.1.0",
3
+ "version": "4.3.0",
4
4
  "description": "Redis storage adapter for Keyv",
5
5
  "type": "module",
6
6
  "main": "dist/index.cjs",
@@ -36,16 +36,16 @@
36
36
  "dependencies": {
37
37
  "cluster-key-slot": "^1.1.2",
38
38
  "redis": "^4.7.0",
39
- "keyv": "^5.2.1"
39
+ "keyv": "^5.3.0"
40
40
  },
41
41
  "devDependencies": {
42
- "@vitest/coverage-v8": "^2.1.8",
42
+ "@vitest/coverage-v8": "^3.0.7",
43
43
  "rimraf": "^6.0.1",
44
44
  "timekeeper": "^2.3.1",
45
45
  "tsd": "^0.31.2",
46
- "vitest": "^2.1.8",
46
+ "vitest": "^3.0.7",
47
47
  "xo": "^0.60.0",
48
- "@keyv/test-suite": "^2.0.3"
48
+ "@keyv/test-suite": "^2.0.5"
49
49
  },
50
50
  "tsd": {
51
51
  "directory": "test"
@@ -59,8 +59,8 @@
59
59
  ],
60
60
  "scripts": {
61
61
  "build": "rimraf ./dist && tsup src/index.ts --format cjs,esm --dts --clean",
62
- "test": "xo --fix && vitest run --coverage",
63
- "test:ci": "xo && vitest --run --sequence.setupFiles=list",
62
+ "test": "xo --fix && vitest run --coverage --typecheck",
63
+ "test:ci": "xo && vitest --run --sequence.setupFiles=list --typecheck",
64
64
  "clean": "rimraf ./node_modules ./coverage ./dist"
65
65
  }
66
66
  }