@elysiumjs/core 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/.prettierignore +5 -0
- package/.prettierrc +25 -0
- package/README.md +112 -0
- package/bun.lock +262 -0
- package/index.ts +50 -0
- package/package.json +49 -0
- package/src/app.ts +503 -0
- package/src/cache.ts +218 -0
- package/src/command.ts +908 -0
- package/src/console.ts +487 -0
- package/src/database.ts +130 -0
- package/src/event.ts +225 -0
- package/src/http.ts +669 -0
- package/src/job.ts +196 -0
- package/src/middleware.ts +122 -0
- package/src/model.ts +312 -0
- package/src/module.ts +98 -0
- package/src/redis.ts +407 -0
- package/src/repository.ts +261 -0
- package/src/service.ts +349 -0
- package/src/utils.ts +41 -0
- package/src/wamp.ts +388 -0
- package/src/websocket.ts +186 -0
- package/src/worker.ts +842 -0
package/src/module.ts
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
// Copyright (c) 2025-present Workbud Technologies Inc. All rights reserved.
|
|
2
|
+
//
|
|
3
|
+
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
// you may not use this file except in compliance with the License.
|
|
5
|
+
// You may obtain a copy of the License at
|
|
6
|
+
//
|
|
7
|
+
// http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
//
|
|
9
|
+
// Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
// See the License for the specific language governing permissions and
|
|
13
|
+
// limitations under the License.
|
|
14
|
+
|
|
15
|
+
import type { Class } from 'type-fest';
|
|
16
|
+
import type { Route } from './http';
|
|
17
|
+
|
|
18
|
+
import { Elysia } from 'elysia';
|
|
19
|
+
import { assign } from 'radash';
|
|
20
|
+
|
|
21
|
+
import { applyMiddlewares } from './middleware';
|
|
22
|
+
import { nextTick, Symbols } from './utils';
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Properties required when declaring a module using the `@module()` decorator.
|
|
26
|
+
* @author Axel Nana <axel.nana@workbud.com>
|
|
27
|
+
*/
|
|
28
|
+
export type ModuleProps = {
|
|
29
|
+
/**
|
|
30
|
+
* The list of controllers provided by the module.
|
|
31
|
+
*/
|
|
32
|
+
controllers?: Class<any>[];
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Type for a module class.
|
|
37
|
+
* @author Axel Nana <axel.nana@workbud.com>
|
|
38
|
+
*/
|
|
39
|
+
export type ModuleClass = Class<Module>;
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Base class for all modules.
|
|
43
|
+
* @author Axel Nana <axel.nana@workbud.com>
|
|
44
|
+
*
|
|
45
|
+
* This class provides base features for modules, such as hooks and lifecycle methods.
|
|
46
|
+
*/
|
|
47
|
+
export abstract class Module {
|
|
48
|
+
/**
|
|
49
|
+
* Marks a class as a module.
|
|
50
|
+
* @author Axel Nana <axel.nana@workbud.com>
|
|
51
|
+
* @param options The decorator options.
|
|
52
|
+
*/
|
|
53
|
+
public static register(options: ModuleProps = {}) {
|
|
54
|
+
return function (target: ModuleClass) {
|
|
55
|
+
async function handleModule(m: Module): Promise<Elysia<Route>> {
|
|
56
|
+
// TODO: Use the logger service here
|
|
57
|
+
console.log(`Registering module ${target.name}`);
|
|
58
|
+
await nextTick();
|
|
59
|
+
|
|
60
|
+
const props = assign({ controllers: [] }, options) as Required<ModuleProps>;
|
|
61
|
+
|
|
62
|
+
const plugin: Elysia<Route> = new Elysia({ name: target.name });
|
|
63
|
+
plugin.decorate('module', m);
|
|
64
|
+
|
|
65
|
+
const middlewares = Reflect.getMetadata(Symbols.middlewares, target) ?? [];
|
|
66
|
+
applyMiddlewares(middlewares, plugin);
|
|
67
|
+
|
|
68
|
+
for (const controller of props.controllers) {
|
|
69
|
+
const app = Reflect.getMetadata(Symbols.elysiaPlugin, controller);
|
|
70
|
+
if (app === undefined) {
|
|
71
|
+
// TODO: Use the logger service here
|
|
72
|
+
console.error(
|
|
73
|
+
`Invalid controller class ${controller.name} registered in module ${target.name}. Ensure that you either used the @http(), or @websocket() decorators on the controller.`
|
|
74
|
+
);
|
|
75
|
+
process.exit(1);
|
|
76
|
+
} else {
|
|
77
|
+
// TODO: Add middlewares here
|
|
78
|
+
plugin.use(await app());
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
return plugin;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
Reflect.defineMetadata(Symbols.elysiaPlugin, handleModule, target);
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Hooks that are executed before the module is registered.
|
|
91
|
+
*/
|
|
92
|
+
public beforeRegister(): void {}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Hooks that are executed after the module is registered.
|
|
96
|
+
*/
|
|
97
|
+
public afterRegister(): void {}
|
|
98
|
+
}
|
package/src/redis.ts
ADDED
|
@@ -0,0 +1,407 @@
|
|
|
1
|
+
// Copyright (c) 2025-present Workbud Technologies Inc. All rights reserved.
|
|
2
|
+
//
|
|
3
|
+
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
// you may not use this file except in compliance with the License.
|
|
5
|
+
// You may obtain a copy of the License at
|
|
6
|
+
//
|
|
7
|
+
// http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
//
|
|
9
|
+
// Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
// See the License for the specific language governing permissions and
|
|
13
|
+
// limitations under the License.
|
|
14
|
+
|
|
15
|
+
import type { KeyvStoreAdapter } from 'cacheable';
|
|
16
|
+
import type { KeyvEntry, StoredData } from 'keyv';
|
|
17
|
+
|
|
18
|
+
import { EventEmitter } from 'node:events';
|
|
19
|
+
|
|
20
|
+
import { omit } from 'radash';
|
|
21
|
+
|
|
22
|
+
import { Event } from './event';
|
|
23
|
+
import { Service } from './service';
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Properties used to create a new redis connection.
|
|
27
|
+
* @author Axel Nana <axel.nana@workbud.com>
|
|
28
|
+
*/
|
|
29
|
+
export type RedisConnectionProps = Bun.RedisOptions;
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Keyv adapter for redis. This adapter is based on the Bun's Redis client.
|
|
33
|
+
* @author Axel Nana <axel.nana@workbud.com>
|
|
34
|
+
*/
|
|
35
|
+
export class KeyvRedis extends EventEmitter implements KeyvStoreAdapter {
|
|
36
|
+
#client?: Bun.RedisClient;
|
|
37
|
+
#namespace: string | undefined;
|
|
38
|
+
#keyPrefixSeparator = '::';
|
|
39
|
+
#clearBatchSize = 1000;
|
|
40
|
+
#useUnlink = true;
|
|
41
|
+
#noNamespaceAffectsAll = false;
|
|
42
|
+
|
|
43
|
+
#connection: string;
|
|
44
|
+
|
|
45
|
+
constructor(props: {
|
|
46
|
+
/**
|
|
47
|
+
* The Redis connection to use.
|
|
48
|
+
*/
|
|
49
|
+
connection: string;
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Namespace for the connection.
|
|
53
|
+
*/
|
|
54
|
+
namespace?: string;
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Separator to use between namespace and key.
|
|
58
|
+
*/
|
|
59
|
+
keyPrefixSeparator?: string;
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Number of keys to delete in a single batch.
|
|
63
|
+
*/
|
|
64
|
+
clearBatchSize?: number;
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Enable Unlink instead of using Del for clearing keys. This is more performant but may not be supported by all Redis versions.
|
|
68
|
+
*/
|
|
69
|
+
useUnlink?: boolean;
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Whether to allow clearing all keys when no namespace is set.
|
|
73
|
+
* If set to true and no namespace is set, iterate() will return all keys.
|
|
74
|
+
* Defaults to `false`.
|
|
75
|
+
*/
|
|
76
|
+
noNamespaceAffectsAll?: boolean;
|
|
77
|
+
}) {
|
|
78
|
+
super();
|
|
79
|
+
|
|
80
|
+
Event.once('elysium:app:launched', () => {
|
|
81
|
+
this.#client = Redis.getConnection(props.connection);
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
this.#connection = props.connection;
|
|
85
|
+
this.#namespace = props.namespace;
|
|
86
|
+
this.#keyPrefixSeparator = props.keyPrefixSeparator ?? '::';
|
|
87
|
+
this.#clearBatchSize = props.clearBatchSize ?? 1000;
|
|
88
|
+
this.#useUnlink = props.useUnlink ?? true;
|
|
89
|
+
this.#noNamespaceAffectsAll = props.noNamespaceAffectsAll ?? false;
|
|
90
|
+
|
|
91
|
+
this.on('error', (error) => {
|
|
92
|
+
Event.emit('elysium:error', error);
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
public get client() {
|
|
97
|
+
return this.#client!;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Get the options for the adapter.
|
|
102
|
+
*/
|
|
103
|
+
public get opts() {
|
|
104
|
+
return {
|
|
105
|
+
namespace: this.#namespace,
|
|
106
|
+
keyPrefixSeparator: this.#keyPrefixSeparator,
|
|
107
|
+
clearBatchSize: this.#clearBatchSize,
|
|
108
|
+
noNamespaceAffectsAll: this.#noNamespaceAffectsAll,
|
|
109
|
+
dialect: 'redis',
|
|
110
|
+
url: this.#connection
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Gets the namespace for the adapter. If undefined, it will not use a namespace including keyPrefixing.
|
|
116
|
+
* @default undefined
|
|
117
|
+
*/
|
|
118
|
+
public get namespace(): string | undefined {
|
|
119
|
+
return this.#namespace;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Sets the namespace for the adapter. If undefined, it will not use a namespace including keyPrefixing.
|
|
124
|
+
*/
|
|
125
|
+
public set namespace(value: string | undefined) {
|
|
126
|
+
this.#namespace = value;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
public async get<Value>(key: string): Promise<StoredData<Value> | undefined> {
|
|
130
|
+
key = this.createKeyPrefix(key, this.#namespace);
|
|
131
|
+
const value = await this.client.get(key);
|
|
132
|
+
|
|
133
|
+
return value === null ? undefined : (value as Value);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
public async set(key: string, value: any, ttl?: number) {
|
|
137
|
+
key = this.createKeyPrefix(key, this.#namespace);
|
|
138
|
+
|
|
139
|
+
if (ttl) {
|
|
140
|
+
await this.client.set(key, value, 'PX', ttl);
|
|
141
|
+
} else {
|
|
142
|
+
await this.client.set(key, value);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
public async setMany(values: Array<KeyvEntry>): Promise<void> {
|
|
147
|
+
// TODO: Use MULTI when available in Bun
|
|
148
|
+
const multi = [];
|
|
149
|
+
|
|
150
|
+
for (const { key, value, ttl } of values) {
|
|
151
|
+
const prefixedKey = this.createKeyPrefix(key, this.#namespace);
|
|
152
|
+
if (ttl) {
|
|
153
|
+
// eslint-disable-next-line @typescript-eslint/naming-convention, @typescript-eslint/no-unsafe-argument
|
|
154
|
+
multi.push(this.client.set(prefixedKey, value, 'PX', ttl));
|
|
155
|
+
} else {
|
|
156
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
|
157
|
+
multi.push(this.client.set(prefixedKey, value));
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
await Promise.all(multi);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
public async delete(key: string): Promise<boolean> {
|
|
165
|
+
key = this.createKeyPrefix(key, this.#namespace);
|
|
166
|
+
// TODO: Use UNLINK when available in Bun
|
|
167
|
+
const deleted = await (this.#useUnlink
|
|
168
|
+
? this.client.send('UNLINK', [key])
|
|
169
|
+
: this.client.del(key));
|
|
170
|
+
|
|
171
|
+
return deleted > 0;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
public async clear(): Promise<void> {
|
|
175
|
+
try {
|
|
176
|
+
if (!this.#namespace && this.#noNamespaceAffectsAll) {
|
|
177
|
+
await this.client.send('FLUSHDB', []);
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
let cursor = '0';
|
|
182
|
+
const batchSize = this.#clearBatchSize;
|
|
183
|
+
const match = this.#namespace ? `${this.#namespace}${this.#keyPrefixSeparator}*` : '*';
|
|
184
|
+
const deletePromises = [];
|
|
185
|
+
|
|
186
|
+
do {
|
|
187
|
+
const result = await this.client.send('SCAN', [
|
|
188
|
+
cursor,
|
|
189
|
+
'MATCH',
|
|
190
|
+
match,
|
|
191
|
+
'COUNT',
|
|
192
|
+
batchSize.toString(),
|
|
193
|
+
'TYPE',
|
|
194
|
+
'string'
|
|
195
|
+
]);
|
|
196
|
+
|
|
197
|
+
// Parse the result
|
|
198
|
+
let [newCursor, keys] = result;
|
|
199
|
+
cursor = newCursor.toString();
|
|
200
|
+
|
|
201
|
+
if (keys.length === 0) {
|
|
202
|
+
continue;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
if (!this.#namespace) {
|
|
206
|
+
keys = keys.filter((key: string) => !key.includes(this.#keyPrefixSeparator));
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
deletePromises.push(keys.map((key: string) => this.client.del(key)));
|
|
210
|
+
} while (cursor !== '0');
|
|
211
|
+
|
|
212
|
+
await Promise.all(deletePromises);
|
|
213
|
+
} catch (error) {
|
|
214
|
+
this.emit('error', error);
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
public async has(key: string): Promise<boolean> {
|
|
219
|
+
key = this.createKeyPrefix(key, this.#namespace);
|
|
220
|
+
return this.client.exists(key);
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
public async hasMany(keys: string[]): Promise<boolean[]> {
|
|
224
|
+
const multi = [];
|
|
225
|
+
|
|
226
|
+
for (const key of keys) {
|
|
227
|
+
const prefixedKey = this.createKeyPrefix(key, this.#namespace);
|
|
228
|
+
multi.push(this.client.exists(prefixedKey));
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
return Promise.all(multi);
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
public async getMany<Value>(keys: string[]): Promise<Array<StoredData<Value | undefined>>> {
|
|
235
|
+
if (keys.length === 0) {
|
|
236
|
+
return [];
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
keys = keys.map((key) => this.createKeyPrefix(key, this.#namespace));
|
|
240
|
+
const values = await this.client.mget(...keys);
|
|
241
|
+
|
|
242
|
+
return values as Value[];
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
public async disconnect(): Promise<void> {
|
|
246
|
+
this.client.close();
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
public async deleteMany(keys: string[]): Promise<boolean> {
|
|
250
|
+
let result = false;
|
|
251
|
+
|
|
252
|
+
// TODO: Use MULTI when available in Bun
|
|
253
|
+
const multi = [];
|
|
254
|
+
|
|
255
|
+
for (const key of keys) {
|
|
256
|
+
const prefixedKey = this.createKeyPrefix(key, this.#namespace);
|
|
257
|
+
if (this.#useUnlink) {
|
|
258
|
+
multi.push(this.client.send('UNLINK', [prefixedKey]));
|
|
259
|
+
} else {
|
|
260
|
+
multi.push(this.client.del(prefixedKey));
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
const results = await Promise.all(multi);
|
|
265
|
+
|
|
266
|
+
for (const deleted of results) {
|
|
267
|
+
if (typeof deleted === 'number' && deleted > 0) {
|
|
268
|
+
result = true;
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
return result;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
public async *iterator<Value>(
|
|
276
|
+
namespace?: string
|
|
277
|
+
): AsyncGenerator<Array<string | Awaited<Value> | undefined>, void> {
|
|
278
|
+
const match = namespace ? `${namespace}${this.#keyPrefixSeparator}*` : '*';
|
|
279
|
+
let cursor = '0';
|
|
280
|
+
|
|
281
|
+
do {
|
|
282
|
+
const result = await this.client.send('SCAN', [cursor, 'MATCH', match, 'TYPE', 'string']);
|
|
283
|
+
|
|
284
|
+
// Parse the result
|
|
285
|
+
let [newCursor, keys] = result;
|
|
286
|
+
cursor = newCursor.toString();
|
|
287
|
+
|
|
288
|
+
if (!namespace && !this.#noNamespaceAffectsAll) {
|
|
289
|
+
keys = keys.filter((key: string) => !key.includes(this.#keyPrefixSeparator));
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
if (keys.length > 0) {
|
|
293
|
+
const values = await this.client.mget(...keys);
|
|
294
|
+
for (const i of keys.keys()) {
|
|
295
|
+
const key = this.getKeyWithoutPrefix(keys[i], namespace);
|
|
296
|
+
const value = values[i];
|
|
297
|
+
yield [key, value!];
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
} while (cursor !== '0');
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
/**
|
|
304
|
+
* Helper function to create a key with a namespace.
|
|
305
|
+
* @param key The key to prefix.
|
|
306
|
+
* @param namespace The namespace to prefix the key with.
|
|
307
|
+
* @returns The key with the namespace such as 'namespace::key'.
|
|
308
|
+
*/
|
|
309
|
+
public createKeyPrefix(key: string, namespace?: string): string {
|
|
310
|
+
return !!namespace ? `${namespace}${this.#keyPrefixSeparator}${key}` : key;
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
/**
|
|
314
|
+
* Helper function to remove the namespace from a key.
|
|
315
|
+
* @param key The key to remove the namespace from.
|
|
316
|
+
* @param namespace The namespace to remove from the key.
|
|
317
|
+
* @returns The key without the namespace.
|
|
318
|
+
*/
|
|
319
|
+
public getKeyWithoutPrefix(key: string, namespace?: string): string {
|
|
320
|
+
return !!namespace ? key.replace(`${namespace}${this.#keyPrefixSeparator}`, '') : key;
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
export namespace Redis {
|
|
325
|
+
/**
|
|
326
|
+
* Creates a service name for a redis connection.
|
|
327
|
+
* @author Axel Nana <axel.nana@workbud.com>
|
|
328
|
+
* @param name The name of the connection.
|
|
329
|
+
* @returns A service name for the connection.
|
|
330
|
+
*/
|
|
331
|
+
const getConnectionName = (name: string) => {
|
|
332
|
+
return `redis.connection.${name}`;
|
|
333
|
+
};
|
|
334
|
+
|
|
335
|
+
/**
|
|
336
|
+
* Retrieves the client for a redis connection.
|
|
337
|
+
* @author Axel Nana <axel.nana@workbud.com>
|
|
338
|
+
* @param name The name of the connection.
|
|
339
|
+
* @returns The Bun.RedisClient for the connection with the given name.
|
|
340
|
+
*/
|
|
341
|
+
export const getConnection = (name: string) => {
|
|
342
|
+
if (!Service.exists(getConnectionName(name))) {
|
|
343
|
+
// TODO: Use logger service here
|
|
344
|
+
console.error(
|
|
345
|
+
`No connection with name ${name} found. Please make sure to register the connection before using it.`
|
|
346
|
+
);
|
|
347
|
+
process.exit(1);
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
return Service.get<Bun.RedisClient>(getConnectionName(name))!;
|
|
351
|
+
};
|
|
352
|
+
|
|
353
|
+
/**
|
|
354
|
+
* Creates and registers a new redis connection.
|
|
355
|
+
* @author Axel Nana <axel.nana@workbud.com>
|
|
356
|
+
*
|
|
357
|
+
* This will make the registered connection available for dependency injection with
|
|
358
|
+
* the key `redis.connection.{name}`, where `{name}` is replaced with the given name.
|
|
359
|
+
*
|
|
360
|
+
* @param name The name of the connection.
|
|
361
|
+
* @param config The configuration for the redis connection.
|
|
362
|
+
* @returns The newly created and registered redis connection.
|
|
363
|
+
*/
|
|
364
|
+
export const registerConnection = (name: string, config: Bun.RedisOptions) => {
|
|
365
|
+
if (Service.exists(getConnectionName(name))) {
|
|
366
|
+
// TODO: Use logger service here
|
|
367
|
+
console.error(`A connection with the name ${name} has already been registered.`);
|
|
368
|
+
process.exit(1);
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
return Service.instance(
|
|
372
|
+
getConnectionName(name),
|
|
373
|
+
new Bun.RedisClient(config.url, omit(config, ['url']))
|
|
374
|
+
);
|
|
375
|
+
};
|
|
376
|
+
|
|
377
|
+
/**
|
|
378
|
+
* Checks if a redis connection with the given name exists.
|
|
379
|
+
* @author Axel Nana <axel.nana@workbud.com>
|
|
380
|
+
* @param name The name of the connection to check.
|
|
381
|
+
* @returns `true` if the connection exists, `false` otherwise.
|
|
382
|
+
*/
|
|
383
|
+
export const connectionExists = (name: string) => {
|
|
384
|
+
return Service.exists(getConnectionName(name));
|
|
385
|
+
};
|
|
386
|
+
|
|
387
|
+
/**
|
|
388
|
+
* Retrieves the default redis connection.
|
|
389
|
+
* @author Axel Nana <axel.nana@workbud.com>
|
|
390
|
+
* @returns The default redis connection.
|
|
391
|
+
*/
|
|
392
|
+
export const getDefaultConnection = () => {
|
|
393
|
+
return getConnection('default');
|
|
394
|
+
};
|
|
395
|
+
|
|
396
|
+
/**
|
|
397
|
+
* Sets the default redis connection.
|
|
398
|
+
* @author Axel Nana <axel.nana@workbud.com>
|
|
399
|
+
* @param name The name of the connection to set as default.
|
|
400
|
+
* @returns The default redis connection.
|
|
401
|
+
*/
|
|
402
|
+
export const setDefaultConnection = (name: string) => {
|
|
403
|
+
const serviceName = getConnectionName('default');
|
|
404
|
+
Service.remove(serviceName);
|
|
405
|
+
return Service.instance(serviceName, getConnection(name));
|
|
406
|
+
};
|
|
407
|
+
}
|