"""ORM model for cached lyrics (plan §6.7). Cached per track (one row, ``track_id`` unique) so the external provider (LRCLIB) isn't hit on every play. ``not_found`` is cached too — re-fetch policy (TTL) lives in the service. ``synced`` holds timestamped LRC; ``plain`` the fallback text. """ import datetime as dt import uuid from sqlalchemy import DateTime, ForeignKey, String, Text, func from sqlalchemy.orm import Mapped, mapped_column from app.infrastructure.db.base import Base from app.infrastructure.db.models.enums import LyricsStatus from app.infrastructure.db.models.mixins import UUIDPrimaryKeyMixin class LyricsModel(UUIDPrimaryKeyMixin, Base): __tablename__ = "lyrics" track_id: Mapped[uuid.UUID] = mapped_column( ForeignKey("tracks.id", ondelete="CASCADE"), unique=True, nullable=False, ) synced: Mapped[str | None] = mapped_column(Text, nullable=True) plain: Mapped[str | None] = mapped_column(Text, nullable=True) source: Mapped[str | None] = mapped_column(String(64), nullable=True) status: Mapped[str] = mapped_column( String(16), nullable=False, default=LyricsStatus.PENDING.value, ) fetched_at: Mapped[dt.datetime] = mapped_column( DateTime(timezone=True), server_default=func.now(), nullable=False, )