Files
brackets/backend/app/models.py
T

149 lines
4.9 KiB
Python

# backend/app/models.py
from datetime import datetime
from typing import Optional
from sqlalchemy import JSON, DateTime, Table, Column
from sqlalchemy import Enum as SqlEnum
from sqlalchemy import ForeignKey, Integer, String, Boolean
from sqlalchemy.orm import Mapped, mapped_column, relationship
from .constants import MatchStatus, TournamentTypes, BracketTypes
from .database import Base
tournament_courts = Table(
"tournament_courts",
Base.metadata,
Column(
"tournament_id",
String(8),
ForeignKey("tournaments.id", ondelete="CASCADE"),
primary_key=True,
),
Column(
"court_id",
Integer,
ForeignKey("courts.id", ondelete="CASCADE"),
primary_key=True,
),
)
class Court(Base):
__tablename__ = "courts"
id: Mapped[int] = mapped_column(Integer, primary_key=True)
name: Mapped[str] = mapped_column(String, nullable=False, unique=True)
tournaments: Mapped[list["Tournament"]] = relationship(
"Tournament", secondary=tournament_courts, back_populates="courts"
)
class Tournament(Base):
__tablename__ = "tournaments"
id: Mapped[str] = mapped_column(String(8), primary_key=True, index=True)
name: Mapped[str] = mapped_column(String, nullable=False)
code: Mapped[str] = mapped_column(String, nullable=True)
timestamp: Mapped[datetime] = mapped_column(DateTime, nullable=False)
duration: Mapped[int] = mapped_column(Integer, default=30)
type: Mapped[TournamentTypes] = mapped_column(SqlEnum(TournamentTypes))
teams: Mapped[list["Team"]] = relationship(
"Team", back_populates="tournament", cascade="all, delete-orphan"
)
courts: Mapped[list["Court"]] = relationship(
"Court", secondary=tournament_courts, back_populates="tournaments"
)
matches: Mapped[list["Match"]] = relationship(
"Match", back_populates="tournament", cascade="all, delete-orphan"
)
@property
def team_count(self) -> int:
return len(self.teams)
@property
def court_count(self) -> int:
return len(self.courts)
# --- NEW: Dynamically check if the tournament has started ---
@property
def has_started(self) -> bool:
return any(m.status == MatchStatus.FINISHED for m in self.matches)
class Team(Base):
__tablename__ = "teams"
id: Mapped[int] = mapped_column(Integer, primary_key=True)
name: Mapped[str] = mapped_column(String, nullable=False)
dropped_out: Mapped[bool] = mapped_column(Boolean, default=False)
tournament_id: Mapped[str] = mapped_column(ForeignKey("tournaments.id"))
tournament: Mapped["Tournament"] = relationship(back_populates="teams")
class Match(Base):
__tablename__ = "matches"
id: Mapped[str] = mapped_column(String, primary_key=True)
tournament_id: Mapped[str] = mapped_column(ForeignKey("tournaments.id"))
match_number: Mapped[int] = mapped_column(Integer)
round_number: Mapped[int] = mapped_column(Integer, default=1)
bracket_type: Mapped[BracketTypes] = mapped_column(SqlEnum(BracketTypes))
court_id: Mapped[Optional[int]] = mapped_column(
ForeignKey("courts.id"), nullable=True
)
start_time: Mapped[Optional[datetime]] = mapped_column(DateTime, nullable=True)
status: Mapped[MatchStatus] = mapped_column(
SqlEnum(MatchStatus), default=MatchStatus.SCHEDULED
)
p1_team_id: Mapped[Optional[int]] = mapped_column(
ForeignKey("teams.id"), nullable=True
)
p2_team_id: Mapped[Optional[int]] = mapped_column(
ForeignKey("teams.id"), nullable=True
)
ref_team_id: Mapped[Optional[int]] = mapped_column(
ForeignKey("teams.id"), nullable=True
)
ref_label: Mapped[Optional[str]] = mapped_column(String, nullable=True)
sets: Mapped[list[dict]] = mapped_column(JSON, default=list)
winner_team_id: Mapped[Optional[int]] = mapped_column(
ForeignKey("teams.id"), nullable=True
)
winner_next_match_id: Mapped[Optional[str]] = mapped_column(
ForeignKey("matches.id"), nullable=True
)
winner_next_match_slot: Mapped[Optional[int]] = mapped_column(
Integer, nullable=True
)
loser_next_match_id: Mapped[Optional[str]] = mapped_column(
ForeignKey("matches.id"), nullable=True
)
loser_next_match_slot: Mapped[Optional[int]] = mapped_column(Integer, nullable=True)
tournament: Mapped["Tournament"] = relationship(back_populates="matches")
court: Mapped[Optional["Court"]] = relationship()
p1_team: Mapped["Team"] = relationship("Team", foreign_keys=[p1_team_id])
p2_team: Mapped["Team"] = relationship("Team", foreign_keys=[p2_team_id])
ref_team: Mapped[Optional["Team"]] = relationship(
"Team", foreign_keys=[ref_team_id]
)
winner_next_match: Mapped["Match"] = relationship(
"Match", remote_side=[id], foreign_keys=[winner_next_match_id]
)
loser_next_match: Mapped["Match"] = relationship(
"Match", remote_side=[id], foreign_keys=[loser_next_match_id]
)