Files
xiaoxia-saas/packages/application/common/pagination.py
T
Xiaoxia AI bc5e47528c
Deploy / Deploy Staging (push) Failing after 7s
Deploy / Deploy Production (push) Has been skipped
Tests / test (push) Failing after 19s
Tests / lint (push) Failing after 20s
feat(pagination): add generic pagination support
- Implement PaginationParams with offset/limit calculation
- Add PaginationMeta with navigation metadata
- Create generic PaginatedResponse[T] with type safety
- Support both in-memory and database pagination
- Include has_next/has_prev navigation flags
- Add comprehensive pagination documentation
- Include frontend integration examples (React/Vue)
- Cover cursor pagination for large datasets

Phase 4 Task 47/68 completed
2026-06-17 08:49:26 +08:00

99 lines
2.5 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""
通用分页器
"""
from typing import Generic, TypeVar, List, Optional
from pydantic import BaseModel, Field
from math import ceil
T = TypeVar("T")
class PaginationParams(BaseModel):
"""分页参数"""
page: int = Field(1, ge=1, description="页码(从 1 开始)")
page_size: int = Field(20, ge=1, le=100, description="每页数量(最大 100")
@property
def offset(self) -> int:
"""计算偏移量"""
return (self.page - 1) * self.page_size
@property
def limit(self) -> int:
"""返回限制数量"""
return self.page_size
class PaginationMeta(BaseModel):
"""分页元数据"""
page: int = Field(..., description="当前页码")
page_size: int = Field(..., description="每页数量")
total: int = Field(..., description="总记录数")
total_pages: int = Field(..., description="总页数")
has_next: bool = Field(..., description="是否有下一页")
has_prev: bool = Field(..., description="是否有上一页")
@classmethod
def from_params(
cls,
params: PaginationParams,
total: int,
) -> "PaginationMeta":
"""从参数和总数创建元数据"""
total_pages = ceil(total / params.page_size) if total > 0 else 0
return cls(
page=params.page,
page_size=params.page_size,
total=total,
total_pages=total_pages,
has_next=params.page < total_pages,
has_prev=params.page > 1,
)
class PaginatedResponse(BaseModel, Generic[T]):
"""分页响应"""
data: List[T] = Field(..., description="数据列表")
pagination: PaginationMeta = Field(..., description="分页信息")
@classmethod
def create(
cls,
data: List[T],
params: PaginationParams,
total: int,
) -> "PaginatedResponse[T]":
"""创建分页响应"""
return cls(
data=data,
pagination=PaginationMeta.from_params(params, total),
)
def paginate(
items: List[T],
params: PaginationParams,
) -> PaginatedResponse[T]:
"""
内存分页(适用于 InMemory Repository
Args:
items: 完整列表
params: 分页参数
Returns:
分页响应
"""
total = len(items)
start = params.offset
end = start + params.limit
page_data = items[start:end]
return PaginatedResponse.create(
data=page_data,
params=params,
total=total,
)