"""Kontrakt danych warstwy bazodanowej. Te modele są JEDYNYM publicznym interfejsem tej warstwy. Warstwa logiczna zna wyłącznie te kształty (poprzez HTTP/JSON) — nie wie nic o Excelu, cache ani SQL. Dzięki temu można podmienić implementację (Excel -> SQL) bez zmiany pozostałych warstw. """ from __future__ import annotations from typing import Any from pydantic import BaseModel, Field class SearchQuery(BaseModel): """Znormalizowane zapytanie wyszukiwania przychodzące z warstwy logicznej.""" key: str = Field(..., description="Pole/kolumna kanoniczna, po której szukamy, np. 'name'.") value: str = Field(..., description="Szukana wartość.") exact: bool = Field(False, description="Dopasowanie dokładne vs. zawieranie (contains).") limit: int = Field(50, ge=1, le=1000) fields: list[str] | None = Field( None, description="Lista pól kanonicznych do zwrócenia; None = wszystkie." ) class SearchResult(BaseModel): """Wynik wyszukiwania zwracany w górę do warstwy logicznej.""" rows: list[dict[str, Any]] total: int elapsed_ms: float cache: str = Field("miss", description="hit/miss/partial — skąd pochodzą dane.") provider: str = Field(..., description="Nazwa aktywnej implementacji, np. 'excel' lub 'sql'.") class HealthInfo(BaseModel): status: str = "ok" provider: str indexed_files: int = 0 details: dict[str, Any] = Field(default_factory=dict)