--- name: cache_to_sqlite kind: function lang: py domain: infra version: "1.0.0" purity: impure signature: "def cache_to_sqlite(db_path: str, namespace: str = 'default') -> CacheStore" description: "Cache key-value persistido en SQLite con TTL y lazy eviction. Cada namespace es un espacio logico dentro de la misma BD. Keys son strings, values se serializan con JSON. TTL en segundos, 0 = sin expiracion. Thread-safe mediante mutex." tags: [cache, sqlite, persistence, ttl, memoize, key-value] uses_functions: [] uses_types: [] returns: [] returns_optional: false error_type: "error_go_core" imports: ["sqlite3", "json", "time", "threading"] params: - name: db_path desc: "ruta al archivo SQLite de cache" - name: namespace desc: "namespace logico dentro de la BD para aislar cachés" output: "instancia CacheStore con metodos set, get, get_or_set, clear y stats" tested: true tests: - "Set y get basico" - "TTL expirado → None" - "TTL 0 → nunca expira" - "get_or_set con factory que solo se llama en miss" - "Namespaces independientes" - "Clear elimina solo el namespace" - "Stats contadores correctos" - "Concurrencia (threading basico)" test_file_path: "python/functions/infra/cache_to_sqlite_test.py" file_path: "python/functions/infra/cache_to_sqlite.py" --- ## Ejemplo ```python from infra.cache_to_sqlite import cache_to_sqlite store = cache_to_sqlite("my_cache.db", namespace="llm") # Almacenar con TTL de 1 hora store.set("prompt:explain_x", "explanation...", ttl=3600) # Recuperar (None si miss o expirado) val = store.get("prompt:explain_x") # Factory pattern: solo computa si no esta en cache result = store.get_or_set( "prompt:explain_y", factory=lambda: call_llm("explain y"), ttl=3600, ) # Estadisticas print(store.stats()) # {"hits": 2, "misses": 1, "size": 5} ``` ## Notas La eviction de entradas expiradas es lazy: se ejecuta en cada llamada a `get` o `stats`, no en background. El schema SQLite usa `(namespace, key)` como PRIMARY KEY para garantizar upserts atomicos. Usa WAL mode para mejor concurrencia de lecturas. Cada thread mantiene su propia conexion SQLite (thread-local), sincronizada via `threading.Lock` para escrituras.