codex-platform 0.1.0__py3-none-any.whl

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.
Files changed (45) hide show
  1. codex_platform/__init__.py +1 -0
  2. codex_platform/notifications/__init__.py +48 -0
  3. codex_platform/notifications/channels.py +24 -0
  4. codex_platform/notifications/clients/__init__.py +3 -0
  5. codex_platform/notifications/clients/smtp.py +134 -0
  6. codex_platform/notifications/delivery/__init__.py +18 -0
  7. codex_platform/notifications/delivery/arq.py +69 -0
  8. codex_platform/notifications/delivery/base.py +39 -0
  9. codex_platform/notifications/delivery/direct.py +89 -0
  10. codex_platform/notifications/dto.py +63 -0
  11. codex_platform/notifications/interfaces.py +30 -0
  12. codex_platform/notifications/orchestrator.py +116 -0
  13. codex_platform/notifications/registry.py +71 -0
  14. codex_platform/notifications/renderer.py +111 -0
  15. codex_platform/redis_service/__init__.py +59 -0
  16. codex_platform/redis_service/base.py +69 -0
  17. codex_platform/redis_service/exceptions.py +20 -0
  18. codex_platform/redis_service/keys.py +110 -0
  19. codex_platform/redis_service/managers/__init__.py +18 -0
  20. codex_platform/redis_service/managers/base_manager.py +31 -0
  21. codex_platform/redis_service/operations/__init__.py +19 -0
  22. codex_platform/redis_service/operations/hash.py +302 -0
  23. codex_platform/redis_service/operations/json_module.py +129 -0
  24. codex_platform/redis_service/operations/json_string.py +113 -0
  25. codex_platform/redis_service/operations/list_.py +219 -0
  26. codex_platform/redis_service/operations/pipeline.py +197 -0
  27. codex_platform/redis_service/operations/set_.py +212 -0
  28. codex_platform/redis_service/operations/string.py +318 -0
  29. codex_platform/redis_service/operations/zset.py +277 -0
  30. codex_platform/redis_service/service.py +80 -0
  31. codex_platform/streams/__init__.py +59 -0
  32. codex_platform/streams/consumer.py +106 -0
  33. codex_platform/streams/dispatcher.py +175 -0
  34. codex_platform/streams/processor.py +217 -0
  35. codex_platform/streams/producer.py +60 -0
  36. codex_platform/streams/router.py +78 -0
  37. codex_platform/workers/__init__.py +1 -0
  38. codex_platform/workers/arq/__init__.py +27 -0
  39. codex_platform/workers/arq/base.py +170 -0
  40. codex_platform/workers/arq/config.py +67 -0
  41. codex_platform/workers/arq/task_utils.py +72 -0
  42. codex_platform/workers/arq/types.py +11 -0
  43. codex_platform-0.1.0.dist-info/METADATA +120 -0
  44. codex_platform-0.1.0.dist-info/RECORD +45 -0
  45. codex_platform-0.1.0.dist-info/WHEEL +4 -0
@@ -0,0 +1,318 @@
1
+ """
2
+ codex_platform.redis_service.operations.string
3
+ ===============================================
4
+ Redis String/Key operations.
5
+ """
6
+
7
+ import logging
8
+ from typing import Any
9
+
10
+ from redis.asyncio import Redis
11
+
12
+ from codex_platform.redis_service.base import catch_redis_errors
13
+ from codex_platform.redis_service.keys import BaseRedisKey, resolve_key
14
+
15
+ log = logging.getLogger(__name__)
16
+
17
+
18
+ class StringOperations:
19
+ """Redis String and key-level operations (SET / GET / EXPIRE / TTL and more).
20
+
21
+ Accepts an already-constructed ``redis.asyncio.Redis`` client.
22
+ All methods wrap Redis errors in typed exceptions.
23
+
24
+ Example::
25
+
26
+ ops = StringOperations(client)
27
+ await ops.set("session:abc", "token-value", ttl=3600)
28
+ token = await ops.get("session:abc")
29
+ """
30
+
31
+ def __init__(self, client: Redis) -> None:
32
+ self.client = client
33
+
34
+ @catch_redis_errors
35
+ async def set(self, key: "str | BaseRedisKey", value: str, ttl: int | None = None, **kwargs: Any) -> None:
36
+ """Set a string value (SET).
37
+
38
+ Args:
39
+ key: Redis key or a ``BaseRedisKey`` instance.
40
+ value: String value to store.
41
+ ttl: Expiry in seconds. ``None`` means no expiry.
42
+ **kwargs: Extra parameters forwarded to ``resolve_key``.
43
+
44
+ Raises:
45
+ RedisConnectionError: Redis connection failure.
46
+ RedisServiceError: Redis operation failure.
47
+ """
48
+ real_key = resolve_key(key, **kwargs)
49
+ await self.client.set(real_key, value, ex=ttl)
50
+
51
+ @catch_redis_errors
52
+ async def setnx(self, key: "str | BaseRedisKey", value: str, ttl: int | None = None, **kwargs: Any) -> bool:
53
+ """Set a value only if the key does not exist (SET NX).
54
+
55
+ Args:
56
+ key: Redis key or a ``BaseRedisKey`` instance.
57
+ value: String value to store.
58
+ ttl: Expiry in seconds. ``None`` means no expiry.
59
+ **kwargs: Extra parameters forwarded to ``resolve_key``.
60
+
61
+ Returns:
62
+ ``True`` if the value was set, ``False`` if the key already existed.
63
+
64
+ Raises:
65
+ RedisConnectionError: Redis connection failure.
66
+ RedisServiceError: Redis operation failure.
67
+ """
68
+ real_key = resolve_key(key, **kwargs)
69
+ return bool(await self.client.set(real_key, value, ex=ttl, nx=True))
70
+
71
+ @catch_redis_errors
72
+ async def get(self, key: "str | BaseRedisKey", **kwargs: Any) -> str | None:
73
+ """Retrieve a string value (GET).
74
+
75
+ Args:
76
+ key: Redis key or a ``BaseRedisKey`` instance.
77
+ **kwargs: Extra parameters forwarded to ``resolve_key``.
78
+
79
+ Returns:
80
+ String value, or ``None`` if the key does not exist.
81
+
82
+ Raises:
83
+ RedisConnectionError: Redis connection failure.
84
+ RedisServiceError: Redis operation failure.
85
+ """
86
+ real_key = resolve_key(key, **kwargs)
87
+ val = await self.client.get(real_key)
88
+ return str(val) if val is not None else None
89
+
90
+ @catch_redis_errors
91
+ async def getset(self, key: "str | BaseRedisKey", value: str, **kwargs: Any) -> str | None:
92
+ """Atomically set a new value and return the previous one (GETSET).
93
+
94
+ Args:
95
+ key: Redis key or a ``BaseRedisKey`` instance.
96
+ value: New value to store.
97
+ **kwargs: Extra parameters forwarded to ``resolve_key``.
98
+
99
+ Returns:
100
+ Previous value, or ``None`` if the key did not exist.
101
+
102
+ Raises:
103
+ RedisConnectionError: Redis connection failure.
104
+ RedisServiceError: Redis operation failure.
105
+ """
106
+ real_key = resolve_key(key, **kwargs)
107
+ val = await self.client.getset(real_key, value)
108
+ return str(val) if val is not None else None
109
+
110
+ @catch_redis_errors
111
+ async def mget(self, *keys: str) -> list[str | None]:
112
+ """Retrieve values for multiple keys in a single request (MGET).
113
+
114
+ Args:
115
+ *keys: Redis key strings.
116
+
117
+ Returns:
118
+ List of values in the same order as ``keys``.
119
+ ``None`` for keys that do not exist.
120
+
121
+ Raises:
122
+ RedisConnectionError: Redis connection failure.
123
+ RedisServiceError: Redis operation failure.
124
+ """
125
+ values = await self.client.mget(list(keys))
126
+ return [str(v) if v is not None else None for v in values]
127
+
128
+ @catch_redis_errors
129
+ async def mset(self, mapping: dict[str, str]) -> None:
130
+ """Set values for multiple keys in a single call (MSET).
131
+
132
+ Args:
133
+ mapping: Dict of ``{key: value}`` pairs to write.
134
+
135
+ Raises:
136
+ RedisConnectionError: Redis connection failure.
137
+ RedisServiceError: Redis operation failure.
138
+ """
139
+ await self.client.mset(mapping)
140
+
141
+ @catch_redis_errors
142
+ async def incr(self, key: "str | BaseRedisKey", **kwargs: Any) -> int:
143
+ """Increment a numeric value by 1 (INCR).
144
+
145
+ Args:
146
+ key: Redis key or a ``BaseRedisKey`` instance.
147
+ **kwargs: Extra parameters forwarded to ``resolve_key``.
148
+
149
+ Returns:
150
+ New value after incrementing.
151
+
152
+ Raises:
153
+ RedisConnectionError: Redis connection failure.
154
+ RedisServiceError: Redis operation failure.
155
+ """
156
+ real_key = resolve_key(key, **kwargs)
157
+ return int(await self.client.incr(real_key))
158
+
159
+ @catch_redis_errors
160
+ async def incrby(self, key: "str | BaseRedisKey", amount: int, **kwargs: Any) -> int:
161
+ """Increment a numeric value by a given amount (INCRBY).
162
+
163
+ Args:
164
+ key: Redis key or a ``BaseRedisKey`` instance.
165
+ amount: Increment step.
166
+ **kwargs: Extra parameters forwarded to ``resolve_key``.
167
+
168
+ Returns:
169
+ New value after incrementing.
170
+
171
+ Raises:
172
+ RedisConnectionError: Redis connection failure.
173
+ RedisServiceError: Redis operation failure.
174
+ """
175
+ real_key = resolve_key(key, **kwargs)
176
+ return int(await self.client.incrby(real_key, amount))
177
+
178
+ @catch_redis_errors
179
+ async def append(self, key: "str | BaseRedisKey", value: str, **kwargs: Any) -> int:
180
+ """Append a string to an existing value (APPEND).
181
+
182
+ Args:
183
+ key: Redis key or a ``BaseRedisKey`` instance.
184
+ value: String to append.
185
+ **kwargs: Extra parameters forwarded to ``resolve_key``.
186
+
187
+ Returns:
188
+ New total length of the value after appending.
189
+
190
+ Raises:
191
+ RedisConnectionError: Redis connection failure.
192
+ RedisServiceError: Redis operation failure.
193
+ """
194
+ real_key = resolve_key(key, **kwargs)
195
+ return int(await self.client.append(real_key, value))
196
+
197
+ @catch_redis_errors
198
+ async def delete(self, key: "str | BaseRedisKey", **kwargs: Any) -> None:
199
+ """Delete a key (DEL).
200
+
201
+ Args:
202
+ key: Redis key or a ``BaseRedisKey`` instance.
203
+ **kwargs: Extra parameters forwarded to ``resolve_key``.
204
+
205
+ Raises:
206
+ RedisConnectionError: Redis connection failure.
207
+ RedisServiceError: Redis operation failure.
208
+ """
209
+ real_key = resolve_key(key, **kwargs)
210
+ await self.client.delete(real_key)
211
+
212
+ @catch_redis_errors
213
+ async def delete_by_pattern(self, pattern: str) -> int:
214
+ """Delete all keys matching a glob pattern (SCAN + DEL).
215
+
216
+ Args:
217
+ pattern: Glob pattern, e.g. ``"session:*"``.
218
+
219
+ Returns:
220
+ Number of keys deleted.
221
+
222
+ Raises:
223
+ RedisConnectionError: Redis connection failure.
224
+ RedisServiceError: Redis operation failure.
225
+ """
226
+ keys = [k async for k in self.client.scan_iter(match=pattern)]
227
+ if not keys:
228
+ return 0
229
+ return int(await self.client.delete(*keys))
230
+
231
+ @catch_redis_errors
232
+ async def expire(self, key: "str | BaseRedisKey", ttl: int, **kwargs: Any) -> bool:
233
+ """Set a TTL (expiry) on a key in seconds (EXPIRE).
234
+
235
+ Args:
236
+ key: Redis key or a ``BaseRedisKey`` instance.
237
+ ttl: Time-to-live in seconds.
238
+ **kwargs: Extra parameters forwarded to ``resolve_key``.
239
+
240
+ Returns:
241
+ ``True`` if the TTL was set, ``False`` if the key does not exist.
242
+
243
+ Raises:
244
+ RedisConnectionError: Redis connection failure.
245
+ RedisServiceError: Redis operation failure.
246
+ """
247
+ real_key = resolve_key(key, **kwargs)
248
+ return bool(await self.client.expire(real_key, ttl))
249
+
250
+ @catch_redis_errors
251
+ async def ttl(self, key: "str | BaseRedisKey", **kwargs: Any) -> int:
252
+ """Return the remaining TTL of a key in seconds (TTL).
253
+
254
+ Args:
255
+ key: Redis key or a ``BaseRedisKey`` instance.
256
+ **kwargs: Extra parameters forwarded to ``resolve_key``.
257
+
258
+ Returns:
259
+ Remaining TTL in seconds. ``-1`` if no TTL is set, ``-2`` if the key does not exist.
260
+
261
+ Raises:
262
+ RedisConnectionError: Redis connection failure.
263
+ RedisServiceError: Redis operation failure.
264
+ """
265
+ real_key = resolve_key(key, **kwargs)
266
+ return int(await self.client.ttl(real_key))
267
+
268
+ @catch_redis_errors
269
+ async def exists(self, key: "str | BaseRedisKey", **kwargs: Any) -> bool:
270
+ """Check whether a key exists (EXISTS).
271
+
272
+ Args:
273
+ key: Redis key or a ``BaseRedisKey`` instance.
274
+ **kwargs: Extra parameters forwarded to ``resolve_key``.
275
+
276
+ Returns:
277
+ ``True`` if the key exists, ``False`` otherwise.
278
+
279
+ Raises:
280
+ RedisConnectionError: Redis connection failure.
281
+ RedisServiceError: Redis operation failure.
282
+ """
283
+ real_key = resolve_key(key, **kwargs)
284
+ return bool(await self.client.exists(real_key))
285
+
286
+ @catch_redis_errors
287
+ async def rename(self, key: "str | BaseRedisKey", new_key: str, **kwargs: Any) -> None:
288
+ """Rename a key (RENAME).
289
+
290
+ Args:
291
+ key: Redis key or a ``BaseRedisKey`` instance.
292
+ new_key: Target key name.
293
+ **kwargs: Extra parameters forwarded to ``resolve_key``.
294
+
295
+ Raises:
296
+ RedisConnectionError: Redis connection failure.
297
+ RedisServiceError: Redis operation failure.
298
+ """
299
+ real_key = resolve_key(key, **kwargs)
300
+ await self.client.rename(real_key, new_key)
301
+
302
+ @catch_redis_errors
303
+ async def key_type(self, key: "str | BaseRedisKey", **kwargs: Any) -> str:
304
+ """Return the data type stored at a key (TYPE).
305
+
306
+ Args:
307
+ key: Redis key or a ``BaseRedisKey`` instance.
308
+ **kwargs: Extra parameters forwarded to ``resolve_key``.
309
+
310
+ Returns:
311
+ One of: ``"string"``, ``"list"``, ``"set"``, ``"zset"``, ``"hash"``, ``"stream"``.
312
+
313
+ Raises:
314
+ RedisConnectionError: Redis connection failure.
315
+ RedisServiceError: Redis operation failure.
316
+ """
317
+ real_key = resolve_key(key, **kwargs)
318
+ return await self.client.type(real_key)
@@ -0,0 +1,277 @@
1
+ """
2
+ codex_platform.redis_service.operations.zset
3
+ =============================================
4
+ Redis Sorted Set (ZSet) operations.
5
+
6
+ A Sorted Set is a set where every member has an associated float score.
7
+ Use it for leaderboards, priority queues, and time-based event indexes.
8
+ """
9
+
10
+ import logging
11
+ from typing import Any
12
+
13
+ from redis.asyncio import Redis
14
+
15
+ from codex_platform.redis_service.base import catch_redis_errors
16
+ from codex_platform.redis_service.keys import BaseRedisKey, resolve_key
17
+
18
+ log = logging.getLogger(__name__)
19
+
20
+
21
+ class ZSetOperations:
22
+ """Redis Sorted Set operations (ZADD / ZRANGE / ZRANGEBYSCORE / ZREM and more).
23
+
24
+ Accepts an already-constructed ``redis.asyncio.Redis`` client.
25
+ All methods wrap Redis errors in typed exceptions.
26
+
27
+ Example::
28
+
29
+ ops = ZSetOperations(client)
30
+ await ops.add("leaderboard", {"alice": 1500.0, "bob": 1200.0})
31
+ top = await ops.range("leaderboard", 0, 9, reverse=True, with_scores=True)
32
+ """
33
+
34
+ def __init__(self, client: Redis) -> None:
35
+ self.client = client
36
+
37
+ @catch_redis_errors
38
+ async def add(self, key: "str | BaseRedisKey", mapping: dict[str, float], **kwargs: Any) -> int:
39
+ """Add members with scores to a sorted set (ZADD).
40
+
41
+ Args:
42
+ key: Redis key or a ``BaseRedisKey`` instance.
43
+ mapping: Dict of ``{member: score}`` pairs.
44
+ **kwargs: Extra parameters forwarded to ``resolve_key``.
45
+
46
+ Returns:
47
+ Number of new members added (existing members with updated scores are not counted).
48
+
49
+ Raises:
50
+ RedisConnectionError: Redis connection failure.
51
+ RedisServiceError: Redis operation failure.
52
+ """
53
+ real_key = resolve_key(key, **kwargs)
54
+ return int(await self.client.zadd(real_key, mapping))
55
+
56
+ @catch_redis_errors
57
+ async def score(self, key: "str | BaseRedisKey", member: str, **kwargs: Any) -> float | None:
58
+ """Return the score of a member in a sorted set (ZSCORE).
59
+
60
+ Args:
61
+ key: Redis key or a ``BaseRedisKey`` instance.
62
+ member: Member name.
63
+ **kwargs: Extra parameters forwarded to ``resolve_key``.
64
+
65
+ Returns:
66
+ Float score of the member, or ``None`` if the member does not exist.
67
+
68
+ Raises:
69
+ RedisConnectionError: Redis connection failure.
70
+ RedisServiceError: Redis operation failure.
71
+ """
72
+ real_key = resolve_key(key, **kwargs)
73
+ val = await self.client.zscore(real_key, member)
74
+ return float(val) if val is not None else None
75
+
76
+ @catch_redis_errors
77
+ async def rank(self, key: "str | BaseRedisKey", member: str, reverse: bool = False, **kwargs: Any) -> int | None:
78
+ """Return the rank (position) of a member in a sorted set (ZRANK / ZREVRANK).
79
+
80
+ Args:
81
+ key: Redis key or a ``BaseRedisKey`` instance.
82
+ member: Member name.
83
+ reverse: If ``True``, use ZREVRANK (rank by descending score). Defaults to ``False``.
84
+ **kwargs: Extra parameters forwarded to ``resolve_key``.
85
+
86
+ Returns:
87
+ Zero-based rank of the member, or ``None`` if the member does not exist.
88
+
89
+ Raises:
90
+ RedisConnectionError: Redis connection failure.
91
+ RedisServiceError: Redis operation failure.
92
+ """
93
+ real_key = resolve_key(key, **kwargs)
94
+ fn = self.client.zrevrank if reverse else self.client.zrank
95
+ result = await fn(real_key, member)
96
+ return int(result) if result is not None else None
97
+
98
+ @catch_redis_errors
99
+ async def range(
100
+ self,
101
+ key: "str | BaseRedisKey",
102
+ start: int = 0,
103
+ end: int = -1,
104
+ reverse: bool = False,
105
+ with_scores: bool = False,
106
+ **kwargs: Any,
107
+ ) -> list[str] | list[tuple[str, float]]:
108
+ """Return a range of members by rank (ZRANGE / ZREVRANGE).
109
+
110
+ Args:
111
+ key: Redis key or a ``BaseRedisKey`` instance.
112
+ start: Start rank (0-based).
113
+ end: End rank inclusive. ``-1`` means the last member.
114
+ reverse: If ``True``, return members in descending score order (ZREVRANGE).
115
+ with_scores: If ``True``, return ``[(member, score), ...]`` tuples.
116
+ **kwargs: Extra parameters forwarded to ``resolve_key``.
117
+
118
+ Returns:
119
+ List of member strings, or list of ``(member, score)`` tuples if ``with_scores=True``.
120
+
121
+ Raises:
122
+ RedisConnectionError: Redis connection failure.
123
+ RedisServiceError: Redis operation failure.
124
+ """
125
+ real_key = resolve_key(key, **kwargs)
126
+ if reverse:
127
+ result = await self.client.zrevrange(real_key, start, end, withscores=with_scores)
128
+ else:
129
+ result = await self.client.zrange(real_key, start, end, withscores=with_scores)
130
+ return result
131
+
132
+ @catch_redis_errors
133
+ async def range_by_score(
134
+ self,
135
+ key: "str | BaseRedisKey",
136
+ min_score: float,
137
+ max_score: float,
138
+ with_scores: bool = False,
139
+ **kwargs: Any,
140
+ ) -> list[str] | list[tuple[str, float]]:
141
+ """Return members within a score range (ZRANGEBYSCORE).
142
+
143
+ Args:
144
+ key: Redis key or a ``BaseRedisKey`` instance.
145
+ min_score: Minimum score (inclusive).
146
+ max_score: Maximum score (inclusive).
147
+ with_scores: If ``True``, return ``[(member, score), ...]`` tuples.
148
+ **kwargs: Extra parameters forwarded to ``resolve_key``.
149
+
150
+ Returns:
151
+ List of member strings, or list of ``(member, score)`` tuples if ``with_scores=True``.
152
+
153
+ Raises:
154
+ RedisConnectionError: Redis connection failure.
155
+ RedisServiceError: Redis operation failure.
156
+ """
157
+ real_key = resolve_key(key, **kwargs)
158
+ return await self.client.zrangebyscore(real_key, min_score, max_score, withscores=with_scores)
159
+
160
+ @catch_redis_errors
161
+ async def remove(self, key: "str | BaseRedisKey", *members: str, **kwargs: Any) -> int:
162
+ """Remove one or more members from a sorted set (ZREM).
163
+
164
+ Args:
165
+ key: Redis key or a ``BaseRedisKey`` instance.
166
+ *members: Member names to remove.
167
+ **kwargs: Extra parameters forwarded to ``resolve_key``.
168
+
169
+ Returns:
170
+ Number of members actually removed.
171
+
172
+ Raises:
173
+ RedisConnectionError: Redis connection failure.
174
+ RedisServiceError: Redis operation failure.
175
+ """
176
+ real_key = resolve_key(key, **kwargs)
177
+ return int(await self.client.zrem(real_key, *members))
178
+
179
+ @catch_redis_errors
180
+ async def card(self, key: "str | BaseRedisKey", **kwargs: Any) -> int:
181
+ """Return the number of members in a sorted set (ZCARD).
182
+
183
+ Args:
184
+ key: Redis key or a ``BaseRedisKey`` instance.
185
+ **kwargs: Extra parameters forwarded to ``resolve_key``.
186
+
187
+ Returns:
188
+ Number of members. ``0`` if the key does not exist.
189
+
190
+ Raises:
191
+ RedisConnectionError: Redis connection failure.
192
+ RedisServiceError: Redis operation failure.
193
+ """
194
+ real_key = resolve_key(key, **kwargs)
195
+ return int(await self.client.zcard(real_key))
196
+
197
+ @catch_redis_errors
198
+ async def increment(self, key: "str | BaseRedisKey", member: str, amount: float = 1.0, **kwargs: Any) -> float:
199
+ """Increment the score of a member by the given amount (ZINCRBY).
200
+
201
+ Args:
202
+ key: Redis key or a ``BaseRedisKey`` instance.
203
+ member: Member name.
204
+ amount: Increment value. Defaults to ``1.0``.
205
+ **kwargs: Extra parameters forwarded to ``resolve_key``.
206
+
207
+ Returns:
208
+ New score of the member after incrementing.
209
+
210
+ Raises:
211
+ RedisConnectionError: Redis connection failure.
212
+ RedisServiceError: Redis operation failure.
213
+ """
214
+ real_key = resolve_key(key, **kwargs)
215
+ return float(await self.client.zincrby(real_key, amount, member))
216
+
217
+ @catch_redis_errors
218
+ async def count(self, key: "str | BaseRedisKey", min_score: float, max_score: float, **kwargs: Any) -> int:
219
+ """Count members within a score range (ZCOUNT).
220
+
221
+ Args:
222
+ key: Redis key or a ``BaseRedisKey`` instance.
223
+ min_score: Minimum score (inclusive).
224
+ max_score: Maximum score (inclusive).
225
+ **kwargs: Extra parameters forwarded to ``resolve_key``.
226
+
227
+ Returns:
228
+ Number of members with score in ``[min_score, max_score]``.
229
+
230
+ Raises:
231
+ RedisConnectionError: Redis connection failure.
232
+ RedisServiceError: Redis operation failure.
233
+ """
234
+ real_key = resolve_key(key, **kwargs)
235
+ return int(await self.client.zcount(real_key, min_score, max_score))
236
+
237
+ @catch_redis_errors
238
+ async def remove_by_rank(self, key: "str | BaseRedisKey", start: int, end: int, **kwargs: Any) -> int:
239
+ """Remove members by rank range (ZREMRANGEBYRANK).
240
+
241
+ Args:
242
+ key: Redis key or a ``BaseRedisKey`` instance.
243
+ start: Start rank (inclusive, 0-based).
244
+ end: End rank (inclusive).
245
+ **kwargs: Extra parameters forwarded to ``resolve_key``.
246
+
247
+ Returns:
248
+ Number of members removed.
249
+
250
+ Raises:
251
+ RedisConnectionError: Redis connection failure.
252
+ RedisServiceError: Redis operation failure.
253
+ """
254
+ real_key = resolve_key(key, **kwargs)
255
+ return int(await self.client.zremrangebyrank(real_key, start, end))
256
+
257
+ @catch_redis_errors
258
+ async def remove_by_score(
259
+ self, key: "str | BaseRedisKey", min_score: float, max_score: float, **kwargs: Any
260
+ ) -> int:
261
+ """Remove members within a score range (ZREMRANGEBYSCORE).
262
+
263
+ Args:
264
+ key: Redis key or a ``BaseRedisKey`` instance.
265
+ min_score: Minimum score (inclusive).
266
+ max_score: Maximum score (inclusive).
267
+ **kwargs: Extra parameters forwarded to ``resolve_key``.
268
+
269
+ Returns:
270
+ Number of members removed.
271
+
272
+ Raises:
273
+ RedisConnectionError: Redis connection failure.
274
+ RedisServiceError: Redis operation failure.
275
+ """
276
+ real_key = resolve_key(key, **kwargs)
277
+ return int(await self.client.zremrangebyscore(real_key, min_score, max_score))
@@ -0,0 +1,80 @@
1
+ """
2
+ codex_platform.redis_service.service
3
+ =====================================
4
+ Full Redis service via composition.
5
+
6
+ Usage::
7
+
8
+ from redis.asyncio import Redis
9
+ from codex_platform.redis_service import RedisService
10
+
11
+ redis_client = Redis(host="localhost", port=6379)
12
+ service = RedisService(redis_client)
13
+
14
+ await service.hash.set_json("u:42", "profile", data)
15
+ await service.string.set("session:abc", "token", ttl=3600)
16
+
17
+ # JSON as plain string (no server modules required):
18
+ await service.json.set("user:42", {"name": "Alice"}, ttl=3600)
19
+ user = await service.json.get("user:42")
20
+
21
+ # JSON via RedisJSON module (requires server module):
22
+ await service.json_module.set("user:42", "$", {"name": "Alice"})
23
+ name = await service.json_module.get("user:42", "$.name")
24
+
25
+ For selective composition use operations directly::
26
+
27
+ from codex_platform.redis_service.operations import HashOperations, StringOperations
28
+
29
+ class MyService:
30
+ def __init__(self, client: Redis):
31
+ self.hash = HashOperations(client)
32
+ self.string = StringOperations(client)
33
+ """
34
+
35
+ from redis.asyncio import Redis
36
+
37
+ from .operations import (
38
+ HashOperations,
39
+ JsonModuleOperations,
40
+ JsonStringOperations,
41
+ ListOperations,
42
+ PipelineOperations,
43
+ SetOperations,
44
+ StringOperations,
45
+ ZSetOperations,
46
+ )
47
+
48
+
49
+ class RedisService:
50
+ """Unified Redis service — all data-type operations in one place.
51
+
52
+ Suitable for projects that need access to multiple Redis data types through
53
+ a single entry point. For selective composition, instantiate individual
54
+ ``Operations`` classes directly.
55
+
56
+ Attributes:
57
+ hash: Hash operations (HSET / HGET / HGETALL …).
58
+ string: String and key-level operations (SET / GET / EXPIRE …).
59
+ list: List operations (RPUSH / LPOP / LRANGE …).
60
+ set: Set operations (SADD / SREM / SMEMBERS …).
61
+ zset: Sorted-set operations (ZADD / ZRANGE / ZRANK …).
62
+ json: JSON stored as Redis strings — works with any Redis instance.
63
+ json_module: JSON via the server-side RedisJSON module (requires RedisJSON).
64
+ pipeline: Pipeline / transaction helpers.
65
+ """
66
+
67
+ def __init__(self, client: Redis) -> None:
68
+ """Initialize the service with an existing async Redis client.
69
+
70
+ Args:
71
+ client: An already-constructed ``redis.asyncio.Redis`` instance.
72
+ """
73
+ self.hash = HashOperations(client)
74
+ self.string = StringOperations(client)
75
+ self.list = ListOperations(client)
76
+ self.set = SetOperations(client)
77
+ self.zset = ZSetOperations(client)
78
+ self.json = JsonStringOperations(client)
79
+ self.json_module = JsonModuleOperations(client)
80
+ self.pipeline = PipelineOperations(client)