effect-redis 0.0.2 → 0.0.3
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/package.json +2 -2
- package/src/index.ts +1 -0
- package/src/redis.ts +190 -0
package/package.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "effect-redis",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.3",
|
|
4
4
|
"description": "Simple Effect wrapper for Redis.",
|
|
5
5
|
"module": "dist/index.js",
|
|
6
6
|
"main": "dist/index.js",
|
|
7
7
|
"types": "dist/index.d.ts",
|
|
8
8
|
"type": "module",
|
|
9
|
-
"files": ["dist", "README.md"],
|
|
9
|
+
"files": ["dist", "src", "README.md"],
|
|
10
10
|
"scripts": {
|
|
11
11
|
"build:main": "bun build --minify-syntax --minify-whitespace ./src/index.ts --outdir ./dist --target node --format esm",
|
|
12
12
|
"build:types": "bun tsc --emitDeclarationOnly --outDir dist",
|
package/src/index.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './redis';
|
package/src/redis.ts
ADDED
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
import { Context, Data, Effect, Layer } from 'effect';
|
|
2
|
+
import { createClient } from 'redis';
|
|
3
|
+
|
|
4
|
+
export class RedisError extends Data.TaggedError('RedisError')<{
|
|
5
|
+
cause: unknown;
|
|
6
|
+
message: string;
|
|
7
|
+
}> {}
|
|
8
|
+
|
|
9
|
+
interface RedisConnectionOptionsShape {
|
|
10
|
+
options?: Parameters<typeof createClient>[0];
|
|
11
|
+
}
|
|
12
|
+
class RedisConnectionOptions extends Context.Tag('RedisConnectionOptions')<
|
|
13
|
+
RedisConnectionOptions,
|
|
14
|
+
RedisConnectionOptionsShape
|
|
15
|
+
>() {}
|
|
16
|
+
|
|
17
|
+
const RedisConnectionOptionsLive = (
|
|
18
|
+
options?: Parameters<typeof createClient>[0],
|
|
19
|
+
) =>
|
|
20
|
+
Layer.succeed(
|
|
21
|
+
RedisConnectionOptions,
|
|
22
|
+
RedisConnectionOptions.of({
|
|
23
|
+
options,
|
|
24
|
+
}),
|
|
25
|
+
);
|
|
26
|
+
|
|
27
|
+
interface RedisShape {
|
|
28
|
+
use: <T>(
|
|
29
|
+
fn: (client: ReturnType<typeof createClient>) => T,
|
|
30
|
+
) => Effect.Effect<Awaited<T>, RedisError, never>;
|
|
31
|
+
}
|
|
32
|
+
class Redis extends Context.Tag('Redis')<Redis, RedisShape>() {}
|
|
33
|
+
|
|
34
|
+
const bootstrapRedisEffect = Effect.gen(function* () {
|
|
35
|
+
const client = yield* redisClientEffect;
|
|
36
|
+
return Redis.of({
|
|
37
|
+
use: (fn) =>
|
|
38
|
+
Effect.gen(function* () {
|
|
39
|
+
const result = yield* Effect.try({
|
|
40
|
+
try: () => fn(client),
|
|
41
|
+
catch: (e) =>
|
|
42
|
+
new RedisError({
|
|
43
|
+
cause: e,
|
|
44
|
+
message: 'Synchronous error in `Redis.use`',
|
|
45
|
+
}),
|
|
46
|
+
});
|
|
47
|
+
if (result instanceof Promise) {
|
|
48
|
+
return yield* Effect.tryPromise({
|
|
49
|
+
try: () => result,
|
|
50
|
+
catch: (e) =>
|
|
51
|
+
new RedisError({
|
|
52
|
+
cause: e,
|
|
53
|
+
message: 'Asynchronous error in `Redis.use`',
|
|
54
|
+
}),
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
return result;
|
|
58
|
+
}),
|
|
59
|
+
});
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
const RedisLive = Layer.scoped(Redis, bootstrapRedisEffect);
|
|
63
|
+
|
|
64
|
+
interface RedisPubSubShape {
|
|
65
|
+
publish: (
|
|
66
|
+
channel: string,
|
|
67
|
+
message: string,
|
|
68
|
+
) => Effect.Effect<void, RedisError, never>;
|
|
69
|
+
subscribe: (
|
|
70
|
+
channel: string,
|
|
71
|
+
handler: (message: string) => void,
|
|
72
|
+
) => Effect.Effect<void, RedisError, never>;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
class RedisPubSub extends Context.Tag('RedisPubSub')<
|
|
76
|
+
RedisPubSub,
|
|
77
|
+
RedisPubSubShape
|
|
78
|
+
>() {}
|
|
79
|
+
|
|
80
|
+
interface RedisPersistenceShape {
|
|
81
|
+
setValue: (
|
|
82
|
+
key: string,
|
|
83
|
+
value: string,
|
|
84
|
+
) => Effect.Effect<void, RedisError, never>;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
class RedisPersistence extends Context.Tag('RedisPersistence')<
|
|
88
|
+
RedisPersistence,
|
|
89
|
+
RedisPersistenceShape
|
|
90
|
+
>() {}
|
|
91
|
+
|
|
92
|
+
const redisClientEffect = Effect.gen(function* () {
|
|
93
|
+
const { options } = yield* RedisConnectionOptions;
|
|
94
|
+
|
|
95
|
+
return yield* Effect.acquireRelease(
|
|
96
|
+
Effect.tryPromise({
|
|
97
|
+
try: () =>
|
|
98
|
+
createClient(options)
|
|
99
|
+
.connect()
|
|
100
|
+
.then((r) => {
|
|
101
|
+
console.log('Connected to Redis');
|
|
102
|
+
r.on('error', (e) => {
|
|
103
|
+
console.log('Redis error(on error):', e.message);
|
|
104
|
+
r.destroy();
|
|
105
|
+
});
|
|
106
|
+
r.on('end', () => {
|
|
107
|
+
console.log('Connection to Redis ended');
|
|
108
|
+
});
|
|
109
|
+
return r;
|
|
110
|
+
}),
|
|
111
|
+
catch: (e) =>
|
|
112
|
+
new RedisError({
|
|
113
|
+
cause: e,
|
|
114
|
+
message: 'Error while connecting to Redis',
|
|
115
|
+
}),
|
|
116
|
+
}),
|
|
117
|
+
(client) =>
|
|
118
|
+
Effect.sync(() => {
|
|
119
|
+
if (client.isReady) {
|
|
120
|
+
client.quit();
|
|
121
|
+
}
|
|
122
|
+
}),
|
|
123
|
+
);
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
const bootstrapRedisPersistenceEffect = Effect.gen(function* () {
|
|
127
|
+
const client = yield* redisClientEffect;
|
|
128
|
+
|
|
129
|
+
return RedisPersistence.of({
|
|
130
|
+
setValue: (key, value) =>
|
|
131
|
+
Effect.gen(function* () {
|
|
132
|
+
return yield* Effect.tryPromise({
|
|
133
|
+
try: () => client.set(key, value),
|
|
134
|
+
catch: (e) =>
|
|
135
|
+
new RedisError({
|
|
136
|
+
cause: e,
|
|
137
|
+
message: 'Error in `Redis.setValue`',
|
|
138
|
+
}),
|
|
139
|
+
});
|
|
140
|
+
}),
|
|
141
|
+
});
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
const RedisPersistenceLive = Layer.scoped(
|
|
145
|
+
RedisPersistence,
|
|
146
|
+
bootstrapRedisPersistenceEffect,
|
|
147
|
+
);
|
|
148
|
+
|
|
149
|
+
const bootstrapRedisPubSubEffect = Effect.gen(function* () {
|
|
150
|
+
const clientPublish = yield* redisClientEffect;
|
|
151
|
+
const clientSubscribe = yield* redisClientEffect;
|
|
152
|
+
|
|
153
|
+
return RedisPubSub.of({
|
|
154
|
+
publish: (channel, message) =>
|
|
155
|
+
Effect.gen(function* () {
|
|
156
|
+
return yield* Effect.tryPromise({
|
|
157
|
+
try: () => clientPublish.publish(channel, message),
|
|
158
|
+
catch: (e) =>
|
|
159
|
+
new RedisError({
|
|
160
|
+
cause: e,
|
|
161
|
+
message: 'Error in `Redis.publish`',
|
|
162
|
+
}),
|
|
163
|
+
});
|
|
164
|
+
}),
|
|
165
|
+
subscribe: (channel, handler) =>
|
|
166
|
+
Effect.gen(function* () {
|
|
167
|
+
return yield* Effect.tryPromise({
|
|
168
|
+
try: () => clientSubscribe.subscribe(channel, handler),
|
|
169
|
+
catch: (e) =>
|
|
170
|
+
new RedisError({
|
|
171
|
+
cause: e,
|
|
172
|
+
message: 'Error in `Redis.subscribe`',
|
|
173
|
+
}),
|
|
174
|
+
});
|
|
175
|
+
}),
|
|
176
|
+
});
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
const RedisPubSubLive = Layer.scoped(RedisPubSub, bootstrapRedisPubSubEffect);
|
|
180
|
+
|
|
181
|
+
export {
|
|
182
|
+
RedisPersistence,
|
|
183
|
+
RedisPubSub,
|
|
184
|
+
RedisConnectionOptions,
|
|
185
|
+
Redis,
|
|
186
|
+
RedisPersistenceLive,
|
|
187
|
+
RedisPubSubLive,
|
|
188
|
+
RedisConnectionOptionsLive,
|
|
189
|
+
RedisLive,
|
|
190
|
+
};
|