mirror of
https://github.com/jxxghp/MoviePilot.git
synced 2026-08-10 16:04:37 +08:00
fix(history): stabilize download history pagination
This commit is contained in:
@@ -140,7 +140,7 @@ async def download_history(
|
||||
_: schemas.TokenPayload = Depends(verify_token),
|
||||
) -> Any:
|
||||
"""
|
||||
查询下载历史记录
|
||||
按下载时间倒序查询下载历史记录
|
||||
"""
|
||||
return await DownloadHistory.async_list_by_page(db, page, count)
|
||||
|
||||
|
||||
@@ -148,14 +148,25 @@ class DownloadHistory(Base):
|
||||
def list_by_page(
|
||||
cls, db: Session, page: Optional[int] = 1, count: Optional[int] = 30
|
||||
):
|
||||
return db.query(DownloadHistory).offset((page - 1) * count).limit(count).all()
|
||||
return (
|
||||
db.query(DownloadHistory)
|
||||
.order_by(DownloadHistory.date.desc(), DownloadHistory.id.desc())
|
||||
.offset((page - 1) * count)
|
||||
.limit(count)
|
||||
.all()
|
||||
)
|
||||
|
||||
@classmethod
|
||||
@async_db_query
|
||||
async def async_list_by_page(
|
||||
cls, db: AsyncSession, page: Optional[int] = 1, count: Optional[int] = 30
|
||||
):
|
||||
result = await db.execute(select(cls).offset((page - 1) * count).limit(count))
|
||||
result = await db.execute(
|
||||
select(cls)
|
||||
.order_by(cls.date.desc(), cls.id.desc())
|
||||
.offset((page - 1) * count)
|
||||
.limit(count)
|
||||
)
|
||||
return result.scalars().all()
|
||||
|
||||
@classmethod
|
||||
|
||||
@@ -251,7 +251,7 @@ Streaming search sends `{"type":"heartbeat"}` every 15 seconds without business
|
||||
|
||||
| Method | Path | Description |
|
||||
|--------|------|-------------|
|
||||
| GET | `/api/v1/history/download` | Download history. Params: `page`, `count` |
|
||||
| GET | `/api/v1/history/download` | Download history, newest first. Params: `page`, `count` |
|
||||
| DELETE | `/api/v1/history/download` | Delete download history. Body: DownloadHistory JSON |
|
||||
| GET | `/api/v1/history/transfer` | Transfer history. Params: `title`, `page`, `count`, `status` |
|
||||
| DELETE | `/api/v1/history/transfer` | Delete transfer history. Params: `deletesrc`, `deletedest`. Body: TransferHistory |
|
||||
|
||||
@@ -98,3 +98,92 @@ def test_download_history_title_search_is_case_insensitive(tmp_path: Path):
|
||||
await engine.dispose()
|
||||
|
||||
asyncio.run(run_case())
|
||||
|
||||
|
||||
def test_download_history_page_is_newest_first(tmp_path: Path):
|
||||
"""下载历史分页应按时间和 ID 倒序稳定返回。"""
|
||||
engine = create_engine(f"sqlite:///{tmp_path / 'download_history_page.db'}")
|
||||
SessionFactory = sessionmaker(bind=engine)
|
||||
Base.metadata.create_all(bind=engine)
|
||||
|
||||
try:
|
||||
with SessionFactory() as db:
|
||||
db.add_all(
|
||||
[
|
||||
DownloadHistory(
|
||||
path="/downloads/oldest",
|
||||
type="电影",
|
||||
title="Oldest",
|
||||
date="2026-06-01 00:00:00",
|
||||
),
|
||||
DownloadHistory(
|
||||
path="/downloads/newer-first",
|
||||
type="电影",
|
||||
title="Newer First",
|
||||
date="2026-06-02 00:00:00",
|
||||
),
|
||||
DownloadHistory(
|
||||
path="/downloads/newer-second",
|
||||
type="电影",
|
||||
title="Newer Second",
|
||||
date="2026-06-02 00:00:00",
|
||||
),
|
||||
]
|
||||
)
|
||||
db.commit()
|
||||
|
||||
first_page = DownloadHistory.list_by_page(db, page=1, count=2)
|
||||
second_page = DownloadHistory.list_by_page(db, page=2, count=2)
|
||||
|
||||
assert [item.title for item in first_page] == ["Newer Second", "Newer First"]
|
||||
assert [item.title for item in second_page] == ["Oldest"]
|
||||
finally:
|
||||
engine.dispose()
|
||||
|
||||
|
||||
def test_async_download_history_page_is_newest_first(tmp_path: Path):
|
||||
"""异步下载历史分页应按时间和 ID 倒序稳定返回。"""
|
||||
|
||||
async def run_case():
|
||||
"""执行异步分页顺序断言。"""
|
||||
engine = create_async_engine(f"sqlite+aiosqlite:///{tmp_path / 'async_download_history_page.db'}")
|
||||
SessionFactory = async_sessionmaker(bind=engine)
|
||||
|
||||
try:
|
||||
async with engine.begin() as conn:
|
||||
await conn.run_sync(Base.metadata.create_all)
|
||||
|
||||
async with SessionFactory() as db:
|
||||
db.add_all(
|
||||
[
|
||||
DownloadHistory(
|
||||
path="/downloads/oldest",
|
||||
type="电影",
|
||||
title="Oldest",
|
||||
date="2026-06-01 00:00:00",
|
||||
),
|
||||
DownloadHistory(
|
||||
path="/downloads/newer-first",
|
||||
type="电影",
|
||||
title="Newer First",
|
||||
date="2026-06-02 00:00:00",
|
||||
),
|
||||
DownloadHistory(
|
||||
path="/downloads/newer-second",
|
||||
type="电影",
|
||||
title="Newer Second",
|
||||
date="2026-06-02 00:00:00",
|
||||
),
|
||||
]
|
||||
)
|
||||
await db.commit()
|
||||
|
||||
first_page = await DownloadHistory.async_list_by_page(db, page=1, count=2)
|
||||
second_page = await DownloadHistory.async_list_by_page(db, page=2, count=2)
|
||||
|
||||
assert [item.title for item in first_page] == ["Newer Second", "Newer First"]
|
||||
assert [item.title for item in second_page] == ["Oldest"]
|
||||
finally:
|
||||
await engine.dispose()
|
||||
|
||||
asyncio.run(run_case())
|
||||
|
||||
Reference in New Issue
Block a user