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:
Yaojia Wang
2026-07-08 12:39:31 +02:00
parent 1392830e57
commit 0892ff6cda
9 changed files with 121 additions and 31 deletions

View File

@@ -0,0 +1,37 @@
"""列表端点的分页参数(`limit`/`offset`,边界校验 + 合理默认)。
无界列表端点owner 维度projects / templates原来一次返回全部行行数随用户
数据线性增长。这里提供一个可复用的 FastAPI 依赖 `get_page`,把 `limit`/`offset`
在边界处校验(越界 → 422后交端点。默认返回第一页`offset=0` + `DEFAULT_PAGE_LIMIT`
不传参的老客户端行为不破坏;`limit` 有上限(`MAX_PAGE_LIMIT`)防一次性拉爆。
"""
from __future__ import annotations
from dataclasses import dataclass
from typing import Annotated
from fastapi import Depends, Query
# 合理默认 + 上限(单用户原型:默认页足够覆盖常见数据量;上限防一次拉全表)。
DEFAULT_PAGE_LIMIT = 50
MAX_PAGE_LIMIT = 200
@dataclass(frozen=True)
class Page:
"""一页的边界(不可变):`limit` 条数上限、`offset` 起始偏移。"""
limit: int
offset: int
def get_page(
limit: Annotated[int, Query(ge=1, le=MAX_PAGE_LIMIT)] = DEFAULT_PAGE_LIMIT,
offset: Annotated[int, Query(ge=0)] = 0,
) -> Page:
"""校验并封装分页参数(`limit∈[1,MAX]`、`offset≥0`;越界 FastAPI 返 422"""
return Page(limit=limit, offset=offset)
PageDep = Annotated[Page, Depends(get_page)]