Files
astrololo/services/logic/app/service.py
gitea 16d35c16dc Szkielet aplikacji trójwarstwowej (prezentacja / logika / dane)
Trzy niezależne usługi FastAPI komunikujące się przez HTTP/JSON, każda
zna tylko adres warstwy bezpośrednio pod nią:

- presentation (:8000) — strona WWW + formularz
- logic (:8001) — reguły biznesowe, pośrednik
- data (:8002) — wyszukiwanie danych za interfejsem DataProvider

Warstwa danych: czytanie setek plików .xlsx z wykrywaniem nagłówka i
mapowaniem układu kolumn na schemat kanoniczny, z 4-poziomowym cache
(schemat L1, Parquet L2, wyniki zapytań L3, odwrócony indeks L4) i
unieważnianiem po odcisku pliku. Gotowa ścieżka migracji do SQL
(ingest/to_sql.py + SqlDataProvider, przełączane przez DATA_PROVIDER).

Zawiera docker-compose, Makefile, generator danych przykładowych.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-26 17:35:09 +02:00

44 lines
1.6 KiB
Python

"""Logika biznesowa — serce warstwy logicznej.
Tu (a nie w prezentacji ani w bazie) żyją reguły: walidacja/normalizacja danych
z formularza, tłumaczenie zapytania użytkownika na znormalizowane zapytanie do
bazy, oraz opracowanie/wzbogacenie wyników w drodze w górę.
To jest miejsce do rozbudowy o właściwą domenę (obliczenia, reguły, agregacje).
"""
from __future__ import annotations
from app.clients.data_client import DataClient
from app.models import QueryRequest, QueryResponse
class QueryService:
def __init__(self, data_client: DataClient | None = None) -> None:
self.data = data_client or DataClient()
def handle(self, req: QueryRequest) -> QueryResponse:
# 1) normalizacja wejścia z formularza (reguła biznesowa)
value = req.query.strip()
key = req.field.strip().lower()
# 2) zapytanie w dół do warstwy bazodanowej
raw = self.data.search(key=key, value=value, exact=req.exact, limit=req.limit)
# 3) opracowanie wyników w górę (tu można liczyć/wzbogacać/sortować)
results = raw.get("rows", [])
results = sorted(results, key=lambda r: str(r.get(key, "")))
return QueryResponse(
status="ok",
query=value,
count=len(results),
results=results,
meta={
"field": key,
"exact": req.exact,
"data_cache": raw.get("cache"),
"data_provider": raw.get("provider"),
"data_elapsed_ms": raw.get("elapsed_ms"),
},
)