"""Cache schematu: wykryty wiersz nagłówka + mapowanie kolumn, per (plik, arkusz). POZIOM 1 cache. Najdroższe jest samo wykrywanie nagłówka i wnioskowanie układu kolumn. Robimy to RAZ na wersję pliku i zapisujemy w SQLite. Kolejne odczyty pomijają skanowanie. """ from __future__ import annotations import json import sqlite3 from pathlib import Path class SchemaCache: def __init__(self, cache_dir: Path) -> None: self._db = sqlite3.connect(str(cache_dir / "schema.db"), check_same_thread=False) self._db.execute( """ CREATE TABLE IF NOT EXISTS schema_cache ( fingerprint TEXT, sheet TEXT, header_row INTEGER, mapping TEXT, PRIMARY KEY (fingerprint, sheet) ) """ ) self._db.commit() def get(self, fp: str, sheet: str) -> tuple[int, dict[str, str]] | None: cur = self._db.execute( "SELECT header_row, mapping FROM schema_cache WHERE fingerprint=? AND sheet=?", (fp, sheet), ) row = cur.fetchone() if row is None: return None return int(row[0]), json.loads(row[1]) def put(self, fp: str, sheet: str, header_row: int, mapping: dict[str, str]) -> None: self._db.execute( "INSERT OR REPLACE INTO schema_cache VALUES (?,?,?,?)", (fp, sheet, header_row, json.dumps(mapping, ensure_ascii=False)), ) self._db.commit()