@keyv/redis 4.0.0 → 4.0.2
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 +35 -13
- package/dist/index.cjs +43 -14
- package/dist/index.d.cts +24 -10
- package/dist/index.d.ts +24 -10
- package/dist/index.js +48 -16
- package/package.json +5 -20
package/README.md
CHANGED
|
@@ -47,6 +47,16 @@ const keyv = new Keyv(new KeyvRedis('redis://user:pass@localhost:6379'));
|
|
|
47
47
|
keyv.on('error', handleConnectionError);
|
|
48
48
|
```
|
|
49
49
|
|
|
50
|
+
Here is the same example but with the `Keyv` instance created with the `createKeyv` function:
|
|
51
|
+
|
|
52
|
+
```js
|
|
53
|
+
import { createKeyv } from '@keyv/redis';
|
|
54
|
+
|
|
55
|
+
const keyv = createKeyv('redis://user:pass@localhost:6379', { namespace: 'my-namespace' });
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
You only have to import the `@keyv/redis` library if you are using the `createKeyv` function. 🎉 Otherwise, you can import `Keyv` and `@keyv/redis` independently.
|
|
59
|
+
|
|
50
60
|
Here you can pass in the Redis options directly:
|
|
51
61
|
|
|
52
62
|
```js
|
|
@@ -81,17 +91,7 @@ const keyvRedis = new KeyvRedis(redis);
|
|
|
81
91
|
const keyv = new Keyv({ store: keyvRedis });
|
|
82
92
|
```
|
|
83
93
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
```js
|
|
87
|
-
import { createKeyv } from '@keyv/redis';
|
|
88
|
-
|
|
89
|
-
const keyv = createKeyv('redis://user:pass@localhost:6379', { namespace: 'my-namespace' });
|
|
90
|
-
```
|
|
91
|
-
|
|
92
|
-
You only have to import the `@keyv/redis` library if you are using the `createKeyv` function. 🎉 Otherwise, you can import `Keyv` and `@keyv/redis` independently.
|
|
93
|
-
|
|
94
|
-
# Namspaces
|
|
94
|
+
# Namespaces
|
|
95
95
|
|
|
96
96
|
You can set a namespace for your keys. This is useful if you want to manage your keys in a more organized way. Here is an example of how to set a namespace:
|
|
97
97
|
|
|
@@ -121,7 +121,7 @@ With namespaces being prefix based it is critical to understand some of the perf
|
|
|
121
121
|
|
|
122
122
|
* `useUnlink` - This option is set to `true` by default. This is because `UNLINK` is a non-blocking command that is more efficient than `DEL`. If you are not using `UNLINK` and are doing a lot of deletes it is recommended to set this option to `true`.
|
|
123
123
|
|
|
124
|
-
* `setMany`, `getMany`, `deleteMany` - These methods are more efficient than their singular counterparts.
|
|
124
|
+
* `setMany`, `getMany`, `deleteMany` - These methods are more efficient than their singular counterparts. These will be used by default in the `Keyv` library such as when using `keyv.delete(string[])` it will use `deleteMany()`.
|
|
125
125
|
|
|
126
126
|
If you want to see even better performance please see the [Using Cacheable with Redis](#using-cacheable-with-redis) section as it has non-blocking and in-memory primary caching that goes along well with this library and Keyv.
|
|
127
127
|
|
|
@@ -183,6 +183,10 @@ const cluster = createCluster({
|
|
|
183
183
|
const keyv = new Keyv({ store: new KeyvRedis(cluster) });
|
|
184
184
|
```
|
|
185
185
|
|
|
186
|
+
There are some features that are not supported in clustering such as `clear()` and `iterator()`. This is because the `SCAN` command is not supported in clustering. If you need to clear or delete keys you can use the `deleteMany()` method.
|
|
187
|
+
|
|
188
|
+
You can learn more about the `createCluster` function in the [documentation](https://github.com/redis/node-redis/blob/master/docs/clustering.md) at https://github.com/redis/node-redis/tree/master/docs.
|
|
189
|
+
|
|
186
190
|
Here is an example of how to use TLS:
|
|
187
191
|
|
|
188
192
|
```js
|
|
@@ -227,7 +231,25 @@ const keyv = new Keyv({ store: new KeyvRedis(tlsOptions) });
|
|
|
227
231
|
|
|
228
232
|
# Migrating from v3 to v4
|
|
229
233
|
|
|
230
|
-
|
|
234
|
+
Overall the API is the same as v3 with additional options and performance improvements. Here are the main changes:
|
|
235
|
+
* The `ioredis` library has been removed in favor of the `redis` aka `node-redis` library. If you want to use ioredis you can use `@keyv/keyval`
|
|
236
|
+
* The `useUnlink` option has been added to use `UNLINK` instead of `DEL` and set to true by default.
|
|
237
|
+
* The `clearBatchSize` option has been added to set the number of keys to delete in a single batch.
|
|
238
|
+
* The `clear()` and `delete()` methods now use `UNLINK` instead of `DEL`. If you want to use `DEL` you can set the `useUnlink` option to `false`.
|
|
239
|
+
* BREAKING: We no longer support redis sets. This is due to the fact that it caused significant performance issues and was not a good fit for the library.
|
|
240
|
+
* BREAKING: YOUR PREVIOUS KEYS WILL NOT BE VALID. This is because of the fixe of the namespace support and how it is handled. Now, when using `keyv` with `@keyv/redis` as the storage adapter you can do the following:
|
|
241
|
+
|
|
242
|
+
```js
|
|
243
|
+
import Keyv from 'keyv';
|
|
244
|
+
import KeyvRedis from '@keyv/redis';
|
|
245
|
+
|
|
246
|
+
const redis = new KeyvRedis('redis://user:pass@localhost:6379');
|
|
247
|
+
const keyv = new Keyv({ store: redis, namespace: 'my-namespace', useKeyPrefix: false });
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
This will make it so the storage adapter `@keyv/redis` will handle the namespace and not the `keyv` instance. If you leave it on it will just look duplicated like `my-namespace:my-namespace:key`.
|
|
251
|
+
|
|
252
|
+
|
|
231
253
|
|
|
232
254
|
# About Redis Sets and its Support in v4
|
|
233
255
|
|
package/dist/index.cjs
CHANGED
|
@@ -37,12 +37,12 @@ __export(src_exports, {
|
|
|
37
37
|
default: () => KeyvRedis
|
|
38
38
|
});
|
|
39
39
|
module.exports = __toCommonJS(src_exports);
|
|
40
|
-
var
|
|
40
|
+
var import_node_events = __toESM(require("events"), 1);
|
|
41
41
|
var import_redis = require("redis");
|
|
42
42
|
var import_keyv = require("keyv");
|
|
43
43
|
var import_redis2 = require("redis");
|
|
44
44
|
var import_keyv2 = require("keyv");
|
|
45
|
-
var KeyvRedis = class extends
|
|
45
|
+
var KeyvRedis = class extends import_node_events.default {
|
|
46
46
|
_client = (0, import_redis.createClient)();
|
|
47
47
|
_namespace;
|
|
48
48
|
_keyPrefixSeparator = "::";
|
|
@@ -59,9 +59,9 @@ var KeyvRedis = class extends import_events.default {
|
|
|
59
59
|
if (typeof connect === "string") {
|
|
60
60
|
this._client = (0, import_redis.createClient)({ url: connect });
|
|
61
61
|
} else if (connect.connect !== void 0) {
|
|
62
|
-
this._client = connect;
|
|
62
|
+
this._client = this.isClientCluster(connect) ? connect : connect;
|
|
63
63
|
} else if (connect instanceof Object) {
|
|
64
|
-
this._client = (0, import_redis.createClient)(connect);
|
|
64
|
+
this._client = connect.rootNodes === void 0 ? (0, import_redis.createClient)(connect) : (0, import_redis.createCluster)(connect);
|
|
65
65
|
}
|
|
66
66
|
}
|
|
67
67
|
this.setOptions(options);
|
|
@@ -84,13 +84,18 @@ var KeyvRedis = class extends import_events.default {
|
|
|
84
84
|
* Get the options for the adapter.
|
|
85
85
|
*/
|
|
86
86
|
get opts() {
|
|
87
|
-
|
|
87
|
+
let url = "";
|
|
88
|
+
if (this._client.options) {
|
|
89
|
+
url = this._client.options?.url ?? "redis://localhost:6379";
|
|
90
|
+
}
|
|
91
|
+
const results = {
|
|
88
92
|
namespace: this._namespace,
|
|
89
93
|
keyPrefixSeparator: this._keyPrefixSeparator,
|
|
90
94
|
clearBatchSize: this._clearBatchSize,
|
|
91
95
|
dialect: "redis",
|
|
92
|
-
url
|
|
96
|
+
url
|
|
93
97
|
};
|
|
98
|
+
return results;
|
|
94
99
|
}
|
|
95
100
|
/**
|
|
96
101
|
* Set the options for the adapter.
|
|
@@ -255,11 +260,7 @@ var KeyvRedis = class extends import_events.default {
|
|
|
255
260
|
const client = await this.getClient();
|
|
256
261
|
key = this.createKeyPrefix(key, this._namespace);
|
|
257
262
|
let deleted = 0;
|
|
258
|
-
|
|
259
|
-
deleted = await client.unlink(key);
|
|
260
|
-
} else {
|
|
261
|
-
deleted = await client.del(key);
|
|
262
|
-
}
|
|
263
|
+
deleted = await (this._useUnlink ? client.unlink(key) : client.del(key));
|
|
263
264
|
return deleted > 0;
|
|
264
265
|
}
|
|
265
266
|
/**
|
|
@@ -320,12 +321,31 @@ var KeyvRedis = class extends import_events.default {
|
|
|
320
321
|
}
|
|
321
322
|
return key;
|
|
322
323
|
}
|
|
324
|
+
/**
|
|
325
|
+
* Is the client a cluster.
|
|
326
|
+
* @returns {boolean} - true if the client is a cluster, false if not
|
|
327
|
+
*/
|
|
328
|
+
isCluster() {
|
|
329
|
+
return this.isClientCluster(this._client);
|
|
330
|
+
}
|
|
323
331
|
/**
|
|
324
332
|
* Get an async iterator for the keys and values in the store. If a namespace is provided, it will only iterate over keys with that namespace.
|
|
325
333
|
* @param {string} [namespace] - the namespace to iterate over
|
|
326
334
|
* @returns {AsyncGenerator<[string, T | undefined], void, unknown>} - async iterator with key value pairs
|
|
327
335
|
*/
|
|
328
336
|
async *iterator(namespace) {
|
|
337
|
+
if (this.isCluster()) {
|
|
338
|
+
throw new Error("Iterating over keys in a cluster is not supported.");
|
|
339
|
+
} else {
|
|
340
|
+
yield* this.iteratorClient(namespace);
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
/**
|
|
344
|
+
* Get an async iterator for the keys and values in the store. If a namespace is provided, it will only iterate over keys with that namespace.
|
|
345
|
+
* @param {string} [namespace] - the namespace to iterate over
|
|
346
|
+
* @returns {AsyncGenerator<[string, T | undefined], void, unknown>} - async iterator with key value pairs
|
|
347
|
+
*/
|
|
348
|
+
async *iteratorClient(namespace) {
|
|
329
349
|
const client = await this.getClient();
|
|
330
350
|
const match = namespace ? `${namespace}${this._keyPrefixSeparator}*` : "*";
|
|
331
351
|
let cursor = "0";
|
|
@@ -348,13 +368,13 @@ var KeyvRedis = class extends import_events.default {
|
|
|
348
368
|
}
|
|
349
369
|
/**
|
|
350
370
|
* Clear all keys in the store.
|
|
351
|
-
* IMPORTANT: this can cause performance issues if there are a large number of keys in the store. Use with caution as not recommended for production.
|
|
371
|
+
* 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.
|
|
352
372
|
* If a namespace is not set it will clear all keys with no prefix.
|
|
353
373
|
* If a namespace is set it will clear all keys with that namespace.
|
|
354
374
|
* @returns {Promise<void>}
|
|
355
375
|
*/
|
|
356
376
|
async clear() {
|
|
357
|
-
await this.clearNamespace(this._namespace);
|
|
377
|
+
await (this.isCluster() ? this.clearNamespaceCluster(this._namespace) : this.clearNamespace(this._namespace));
|
|
358
378
|
}
|
|
359
379
|
async clearNamespace(namespace) {
|
|
360
380
|
try {
|
|
@@ -384,6 +404,15 @@ var KeyvRedis = class extends import_events.default {
|
|
|
384
404
|
this.emit("error", error);
|
|
385
405
|
}
|
|
386
406
|
}
|
|
407
|
+
async clearNamespaceCluster(namespace) {
|
|
408
|
+
throw new Error("Clearing all keys in a cluster is not supported.");
|
|
409
|
+
}
|
|
410
|
+
isClientCluster(client) {
|
|
411
|
+
if (client.options === void 0 && client.scan === void 0) {
|
|
412
|
+
return true;
|
|
413
|
+
}
|
|
414
|
+
return false;
|
|
415
|
+
}
|
|
387
416
|
setOptions(options) {
|
|
388
417
|
if (!options) {
|
|
389
418
|
return;
|
|
@@ -409,7 +438,7 @@ var KeyvRedis = class extends import_events.default {
|
|
|
409
438
|
};
|
|
410
439
|
function createKeyv(connect, options) {
|
|
411
440
|
const adapter = new KeyvRedis(connect, options);
|
|
412
|
-
const keyv = new import_keyv.Keyv({ store: adapter, namespace: options?.namespace });
|
|
441
|
+
const keyv = new import_keyv.Keyv({ store: adapter, namespace: options?.namespace, useKeyPrefix: false });
|
|
413
442
|
return keyv;
|
|
414
443
|
}
|
|
415
444
|
// Annotate the CommonJS export names for ESM import in node:
|
package/dist/index.d.cts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import EventEmitter from 'events';
|
|
2
|
-
import { RedisClientOptions,
|
|
3
|
-
export { RedisClientOptions, RedisClientType, createClient, createCluster } from 'redis';
|
|
1
|
+
import EventEmitter from 'node:events';
|
|
2
|
+
import { RedisClientType, RedisClusterType, RedisModules, RedisFunctions, RedisScripts, RedisClientOptions, RedisClusterOptions } from 'redis';
|
|
3
|
+
export { RedisClientOptions, RedisClientType, RedisClusterOptions, RedisClusterType, createClient, createCluster } from 'redis';
|
|
4
4
|
import { KeyvStoreAdapter, Keyv } from 'keyv';
|
|
5
5
|
export { Keyv } from 'keyv';
|
|
6
6
|
|
|
@@ -46,6 +46,7 @@ type KeyvRedisEntry<T> = {
|
|
|
46
46
|
*/
|
|
47
47
|
ttl?: number;
|
|
48
48
|
};
|
|
49
|
+
type RedisClientConnectionType = RedisClientType | RedisClusterType<RedisModules, RedisFunctions, RedisScripts>;
|
|
49
50
|
declare class KeyvRedis extends EventEmitter implements KeyvStoreAdapter {
|
|
50
51
|
private _client;
|
|
51
52
|
private _namespace;
|
|
@@ -57,15 +58,15 @@ declare class KeyvRedis extends EventEmitter implements KeyvStoreAdapter {
|
|
|
57
58
|
* @param {string | RedisClientOptions | RedisClientType} [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.
|
|
58
59
|
* @param {KeyvRedisOptions} [options] Options for the adapter such as namespace, keyPrefixSeparator, and clearBatchSize.
|
|
59
60
|
*/
|
|
60
|
-
constructor(connect?: string | RedisClientOptions |
|
|
61
|
+
constructor(connect?: string | RedisClientOptions | RedisClusterOptions | RedisClientConnectionType, options?: KeyvRedisOptions);
|
|
61
62
|
/**
|
|
62
63
|
* Get the Redis client.
|
|
63
64
|
*/
|
|
64
|
-
get client():
|
|
65
|
+
get client(): RedisClientConnectionType;
|
|
65
66
|
/**
|
|
66
67
|
* Set the Redis client.
|
|
67
68
|
*/
|
|
68
|
-
set client(value:
|
|
69
|
+
set client(value: RedisClientConnectionType);
|
|
69
70
|
/**
|
|
70
71
|
* Get the options for the adapter.
|
|
71
72
|
*/
|
|
@@ -113,7 +114,7 @@ declare class KeyvRedis extends EventEmitter implements KeyvStoreAdapter {
|
|
|
113
114
|
/**
|
|
114
115
|
* Get the Redis URL used to connect to the server. This is used to get a connected client.
|
|
115
116
|
*/
|
|
116
|
-
getClient(): Promise<
|
|
117
|
+
getClient(): Promise<RedisClientConnectionType>;
|
|
117
118
|
/**
|
|
118
119
|
* Set a key value pair in the store. TTL is in milliseconds.
|
|
119
120
|
* @param {string} key - the key to set
|
|
@@ -181,30 +182,43 @@ declare class KeyvRedis extends EventEmitter implements KeyvStoreAdapter {
|
|
|
181
182
|
* @returns {string} - the key without the namespace such as 'key'
|
|
182
183
|
*/
|
|
183
184
|
getKeyWithoutPrefix(key: string, namespace?: string): string;
|
|
185
|
+
/**
|
|
186
|
+
* Is the client a cluster.
|
|
187
|
+
* @returns {boolean} - true if the client is a cluster, false if not
|
|
188
|
+
*/
|
|
189
|
+
isCluster(): boolean;
|
|
184
190
|
/**
|
|
185
191
|
* Get an async iterator for the keys and values in the store. If a namespace is provided, it will only iterate over keys with that namespace.
|
|
186
192
|
* @param {string} [namespace] - the namespace to iterate over
|
|
187
193
|
* @returns {AsyncGenerator<[string, T | undefined], void, unknown>} - async iterator with key value pairs
|
|
188
194
|
*/
|
|
189
195
|
iterator<Value>(namespace?: string): AsyncGenerator<[string, Value | undefined], void, unknown>;
|
|
196
|
+
/**
|
|
197
|
+
* Get an async iterator for the keys and values in the store. If a namespace is provided, it will only iterate over keys with that namespace.
|
|
198
|
+
* @param {string} [namespace] - the namespace to iterate over
|
|
199
|
+
* @returns {AsyncGenerator<[string, T | undefined], void, unknown>} - async iterator with key value pairs
|
|
200
|
+
*/
|
|
201
|
+
iteratorClient<Value>(namespace?: string): AsyncGenerator<[string, Value | undefined], void, unknown>;
|
|
190
202
|
/**
|
|
191
203
|
* Clear all keys in the store.
|
|
192
|
-
* IMPORTANT: this can cause performance issues if there are a large number of keys in the store. Use with caution as not recommended for production.
|
|
204
|
+
* 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.
|
|
193
205
|
* If a namespace is not set it will clear all keys with no prefix.
|
|
194
206
|
* If a namespace is set it will clear all keys with that namespace.
|
|
195
207
|
* @returns {Promise<void>}
|
|
196
208
|
*/
|
|
197
209
|
clear(): Promise<void>;
|
|
198
210
|
private clearNamespace;
|
|
211
|
+
private clearNamespaceCluster;
|
|
212
|
+
private isClientCluster;
|
|
199
213
|
private setOptions;
|
|
200
214
|
private initClient;
|
|
201
215
|
}
|
|
202
216
|
/**
|
|
203
|
-
* Will create a Keyv instance with the Redis adapter.
|
|
217
|
+
* Will create a Keyv instance with the Redis adapter. This will also set the namespace and useKeyPrefix to false.
|
|
204
218
|
* @param connect
|
|
205
219
|
* @param options
|
|
206
220
|
* @returns {Keyv} - Keyv instance with the Redis adapter
|
|
207
221
|
*/
|
|
208
222
|
declare function createKeyv(connect?: string | RedisClientOptions | RedisClientType, options?: KeyvRedisOptions): Keyv;
|
|
209
223
|
|
|
210
|
-
export { type KeyvRedisEntry, type KeyvRedisOptions, type KeyvRedisPropertyOptions, createKeyv, KeyvRedis as default };
|
|
224
|
+
export { type KeyvRedisEntry, type KeyvRedisOptions, type KeyvRedisPropertyOptions, type RedisClientConnectionType, createKeyv, KeyvRedis as default };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import EventEmitter from 'events';
|
|
2
|
-
import { RedisClientOptions,
|
|
3
|
-
export { RedisClientOptions, RedisClientType, createClient, createCluster } from 'redis';
|
|
1
|
+
import EventEmitter from 'node:events';
|
|
2
|
+
import { RedisClientType, RedisClusterType, RedisModules, RedisFunctions, RedisScripts, RedisClientOptions, RedisClusterOptions } from 'redis';
|
|
3
|
+
export { RedisClientOptions, RedisClientType, RedisClusterOptions, RedisClusterType, createClient, createCluster } from 'redis';
|
|
4
4
|
import { KeyvStoreAdapter, Keyv } from 'keyv';
|
|
5
5
|
export { Keyv } from 'keyv';
|
|
6
6
|
|
|
@@ -46,6 +46,7 @@ type KeyvRedisEntry<T> = {
|
|
|
46
46
|
*/
|
|
47
47
|
ttl?: number;
|
|
48
48
|
};
|
|
49
|
+
type RedisClientConnectionType = RedisClientType | RedisClusterType<RedisModules, RedisFunctions, RedisScripts>;
|
|
49
50
|
declare class KeyvRedis extends EventEmitter implements KeyvStoreAdapter {
|
|
50
51
|
private _client;
|
|
51
52
|
private _namespace;
|
|
@@ -57,15 +58,15 @@ declare class KeyvRedis extends EventEmitter implements KeyvStoreAdapter {
|
|
|
57
58
|
* @param {string | RedisClientOptions | RedisClientType} [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.
|
|
58
59
|
* @param {KeyvRedisOptions} [options] Options for the adapter such as namespace, keyPrefixSeparator, and clearBatchSize.
|
|
59
60
|
*/
|
|
60
|
-
constructor(connect?: string | RedisClientOptions |
|
|
61
|
+
constructor(connect?: string | RedisClientOptions | RedisClusterOptions | RedisClientConnectionType, options?: KeyvRedisOptions);
|
|
61
62
|
/**
|
|
62
63
|
* Get the Redis client.
|
|
63
64
|
*/
|
|
64
|
-
get client():
|
|
65
|
+
get client(): RedisClientConnectionType;
|
|
65
66
|
/**
|
|
66
67
|
* Set the Redis client.
|
|
67
68
|
*/
|
|
68
|
-
set client(value:
|
|
69
|
+
set client(value: RedisClientConnectionType);
|
|
69
70
|
/**
|
|
70
71
|
* Get the options for the adapter.
|
|
71
72
|
*/
|
|
@@ -113,7 +114,7 @@ declare class KeyvRedis extends EventEmitter implements KeyvStoreAdapter {
|
|
|
113
114
|
/**
|
|
114
115
|
* Get the Redis URL used to connect to the server. This is used to get a connected client.
|
|
115
116
|
*/
|
|
116
|
-
getClient(): Promise<
|
|
117
|
+
getClient(): Promise<RedisClientConnectionType>;
|
|
117
118
|
/**
|
|
118
119
|
* Set a key value pair in the store. TTL is in milliseconds.
|
|
119
120
|
* @param {string} key - the key to set
|
|
@@ -181,30 +182,43 @@ declare class KeyvRedis extends EventEmitter implements KeyvStoreAdapter {
|
|
|
181
182
|
* @returns {string} - the key without the namespace such as 'key'
|
|
182
183
|
*/
|
|
183
184
|
getKeyWithoutPrefix(key: string, namespace?: string): string;
|
|
185
|
+
/**
|
|
186
|
+
* Is the client a cluster.
|
|
187
|
+
* @returns {boolean} - true if the client is a cluster, false if not
|
|
188
|
+
*/
|
|
189
|
+
isCluster(): boolean;
|
|
184
190
|
/**
|
|
185
191
|
* Get an async iterator for the keys and values in the store. If a namespace is provided, it will only iterate over keys with that namespace.
|
|
186
192
|
* @param {string} [namespace] - the namespace to iterate over
|
|
187
193
|
* @returns {AsyncGenerator<[string, T | undefined], void, unknown>} - async iterator with key value pairs
|
|
188
194
|
*/
|
|
189
195
|
iterator<Value>(namespace?: string): AsyncGenerator<[string, Value | undefined], void, unknown>;
|
|
196
|
+
/**
|
|
197
|
+
* Get an async iterator for the keys and values in the store. If a namespace is provided, it will only iterate over keys with that namespace.
|
|
198
|
+
* @param {string} [namespace] - the namespace to iterate over
|
|
199
|
+
* @returns {AsyncGenerator<[string, T | undefined], void, unknown>} - async iterator with key value pairs
|
|
200
|
+
*/
|
|
201
|
+
iteratorClient<Value>(namespace?: string): AsyncGenerator<[string, Value | undefined], void, unknown>;
|
|
190
202
|
/**
|
|
191
203
|
* Clear all keys in the store.
|
|
192
|
-
* IMPORTANT: this can cause performance issues if there are a large number of keys in the store. Use with caution as not recommended for production.
|
|
204
|
+
* 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.
|
|
193
205
|
* If a namespace is not set it will clear all keys with no prefix.
|
|
194
206
|
* If a namespace is set it will clear all keys with that namespace.
|
|
195
207
|
* @returns {Promise<void>}
|
|
196
208
|
*/
|
|
197
209
|
clear(): Promise<void>;
|
|
198
210
|
private clearNamespace;
|
|
211
|
+
private clearNamespaceCluster;
|
|
212
|
+
private isClientCluster;
|
|
199
213
|
private setOptions;
|
|
200
214
|
private initClient;
|
|
201
215
|
}
|
|
202
216
|
/**
|
|
203
|
-
* Will create a Keyv instance with the Redis adapter.
|
|
217
|
+
* Will create a Keyv instance with the Redis adapter. This will also set the namespace and useKeyPrefix to false.
|
|
204
218
|
* @param connect
|
|
205
219
|
* @param options
|
|
206
220
|
* @returns {Keyv} - Keyv instance with the Redis adapter
|
|
207
221
|
*/
|
|
208
222
|
declare function createKeyv(connect?: string | RedisClientOptions | RedisClientType, options?: KeyvRedisOptions): Keyv;
|
|
209
223
|
|
|
210
|
-
export { type KeyvRedisEntry, type KeyvRedisOptions, type KeyvRedisPropertyOptions, createKeyv, KeyvRedis as default };
|
|
224
|
+
export { type KeyvRedisEntry, type KeyvRedisOptions, type KeyvRedisPropertyOptions, type RedisClientConnectionType, createKeyv, KeyvRedis as default };
|
package/dist/index.js
CHANGED
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
// src/index.ts
|
|
2
|
-
import EventEmitter from "events";
|
|
3
|
-
import {
|
|
2
|
+
import EventEmitter from "node:events";
|
|
3
|
+
import {
|
|
4
|
+
createClient,
|
|
5
|
+
createCluster
|
|
6
|
+
} from "redis";
|
|
4
7
|
import { Keyv } from "keyv";
|
|
5
8
|
import {
|
|
6
9
|
createClient as createClient2,
|
|
7
|
-
createCluster
|
|
10
|
+
createCluster as createCluster2
|
|
8
11
|
} from "redis";
|
|
9
12
|
import {
|
|
10
13
|
Keyv as Keyv2
|
|
@@ -26,9 +29,9 @@ var KeyvRedis = class extends EventEmitter {
|
|
|
26
29
|
if (typeof connect === "string") {
|
|
27
30
|
this._client = createClient({ url: connect });
|
|
28
31
|
} else if (connect.connect !== void 0) {
|
|
29
|
-
this._client = connect;
|
|
32
|
+
this._client = this.isClientCluster(connect) ? connect : connect;
|
|
30
33
|
} else if (connect instanceof Object) {
|
|
31
|
-
this._client = createClient(connect);
|
|
34
|
+
this._client = connect.rootNodes === void 0 ? createClient(connect) : createCluster(connect);
|
|
32
35
|
}
|
|
33
36
|
}
|
|
34
37
|
this.setOptions(options);
|
|
@@ -51,13 +54,18 @@ var KeyvRedis = class extends EventEmitter {
|
|
|
51
54
|
* Get the options for the adapter.
|
|
52
55
|
*/
|
|
53
56
|
get opts() {
|
|
54
|
-
|
|
57
|
+
let url = "";
|
|
58
|
+
if (this._client.options) {
|
|
59
|
+
url = this._client.options?.url ?? "redis://localhost:6379";
|
|
60
|
+
}
|
|
61
|
+
const results = {
|
|
55
62
|
namespace: this._namespace,
|
|
56
63
|
keyPrefixSeparator: this._keyPrefixSeparator,
|
|
57
64
|
clearBatchSize: this._clearBatchSize,
|
|
58
65
|
dialect: "redis",
|
|
59
|
-
url
|
|
66
|
+
url
|
|
60
67
|
};
|
|
68
|
+
return results;
|
|
61
69
|
}
|
|
62
70
|
/**
|
|
63
71
|
* Set the options for the adapter.
|
|
@@ -222,11 +230,7 @@ var KeyvRedis = class extends EventEmitter {
|
|
|
222
230
|
const client = await this.getClient();
|
|
223
231
|
key = this.createKeyPrefix(key, this._namespace);
|
|
224
232
|
let deleted = 0;
|
|
225
|
-
|
|
226
|
-
deleted = await client.unlink(key);
|
|
227
|
-
} else {
|
|
228
|
-
deleted = await client.del(key);
|
|
229
|
-
}
|
|
233
|
+
deleted = await (this._useUnlink ? client.unlink(key) : client.del(key));
|
|
230
234
|
return deleted > 0;
|
|
231
235
|
}
|
|
232
236
|
/**
|
|
@@ -287,12 +291,31 @@ var KeyvRedis = class extends EventEmitter {
|
|
|
287
291
|
}
|
|
288
292
|
return key;
|
|
289
293
|
}
|
|
294
|
+
/**
|
|
295
|
+
* Is the client a cluster.
|
|
296
|
+
* @returns {boolean} - true if the client is a cluster, false if not
|
|
297
|
+
*/
|
|
298
|
+
isCluster() {
|
|
299
|
+
return this.isClientCluster(this._client);
|
|
300
|
+
}
|
|
290
301
|
/**
|
|
291
302
|
* Get an async iterator for the keys and values in the store. If a namespace is provided, it will only iterate over keys with that namespace.
|
|
292
303
|
* @param {string} [namespace] - the namespace to iterate over
|
|
293
304
|
* @returns {AsyncGenerator<[string, T | undefined], void, unknown>} - async iterator with key value pairs
|
|
294
305
|
*/
|
|
295
306
|
async *iterator(namespace) {
|
|
307
|
+
if (this.isCluster()) {
|
|
308
|
+
throw new Error("Iterating over keys in a cluster is not supported.");
|
|
309
|
+
} else {
|
|
310
|
+
yield* this.iteratorClient(namespace);
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
/**
|
|
314
|
+
* Get an async iterator for the keys and values in the store. If a namespace is provided, it will only iterate over keys with that namespace.
|
|
315
|
+
* @param {string} [namespace] - the namespace to iterate over
|
|
316
|
+
* @returns {AsyncGenerator<[string, T | undefined], void, unknown>} - async iterator with key value pairs
|
|
317
|
+
*/
|
|
318
|
+
async *iteratorClient(namespace) {
|
|
296
319
|
const client = await this.getClient();
|
|
297
320
|
const match = namespace ? `${namespace}${this._keyPrefixSeparator}*` : "*";
|
|
298
321
|
let cursor = "0";
|
|
@@ -315,13 +338,13 @@ var KeyvRedis = class extends EventEmitter {
|
|
|
315
338
|
}
|
|
316
339
|
/**
|
|
317
340
|
* Clear all keys in the store.
|
|
318
|
-
* IMPORTANT: this can cause performance issues if there are a large number of keys in the store. Use with caution as not recommended for production.
|
|
341
|
+
* 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.
|
|
319
342
|
* If a namespace is not set it will clear all keys with no prefix.
|
|
320
343
|
* If a namespace is set it will clear all keys with that namespace.
|
|
321
344
|
* @returns {Promise<void>}
|
|
322
345
|
*/
|
|
323
346
|
async clear() {
|
|
324
|
-
await this.clearNamespace(this._namespace);
|
|
347
|
+
await (this.isCluster() ? this.clearNamespaceCluster(this._namespace) : this.clearNamespace(this._namespace));
|
|
325
348
|
}
|
|
326
349
|
async clearNamespace(namespace) {
|
|
327
350
|
try {
|
|
@@ -351,6 +374,15 @@ var KeyvRedis = class extends EventEmitter {
|
|
|
351
374
|
this.emit("error", error);
|
|
352
375
|
}
|
|
353
376
|
}
|
|
377
|
+
async clearNamespaceCluster(namespace) {
|
|
378
|
+
throw new Error("Clearing all keys in a cluster is not supported.");
|
|
379
|
+
}
|
|
380
|
+
isClientCluster(client) {
|
|
381
|
+
if (client.options === void 0 && client.scan === void 0) {
|
|
382
|
+
return true;
|
|
383
|
+
}
|
|
384
|
+
return false;
|
|
385
|
+
}
|
|
354
386
|
setOptions(options) {
|
|
355
387
|
if (!options) {
|
|
356
388
|
return;
|
|
@@ -376,13 +408,13 @@ var KeyvRedis = class extends EventEmitter {
|
|
|
376
408
|
};
|
|
377
409
|
function createKeyv(connect, options) {
|
|
378
410
|
const adapter = new KeyvRedis(connect, options);
|
|
379
|
-
const keyv = new Keyv({ store: adapter, namespace: options?.namespace });
|
|
411
|
+
const keyv = new Keyv({ store: adapter, namespace: options?.namespace, useKeyPrefix: false });
|
|
380
412
|
return keyv;
|
|
381
413
|
}
|
|
382
414
|
export {
|
|
383
415
|
Keyv2 as Keyv,
|
|
384
416
|
createClient2 as createClient,
|
|
385
|
-
createCluster,
|
|
417
|
+
createCluster2 as createCluster,
|
|
386
418
|
createKeyv,
|
|
387
419
|
KeyvRedis as default
|
|
388
420
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@keyv/redis",
|
|
3
|
-
"version": "4.0.
|
|
3
|
+
"version": "4.0.2",
|
|
4
4
|
"description": "Redis storage adapter for Keyv",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.cjs",
|
|
@@ -12,23 +12,6 @@
|
|
|
12
12
|
"import": "./dist/index.js"
|
|
13
13
|
}
|
|
14
14
|
},
|
|
15
|
-
"xo": {
|
|
16
|
-
"rules": {
|
|
17
|
-
"import/no-named-as-default": "off",
|
|
18
|
-
"unicorn/prefer-module": "off",
|
|
19
|
-
"unicorn/prefer-event-target": "off",
|
|
20
|
-
"unicorn/prefer-node-protocol": "off",
|
|
21
|
-
"unicorn/no-typeof-undefined": "off",
|
|
22
|
-
"import/extensions": "off",
|
|
23
|
-
"@typescript-eslint/no-unsafe-call": "off",
|
|
24
|
-
"@typescript-eslint/no-unsafe-assignment": "off",
|
|
25
|
-
"@typescript-eslint/no-unsafe-return": "off",
|
|
26
|
-
"unicorn/prefer-ternary": "off",
|
|
27
|
-
"unicorn/no-array-callback-reference": "off",
|
|
28
|
-
"import/no-extraneous-dependencies": "off",
|
|
29
|
-
"@typescript-eslint/no-confusing-void-expression": "off"
|
|
30
|
-
}
|
|
31
|
-
},
|
|
32
15
|
"repository": {
|
|
33
16
|
"type": "git",
|
|
34
17
|
"url": "git+https://github.com/jaredwray/keyv.git"
|
|
@@ -51,14 +34,16 @@
|
|
|
51
34
|
},
|
|
52
35
|
"homepage": "https://github.com/jaredwray/keyv",
|
|
53
36
|
"dependencies": {
|
|
54
|
-
"
|
|
55
|
-
"
|
|
37
|
+
"keyv": "*",
|
|
38
|
+
"redis": "^4.7.0"
|
|
56
39
|
},
|
|
57
40
|
"devDependencies": {
|
|
58
41
|
"@keyv/test-suite": "*",
|
|
42
|
+
"@vitest/coverage-v8": "^2.1.5",
|
|
59
43
|
"rimraf": "^6.0.1",
|
|
60
44
|
"timekeeper": "^2.3.1",
|
|
61
45
|
"tsd": "^0.31.2",
|
|
46
|
+
"vitest": "^2.1.5",
|
|
62
47
|
"xo": "^0.59.3"
|
|
63
48
|
},
|
|
64
49
|
"tsd": {
|