Add initial (untested) race guess points calculation

This commit is contained in:
2024-02-27 21:01:09 +01:00
parent 70fae278a8
commit cf0dc88284
4 changed files with 379 additions and 178 deletions

View File

@ -1,4 +1,4 @@
from typing import Callable, List
from typing import Callable, Dict, List, overload
from sqlalchemy import desc
from formula10.database.model.db_driver import DbDriver
@ -8,7 +8,7 @@ from formula10.database.model.db_race_result import DbRaceResult
from formula10.database.model.db_season_guess import DbSeasonGuess
from formula10.database.model.db_team import DbTeam
from formula10.database.model.db_user import DbUser
from formula10.database.validation import find_multiple_strict
from formula10.database.validation import find_multiple_strict, find_single_or_none_strict, find_single_strict
from formula10.domain.model.driver import NONE_DRIVER, Driver
from formula10.domain.model.race import Race
from formula10.domain.model.race_guess import RaceGuess
@ -30,7 +30,7 @@ class Model():
def all_users(self) -> List[User]:
"""
Returns a list of all users in the database.
Returns a list of all enabled users.
"""
if self._all_users is None:
self._all_users = [
@ -42,7 +42,7 @@ class Model():
def all_race_results(self) -> List[RaceResult]:
"""
Returns a list of all race results in the database, in descending order (most recent first).
Returns a list of all race results, in descending order (most recent first).
"""
if self._all_race_results is None:
self._all_race_results = [
@ -54,7 +54,7 @@ class Model():
def all_race_guesses(self) -> List[RaceGuess]:
"""
Returns a list of all race guesses in the database.
Returns a list of all race guesses (of enabled users).
"""
if self._all_race_guesses is None:
self._all_race_guesses = [
@ -65,6 +65,9 @@ class Model():
return self._all_race_guesses
def all_season_guesses(self) -> List[SeasonGuess]:
"""
Returns a list of all season guesses (of enabled users).
"""
if self._all_season_guesses is None:
self._all_season_guesses = [
SeasonGuess.from_db_season_guess(db_season_guess)
@ -75,7 +78,7 @@ class Model():
def all_races(self) -> List[Race]:
"""
Returns a list of all races in the database.
Returns a list of all races, in descending order (last race first).
"""
if self._all_races is None:
self._all_races = [
@ -87,7 +90,7 @@ class Model():
def all_drivers(self, *, include_none: bool) -> List[Driver]:
"""
Returns a list of all drivers in the database.
Returns a list of all drivers.
"""
if self._all_drivers is None:
self._all_drivers = [
@ -103,7 +106,7 @@ class Model():
def all_teams(self, *, include_none: bool) -> List[Team]:
"""
Returns a list of all teams in the database.
Returns a list of all teams.
"""
if self._all_teams is None:
self._all_teams = [
@ -115,4 +118,198 @@ class Model():
return self._all_teams
else:
predicate: Callable[[Team], bool] = lambda team: team != NONE_TEAM
return find_multiple_strict(predicate, self._all_teams)
return find_multiple_strict(predicate, self._all_teams)
#
# User queries
#
@overload
def user_by(self, *, user_name: str) -> User:
"""
Tries to obtain the user object for a specific username.
"""
return self.user_by(user_name=user_name)
@overload
def user_by(self, *, user_name: str, ignore: List[str]) -> User | None:
"""
Tries to obtain the user object for a specific username, but ignores certain usernames.
"""
return self.user_by(user_name=user_name, ignore=ignore)
def user_by(self, *, user_name: str, ignore: List[str] | None = None) -> User | None:
if ignore is None:
ignore = []
if len(ignore) > 0 and user_name in ignore:
return None
predicate: Callable[[User], bool] = lambda user: user.name == user_name
return find_single_strict(predicate, self.all_users())
#
# Race result queries
#
def race_result_by(self, *, race_name: str) -> RaceResult | None:
"""
Tries to obtain the race result corresponding to a race name.
"""
predicate: Callable[[RaceResult], bool] = lambda result: result.race.name == race_name
return find_single_or_none_strict(predicate, self.all_race_results())
#
# Race guess queries
#
@overload
def race_guesses_by(self, *, user_name: str) -> List[RaceGuess]:
"""
Returns a list of all race guesses made by a specific user.
"""
return self.race_guesses_by(user_name=user_name)
@overload
def race_guesses_by(self, *, race_name: str) -> List[RaceGuess]:
"""
Returns a list of all race guesses made for a specific race.
"""
return self.race_guesses_by(race_name=race_name)
@overload
def race_guesses_by(self, *, user_name: str, race_name: str) -> RaceGuess | None:
"""
Returns a single race guess by a specific user for a specific race, or None, if this guess doesn't exist.
"""
return self.race_guesses_by(user_name=user_name, race_name=race_name)
@overload
def race_guesses_by(self) -> Dict[str, Dict[str, RaceGuess]]:
"""
Returns a dictionary that maps race-ids to user-id - guess dictionaries.
"""
return self.race_guesses_by()
def race_guesses_by(self, *, user_name: str | None = None, race_name: str | None = None) -> RaceGuess | List[RaceGuess] | Dict[str, Dict[str, RaceGuess]] | None:
# List of all guesses by a single user
if user_name is not None and race_name is None:
predicate: Callable[[RaceGuess], bool] = lambda guess: guess.user.name == user_name
return find_multiple_strict(predicate, self.all_race_guesses())
# List of all guesses for a single race
if user_name is None and race_name is not None:
predicate: Callable[[RaceGuess], bool] = lambda guess: guess.race.name == race_name
return find_multiple_strict(predicate, self.all_race_guesses())
# Guess for a single race by a single user
if user_name is not None and race_name is not None:
predicate: Callable[[RaceGuess], bool] = lambda guess: guess.user.name == user_name and guess.race.name == race_name
return find_single_or_none_strict(predicate, self.all_race_guesses())
# Dict with all guesses
if user_name is None and race_name is None:
guesses_by: Dict[str, Dict[str, RaceGuess]] = dict()
guess: RaceGuess
for guess in self.all_race_guesses():
if guess.race.name not in guesses_by:
guesses_by[guess.race.name] = dict()
guesses_by[guess.race.name][guess.user.name] = guess
return guesses_by
raise Exception("race_guesses_by encountered illegal combination of arguments")
#
# Season guess queries
#
@overload
def season_guesses_by(self, *, user_name: str) -> SeasonGuess:
"""
Returns the season guess made by a specific user.
"""
return self.season_guesses_by(user_name=user_name)
@overload
def season_guesses_by(self) -> Dict[str, SeasonGuess]:
"""
Returns a dictionary of season guesses mapped to usernames.
"""
return self.season_guesses_by()
def season_guesses_by(self, *, user_name: str | None = None) -> SeasonGuess | Dict[str, SeasonGuess] | None:
if user_name is not None:
predicate: Callable[[SeasonGuess], bool] = lambda guess: guess.user.name == user_name
return find_single_or_none_strict(predicate, self.all_season_guesses())
if user_name is None:
guesses_by: Dict[str, SeasonGuess] = dict()
guess: SeasonGuess
for guess in self.all_season_guesses():
guesses_by[guess.user.name] = guess
return guesses_by
raise Exception("season_guesses_by encountered illegal combination of arguments")
#
# Team queries
#
def none_team(self) -> Team:
return NONE_TEAM
#
# Driver queries
#
def none_driver(self) -> Driver:
return NONE_DRIVER
@overload
def drivers_by(self, *, team_name: str) -> List[Driver]:
"""
Returns a list of all drivers driving for a certain team.
"""
return self.drivers_by(team_name=team_name)
@overload
def drivers_by(self) -> Dict[str, List[Driver]]:
"""
Returns a dictionary of drivers mapped to team names.
"""
return self.drivers_by()
def drivers_by(self, *, team_name: str | None = None) -> List[Driver] | Dict[str, List[Driver]]:
if team_name is not None:
predicate: Callable[[Driver], bool] = lambda driver: driver.team.name == team_name
return find_multiple_strict(predicate, self.all_drivers(include_none=False), 2)
if team_name is None:
drivers_by: Dict[str, List[Driver]] = dict()
driver: Driver
team: Team
for team in self.all_teams(include_none=False):
drivers_by[team.name] = []
for driver in self.all_drivers(include_none=False):
drivers_by[driver.team.name] += [driver]
return drivers_by
raise Exception("drivers_by encountered illegal combination of arguments")
#
# Race queries
#
def race_by(self, *, race_name: str) -> Race:
for race in self.all_races():
if race.name == race_name:
return race
raise Exception(f"Couldn't find race {race_name}")