Files
brackets/backend/app/models.py
T
2026-02-11 23:54:42 +01:00

122 lines
4.2 KiB
Python

# backend/app/models.py
from datetime import datetime
from typing import Optional
from sqlalchemy import JSON, DateTime
from sqlalchemy import Enum as SqlEnum
from sqlalchemy import ForeignKey, Integer, String
from sqlalchemy.orm import Mapped, mapped_column, relationship
from .constants import (
TournamentTypes,
MatchSourceType,
MatchStatus,
WinnerSide,
BracketType,
)
from .database import Base
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", back_populates="tournament", cascade="all, delete-orphan"
)
matches: Mapped[list["Match"]] = relationship(
"Match", back_populates="tournament", cascade="all, delete-orphan"
)
# --- ADD THESE PROPERTIES ---
@property
def team_count(self) -> int:
return len(self.teams)
@property
def court_count(self) -> int:
return len(self.courts)
class Team(Base):
__tablename__ = "teams"
id: Mapped[int] = mapped_column(Integer, primary_key=True)
name: Mapped[str] = mapped_column(String, nullable=False)
tournament_id: Mapped[str] = mapped_column(ForeignKey("tournaments.id"))
tournament: Mapped["Tournament"] = relationship(back_populates="teams")
class Court(Base):
__tablename__ = "courts"
id: Mapped[int] = mapped_column(Integer, primary_key=True)
name: Mapped[str] = mapped_column(String, nullable=False)
tournament_id: Mapped[str] = mapped_column(ForeignKey("tournaments.id"))
tournament: Mapped["Tournament"] = relationship(back_populates="courts")
class Match(Base):
__tablename__ = "matches"
id: Mapped[str] = mapped_column(String, primary_key=True)
tournament_id: Mapped[str] = mapped_column(
ForeignKey("tournaments.id"), primary_key=True
)
# --- Structural Info ---
bracket: Mapped[BracketType] = mapped_column(
SqlEnum(BracketType, native_enum=False)
)
round: Mapped[int] = mapped_column(Integer)
number: Mapped[Optional[int]] = mapped_column(Integer, nullable=True)
# --- Scheduling ---
timestamp: Mapped[Optional[datetime]] = mapped_column(DateTime, nullable=True)
court_name: Mapped[Optional[str]] = mapped_column(String, nullable=True)
# --- Player Info ---
p1_name: Mapped[Optional[str]] = mapped_column(String, nullable=True)
p2_name: Mapped[Optional[str]] = mapped_column(String, nullable=True)
winner: Mapped[Optional[str]] = mapped_column(String, nullable=True)
status: Mapped[MatchStatus] = mapped_column(
SqlEnum(MatchStatus, native_enum=False), default=MatchStatus.PENDING
)
sets: Mapped[list[dict]] = mapped_column(JSON, default=list)
previous_match_p1_id: Mapped[Optional[str]] = mapped_column(String, nullable=True)
previous_match_p2_id: Mapped[Optional[str]] = mapped_column(String, nullable=True)
source_p1_type: Mapped[Optional[MatchSourceType]] = mapped_column(
SqlEnum(MatchSourceType, native_enum=False), nullable=True
)
source_p2_type: Mapped[Optional[MatchSourceType]] = mapped_column(
SqlEnum(MatchSourceType, native_enum=False), nullable=True
)
winner_next_match_id: Mapped[Optional[str]] = mapped_column(String, nullable=True)
loser_next_match_id: Mapped[Optional[str]] = mapped_column(String, nullable=True)
tournament: Mapped["Tournament"] = relationship(back_populates="matches")
@property
def winner_side(self) -> WinnerSide:
if not self.winner:
return WinnerSide.NONE
if self.winner == self.p1_name:
return WinnerSide.P1
if self.winner == self.p2_name:
return WinnerSide.P2
return WinnerSide.NONE