This commit is contained in:
2025-12-30 17:37:14 +03:00
commit c33c5fd674
66 changed files with 10282 additions and 0 deletions

105
backend/app/db_models.py Normal file
View 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})>"