perf(backend): 大纲卷过滤下推 DB WHERE——list_for_project 加 volume 参数
GET /outline?volume=N 原在端点 Python 侧过滤全部章节;现把 volume 条件下推到 OutlineRepo.list_for_project 的 DB WHERE,只查该卷行(少读多余卷 + 语义正确)。 Protocol/SqlOutlineRepo/各 OutlineRepo fake 同步加 keyword-only volume;补 repo 级 下推断言测试。向后兼容:不传 volume 仍返回全部(默认 None)。
This commit is contained in:
@@ -44,8 +44,11 @@ class FakeOutlineRepo:
|
||||
async def get(self, project_id: uuid.UUID, chapter_no: int) -> OutlineView | None:
|
||||
return self.rows.get(chapter_no)
|
||||
|
||||
async def list_for_project(self, project_id: uuid.UUID) -> list[OutlineView]:
|
||||
return [self.rows[k] for k in sorted(self.rows)]
|
||||
async def list_for_project(
|
||||
self, project_id: uuid.UUID, *, volume: int | None = None
|
||||
) -> list[OutlineView]:
|
||||
rows = [self.rows[k] for k in sorted(self.rows)]
|
||||
return [v for v in rows if volume is None or v.volume == volume]
|
||||
|
||||
|
||||
@dataclass
|
||||
|
||||
@@ -115,7 +115,11 @@ class ProjectSpecView(BaseModel):
|
||||
class OutlineRepo(Protocol):
|
||||
async def get(self, project_id: uuid.UUID, chapter_no: int) -> OutlineView | None: ...
|
||||
|
||||
async def list_for_project(self, project_id: uuid.UUID) -> list[OutlineView]: ...
|
||||
async def list_for_project(
|
||||
self, project_id: uuid.UUID, *, volume: int | None = None
|
||||
) -> list[OutlineView]:
|
||||
"""按 chapter_no 升序返回。`volume` 非 None 时**在 DB WHERE 下推**只取该卷。"""
|
||||
...
|
||||
|
||||
|
||||
class CharacterRepo(Protocol):
|
||||
|
||||
@@ -56,12 +56,13 @@ class SqlOutlineRepo:
|
||||
foreshadow_windows=list(row.foreshadow_windows or []),
|
||||
)
|
||||
|
||||
async def list_for_project(self, project_id: uuid.UUID) -> list[OutlineView]:
|
||||
rows = (
|
||||
await self._s.execute(
|
||||
select(Outline).where(Outline.project_id == project_id).order_by(Outline.chapter_no)
|
||||
)
|
||||
).scalars()
|
||||
async def list_for_project(
|
||||
self, project_id: uuid.UUID, *, volume: int | None = None
|
||||
) -> list[OutlineView]:
|
||||
stmt = select(Outline).where(Outline.project_id == project_id)
|
||||
if volume is not None:
|
||||
stmt = stmt.where(Outline.volume == volume)
|
||||
rows = (await self._s.execute(stmt.order_by(Outline.chapter_no))).scalars()
|
||||
return [
|
||||
OutlineView(
|
||||
volume=r.volume,
|
||||
|
||||
Reference in New Issue
Block a user