""" Repository for working with the :class:`~server.modules.rate.repository.models.Vote` model. Only the “write‑only” operation – adding a vote – is required in the current application logic. The repository keeps the database interaction encapsulated and provides an asynchronous API that can be used by the service layer (or any other consumer). The implementation uses the same pattern that is already present in the ``CharactersRepository`` – an async session manager from ``server.infra.db.AsyncDB`` and an interface that makes unit‑testing straightforward. """ from abc import ABCMeta, abstractmethod from server.infra.db import AsyncDB from server.modules.rate.repository import models # --------------------------------------------------------------------------- # # 1️⃣ Base interface # --------------------------------------------------------------------------- # class AVoteRepository(metaclass=ABCMeta): """ Abstract repository that declares the contract for working with votes. At the moment only one operation is required – inserting a new vote. """ @abstractmethod async def add_vote(self, vote: models.Vote) -> None: """Persist ``vote`` into the database.""" raise NotImplementedError # --------------------------------------------------------------------------- # # 2️⃣ Concrete PostgreSQL implementation # --------------------------------------------------------------------------- # class PGVoteRepository(AVoteRepository): """ PostgreSQL implementation of :class:`AVoteRepository`. The repository is intentionally *minimal* – only an ``add_vote`` method is exposed. The rest of the CRUD operations are expected to be added later if/when the business logic grows. """ _db: AsyncDB def __init__(self, db: AsyncDB): self._db = db # --------------------------------------------------------------------- # # 2.1 Add a vote # --------------------------------------------------------------------- # async def add_vote(self, vote: models.Vote) -> None: """ Insert ``vote`` into the ``votes`` table. Parameters ---------- vote: Instance of :class:`~server.modules.rate.repository.models.Vote` containing all necessary fields (``id``, ``attachment_id``, ``beerd_id``, ``rate`` and ``created_at``). The instance is a *mapped* dataclass, therefore SQLAlchemy can persist it directly. Notes ----- * No explicit caching – the operation mutates the database and should never be served from a cache. * The method is deliberately ``async`` because it uses ``AsyncDB.async_session``. """ async with self._db.async_session() as session: # We use the *instance* directly – SQLAlchemy will handle the # mapping for us. ``insert`` could also be used, but the # instance‑based approach keeps type‑checking and IDE # auto‑completion in sync with the dataclass. session.add(vote) await session.commit()