"""Cache wyników zapytań: in-memory LRU + TTL. POZIOM 3 cache. Te same zapytania powtarzają się (popularne wyszukiwania). Tu trzymamy gotowy wynik przez krótki TTL. Bez zewnętrznych zależności — w produkcji można podmienić na Redis (ten sam interfejs get/put), by współdzielić cache między instancjami. """ from __future__ import annotations import time from collections import OrderedDict from typing import Any class QueryCache: def __init__(self, max_size: int = 512, ttl: int = 300) -> None: self.max_size = max_size self.ttl = ttl self._store: OrderedDict[str, tuple[float, Any]] = OrderedDict() def get(self, key: str) -> Any | None: item = self._store.get(key) if item is None: return None ts, value = item if time.time() - ts > self.ttl: del self._store[key] return None self._store.move_to_end(key) return value def put(self, key: str, value: Any) -> None: self._store[key] = (time.time(), value) self._store.move_to_end(key) while len(self._store) > self.max_size: self._store.popitem(last=False) def clear(self) -> None: self._store.clear()