byceps/byceps

View on GitHub
byceps/services/tourney/tourney_service.py

Summary

Maintainability
A
0 mins
Test Coverage
F
36%
"""
byceps.services.tourney.tourney_service
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

:Copyright: 2014-2024 Jochen Kupperschmidt
:License: Revised BSD (see `LICENSE` file for details)
"""

from datetime import datetime

from sqlalchemy import delete, select

from byceps.database import db
from byceps.events.tourney import TourneyCreatedEvent
from byceps.services.party.models import Party, PartyID
from byceps.services.user.models.user import User

from . import tourney_category_service, tourney_domain_service
from .dbmodels.participant import DbParticipant
from .dbmodels.tourney import DbTourney
from .dbmodels.tourney_category import DbTourneyCategory
from .models import (
    Tourney,
    TourneyCategory,
    TourneyCategoryID,
    TourneyID,
    TourneyWithCategory,
)


def create_tourney(
    party: Party,
    creator: User,
    title: str,
    category: TourneyCategory,
    max_participant_count: int,
    starts_at: datetime,
    *,
    subtitle: str | None = None,
    logo_url: str | None = None,
    registration_open: bool = False,
) -> tuple[Tourney, TourneyCreatedEvent]:
    """Create a tourney."""
    tourney, event = tourney_domain_service.create_tourney(
        party,
        creator,
        title,
        category,
        max_participant_count,
        starts_at,
        subtitle=subtitle,
        logo_url=logo_url,
        registration_open=registration_open,
    )

    _persist_tourney_creation(tourney)

    return tourney, event


def _persist_tourney_creation(tourney: Tourney) -> None:
    db_tourney = DbTourney(
        tourney.party_id,
        tourney.title,
        tourney.category_id,
        tourney.max_participant_count,
        tourney.starts_at,
        subtitle=tourney.subtitle,
        logo_url=tourney.logo_url,
        registration_open=tourney.registration_open,
    )

    db.session.add(db_tourney)
    db.session.commit()


def update_tourney(
    tourney_id: TourneyID,
    title: str,
    subtitle: str | None,
    logo_url: str | None,
    category_id: TourneyCategoryID,
    max_participant_count: int,
    starts_at: datetime,
    registration_open: bool,
) -> Tourney:
    """Update tourney."""
    db_tourney = _get_db_tourney(tourney_id)

    db_tourney.title = title
    db_tourney.subtitle = subtitle
    db_tourney.logo_url = logo_url
    db_tourney.category_id = category_id
    db_tourney.max_participant_count = max_participant_count
    db_tourney.starts_at = starts_at
    db_tourney.registration_open = registration_open

    db.session.commit()

    return _db_entity_to_tourney(db_tourney)


def delete_tourney(tourney_id: TourneyID) -> None:
    """Delete a tourney."""
    tourney = get_tourney(tourney_id)

    db.session.execute(delete(DbTourney).filter_by(id=tourney.id))
    db.session.commit()


def find_tourney(tourney_id: TourneyID) -> Tourney | None:
    """Return the tourney with that id, or `None` if not found."""
    db_tourney = _find_db_tourney(tourney_id)

    if db_tourney is None:
        return None

    return _db_entity_to_tourney(db_tourney)


def _find_db_tourney(tourney_id: TourneyID) -> DbTourney | None:
    return db.session.get(DbTourney, tourney_id)


def get_tourney(tourney_id: TourneyID) -> Tourney:
    """Return the tourney with that ID.

    Raise an exception if not found.
    """
    tourney = find_tourney(tourney_id)

    if tourney is None:
        raise ValueError(f'Unknown tourney ID "{tourney_id}"')

    return tourney


def _get_db_tourney(tourney_id: TourneyID) -> DbTourney:
    db_tourney = _find_db_tourney(tourney_id)

    if db_tourney is None:
        raise ValueError(f'Unknown tourney ID "{tourney_id}"')

    return db_tourney


def get_tourneys_for_party(party_id: PartyID) -> list[TourneyWithCategory]:
    """Return the tourneys for that party."""
    rows = db.session.execute(
        select(DbTourney, DbTourneyCategory, db.func.count(DbParticipant.id))
        .join(DbTourneyCategory)
        .join(DbParticipant, isouter=True)
        .filter(DbTourney.party_id == party_id)
        .group_by(DbTourney.id, DbTourneyCategory)
    ).all()

    return [
        _to_tourney_with_category(db_tourney, db_category, participant_count)
        for db_tourney, db_category, participant_count in rows
    ]


def _db_entity_to_tourney(
    db_tourney: DbTourney,
    current_participant_count: int = -1,
) -> Tourney:
    return Tourney(
        id=db_tourney.id,
        party_id=db_tourney.party_id,
        title=db_tourney.title,
        subtitle=db_tourney.subtitle,
        logo_url=db_tourney.logo_url,
        category_id=db_tourney.category_id,
        current_participant_count=current_participant_count,
        max_participant_count=db_tourney.max_participant_count,
        starts_at=db_tourney.starts_at,
        registration_open=db_tourney.registration_open,
    )


def _to_tourney_with_category(
    db_tourney: DbTourney,
    db_category: DbTourneyCategory,
    current_participant_count: int = -1,
) -> TourneyWithCategory:
    tourney = _db_entity_to_tourney(db_tourney, current_participant_count)
    category = tourney_category_service._db_entity_to_category(db_category)

    return TourneyWithCategory.from_tourney_and_category(
        tourney, category, current_participant_count
    )