feat(backend): 无界列表端点加分页——projects/templates 支持 limit/offset
GET /projects 与 GET /templates 原一次返回全部 owner 行,行数随数据线性增长。 新增可复用分页依赖 ww_api.pagination.get_page(limit∈[1,200] 默认 50、offset≥0, 越界 → 422),两端点接入,Repository.list_for_owner 加 keyword-only limit/offset 把 LIMIT/OFFSET 下推 DB。向后兼容:不传参返回第一页。补 projects 分页 + 边界 422 测试。
This commit is contained in:
@@ -38,8 +38,13 @@ class _FakeTemplateRepo:
|
||||
self.flushed += 1
|
||||
return view
|
||||
|
||||
async def list_for_owner(self, owner_id: uuid.UUID) -> list[TemplateView]:
|
||||
return [v for tid, v in self.rows.items() if self.owners[tid] == owner_id]
|
||||
async def list_for_owner(
|
||||
self, owner_id: uuid.UUID, *, limit: int | None = None, offset: int = 0
|
||||
) -> list[TemplateView]:
|
||||
views = [v for tid, v in self.rows.items() if self.owners[tid] == owner_id]
|
||||
if limit is None:
|
||||
return views
|
||||
return views[offset : offset + limit]
|
||||
|
||||
async def delete(self, owner_id: uuid.UUID, template_id: uuid.UUID) -> bool:
|
||||
if self.rows.get(template_id) is None or self.owners.get(template_id) != owner_id:
|
||||
|
||||
@@ -57,7 +57,11 @@ class ProjectRepo(Protocol):
|
||||
|
||||
async def create(self, owner_id: uuid.UUID, data: ProjectCreate) -> ProjectView: ...
|
||||
|
||||
async def list_for_owner(self, owner_id: uuid.UUID) -> list[ProjectView]: ...
|
||||
async def list_for_owner(
|
||||
self, owner_id: uuid.UUID, *, limit: int | None = None, offset: int = 0
|
||||
) -> list[ProjectView]:
|
||||
"""按 created_at 升序。`limit` 非 None 时在 DB 层 LIMIT/OFFSET 分页。"""
|
||||
...
|
||||
|
||||
async def get(self, owner_id: uuid.UUID, project_id: uuid.UUID) -> ProjectView | None: ...
|
||||
|
||||
@@ -110,16 +114,13 @@ class SqlProjectRepo:
|
||||
await self._s.refresh(row)
|
||||
return _to_view(row)
|
||||
|
||||
async def list_for_owner(self, owner_id: uuid.UUID) -> list[ProjectView]:
|
||||
projects = (
|
||||
(
|
||||
await self._s.execute(
|
||||
select(Project).where(Project.owner_id == owner_id).order_by(Project.created_at)
|
||||
)
|
||||
)
|
||||
.scalars()
|
||||
.all()
|
||||
)
|
||||
async def list_for_owner(
|
||||
self, owner_id: uuid.UUID, *, limit: int | None = None, offset: int = 0
|
||||
) -> list[ProjectView]:
|
||||
stmt = select(Project).where(Project.owner_id == owner_id).order_by(Project.created_at)
|
||||
if limit is not None:
|
||||
stmt = stmt.limit(limit).offset(offset)
|
||||
projects = (await self._s.execute(stmt)).scalars().all()
|
||||
project_ids = [p.id for p in projects]
|
||||
pending_counts = await self._pending_review_counts(project_ids)
|
||||
activity_times = await self._activity_times(project_ids)
|
||||
|
||||
@@ -45,7 +45,11 @@ class TemplateRepo(Protocol):
|
||||
|
||||
async def create(self, owner_id: uuid.UUID, data: TemplateCreate) -> TemplateView: ...
|
||||
|
||||
async def list_for_owner(self, owner_id: uuid.UUID) -> list[TemplateView]: ...
|
||||
async def list_for_owner(
|
||||
self, owner_id: uuid.UUID, *, limit: int | None = None, offset: int = 0
|
||||
) -> list[TemplateView]:
|
||||
"""按 created_at 升序。`limit` 非 None 时在 DB 层 LIMIT/OFFSET 分页。"""
|
||||
...
|
||||
|
||||
async def delete(self, owner_id: uuid.UUID, template_id: uuid.UUID) -> bool: ...
|
||||
|
||||
@@ -79,14 +83,17 @@ class SqlTemplateRepo:
|
||||
await self._s.refresh(row)
|
||||
return _to_view(row)
|
||||
|
||||
async def list_for_owner(self, owner_id: uuid.UUID) -> list[TemplateView]:
|
||||
rows = (
|
||||
await self._s.execute(
|
||||
select(PromptTemplate)
|
||||
.where(PromptTemplate.owner_id == owner_id)
|
||||
.order_by(PromptTemplate.created_at)
|
||||
)
|
||||
).scalars()
|
||||
async def list_for_owner(
|
||||
self, owner_id: uuid.UUID, *, limit: int | None = None, offset: int = 0
|
||||
) -> list[TemplateView]:
|
||||
stmt = (
|
||||
select(PromptTemplate)
|
||||
.where(PromptTemplate.owner_id == owner_id)
|
||||
.order_by(PromptTemplate.created_at)
|
||||
)
|
||||
if limit is not None:
|
||||
stmt = stmt.limit(limit).offset(offset)
|
||||
rows = (await self._s.execute(stmt)).scalars()
|
||||
return [_to_view(r) for r in rows]
|
||||
|
||||
async def delete(self, owner_id: uuid.UUID, template_id: uuid.UUID) -> bool:
|
||||
|
||||
Reference in New Issue
Block a user