app v1
This commit is contained in:
105
backend/app/db_models.py
Normal file
105
backend/app/db_models.py
Normal file
@@ -0,0 +1,105 @@
|
||||
from datetime import datetime
|
||||
from typing import List, Optional
|
||||
from sqlalchemy import String, Integer, ForeignKey, DateTime, Enum as SQLEnum, func
|
||||
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
||||
import enum
|
||||
|
||||
from .database import Base
|
||||
|
||||
|
||||
class Difficulty(str, enum.Enum):
|
||||
EASY = "easy"
|
||||
MEDIUM = "medium"
|
||||
HARD = "hard"
|
||||
|
||||
|
||||
class Opening(Base):
|
||||
"""Anime opening entity."""
|
||||
__tablename__ = "openings"
|
||||
|
||||
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
|
||||
anime_name: Mapped[str] = mapped_column(String(255), nullable=False, index=True)
|
||||
op_number: Mapped[str] = mapped_column(String(20), nullable=False) # e.g., "OP1", "ED2"
|
||||
song_name: Mapped[Optional[str]] = mapped_column(String(255), nullable=True)
|
||||
audio_file: Mapped[str] = mapped_column(String(512), nullable=False) # S3 key
|
||||
|
||||
# Usage tracking
|
||||
last_usage: Mapped[Optional[datetime]] = mapped_column(
|
||||
DateTime(timezone=True),
|
||||
nullable=True,
|
||||
default=None
|
||||
)
|
||||
|
||||
# Timestamps
|
||||
created_at: Mapped[datetime] = mapped_column(
|
||||
DateTime(timezone=True),
|
||||
server_default=func.now()
|
||||
)
|
||||
updated_at: Mapped[datetime] = mapped_column(
|
||||
DateTime(timezone=True),
|
||||
server_default=func.now(),
|
||||
onupdate=func.now()
|
||||
)
|
||||
|
||||
# Relationships
|
||||
posters: Mapped[List["OpeningPoster"]] = relationship(
|
||||
"OpeningPoster",
|
||||
back_populates="opening",
|
||||
cascade="all, delete-orphan"
|
||||
)
|
||||
|
||||
def __repr__(self):
|
||||
return f"<Opening {self.anime_name} - {self.op_number}>"
|
||||
|
||||
|
||||
class OpeningPoster(Base):
|
||||
"""Poster image for an opening."""
|
||||
__tablename__ = "opening_posters"
|
||||
|
||||
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
|
||||
opening_id: Mapped[int] = mapped_column(
|
||||
Integer,
|
||||
ForeignKey("openings.id", ondelete="CASCADE"),
|
||||
nullable=False
|
||||
)
|
||||
poster_file: Mapped[str] = mapped_column(String(512), nullable=False) # S3 key
|
||||
is_default: Mapped[bool] = mapped_column(default=False)
|
||||
|
||||
created_at: Mapped[datetime] = mapped_column(
|
||||
DateTime(timezone=True),
|
||||
server_default=func.now()
|
||||
)
|
||||
|
||||
# Relationships
|
||||
opening: Mapped["Opening"] = relationship("Opening", back_populates="posters")
|
||||
|
||||
def __repr__(self):
|
||||
return f"<OpeningPoster {self.poster_file}>"
|
||||
|
||||
|
||||
class Background(Base):
|
||||
"""Background video entity."""
|
||||
__tablename__ = "backgrounds"
|
||||
|
||||
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
|
||||
name: Mapped[str] = mapped_column(String(255), nullable=False)
|
||||
video_file: Mapped[str] = mapped_column(String(512), nullable=False) # S3 key
|
||||
difficulty: Mapped[Difficulty] = mapped_column(
|
||||
SQLEnum(Difficulty, native_enum=False),
|
||||
nullable=False,
|
||||
default=Difficulty.MEDIUM
|
||||
)
|
||||
|
||||
# Timestamps
|
||||
created_at: Mapped[datetime] = mapped_column(
|
||||
DateTime(timezone=True),
|
||||
server_default=func.now()
|
||||
)
|
||||
updated_at: Mapped[datetime] = mapped_column(
|
||||
DateTime(timezone=True),
|
||||
server_default=func.now(),
|
||||
onupdate=func.now()
|
||||
)
|
||||
|
||||
def __repr__(self):
|
||||
return f"<Background {self.name} ({self.difficulty})>"
|
||||
Reference in New Issue
Block a user