82 lines
3.1 KiB
Python
82 lines
3.1 KiB
Python
"""
|
||
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()
|