effect-redis 0.0.1 → 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.
@@ -0,0 +1,40 @@
1
+ import { Context, Effect, Layer } from 'effect';
2
+ import { createClient } from 'redis';
3
+ declare const RedisError_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").Equals<A, {}> extends true ? void : { readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }) => import("effect/Cause").YieldableError & {
4
+ readonly _tag: "RedisError";
5
+ } & Readonly<A>;
6
+ export declare class RedisError extends RedisError_base<{
7
+ cause: unknown;
8
+ message: string;
9
+ }> {
10
+ }
11
+ interface RedisConnectionOptionsShape {
12
+ options?: Parameters<typeof createClient>[0];
13
+ }
14
+ declare const RedisConnectionOptions_base: Context.TagClass<RedisConnectionOptions, "RedisConnectionOptions", RedisConnectionOptionsShape>;
15
+ declare class RedisConnectionOptions extends RedisConnectionOptions_base {
16
+ }
17
+ declare const RedisConnectionOptionsLive: (options?: Parameters<typeof createClient>[0]) => Layer.Layer<RedisConnectionOptions, never, never>;
18
+ interface RedisShape {
19
+ use: <T>(fn: (client: ReturnType<typeof createClient>) => T) => Effect.Effect<Awaited<T>, RedisError, never>;
20
+ }
21
+ declare const Redis_base: Context.TagClass<Redis, "Redis", RedisShape>;
22
+ declare class Redis extends Redis_base {
23
+ }
24
+ declare const RedisLive: Layer.Layer<Redis, RedisError, RedisConnectionOptions>;
25
+ interface RedisPubSubShape {
26
+ publish: (channel: string, message: string) => Effect.Effect<void, RedisError, never>;
27
+ subscribe: (channel: string, handler: (message: string) => void) => Effect.Effect<void, RedisError, never>;
28
+ }
29
+ declare const RedisPubSub_base: Context.TagClass<RedisPubSub, "RedisPubSub", RedisPubSubShape>;
30
+ declare class RedisPubSub extends RedisPubSub_base {
31
+ }
32
+ interface RedisPersistenceShape {
33
+ setValue: (key: string, value: string) => Effect.Effect<void, RedisError, never>;
34
+ }
35
+ declare const RedisPersistence_base: Context.TagClass<RedisPersistence, "RedisPersistence", RedisPersistenceShape>;
36
+ declare class RedisPersistence extends RedisPersistence_base {
37
+ }
38
+ declare const RedisPersistenceLive: Layer.Layer<RedisPersistence, RedisError, RedisConnectionOptions>;
39
+ declare const RedisPubSubLive: Layer.Layer<RedisPubSub, RedisError, RedisConnectionOptions>;
40
+ export { RedisPersistence, RedisPubSub, RedisConnectionOptions, Redis, RedisPersistenceLive, RedisPubSubLive, RedisConnectionOptionsLive, RedisLive, };
package/package.json CHANGED
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "effect-redis",
3
- "version": "0.0.1",
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",
@@ -21,6 +21,9 @@
21
21
  "@types/bun": "latest"
22
22
  },
23
23
  "peerDependencies": {
24
- "typescript": "^5"
25
- }
24
+ "typescript": "^5",
25
+ "effect": "^3.15.4",
26
+ "redis": "^5.1.0"
27
+ },
28
+ "dependencies": {}
26
29
  }
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
+ };