Paginate the leaderboard from materialized player ratings
CI / Build and push docker image (push) Successful in 1m19s
CI / Build and push docker image (push) Successful in 1m19s
Store each player's leaderboard totals (wins, accumulated points and the latest display name) on player_rating alongside the Elo rating, updated in the same transaction as the match, so the board is a single indexed table query instead of aggregating every participation on each request. GET /api/leaderboard is now page-number paginated (page/limit) and returns the page, page count and total, plus the caller's own rank and page when authenticated; focus=me returns the caller's page directly. The migration adds the columns, backfills them from the match history (inserting rows for players from pre-Elo matches at the initial rating) and replaces the index. backfill_elo rebuilds the aggregates too. The web page opens on the page containing the signed-in player, marks their row and adds a numbered footer pager.
This commit is contained in:
@@ -190,7 +190,12 @@ class ScopaWebSocketTest(unittest.TestCase):
|
||||
self.assertEqual(1, game["last_move"]["seat"])
|
||||
self.assertEqual(card, game["last_move"]["card"])
|
||||
if options:
|
||||
self.assertEqual(2, game["players"][1]["captured_count"])
|
||||
# The pile grows by the captured table cards
|
||||
# plus the card just played.
|
||||
self.assertEqual(
|
||||
len(options[0]) + 1,
|
||||
game["players"][1]["captured_count"],
|
||||
)
|
||||
else:
|
||||
self.assertEqual(5, len(game["table"]))
|
||||
|
||||
|
||||
@@ -133,11 +133,25 @@ class ScoponeStatsTest(unittest.TestCase):
|
||||
self.assertIn("your_elo_delta", results[0])
|
||||
self.assertEqual(4, len(results[0]["players"]))
|
||||
|
||||
board = await client.get("/api/leaderboard")
|
||||
with oidc_user("alice"):
|
||||
board = await client.get("/api/leaderboard")
|
||||
self.assertEqual(200, board.status_code)
|
||||
by_sub = {r["user_sub"]: r for r in board.json()["results"]}
|
||||
body = board.json()
|
||||
by_sub = {r["user_sub"]: r for r in body["results"]}
|
||||
self.assertEqual(4, len(by_sub))
|
||||
self.assertTrue(all(r["matches"] == 1 for r in by_sub.values()))
|
||||
self.assertEqual(1, body["page"])
|
||||
self.assertEqual(1, body["pages"])
|
||||
self.assertEqual(4, body["total"])
|
||||
# The caller's own rank rides along on the response.
|
||||
self.assertIsNotNone(body["your_rank"])
|
||||
self.assertEqual(1, body["your_page"])
|
||||
|
||||
paged = await client.get("/api/leaderboard?limit=1&page=2")
|
||||
self.assertEqual(200, paged.status_code)
|
||||
self.assertEqual(4, paged.json()["pages"])
|
||||
self.assertEqual(2, paged.json()["page"])
|
||||
self.assertEqual(1, len(paged.json()["results"]))
|
||||
|
||||
|
||||
async def _finished_briscola_session() -> GameSession:
|
||||
|
||||
Reference in New Issue
Block a user