Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion docs/pagination.md
Original file line number Diff line number Diff line change
@@ -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:
Expand Down
32 changes: 18 additions & 14 deletions src/fastsqla.py
Original file line number Diff line number Diff line change
Expand Up @@ -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


Expand Down Expand Up @@ -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.
"""
23 changes: 12 additions & 11 deletions tests/integration/test_pagination.py
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -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
Expand All @@ -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(
Expand All @@ -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,
Expand Down