from typing import Generic, TypeVar from fastapi import Query from pydantic import BaseModel from sqlalchemy import Select, func, select from sqlalchemy.orm import Session T = TypeVar("T") class PageParams: def __init__( self, page: int = Query(1, ge=1), page_size: int = Query(50, ge=1, le=200), ): self.page = page self.page_size = page_size @property def offset(self) -> int: return (self.page - 1) * self.page_size class Page(BaseModel, Generic[T]): items: list[T] total: int page: int page_size: int def paginate(db: Session, stmt: Select, params: PageParams) -> tuple[list, int]: total = db.scalar(select(func.count()).select_from(stmt.subquery())) or 0 rows = db.scalars(stmt.offset(params.offset).limit(params.page_size)).all() return list(rows), total