"""Track repository — adapter over ``AsyncSession``.""" import uuid from sqlalchemy import select from sqlalchemy.ext.asyncio import AsyncSession from app.domain.entities.track import Track from app.infrastructure.db.models.track import TrackModel def _to_entity(row: TrackModel) -> Track: return Track( id=row.id, title=row.title, artist_id=row.artist_id, file_path=row.file_path, file_format=row.file_format, file_size=row.file_size, source=row.source, source_id=row.source_id, duration_seconds=row.duration_seconds, metadata_status=row.metadata_status, created_at=row.created_at, updated_at=row.updated_at, ) class SqlAlchemyTrackRepository: def __init__(self, session: AsyncSession) -> None: self._session = session async def get_by_id(self, track_id: uuid.UUID) -> Track | None: row = await self._session.get(TrackModel, track_id) return _to_entity(row) if row is not None else None async def get_by_source(self, source: str, source_id: str) -> Track | None: row = ( await self._session.execute( select(TrackModel).where( TrackModel.source == source, TrackModel.source_id == source_id, ) ) ).scalar_one_or_none() return _to_entity(row) if row is not None else None async def add( self, *, id: uuid.UUID, title: str, artist_id: uuid.UUID, file_path: str, file_format: str, file_size: int, source: str, source_id: str, metadata_status: str, added_by: uuid.UUID | None, ) -> Track: row = TrackModel( id=id, title=title, artist_id=artist_id, file_path=file_path, file_format=file_format, file_size=file_size, source=source, source_id=source_id, metadata_status=metadata_status, added_by=added_by, ) self._session.add(row) await self._session.flush() await self._session.refresh(row) return _to_entity(row) async def delete(self, track_id: uuid.UUID) -> None: row = await self._session.get(TrackModel, track_id) if row is not None: await self._session.delete(row) await self._session.flush()