Paginate the leaderboard from materialized player ratings
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:
1 parent
bf613eb1c4
commit
551c4c9c28
16 files changed
+818
-167
No files matched your search
@@ -14,7 +14,14 @@ from datetime import datetime, timezone
|
||||
from typing import Any, List
|
||||
|
||||
from tavolo.platform.models import Match
|
||||
from tavolo.platform.pagination import Cursor, decode_cursor, encode_cursor, paginate
|
||||
from tavolo.platform.pagination import (
|
||||
Cursor,
|
||||
PageParamsError,
|
||||
decode_cursor,
|
||||
encode_cursor,
|
||||
paginate,
|
||||
parse_page_params,
|
||||
)
|
||||
|
||||
from helpers import async_test
|
||||
|
||||
@@ -77,5 +84,22 @@ class PaginateCursorTypesTest(unittest.TestCase):
|
||||
self.assertEqual(match_id, id_values[0])
|
||||
|
||||
|
||||
class PageParamsTest(unittest.TestCase):
|
||||
def test_defaults(self) -> None:
|
||||
self.assertEqual((1, 20), parse_page_params(""))
|
||||
|
||||
def test_page_and_limit(self) -> None:
|
||||
self.assertEqual((3, 5), parse_page_params("page=3&limit=5"))
|
||||
|
||||
def test_limit_is_clamped(self) -> None:
|
||||
self.assertEqual((1, 100), parse_page_params("limit=500"))
|
||||
self.assertEqual((1, 1), parse_page_params("limit=0"))
|
||||
|
||||
def test_invalid_values_raise(self) -> None:
|
||||
for query in ("page=0", "page=-2", "page=abc", "limit=abc"):
|
||||
with self.assertRaises(PageParamsError, msg=query):
|
||||
parse_page_params(query)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Reference in new issue
Block a user