diff --git a/docs/pagination.md b/docs/pagination.md index 7b43482..ec47648 100644 --- a/docs/pagination.md +++ b/docs/pagination.md @@ -1,6 +1,14 @@ # Pagination -## `fastsqla.Paginate[T]` +## `fastapi.Page[T]` + +::: fastsqla.Page + options: + heading_level: false + show_source: false + + +## `fastsqla.Paginate` ::: fastsqla.Paginate options: diff --git a/src/fastsqla.py b/src/fastsqla.py index 1a42e37..1a2833b 100644 --- a/src/fastsqla.py +++ b/src/fastsqla.py @@ -283,6 +283,23 @@ class Collection(BaseModel, Generic[T]): class Page(Collection[T]): + """Generic container that contains collection data and page metadata. + + The `Page` model is used to return paginated data in paginated endpoints: + + ```json + { + "data": list[T], + "meta": { + "offset": int, + "total_items": int, + "total_pages": int, + "page_number": int, + } + } + ``` + """ + meta: Meta @@ -360,18 +377,5 @@ async def paginate(stmt: Select) -> Page: """A dependency used in endpoints to paginate `SQLAlchemy` select queries. It adds **`offset`** and **`limit`** query parameters to the endpoint, which are used to -paginate. The model returned by the endpoint is a `Page` model. It contains a page of -data and metadata: - -```json -{ - "data": List[T], - "meta": { - "offset": int, - "total_items": int, - "total_pages": int, - "page_number": int, - } -} -``` +paginate. The model returned by the endpoint is a [`Page`][fastsqla.Page] model. """ diff --git a/tests/integration/test_pagination.py b/tests/integration/test_pagination.py index acfc6f0..abbfe50 100644 --- a/tests/integration/test_pagination.py +++ b/tests/integration/test_pagination.py @@ -1,7 +1,8 @@ from typing import Annotated, cast from fastapi import Depends +from pydantic import EmailStr from pytest import fixture -from sqlalchemy import MetaData, Table, func, select, text +from sqlalchemy import ForeignKey, MetaData, String, Table, func, select, text TOTAL_USERS = 42 STICKY_PER_USER = 5 @@ -56,21 +57,21 @@ async def setup_tear_down(engine, faker): @fixture def app(app): - from fastsqla import ( - Base, - Page, - Paginate, - PaginateType, - Session, - new_pagination, - ) + from fastsqla import Base, Page, Paginate, PaginateType, Session, new_pagination from pydantic import BaseModel + from sqlalchemy.orm import Mapped, mapped_column class User(Base): __tablename__ = "user" + id: Mapped[int] = mapped_column(primary_key=True) + email: Mapped[EmailStr] = mapped_column(String, unique=True) + name: Mapped[str] class Sticky(Base): __tablename__ = "sticky" + id: Mapped[int] = mapped_column(primary_key=True) + user_id: Mapped[int] = mapped_column(ForeignKey(User.id)) + body: Mapped[str] class UserModel(BaseModel): id: int @@ -93,7 +94,7 @@ async def query_count(session: Session) -> int: result = await session.execute(stmt) return cast(int, result.scalar()) - CustomResultProcessor = Annotated[ + CustomPaginate = Annotated[ PaginateType[StickyModel], Depends( new_pagination( @@ -104,7 +105,7 @@ async def query_count(session: Session) -> int: ] @app.get("/custom-pagination") - async def list_stickies(paginate: CustomResultProcessor) -> Page[StickyModel]: + async def list_stickies(paginate: CustomPaginate) -> Page[StickyModel]: stmt = select( Sticky.id, Sticky.body,