diff --git a/wordlinator/db/pg.py b/wordlinator/db/pg.py index b5bd311..1be8b02 100644 --- a/wordlinator/db/pg.py +++ b/wordlinator/db/pg.py @@ -50,6 +50,9 @@ class Player(BaseModel): user_id = peewee.ForeignKeyField(User, "user_id", null=False) game_id = peewee.ForeignKeyField(Game, "game_id", null=False) + class Meta: + primary_key = peewee.CompositeKey("user_id", "game_id") + class Hole(BaseModel): hole_id = peewee.AutoField() @@ -81,14 +84,17 @@ class WordleDb: def get_users(self): return list(User.select()) - def get_users_by_round(self, round_no): - res = ( + def get_users_by_round(self, round_no=None, round_id=None): + query = ( User.select(User, Player.user_id, Game.game) .join(Player, on=(Player.user_id == User.user_id)) .join(Game, on=(Game.game_id == Player.game_id)) - .filter(Game.game == round_no) ) - return list(res) + if round_no: + query = query.filter(Game.game == round_no) + elif round_id: + query = query.filter(Game.game_id == round_id) + return list(query) def get_user_id(self, username): user = self.get_user(username) @@ -131,7 +137,7 @@ class WordleDb: def get_or_create_player_round(self, user_id, game_id): try: - return Player.get(user_id=user_id, game_id=game_id) + return Player.get(Player.user_id == user_id, Player.game_id == game_id) except peewee.DoesNotExist: return Player.create(user_id=user_id, game_id=game_id) diff --git a/wordlinator/utils/scores.py b/wordlinator/utils/scores.py index cd3a96b..0148fae 100644 --- a/wordlinator/utils/scores.py +++ b/wordlinator/utils/scores.py @@ -153,9 +153,13 @@ class UserRow(ScoreRow): class ScoreMatrix(ScoreContainer): + def __init__(self, *args, usernames=None, **kwargs): + super().__init__(*args, **kwargs) + self.usernames = usernames or [] + def by_user(self, usernames: typing.List[str] = []): res = self.dict_by("user_id.username", UserRow) - for username in usernames: + for username in usernames or self.usernames: if username not in res: res[username] = UserRow([], username) return res diff --git a/wordlinator/utils/web.py b/wordlinator/utils/web.py index e957961..0774b3b 100644 --- a/wordlinator/utils/web.py +++ b/wordlinator/utils/web.py @@ -9,16 +9,24 @@ def _date_range(game): return f"{game.start_date} to {game.end_date}" -def get_date_dropdown(dates): +def get_date_dropdown(dates, wordle_day=None): options = [ {"label": f"Round {d.game} ({_date_range(d)})", "value": d.game_id} for d in dates ] + value = dates[-1].game_id + if wordle_day: + if wordle_day.golf_hole: + match = [d for d in dates if d.game == wordle_day.golf_hole.game_no] + else: + match = [d for d in dates[::-1] if d.end_date <= wordle_day.date] + value = match[0].game_id + return dcc.Dropdown( id="round-selector-dropdown", options=options, - value=dates[-1].game_id, + value=value, clearable=False, ) diff --git a/wordlinator/web/__init__.py b/wordlinator/web/__init__.py index 1121b43..a90679d 100644 --- a/wordlinator/web/__init__.py +++ b/wordlinator/web/__init__.py @@ -69,9 +69,16 @@ def _scores_from_db(round_id, ttl_hash=None): return db.WordleDb().get_scores(round_id=round_id) +@functools.lru_cache() +def _players_from_db(round_id, ttl_hash=None): + return db.WordleDb().get_users_by_round(round_id=round_id) + + def scores_from_db(round_id): + users = _players_from_db(round_id) + usernames = [u.username for u in users] return wordlinator.utils.scores.ScoreMatrix( - _scores_from_db(round_id, get_ttl_hash()) + _scores_from_db(round_id, get_ttl_hash()), usernames=usernames ) @@ -257,7 +264,9 @@ app.layout = dash.html.Div( children=[ dash.html.H1("#WordleGolf", style={"textAlign": "center"}, id="title"), dash.html.Div( - wordlinator.utils.web.get_date_dropdown(games_from_db()), + wordlinator.utils.web.get_date_dropdown( + games_from_db(), wordle_day=wordle_today() + ), id="round-selector", style={"maxWidth": "300px"}, ),