wip: use SQL's limit/offset pagination for nextIndex/maxCount requests

This commit is contained in:
2024-11-14 16:29:24 +07:00
parent cb009f6e23
commit 37d07e6035
5 changed files with 311 additions and 183 deletions

View File

@ -1,16 +1,19 @@
from typing import Dict, List, Optional
from sqlalchemy import Table, Column, UniqueConstraint, PrimaryKeyConstraint, and_
from sqlalchemy.types import Integer, String, TIMESTAMP, Boolean, JSON, BigInteger
from typing import Dict, List, Optional, Union
from sqlalchemy import Column, PrimaryKeyConstraint, Table, UniqueConstraint, and_
from sqlalchemy.dialects.mysql import insert
from sqlalchemy.engine import Row
from sqlalchemy.engine.base import Connection
from sqlalchemy.schema import ForeignKey
from sqlalchemy.engine import Row
from sqlalchemy.sql import func, select
from sqlalchemy.dialects.mysql import insert
from sqlalchemy.sql.expression import exists
from sqlalchemy.types import JSON, TIMESTAMP, BigInteger, Boolean, Integer, String
from core.data.schema import BaseData, metadata
from ..config import ChuniConfig
course = Table(
course: Table = Table(
"chuni_score_course",
metadata,
Column("id", Integer, primary_key=True, nullable=False),
@ -41,7 +44,7 @@ course = Table(
mysql_charset="utf8mb4",
)
best_score = Table(
best_score: Table = Table(
"chuni_score_best",
metadata,
Column("id", Integer, primary_key=True, nullable=False),
@ -229,9 +232,12 @@ class ChuniRomVersion():
return -1
class ChuniScoreData(BaseData):
async def get_courses(self, aime_id: int) -> Optional[Row]:
async def get_courses(self, aime_id: int, limit: Optional[int] = None, offset: int = 0) -> Optional[List[Row]]:
sql = select(course).where(course.c.user == aime_id)
if limit is not None:
sql = sql.order_by(course.c.id.asc()).limit(limit).offset(offset)
result = await self.execute(sql)
if result is None:
return None
@ -249,8 +255,40 @@ class ChuniScoreData(BaseData):
return None
return result.lastrowid
async def get_scores(self, aime_id: int) -> Optional[Row]:
sql = select(best_score).where(best_score.c.user == aime_id)
async def get_scores(
self,
aime_id: int,
levels: Optional[list[int]] = None,
limit: Optional[int] = None,
offset: int = 0,
) -> Optional[List[Row]]:
condition = best_score.c.user == aime_id
if levels is not None:
condition &= best_score.c.level.in_(levels)
if limit is None:
sql = (
select(best_score)
.where(condition)
.order_by(best_score.c.musicId.asc(), best_score.c.level.asc())
)
else:
subq = (
select(best_score.c.musicId)
.distinct()
.where(condition)
.order_by(best_score.c.musicId.asc())
.limit(limit)
.offset(offset)
.subquery()
)
sql = (
select(best_score)
.join(subq, best_score.c.musicId == subq.c.musicId)
.where(condition)
.order_by(best_score.c.musicId.asc(), best_score.c.level.asc())
)
result = await self.execute(sql)
if result is None:
@ -360,11 +398,3 @@ class ChuniScoreData(BaseData):
rows = result.fetchall()
return [dict(row) for row in rows]
async def get_rival_music(self, rival_id: int) -> Optional[List[Dict]]:
sql = select(best_score).where(best_score.c.user == rival_id)
result = await self.execute(sql)
if result is None:
return None
return result.fetchall()