"""Playlist model.""" import uuid from datetime import datetime from typing import TYPE_CHECKING from sqlalchemy import String, Integer, Text, Boolean, ForeignKey from sqlalchemy.dialects.postgresql import UUID, JSONB from sqlalchemy.orm import Mapped, mapped_column, relationship from app.core.database import Base if TYPE_CHECKING: from app.models.user import User from app.models.playlist_track import PlaylistTrack class Playlist(Base): """Playlist model representing user playlists.""" __tablename__ = "playlists" # Primary key id: Mapped[uuid.UUID] = mapped_column( UUID(as_uuid=True), primary_key=True, default=uuid.uuid4, index=True, ) # Foreign key to user user_id: Mapped[uuid.UUID] = mapped_column( UUID(as_uuid=True), ForeignKey("users.id", ondelete="CASCADE"), nullable=False, index=True, ) # Basic info name: Mapped[str] = mapped_column( String(255), nullable=False, ) description: Mapped[str | None] = mapped_column( Text, ) image_url: Mapped[str | None] = mapped_column( String(500), ) # Playlist flags is_public: Mapped[bool] = mapped_column( Boolean, default=False, index=True, ) is_collaborative: Mapped[bool] = mapped_column( Boolean, default=False, ) is_smart: Mapped[bool] = mapped_column( Boolean, default=False, comment="True for rules-based smart playlists", ) # Smart playlist rules stored as JSON smart_rules: Mapped[dict] = mapped_column( JSONB, default=dict, comment="Rules for smart playlists", ) # Playlist stats track_count: Mapped[int] = mapped_column( Integer, default=0, ) total_duration: Mapped[int] = mapped_column( Integer, default=0, comment="Total duration in seconds", ) # Timestamps created_at: Mapped[datetime] = mapped_column( default=datetime.utcnow, nullable=False, ) updated_at: Mapped[datetime] = mapped_column( default=datetime.utcnow, onupdate=datetime.utcnow, nullable=False, ) # Relationships user: Mapped["User"] = relationship( "User", back_populates="playlists", lazy="selectin", ) playlist_tracks: Mapped[list["PlaylistTrack"]] = relationship( "PlaylistTrack", back_populates="playlist", cascade="all, delete-orphan", lazy="selectin", order_by="PlaylistTrack.position", ) def __repr__(self) -> str: return f"" def to_dict(self, include_tracks: bool = False) -> dict: """Convert playlist model to dictionary.""" data = { "id": str(self.id), "user_id": str(self.user_id), "name": self.name, "description": self.description, "image_url": self.image_url, "is_public": self.is_public, "is_collaborative": self.is_collaborative, "is_smart": self.is_smart, "smart_rules": self.smart_rules, "track_count": self.track_count, "total_duration": self.total_duration, "created_at": self.created_at.isoformat(), "updated_at": self.updated_at.isoformat(), } if include_tracks: data["tracks"] = [pt.track.to_dict() for pt in self.playlist_tracks] return data