File size: 2,356 Bytes
409c17a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
"""

Infrastructure - Redis Cache Implementation

"""
import json
from typing import Any, Optional

import redis.asyncio as redis

from app.domain.interfaces import ICache


class RedisCache(ICache):
    """Redis cache implementation"""

    def __init__(self, redis_url: str):
        self.redis_url = redis_url
        self._client: Optional[redis.Redis] = None

    async def _get_client(self) -> redis.Redis:
        """Get or create Redis client"""
        if self._client is None:
            self._client = await redis.from_url(
                self.redis_url, encoding="utf-8", decode_responses=True
            )
        return self._client

    async def get(self, key: str) -> Optional[Any]:
        """Get value from cache"""
        client = await self._get_client()
        value = await client.get(key)

        if value is None:
            return None

        try:
            return json.loads(value)
        except json.JSONDecodeError:
            return value

    async def set(self, key: str, value: Any, ttl: Optional[int] = None) -> bool:
        """Set value in cache"""
        client = await self._get_client()

        # Serialize value
        if isinstance(value, (dict, list)):
            serialized = json.dumps(value)
        else:
            serialized = str(value)

        if ttl:
            await client.setex(key, ttl, serialized)
        else:
            await client.set(key, serialized)

        return True

    async def delete(self, key: str) -> bool:
        """Delete key from cache"""
        client = await self._get_client()
        result = await client.delete(key)
        return result > 0

    async def exists(self, key: str) -> bool:
        """Check if key exists"""
        client = await self._get_client()
        return await client.exists(key) > 0

    async def clear(self, pattern: str = "*") -> int:
        """Clear cache by pattern"""
        client = await self._get_client()
        keys = []

        async for key in client.scan_iter(match=pattern):
            keys.append(key)

        if keys:
            return await client.delete(*keys)

        return 0

    async def close(self) -> None:
        """Close Redis connection"""
        if self._client:
            await self._client.close()