"""Artist repository — adapter over ``AsyncSession``.""" import uuid from sqlalchemy import func, select from sqlalchemy.ext.asyncio import AsyncSession from app.domain.entities.track import Artist from app.infrastructure.db.models.album import AlbumModel from app.infrastructure.db.models.artist import ArtistModel from app.infrastructure.db.models.track import TrackModel def _to_entity(row: ArtistModel) -> Artist: return Artist( id=row.id, name=row.name, created_at=row.created_at, updated_at=row.updated_at, ) class SqlAlchemyArtistRepository: def __init__(self, session: AsyncSession) -> None: self._session = session async def get_or_create(self, name: str) -> Artist: row = ( await self._session.execute(select(ArtistModel).where(ArtistModel.name == name)) ).scalar_one_or_none() if row is None: row = ArtistModel(name=name) self._session.add(row) await self._session.flush() await self._session.refresh(row) return _to_entity(row) async def get_by_id(self, artist_id: uuid.UUID) -> Artist | None: row = await self._session.get(ArtistModel, artist_id) return _to_entity(row) if row is not None else None async def get_many(self, ids: list[uuid.UUID]) -> list[Artist]: if not ids: return [] rows = ( (await self._session.execute(select(ArtistModel).where(ArtistModel.id.in_(ids)))) .scalars() .all() ) return [_to_entity(r) for r in rows] async def list(self, *, q: str | None, limit: int, offset: int) -> list[Artist]: stmt = select(ArtistModel) if q: stmt = stmt.where(ArtistModel.name.ilike(f"%{q}%")) stmt = stmt.order_by(ArtistModel.name).limit(limit).offset(offset) rows = (await self._session.execute(stmt)).scalars().all() return [_to_entity(r) for r in rows] async def count(self, *, q: str | None) -> int: stmt = select(func.count()).select_from(ArtistModel) if q: stmt = stmt.where(ArtistModel.name.ilike(f"%{q}%")) return (await self._session.execute(stmt)).scalar_one() async def album_count(self, artist_id: uuid.UUID) -> int: return ( await self._session.execute( select(func.count()) .select_from(AlbumModel) .where(AlbumModel.artist_id == artist_id) ) ).scalar_one() async def track_count(self, artist_id: uuid.UUID) -> int: return ( await self._session.execute( select(func.count()) .select_from(TrackModel) .where(TrackModel.artist_id == artist_id) ) ).scalar_one()