From dd4515fd5b1d1ac095e818c9f581d57e616c4e87 Mon Sep 17 00:00:00 2001 From: Brad Brown Date: Sun, 5 Jun 2022 14:42:38 -0500 Subject: [PATCH] batch update/create for db score updates --- wordlinator/app/__init__.py | 49 +++++++++++++++++++++++++++++++++++-- wordlinator/db/pg.py | 17 +++++++++++++ 2 files changed, 64 insertions(+), 2 deletions(-) diff --git a/wordlinator/app/__init__.py b/wordlinator/app/__init__.py index 74db03f..198bf69 100644 --- a/wordlinator/app/__init__.py +++ b/wordlinator/app/__init__.py @@ -75,11 +75,56 @@ def _save_db_scores(wordle_day: wordlinator.utils.WordleDay, scores: dict): if not hole_data: return game_no = hole_data.game_no + + db_users = db.get_users() + db_holes = db.get_holes(game_no) + db_scores = db.get_scores(game_no) + + to_update = [] + to_create = [] + for user, score_list in scores.items(): - if not db.get_user(user): + db_user_match = [u for u in db_users if u.username == user] + db_user = db_user_match[0] if db_user_match else None + + if not db_user: continue + for day, score_entry in enumerate(score_list, start=1): - db.add_score(user, game_no, day, score_entry) + try: + score_entry = int(score_entry) + except ValueError: + pass + + score_match = [ + s + for s in db_scores + if s.user_id.username == user and s.hole_id.hole == day + ] + db_score = score_match[0] if score_match else None + + if db_score: + if db_score.score != score_entry: + db_score.score = score_entry + to_update.append(db_score) + + else: + hole = [h for h in db_holes if h.hole == day][0] + to_create.append( + { + "score": score_entry, + "user_id": db_user.user_id, + "game_id": hole.game_id.game_id, + "hole_id": hole.hole_id, + } + ) + + if to_update: + db.bulk_update_scores(to_update) + + if to_create: + db.bulk_insert_scores(to_create) + return async def main_update( diff --git a/wordlinator/db/pg.py b/wordlinator/db/pg.py index 7079fd0..f5ec5f8 100644 --- a/wordlinator/db/pg.py +++ b/wordlinator/db/pg.py @@ -1,4 +1,5 @@ import os +import typing import peewee @@ -54,6 +55,9 @@ class WordleDb: except peewee.DoesNotExist: return None + def get_users(self): + return list(User.select()) + def get_user_id(self, username): user = self.get_user(username) return user.twitter_id if user else None @@ -75,6 +79,10 @@ class WordleDb: except peewee.DoesNotExist: return Hole.create(hole=hole_no, game_id=round.game_id) + def get_holes(self, round_no): + round = self.get_or_create_round(round_no) + return Hole.select().filter(game_id=round.game_id) + def create_round_holes(self, round_no): for hole_no in range(1, 19): self.get_or_create_hole(round_no, hole_no) @@ -108,3 +116,12 @@ class WordleDb: def get_scores(self, round_no): round = self.get_or_create_round(round_no) return Score.select().filter(Score.game_id == round.game_id) + + def bulk_insert_scores(self, scores: typing.List[typing.Dict]): + with db.atomic(): + for batch in peewee.chunked(scores, 50): + Score.insert_many(batch).execute() + + def bulk_update_scores(self, scores: typing.List[Score]): + with db.atomic(): + Score.bulk_update(scores, fields=[Score.score], batch_size=50)