Files
mcma-backend/app/infrastructure/db/models/playlist.py
T
2026-06-07 14:50:35 +03:00

56 lines
1.9 KiB
Python

"""ORM models for playlists and their ordered tracks."""
import datetime as dt
import uuid
from sqlalchemy import DateTime, Float, ForeignKey, Integer, String, UniqueConstraint, func
from sqlalchemy.orm import Mapped, mapped_column
from app.infrastructure.db.base import Base
from app.infrastructure.db.models.mixins import TimestampMixin, UUIDPrimaryKeyMixin
class PlaylistModel(UUIDPrimaryKeyMixin, TimestampMixin, Base):
__tablename__ = "playlists"
name: Mapped[str] = mapped_column(String(512), nullable=False)
description: Mapped[str | None] = mapped_column(String(2048), nullable=True)
owner_id: Mapped[uuid.UUID] = mapped_column(
ForeignKey("users.id", ondelete="CASCADE"),
index=True,
nullable=False,
)
cover_path: Mapped[str | None] = mapped_column(String(1024), nullable=True)
# Optimistic-locking / future sync counter — bumped on every mutation.
version: Mapped[int] = mapped_column(Integer, nullable=False, default=1)
class PlaylistTrackModel(UUIDPrimaryKeyMixin, Base):
"""A track's membership in a playlist.
``position`` is a float so a track can be inserted between two others
without reindexing the whole list (plan §4).
"""
__tablename__ = "playlist_tracks"
__table_args__ = (
UniqueConstraint("playlist_id", "track_id", name="uq_playlist_tracks_playlist_id_track_id"),
)
playlist_id: Mapped[uuid.UUID] = mapped_column(
ForeignKey("playlists.id", ondelete="CASCADE"),
index=True,
nullable=False,
)
track_id: Mapped[uuid.UUID] = mapped_column(
ForeignKey("tracks.id", ondelete="CASCADE"),
index=True,
nullable=False,
)
position: Mapped[float] = mapped_column(Float, nullable=False)
added_at: Mapped[dt.datetime] = mapped_column(
DateTime(timezone=True),
server_default=func.now(),
nullable=False,
)