feat: unify backtest table controls and add refresh action
Deploy production / deploy (push) Successful in 53s

This commit is contained in:
yuxuanhui
2026-09-12 13:29:00 +08:00
parent ed349693db
commit 8206b36cd2
8 changed files with 453 additions and 142 deletions
+17 -3
View File
@@ -1,5 +1,7 @@
"""Authenticated adapters; every mutation is committed before the execution lane wakes."""
from typing import Literal
from fastapi import APIRouter, Depends, Query, Request
from ..business import Business
@@ -48,9 +50,16 @@ async def configure(body: SchedulerInput, request: Request):
@router.get("/drafts")
async def drafts(request: Request, limit: int = Query(25, ge=1, le=100), offset: int = Query(0, ge=0)):
async def drafts(
request: Request,
limit: int = Query(25, ge=1, le=100),
offset: int = Query(0, ge=0),
q: str = Query("", max_length=200),
sort: Literal["name", "updated_at"] = "updated_at",
direction: Literal["asc", "desc"] = "desc",
):
async with request.app.state.sessions() as db:
return await Business(db).backtests.drafts(limit, offset)
return await Business(db).backtests.drafts(limit, offset, q, sort, direction)
@router.post("/drafts", status_code=201)
@@ -108,9 +117,14 @@ async def runs(
source: str | None = Query(None, max_length=100),
reference: str | None = Query(None, max_length=200),
research_id: str | None = Query(None, max_length=200),
q: str = Query("", max_length=200),
sort: Literal["name", "created_at"] = "created_at",
direction: Literal["asc", "desc"] = "desc",
):
async with request.app.state.sessions() as db:
return await Business(db).backtests.runs(limit, offset, source, reference, research_id)
return await Business(db).backtests.runs(
limit, offset, source, reference, research_id, q, sort, direction
)
@router.get("/sources", response_model=list[str])
+15 -6
View File
@@ -151,11 +151,16 @@ class Backtests:
await self.db.flush()
return await self.draft(draft_id)
async def drafts(self, limit=25, offset=0):
async def drafts(self, limit=25, offset=0, q="", sort="updated_at", direction="desc"):
query = select(BacktestDraft)
if q:
query = query.where(BacktestDraft.name.contains(q, autoescape=True))
column = {"name": BacktestDraft.name, "updated_at": BacktestDraft.updated_at}[sort]
order = column.asc() if direction == "asc" else column.desc()
rows = (
await self.db.scalars(
select(BacktestDraft)
.order_by(BacktestDraft.updated_at.desc(), BacktestDraft.id)
query
.order_by(order, BacktestDraft.id)
.limit(limit)
.offset(offset)
)
@@ -173,7 +178,7 @@ class Backtests:
)
for r in rows
],
"total": await self.db.scalar(select(func.count()).select_from(BacktestDraft)),
"total": await self.db.scalar(select(func.count()).select_from(query.subquery())),
"limit": limit,
"offset": offset,
}
@@ -355,15 +360,19 @@ class Backtests:
await self.db.flush()
return await self.run(run.id)
async def runs(self, limit=25, offset=0, source=None, reference=None, research_id=None):
async def runs(self, limit=25, offset=0, source=None, reference=None, research_id=None, q="", sort="created_at", direction="desc"):
query = select(BacktestRun)
if q:
query = query.where(BacktestRun.name.contains(q, autoescape=True))
column = {"name": BacktestRun.name, "created_at": BacktestRun.created_at}[sort]
order = column.asc() if direction == "asc" else column.desc()
for key, value in (("kind", source), ("reference", reference), ("research_id", research_id)):
if value:
query = query.where(BacktestRun.source[key].as_string() == value)
total = await self.db.scalar(select(func.count()).select_from(query.subquery()))
rows = (
await self.db.scalars(
query.order_by(BacktestRun.created_at.desc(), BacktestRun.id).limit(limit).offset(offset)
query.order_by(order, BacktestRun.id).limit(limit).offset(offset)
)
).all()
return {