@tekir/redis 0.1.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/LICENSE +21 -0
- package/README.md +31 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +3 -0
- package/dist/manager.d.ts +121 -0
- package/dist/manager.js +153 -0
- package/dist/provider.d.ts +20 -0
- package/dist/provider.js +25 -0
- package/dist/redis.d.ts +272 -0
- package/dist/redis.js +316 -0
- package/dist/types.d.ts +31 -0
- package/dist/types.js +1 -0
- package/package.json +56 -0
- package/src/index.ts +4 -0
- package/src/manager.ts +161 -0
- package/src/provider.ts +26 -0
- package/src/redis.ts +349 -0
- package/src/types.ts +32 -0
package/dist/redis.js
ADDED
|
@@ -0,0 +1,316 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Redis client wrapper around Bun's native RedisClient.
|
|
3
|
+
*
|
|
4
|
+
* Provides a high-level API for string, hash, set, and pub/sub operations,
|
|
5
|
+
* plus JSON helpers and a cache-aside `remember` method.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```ts
|
|
9
|
+
* const redis = new Redis({ url: 'redis://localhost:6379', prefix: 'app:' })
|
|
10
|
+
* await redis.set('greeting', 'hello')
|
|
11
|
+
* const val = await redis.get('greeting') // 'hello'
|
|
12
|
+
* ```
|
|
13
|
+
*/
|
|
14
|
+
export class Redis {
|
|
15
|
+
client;
|
|
16
|
+
prefix;
|
|
17
|
+
config;
|
|
18
|
+
/**
|
|
19
|
+
* @param config - Redis connection configuration.
|
|
20
|
+
*/
|
|
21
|
+
constructor(config = {}) {
|
|
22
|
+
this.config = config;
|
|
23
|
+
this.prefix = config.prefix || '';
|
|
24
|
+
const { RedisClient } = Bun;
|
|
25
|
+
const url = config.url || process.env.REDIS_URL || 'redis://localhost:6379';
|
|
26
|
+
this.client = new RedisClient(url, {
|
|
27
|
+
connectionTimeout: config.connectionTimeout,
|
|
28
|
+
idleTimeout: config.idleTimeout,
|
|
29
|
+
autoReconnect: config.autoReconnect ?? true,
|
|
30
|
+
maxRetries: config.maxRetries ?? 10,
|
|
31
|
+
enableAutoPipelining: config.enableAutoPipelining ?? true,
|
|
32
|
+
tls: config.tls,
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
key(k) {
|
|
36
|
+
return this.prefix ? `${this.prefix}:${k}` : k;
|
|
37
|
+
}
|
|
38
|
+
// ─── Connection ────────────────────────────────────────
|
|
39
|
+
/**
|
|
40
|
+
* Open the connection to the Redis server.
|
|
41
|
+
*
|
|
42
|
+
* @returns A promise that resolves once the connection is established.
|
|
43
|
+
*
|
|
44
|
+
* @example
|
|
45
|
+
* ```ts
|
|
46
|
+
* await redis.connect()
|
|
47
|
+
* ```
|
|
48
|
+
*/
|
|
49
|
+
async connect() { await this.client.connect(); }
|
|
50
|
+
/**
|
|
51
|
+
* Close the connection to the Redis server.
|
|
52
|
+
*/
|
|
53
|
+
close() { this.client.close(); }
|
|
54
|
+
/**
|
|
55
|
+
* Whether the client is currently connected to Redis.
|
|
56
|
+
*
|
|
57
|
+
* @returns `true` if the connection is active.
|
|
58
|
+
*/
|
|
59
|
+
get connected() { return this.client.connected; }
|
|
60
|
+
// ─── String operations ────────────────────────────────
|
|
61
|
+
/**
|
|
62
|
+
* Get the value of a key.
|
|
63
|
+
*
|
|
64
|
+
* @param key - The key to retrieve.
|
|
65
|
+
* @returns The string value, or `null` if the key does not exist.
|
|
66
|
+
*
|
|
67
|
+
* @example
|
|
68
|
+
* ```ts
|
|
69
|
+
* const val = await redis.get('name') // 'Alice' | null
|
|
70
|
+
* ```
|
|
71
|
+
*/
|
|
72
|
+
async get(key) { return this.client.get(this.key(key)); }
|
|
73
|
+
/**
|
|
74
|
+
* Set the value of a key.
|
|
75
|
+
*
|
|
76
|
+
* @param key - The key to set.
|
|
77
|
+
* @param value - The string or numeric value to store.
|
|
78
|
+
*
|
|
79
|
+
* @example
|
|
80
|
+
* ```ts
|
|
81
|
+
* await redis.set('counter', 42)
|
|
82
|
+
* ```
|
|
83
|
+
*/
|
|
84
|
+
async set(key, value) { await this.client.set(this.key(key), String(value)); }
|
|
85
|
+
/**
|
|
86
|
+
* Delete one or more keys.
|
|
87
|
+
*
|
|
88
|
+
* @param keys - The keys to delete.
|
|
89
|
+
*
|
|
90
|
+
* @example
|
|
91
|
+
* ```ts
|
|
92
|
+
* await redis.del('key1', 'key2')
|
|
93
|
+
* ```
|
|
94
|
+
*/
|
|
95
|
+
async del(...keys) { await this.client.del(...keys.map(k => this.key(k))); }
|
|
96
|
+
/**
|
|
97
|
+
* Check whether a key exists.
|
|
98
|
+
*
|
|
99
|
+
* @param key - The key to check.
|
|
100
|
+
* @returns `true` if the key exists.
|
|
101
|
+
*/
|
|
102
|
+
async exists(key) { return this.client.exists(this.key(key)); }
|
|
103
|
+
/**
|
|
104
|
+
* Increment the integer value of a key by one.
|
|
105
|
+
*
|
|
106
|
+
* @param key - The key to increment.
|
|
107
|
+
* @returns The new value after incrementing.
|
|
108
|
+
*/
|
|
109
|
+
async incr(key) { return this.client.incr(this.key(key)); }
|
|
110
|
+
/**
|
|
111
|
+
* Decrement the integer value of a key by one.
|
|
112
|
+
*
|
|
113
|
+
* @param key - The key to decrement.
|
|
114
|
+
* @returns The new value after decrementing.
|
|
115
|
+
*/
|
|
116
|
+
async decr(key) { return this.client.decr(this.key(key)); }
|
|
117
|
+
/**
|
|
118
|
+
* Set a timeout on a key (in seconds).
|
|
119
|
+
*
|
|
120
|
+
* @param key - The key to set the expiry on.
|
|
121
|
+
* @param seconds - Time-to-live in seconds.
|
|
122
|
+
*/
|
|
123
|
+
async expire(key, seconds) { await this.client.expire(this.key(key), seconds); }
|
|
124
|
+
/**
|
|
125
|
+
* Get the remaining time-to-live of a key in seconds.
|
|
126
|
+
*
|
|
127
|
+
* @param key - The key to query.
|
|
128
|
+
* @returns Remaining TTL in seconds, `-1` if no expiry is set, `-2` if the key does not exist.
|
|
129
|
+
*/
|
|
130
|
+
async ttl(key) { return this.client.ttl(this.key(key)); }
|
|
131
|
+
// ─── Hash operations ──────────────────────────────────
|
|
132
|
+
/**
|
|
133
|
+
* Get the value of a single field in a hash.
|
|
134
|
+
*
|
|
135
|
+
* @param key - The hash key.
|
|
136
|
+
* @param field - The field name within the hash.
|
|
137
|
+
* @returns The field value, or `null` if the field or key does not exist.
|
|
138
|
+
*/
|
|
139
|
+
async hget(key, field) { return this.client.hget(this.key(key), field); }
|
|
140
|
+
/**
|
|
141
|
+
* Set multiple field-value pairs in a hash.
|
|
142
|
+
*
|
|
143
|
+
* @param key - The hash key.
|
|
144
|
+
* @param fields - An array of alternating field names and values (e.g. `['f1', 'v1', 'f2', 'v2']`).
|
|
145
|
+
*/
|
|
146
|
+
async hmset(key, fields) { await this.client.hmset(this.key(key), fields); }
|
|
147
|
+
/**
|
|
148
|
+
* Get the values of multiple fields in a hash.
|
|
149
|
+
*
|
|
150
|
+
* @param key - The hash key.
|
|
151
|
+
* @param fields - An array of field names to retrieve.
|
|
152
|
+
* @returns An array of values corresponding to the requested fields (`null` for missing fields).
|
|
153
|
+
*/
|
|
154
|
+
async hmget(key, fields) { return this.client.hmget(this.key(key), fields); }
|
|
155
|
+
/**
|
|
156
|
+
* Increment a numeric field in a hash by a given amount.
|
|
157
|
+
*
|
|
158
|
+
* @param key - The hash key.
|
|
159
|
+
* @param field - The field name to increment.
|
|
160
|
+
* @param increment - The integer amount to add.
|
|
161
|
+
* @returns The new value of the field after incrementing.
|
|
162
|
+
*/
|
|
163
|
+
async hincrby(key, field, increment) { return this.client.hincrby(this.key(key), field, increment); }
|
|
164
|
+
// ─── Set operations ───────────────────────────────────
|
|
165
|
+
/**
|
|
166
|
+
* Add one or more members to a set.
|
|
167
|
+
*
|
|
168
|
+
* @param key - The set key.
|
|
169
|
+
* @param members - The members to add.
|
|
170
|
+
* @returns The number of members that were added (excluding already-present members).
|
|
171
|
+
*/
|
|
172
|
+
async sadd(key, ...members) { return this.client.sadd(this.key(key), ...members); }
|
|
173
|
+
/**
|
|
174
|
+
* Remove one or more members from a set.
|
|
175
|
+
*
|
|
176
|
+
* @param key - The set key.
|
|
177
|
+
* @param members - The members to remove.
|
|
178
|
+
* @returns The number of members that were removed.
|
|
179
|
+
*/
|
|
180
|
+
async srem(key, ...members) { return this.client.srem(this.key(key), ...members); }
|
|
181
|
+
/**
|
|
182
|
+
* Check whether a value is a member of a set.
|
|
183
|
+
*
|
|
184
|
+
* @param key - The set key.
|
|
185
|
+
* @param member - The value to check for.
|
|
186
|
+
* @returns `true` if the member exists in the set.
|
|
187
|
+
*/
|
|
188
|
+
async sismember(key, member) { return this.client.sismember(this.key(key), member); }
|
|
189
|
+
/**
|
|
190
|
+
* Get all members of a set.
|
|
191
|
+
*
|
|
192
|
+
* @param key - The set key.
|
|
193
|
+
* @returns An array of all members in the set.
|
|
194
|
+
*/
|
|
195
|
+
async smembers(key) { return this.client.smembers(this.key(key)); }
|
|
196
|
+
// ─── Pub/Sub ──────────────────────────────────────────
|
|
197
|
+
/**
|
|
198
|
+
* Publish a message to a channel.
|
|
199
|
+
*
|
|
200
|
+
* @param channel - The channel name.
|
|
201
|
+
* @param message - The message string to publish.
|
|
202
|
+
*/
|
|
203
|
+
async publish(channel, message) { await this.client.publish(channel, message); }
|
|
204
|
+
/**
|
|
205
|
+
* Subscribe to a channel and receive messages via a callback.
|
|
206
|
+
*
|
|
207
|
+
* @param channel - The channel name to subscribe to.
|
|
208
|
+
* @param callback - Invoked for each message received on the channel.
|
|
209
|
+
*
|
|
210
|
+
* @example
|
|
211
|
+
* ```ts
|
|
212
|
+
* await redis.subscribe('events', (msg, ch) => {
|
|
213
|
+
* console.log(`Received on ${ch}: ${msg}`)
|
|
214
|
+
* })
|
|
215
|
+
* ```
|
|
216
|
+
*/
|
|
217
|
+
async subscribe(channel, callback) {
|
|
218
|
+
await this.client.subscribe(channel, callback);
|
|
219
|
+
}
|
|
220
|
+
/**
|
|
221
|
+
* Unsubscribe from a channel, or from all channels if none is specified.
|
|
222
|
+
*
|
|
223
|
+
* @param channel - The channel to unsubscribe from. Omit to unsubscribe from all.
|
|
224
|
+
*/
|
|
225
|
+
async unsubscribe(channel) { await this.client.unsubscribe(channel); }
|
|
226
|
+
// ─── Raw command ──────────────────────────────────────
|
|
227
|
+
/**
|
|
228
|
+
* Send a raw Redis command.
|
|
229
|
+
*
|
|
230
|
+
* @param command - The Redis command string (e.g. `'PING'`, `'INFO'`).
|
|
231
|
+
* @param args - Arguments for the command.
|
|
232
|
+
* @returns The raw response from Redis.
|
|
233
|
+
*
|
|
234
|
+
* @example
|
|
235
|
+
* ```ts
|
|
236
|
+
* const pong = await redis.send('PING') // 'PONG'
|
|
237
|
+
* ```
|
|
238
|
+
*/
|
|
239
|
+
async send(command, args = []) { return this.client.send(command, args); }
|
|
240
|
+
// ─── JSON helpers ─────────────────────────────────────
|
|
241
|
+
/**
|
|
242
|
+
* Get a value from Redis and parse it as JSON.
|
|
243
|
+
*
|
|
244
|
+
* @param key - The key to retrieve.
|
|
245
|
+
* @returns The parsed object, or `null` if the key does not exist or parsing fails.
|
|
246
|
+
*
|
|
247
|
+
* @example
|
|
248
|
+
* ```ts
|
|
249
|
+
* const user = await redis.getJSON<{ name: string }>('user:1')
|
|
250
|
+
* ```
|
|
251
|
+
*/
|
|
252
|
+
async getJSON(key) {
|
|
253
|
+
const val = await this.get(key);
|
|
254
|
+
if (val === null)
|
|
255
|
+
return null;
|
|
256
|
+
try {
|
|
257
|
+
return JSON.parse(val);
|
|
258
|
+
}
|
|
259
|
+
catch {
|
|
260
|
+
return null;
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
/**
|
|
264
|
+
* Serialize a value as JSON and store it in Redis, with an optional TTL.
|
|
265
|
+
*
|
|
266
|
+
* @param key - The key to store the value under.
|
|
267
|
+
* @param value - The value to JSON-serialize and store.
|
|
268
|
+
* @param expireSeconds - Optional time-to-live in seconds.
|
|
269
|
+
*
|
|
270
|
+
* @example
|
|
271
|
+
* ```ts
|
|
272
|
+
* await redis.setJSON('user:1', { name: 'Alice' }, 3600)
|
|
273
|
+
* ```
|
|
274
|
+
*/
|
|
275
|
+
async setJSON(key, value, expireSeconds) {
|
|
276
|
+
await this.set(key, JSON.stringify(value));
|
|
277
|
+
if (expireSeconds)
|
|
278
|
+
await this.expire(key, expireSeconds);
|
|
279
|
+
}
|
|
280
|
+
/**
|
|
281
|
+
* Cache-aside helper: return the cached value if it exists, otherwise execute
|
|
282
|
+
* the callback, store the result in Redis with a TTL, and return it.
|
|
283
|
+
*
|
|
284
|
+
* @param key - The cache key.
|
|
285
|
+
* @param seconds - Time-to-live in seconds for the cached value.
|
|
286
|
+
* @param callback - Async function invoked to compute the value on a cache miss.
|
|
287
|
+
* @returns The cached or freshly computed value.
|
|
288
|
+
*
|
|
289
|
+
* @example
|
|
290
|
+
* ```ts
|
|
291
|
+
* const users = await redis.remember('all-users', 60, async () => {
|
|
292
|
+
* return db.query('SELECT * FROM users')
|
|
293
|
+
* })
|
|
294
|
+
* ```
|
|
295
|
+
*/
|
|
296
|
+
async remember(key, seconds, callback) {
|
|
297
|
+
const cached = await this.getJSON(key);
|
|
298
|
+
if (cached !== null)
|
|
299
|
+
return cached;
|
|
300
|
+
const value = await callback();
|
|
301
|
+
await this.setJSON(key, value, seconds);
|
|
302
|
+
return value;
|
|
303
|
+
}
|
|
304
|
+
/**
|
|
305
|
+
* Delete all keys in the currently selected database.
|
|
306
|
+
*
|
|
307
|
+
* @returns A promise that resolves once the database has been flushed.
|
|
308
|
+
*/
|
|
309
|
+
async flushdb() { await this.send('FLUSHDB', []); }
|
|
310
|
+
/**
|
|
311
|
+
* Get the underlying Bun `RedisClient` instance for advanced operations.
|
|
312
|
+
*
|
|
313
|
+
* @returns The raw Bun RedisClient.
|
|
314
|
+
*/
|
|
315
|
+
getClient() { return this.client; }
|
|
316
|
+
}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/** Configuration for a single Redis connection. */
|
|
2
|
+
export interface RedisConnectionConfig {
|
|
3
|
+
/** Redis connection URL (default: `'redis://localhost:6379'`). */
|
|
4
|
+
url?: string;
|
|
5
|
+
/** Key prefix applied to all operations (e.g. `'myapp:'`). */
|
|
6
|
+
prefix?: string;
|
|
7
|
+
/** Connection timeout in milliseconds. */
|
|
8
|
+
connectionTimeout?: number;
|
|
9
|
+
/** Idle timeout in milliseconds before the connection is closed. */
|
|
10
|
+
idleTimeout?: number;
|
|
11
|
+
/** Whether to automatically reconnect on connection loss (default: `true`). */
|
|
12
|
+
autoReconnect?: boolean;
|
|
13
|
+
/** Maximum number of reconnection attempts (default: `10`). */
|
|
14
|
+
maxRetries?: number;
|
|
15
|
+
/** Enable automatic pipelining for improved throughput (default: `true`). */
|
|
16
|
+
enableAutoPipelining?: boolean;
|
|
17
|
+
/** Enable TLS, or provide a TLS options object. */
|
|
18
|
+
tls?: boolean | object;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Redis configuration supporting both single-connection and multi-connection setups.
|
|
22
|
+
*
|
|
23
|
+
* For a single connection, specify the connection fields directly.
|
|
24
|
+
* For multiple connections, use the `connections` map and optionally set `default`.
|
|
25
|
+
*/
|
|
26
|
+
export type RedisConfig = RedisConnectionConfig & {
|
|
27
|
+
/** Name of the default connection (default: `'default'`). */
|
|
28
|
+
default?: string;
|
|
29
|
+
/** Named connection configurations. */
|
|
30
|
+
connections?: Record<string, RedisConnectionConfig>;
|
|
31
|
+
};
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/package.json
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@tekir/redis",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Redis connection and client management",
|
|
5
|
+
"author": "dev@tekir.io",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "git+https://github.com/tekir-io/tekir.git",
|
|
10
|
+
"directory": "packages/tekir-redis"
|
|
11
|
+
},
|
|
12
|
+
"homepage": "https://github.com/tekir-io/tekir/tree/main/packages/tekir-redis",
|
|
13
|
+
"keywords": [
|
|
14
|
+
"tekir",
|
|
15
|
+
"bun",
|
|
16
|
+
"typescript",
|
|
17
|
+
"framework",
|
|
18
|
+
"nodejs",
|
|
19
|
+
"fullstack"
|
|
20
|
+
],
|
|
21
|
+
"type": "module",
|
|
22
|
+
"main": "dist/index.js",
|
|
23
|
+
"types": "src/index.ts",
|
|
24
|
+
"files": [
|
|
25
|
+
"src",
|
|
26
|
+
"README.md",
|
|
27
|
+
"LICENSE",
|
|
28
|
+
"dist"
|
|
29
|
+
],
|
|
30
|
+
"publishConfig": {
|
|
31
|
+
"access": "public",
|
|
32
|
+
"types": "dist/index.d.ts",
|
|
33
|
+
"exports": {
|
|
34
|
+
".": {
|
|
35
|
+
"types": "./dist/index.d.ts",
|
|
36
|
+
"import": "./dist/index.js",
|
|
37
|
+
"default": "./dist/index.js"
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
},
|
|
41
|
+
"dependencies": {
|
|
42
|
+
"@tekir/core": "^0.1.0"
|
|
43
|
+
},
|
|
44
|
+
"scripts": {
|
|
45
|
+
"build": "rm -rf dist && tsc --noEmit false",
|
|
46
|
+
"prepublishOnly": "bun run build"
|
|
47
|
+
},
|
|
48
|
+
"exports": {
|
|
49
|
+
".": {
|
|
50
|
+
"bun": "./src/index.ts",
|
|
51
|
+
"types": "./src/index.ts",
|
|
52
|
+
"import": "./dist/index.js",
|
|
53
|
+
"default": "./dist/index.js"
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
package/src/index.ts
ADDED
package/src/manager.ts
ADDED
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
import type { RedisConfig } from './types'
|
|
2
|
+
import { Redis } from './redis'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Manages multiple named Redis connections with lazy initialization.
|
|
6
|
+
*
|
|
7
|
+
* Provides proxy methods that delegate to the default connection for convenience,
|
|
8
|
+
* while also allowing access to any named connection via {@link RedisManager.connection}.
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```ts
|
|
12
|
+
* const manager = new RedisManager({
|
|
13
|
+
* default: 'cache',
|
|
14
|
+
* connections: {
|
|
15
|
+
* cache: { url: 'redis://localhost:6379/0' },
|
|
16
|
+
* session: { url: 'redis://localhost:6379/1' },
|
|
17
|
+
* },
|
|
18
|
+
* })
|
|
19
|
+
* await manager.set('key', 'value') // uses 'cache'
|
|
20
|
+
* await manager.connection('session').set('k', 'v') // uses 'session'
|
|
21
|
+
* ```
|
|
22
|
+
*/
|
|
23
|
+
export class RedisManager {
|
|
24
|
+
private _connections = new Map<string, Redis>()
|
|
25
|
+
private _defaultName: string
|
|
26
|
+
private _config: RedisConfig
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Create a new RedisManager.
|
|
30
|
+
*
|
|
31
|
+
* @param config - Redis configuration with optional named connections.
|
|
32
|
+
*/
|
|
33
|
+
constructor(config: RedisConfig = {}) {
|
|
34
|
+
this._config = config
|
|
35
|
+
this._defaultName = config.default || 'default'
|
|
36
|
+
|
|
37
|
+
// If no connections map, treat the whole config as a single connection
|
|
38
|
+
if (!config.connections) {
|
|
39
|
+
this._connections.set(this._defaultName, new Redis(config))
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Get a named Redis connection. The connection is lazy-initialized on first access.
|
|
45
|
+
*
|
|
46
|
+
* @param name - The connection name. Defaults to the configured default connection.
|
|
47
|
+
* @returns The {@link Redis} instance for the named connection.
|
|
48
|
+
* @throws If the named connection is not configured.
|
|
49
|
+
*
|
|
50
|
+
* @example
|
|
51
|
+
* ```ts
|
|
52
|
+
* const cache = manager.connection('cache')
|
|
53
|
+
* await cache.get('key')
|
|
54
|
+
* ```
|
|
55
|
+
*/
|
|
56
|
+
connection(name?: string): Redis {
|
|
57
|
+
const connName = name || this._defaultName
|
|
58
|
+
if (!this._connections.has(connName)) {
|
|
59
|
+
const connConfig = this._config.connections?.[connName]
|
|
60
|
+
if (!connConfig) {
|
|
61
|
+
throw new Error(
|
|
62
|
+
`[@tekir/redis] Connection "${connName}" is not configured. ` +
|
|
63
|
+
`Available: ${this.connectionNames.join(', ')}`
|
|
64
|
+
)
|
|
65
|
+
}
|
|
66
|
+
this._connections.set(connName, new Redis(connConfig))
|
|
67
|
+
}
|
|
68
|
+
return this._connections.get(connName)!
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* List all configured connection names.
|
|
73
|
+
*
|
|
74
|
+
* @returns An array of connection name strings.
|
|
75
|
+
*
|
|
76
|
+
* @example
|
|
77
|
+
* ```ts
|
|
78
|
+
* manager.connectionNames // ['cache', 'session']
|
|
79
|
+
* ```
|
|
80
|
+
*/
|
|
81
|
+
get connectionNames(): string[] {
|
|
82
|
+
if (this._config.connections) return Object.keys(this._config.connections)
|
|
83
|
+
return [this._defaultName]
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Close a specific named connection, or all connections if no name is given.
|
|
88
|
+
*
|
|
89
|
+
* @param name - The connection name to close. Omit to close all connections.
|
|
90
|
+
*
|
|
91
|
+
* @example
|
|
92
|
+
* ```ts
|
|
93
|
+
* manager.close('session') // close one connection
|
|
94
|
+
* manager.close() // close all connections
|
|
95
|
+
* ```
|
|
96
|
+
*/
|
|
97
|
+
close(name?: string): void {
|
|
98
|
+
if (name) {
|
|
99
|
+
this._connections.get(name)?.close()
|
|
100
|
+
this._connections.delete(name)
|
|
101
|
+
} else {
|
|
102
|
+
for (const [, conn] of this._connections) conn.close()
|
|
103
|
+
this._connections.clear()
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// ─── Proxy methods delegating to the default connection ───
|
|
108
|
+
|
|
109
|
+
/** @see {@link Redis.get} */
|
|
110
|
+
get(key: string) { return this.connection().get(key) }
|
|
111
|
+
/** @see {@link Redis.set} */
|
|
112
|
+
set(key: string, value: string | number) { return this.connection().set(key, value) }
|
|
113
|
+
/** @see {@link Redis.del} */
|
|
114
|
+
del(...keys: string[]) { return this.connection().del(...keys) }
|
|
115
|
+
/** @see {@link Redis.exists} */
|
|
116
|
+
exists(key: string) { return this.connection().exists(key) }
|
|
117
|
+
/** @see {@link Redis.incr} */
|
|
118
|
+
incr(key: string) { return this.connection().incr(key) }
|
|
119
|
+
/** @see {@link Redis.decr} */
|
|
120
|
+
decr(key: string) { return this.connection().decr(key) }
|
|
121
|
+
/** @see {@link Redis.expire} */
|
|
122
|
+
expire(key: string, seconds: number) { return this.connection().expire(key, seconds) }
|
|
123
|
+
/** @see {@link Redis.ttl} */
|
|
124
|
+
ttl(key: string) { return this.connection().ttl(key) }
|
|
125
|
+
/** @see {@link Redis.hget} */
|
|
126
|
+
hget(key: string, field: string) { return this.connection().hget(key, field) }
|
|
127
|
+
/** @see {@link Redis.hmset} */
|
|
128
|
+
hmset(key: string, fields: string[]) { return this.connection().hmset(key, fields) }
|
|
129
|
+
/** @see {@link Redis.hmget} */
|
|
130
|
+
hmget(key: string, fields: string[]) { return this.connection().hmget(key, fields) }
|
|
131
|
+
/** @see {@link Redis.hincrby} */
|
|
132
|
+
hincrby(key: string, field: string, increment: number) { return this.connection().hincrby(key, field, increment) }
|
|
133
|
+
/** @see {@link Redis.sadd} */
|
|
134
|
+
sadd(key: string, ...members: string[]) { return this.connection().sadd(key, ...members) }
|
|
135
|
+
/** @see {@link Redis.srem} */
|
|
136
|
+
srem(key: string, ...members: string[]) { return this.connection().srem(key, ...members) }
|
|
137
|
+
/** @see {@link Redis.sismember} */
|
|
138
|
+
sismember(key: string, member: string) { return this.connection().sismember(key, member) }
|
|
139
|
+
/** @see {@link Redis.smembers} */
|
|
140
|
+
smembers(key: string) { return this.connection().smembers(key) }
|
|
141
|
+
/** @see {@link Redis.publish} */
|
|
142
|
+
publish(channel: string, message: string) { return this.connection().publish(channel, message) }
|
|
143
|
+
/** @see {@link Redis.subscribe} */
|
|
144
|
+
subscribe(channel: string, callback: (message: string, channel: string) => void) { return this.connection().subscribe(channel, callback) }
|
|
145
|
+
/** @see {@link Redis.unsubscribe} */
|
|
146
|
+
unsubscribe(channel?: string) { return this.connection().unsubscribe(channel) }
|
|
147
|
+
/** @see {@link Redis.send} */
|
|
148
|
+
send(command: string, args: string[] = []) { return this.connection().send(command, args) }
|
|
149
|
+
/** @see {@link Redis.getJSON} */
|
|
150
|
+
getJSON<T = any>(key: string) { return this.connection().getJSON<T>(key) }
|
|
151
|
+
/** @see {@link Redis.setJSON} */
|
|
152
|
+
setJSON(key: string, value: any, expireSeconds?: number) { return this.connection().setJSON(key, value, expireSeconds) }
|
|
153
|
+
/** @see {@link Redis.remember} */
|
|
154
|
+
remember<T>(key: string, seconds: number, callback: () => Promise<T>) { return this.connection().remember<T>(key, seconds, callback) }
|
|
155
|
+
/** @see {@link Redis.flushdb} */
|
|
156
|
+
flushdb() { return this.connection().flushdb() }
|
|
157
|
+
/** @see {@link Redis.connected} */
|
|
158
|
+
get connected() { return this.connection().connected }
|
|
159
|
+
/** @see {@link Redis.getClient} */
|
|
160
|
+
getClient() { return this.connection().getClient() }
|
|
161
|
+
}
|
package/src/provider.ts
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { App } from '@tekir/core'
|
|
2
|
+
import { RedisManager } from './manager'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Service provider that reads the `redis` configuration and registers
|
|
6
|
+
* a {@link RedisManager} instance in the application container.
|
|
7
|
+
*/
|
|
8
|
+
export class RedisProvider {
|
|
9
|
+
/**
|
|
10
|
+
* Register the Redis manager into the application container.
|
|
11
|
+
*
|
|
12
|
+
* @param app - The Tekir application instance.
|
|
13
|
+
* @returns A promise that resolves once registration is complete.
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* ```ts
|
|
17
|
+
* // In your providers list:
|
|
18
|
+
* app.register(new RedisProvider())
|
|
19
|
+
* ```
|
|
20
|
+
*/
|
|
21
|
+
async register(app: App) {
|
|
22
|
+
const config = app.use('config')
|
|
23
|
+
if (!config('redis')) return
|
|
24
|
+
app.instance('redis', new RedisManager(config('redis')))
|
|
25
|
+
}
|
|
26
|
+
}
|