Coverage for src/lexigram/admin/cache/adapter.py: 73%
66 statements
« prev ^ index » next coverage.py v7.15.4, created at 2026-08-21 14:56 +0800
« prev ^ index » next coverage.py v7.15.4, created at 2026-08-21 14:56 +0800
1"""Adapter that delegates admin caching to ``lexigram-cache``.
3When ``lexigram-cache`` is installed, ``AdminCacheServiceAdapter`` wraps
4``lexigram.cache.service.core.CacheService`` for rich caching features
5(stampede protection, tag invalidation, batch ops). When not installed,
6it falls back to a no-op that satisfies the same protocol.
7"""
9from __future__ import annotations
11from typing import Any
13try:
14 from lexigram.cache.service.core import CacheService as _LexigramCacheService
15 from lexigram.contracts.infra.cache import CacheBackendProtocol
17 _HAS_CACHE = True
18except ImportError: # noqa: F841
19 _HAS_CACHE = False
20 _LexigramCacheService = object # type: ignore[assignment,misc]
21 CacheBackendProtocol = object # type: ignore[assignment,misc]
24class AdminCacheServiceAdapter:
25 """Bridge between admin's cache needs and ``lexigram-cache``'s ``CacheService``.
27 Usage::
29 adapter = AdminCacheServiceAdapter(cache_service=real_service)
30 value = await adapter.get("key")
31 await adapter.set("key", value, ttl=60)
32 """
34 def __init__(
35 self,
36 cache_service: Any | None = None,
37 ) -> None:
38 self._service = cache_service
40 async def get(self, key: str) -> Any | None:
41 """Get a value from cache."""
42 if self._service is None:
43 return None
44 try:
45 return await self._service.get(key)
46 except Exception: # noqa: BLE001
47 return None
49 async def set(self, key: str, value: Any, ttl: int | None = None) -> bool:
50 """Set a value in cache."""
51 if self._service is None:
52 return False
53 try:
54 await self._service.set(key, value, ttl)
55 return True
56 except Exception: # noqa: BLE001
57 return False
59 async def delete(self, key: str) -> bool:
60 """Delete a key from cache."""
61 if self._service is None:
62 return False
63 try:
64 await self._service.delete(key)
65 return True
66 except Exception: # noqa: BLE001
67 return False
69 async def delete_pattern(self, pattern: str) -> int:
70 """Delete all keys matching a pattern."""
71 if self._service is None:
72 return 0
73 try:
74 return await self._service.delete_pattern(pattern)
75 except Exception: # noqa: BLE001
76 return 0
78 async def get_or_set(
79 self,
80 key: str,
81 factory: Any,
82 ttl: int | None = None,
83 ) -> Any:
84 """Get from cache or compute and store."""
85 if self._service is None:
86 return await factory() if callable(factory) else factory
87 try:
88 return await self._service.get_or_set(key, factory, ttl)
89 except Exception: # noqa: BLE001
90 return await factory() if callable(factory) else factory
92 async def exists(self, key: str) -> bool:
93 """Check if a key exists in cache."""
94 if self._service is None:
95 return False
96 try:
97 return await self._service.exists(key)
98 except Exception: # noqa: BLE001
99 return False
101 async def clear(self) -> bool:
102 """Clear all cached entries."""
103 if self._service is None:
104 return False
105 try:
106 await self._service.clear()
107 return True
108 except Exception: # noqa: BLE001
109 return False
112__all__ = ["AdminCacheServiceAdapter"]