beerds/server/modules/descriptions/repository/repository.py

128 lines
5.1 KiB
Python
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

from abc import ABCMeta, abstractmethod
from pathlib import Path
from aiocache import Cache, cached # type: ignore
from sqlalchemy import select
from server.infra.db import AsyncDB
from server.modules.descriptions.domain import Breed
from server.modules.descriptions.repository import models
class ACharactersRepository(metaclass=ABCMeta):
@abstractmethod
async def get_characters(self) -> list[Breed]:
pass
@abstractmethod
async def get_character(self, alias: str) -> Breed | None:
pass
class CharactersRepository(ACharactersRepository):
def __init__(self):
pass
@cached(ttl=60, cache=Cache.MEMORY)
async def get_characters(self) -> list[Breed]:
breed_dir = Path("server/modules/descriptions/repository/breed_descriptions")
breeds: list[Breed] = []
# Идем по каждому текстовому файлу с описанием породы
for breed_file in breed_dir.glob("*.txt"):
breed_name = breed_file.stem # имя файла без расширения - название породы
description = breed_file.read_text(encoding="utf-8") # читаем описание из файла
breeds.append(
Breed(
id=breed_name,
name=breed_name.replace("_", " "),
alias=breed_file.stem,
description=description.strip(),
)
)
breeds.sort(key=lambda b: b.name)
return breeds
async def get_character(self, alias: str) -> Breed | None:
breeds = await self.get_characters()
data = [b for b in breeds if b.alias == alias]
if len(data) == 0:
return None
return data[0]
class PGCharactersRepository(ACharactersRepository):
_db: AsyncDB
def __init__(self, db: AsyncDB):
self._db = db
# ───────────────────────────────────────────────────────────────────── #
# 8⃣ Кешируемый метод, который возвращает **все** породы
# ───────────────────────────────────────────────────────────────────── #
@cached(ttl=60, cache=Cache.MEMORY) # 1мин. кеш
async def get_characters(self) -> list[Breed]:
"""
Читает данные из таблицы `beerds.beerds` и преобразует каждую строку
в экземпляр `Breed`. Поле `signs` игнорируется в `Breed` его нет.
"""
async with self._db.async_session() as session:
# Писем SELECTзапрос (получаем все строки)
stmt = select(
models.Beerds.id,
models.Beerds.name,
models.Beerds.alias,
models.Beerds.descriptions,
)
result = await session.execute(stmt)
rows = result.fetchall()
# Конвертируем в Breed
breeds: list[Breed] = [
Breed(
id=str(row.id),
name=row.name.strip(),
alias=row.alias.strip(),
description=row.descriptions.strip(),
)
for row in rows
]
# Сортируем по имени, как было в файле‑реализации
breeds.sort(key=lambda b: b.name.lower())
return breeds
# ───────────────────────────────────────────────────────────────────── #
# 9⃣ Получить конкретную породу по псевдониму
# ───────────────────────────────────────────────────────────────────── #
async def get_character(self, alias: str) -> Breed | None:
"""
Быстрый запрос без получения всех пород. Если результат
пустой возвращаем `None`.
"""
async with self._db.async_session() as session:
stmt = (
select(
models.Beerds.id,
models.Beerds.name,
models.Beerds.alias,
models.Beerds.descriptions,
)
.where(models.Beerds.alias == alias)
.limit(1)
)
result = await session.execute(stmt)
row = result.fetchone()
if row is None: # pragma: no cover
return None
return Breed(
id=str(row.id),
name=row.name.strip(),
alias=row.alias.strip(),
description=row.descriptions.strip(),
)