diff --git a/app/models/base.py b/app/models/base.py index 80cc117..4562d65 100644 --- a/app/models/base.py +++ b/app/models/base.py @@ -1,6 +1,9 @@ from datetime import UTC, datetime +from typing import Any from sqlalchemy import event +from sqlalchemy.engine import Connection +from sqlalchemy.orm import Mapper from sqlmodel import Field, SQLModel @@ -16,6 +19,8 @@ class BaseModel(SQLModel): # SQLAlchemy event listener to automatically update updated_at timestamp @event.listens_for(BaseModel, "before_update", propagate=True) -def update_timestamp(mapper, connection, target): +def update_timestamp( + mapper: Mapper[Any], connection: Connection, target: BaseModel, # noqa: ARG001 +) -> None: """Automatically set updated_at timestamp before update operations.""" target.updated_at = datetime.now(UTC) diff --git a/app/models/playlist_sound.py b/app/models/playlist_sound.py index 8d56763..0a0c11d 100644 --- a/app/models/playlist_sound.py +++ b/app/models/playlist_sound.py @@ -35,3 +35,5 @@ class PlaylistSound(BaseModel, table=True): # relationships playlist: "Playlist" = Relationship(back_populates="playlist_sounds") sound: "Sound" = Relationship(back_populates="playlist_sounds") + + diff --git a/app/repositories/base.py b/app/repositories/base.py index 5197f86..a3e8dc9 100644 --- a/app/repositories/base.py +++ b/app/repositories/base.py @@ -114,7 +114,8 @@ class BaseRepository[ModelType]: for field, value in update_data.items(): setattr(entity, field, value) - # The updated_at timestamp will be automatically set by the SQLAlchemy event listener + # The updated_at timestamp will be automatically set by the SQLAlchemy + # event listener self.session.add(entity) await self.session.commit() await self.session.refresh(entity) diff --git a/app/repositories/playlist.py b/app/repositories/playlist.py index 14dcd79..2eaf877 100644 --- a/app/repositories/playlist.py +++ b/app/repositories/playlist.py @@ -1,5 +1,6 @@ """Playlist repository for database operations.""" +from datetime import UTC, datetime from enum import Enum from sqlalchemy import func, update @@ -42,6 +43,23 @@ class PlaylistRepository(BaseRepository[Playlist]): """Initialize the playlist repository.""" super().__init__(Playlist, session) + async def _update_playlist_timestamp(self, playlist_id: int) -> None: + """Update the playlist's updated_at timestamp.""" + try: + update_stmt = ( + update(Playlist) + .where(Playlist.id == playlist_id) + .values(updated_at=datetime.now(UTC)) + ) + await self.session.exec(update_stmt) + # Note: No commit here - let the calling method handle transaction + # management + except Exception: + logger.exception( + "Failed to update playlist timestamp for playlist: %s", playlist_id, + ) + raise + async def get_by_name(self, name: str) -> Playlist | None: """Get a playlist by name.""" try: @@ -133,7 +151,8 @@ class PlaylistRepository(BaseRepository[Playlist]): return list(result.all()) except Exception: logger.exception( - "Failed to get playlist sound entries for playlist: %s", playlist_id, + "Failed to get playlist sound entries for playlist: %s", + playlist_id, ) raise @@ -188,6 +207,9 @@ class PlaylistRepository(BaseRepository[Playlist]): position=position, ) self.session.add(playlist_sound) + + # Update playlist timestamp before commit + await self._update_playlist_timestamp(playlist_id) await self.session.commit() await self.session.refresh(playlist_sound) except Exception: @@ -219,6 +241,9 @@ class PlaylistRepository(BaseRepository[Playlist]): if playlist_sound: await self.session.delete(playlist_sound) + + # Update playlist timestamp before commit + await self._update_playlist_timestamp(playlist_id) await self.session.commit() logger.info("Removed sound %s from playlist %s", sound_id, playlist_id) except Exception: @@ -268,6 +293,8 @@ class PlaylistRepository(BaseRepository[Playlist]): if playlist_sound: playlist_sound.position = new_position + # Update playlist timestamp before commit + await self._update_playlist_timestamp(playlist_id) await self.session.commit() logger.info("Reordered sounds in playlist %s", playlist_id) except Exception: