CI / lint (push) Canceled after 0s
CI / typecheck (push) Canceled after 0s
CI / unit-tests (push) Canceled after 0s
CI / integration-tests (push) Canceled after 0s
CI / container-build (push) Canceled after 0s
CI / dependency-audit (push) Canceled after 0s
Production-grade media metadata backend per docs/aurora-core-spec.md: Aurora-owned UUIDv7 identity system, normalized movie/TV/people/credits schema, provider abstraction with a TMDb adapter, an idempotent async ingestion pipeline (normalize -> match -> upsert -> provenance), a Postgres FTS/trigram search layer, a stateless FastAPI v1 API with Redis caching/rate-limiting, arq workers, dev/prod Docker Compose topologies, unit + integration + load tests, CI, and architecture/ database/API/ERD documentation. Co-Authored-By: Claude Sonnet 5 <[email protected]>
41 lines
1.2 KiB
Python
41 lines
1.2 KiB
Python
"""Search provider abstraction (section 16).
|
|
|
|
API clients and the rest of the service layer talk to `SearchProvider`, not
|
|
to PostgreSQL directly, so the underlying engine can be swapped later (e.g.
|
|
for an `OpenSearchProvider`) without touching callers.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import uuid
|
|
from abc import ABC, abstractmethod
|
|
from dataclasses import dataclass, field
|
|
|
|
from sqlalchemy.ext.asyncio import AsyncSession
|
|
|
|
|
|
@dataclass
|
|
class SearchMatch:
|
|
entity_id: uuid.UUID
|
|
score: float
|
|
|
|
|
|
@dataclass
|
|
class SearchResultIDs:
|
|
movies: list[SearchMatch] = field(default_factory=list)
|
|
series: list[SearchMatch] = field(default_factory=list)
|
|
people: list[SearchMatch] = field(default_factory=list)
|
|
collections: list[SearchMatch] = field(default_factory=list)
|
|
companies: list[SearchMatch] = field(default_factory=list)
|
|
|
|
|
|
class SearchProvider(ABC):
|
|
"""Returns ranked Aurora entity IDs matching a query. Never returns
|
|
fully-hydrated entities — that's the SearchService's job, so the
|
|
provider stays a thin, swappable ranking layer."""
|
|
|
|
@abstractmethod
|
|
async def search(
|
|
self, session: AsyncSession, query: str, *, limit_per_type: int = 10
|
|
) -> SearchResultIDs: ...
|