Offset-free Paging for SQLAlchemy

2.0.1775222100 · active · verified Sun Apr 12

sqlakeyset implements keyset-based paging for SQLAlchemy (both ORM and core). It provides an efficient alternative to traditional offset-based pagination, which can become slow with deep pages. The library supports SQLAlchemy 2.0, includes type hints, and is tested with PostgreSQL, MariaDB/MySQL, and SQLite. The current version is 2.0.1775222100. While no explicit release cadence is stated, the GitHub repository shows regular updates and contributions.

Warnings

Install

Imports

Quickstart

Demonstrates basic keyset pagination using `select_page` with a SQLAlchemy 2.0-style query, retrieving the first page and its bookmark for subsequent pages. It includes a simple model, in-memory SQLite setup, data insertion, and then the pagination logic.

from sqlalchemy import create_engine, select, String, Integer
from sqlalchemy.orm import declarative_base, Session, Mapped, mapped_column
from sqlakeyset import select_page

# 1. Define Base
Base = declarative_base()

# 2. Define a simple model
class Book(Base):
    __tablename__ = "books"
    id: Mapped[int] = mapped_column(Integer, primary_key=True)
    author: Mapped[str] = mapped_column(String(50))
    title: Mapped[str] = mapped_column(String(100))

    def __repr__(self):
        return f"Book(id={self.id}, author='{self.author}', title='{self.title}')"

# 3. Create an in-memory SQLite engine
engine = create_engine("sqlite:///:memory:")

# 4. Create tables
Base.metadata.create_all(engine)

# 5. Insert some sample data
with Session(engine) as session:
    session.add_all([
        Book(author="Stephen King", title="It"),
        Book(author="J.R.R. Tolkien", title="The Hobbit"),
        Book(author="Stephen King", title="The Stand"),
        Book(author="Frank Herbert", title="Dune"),
        Book(author="J.R.R. Tolkien", title="The Lord of the Rings"),
    ])
    session.commit()

# 6. Perform keyset pagination
with Session(engine) as session:
    # Build a query with ordering, including a unique key (id) at the end
    q = select(Book).order_by(Book.author, Book.title, Book.id)

    # Get the first page
    page1 = select_page(session, q, per_page=2)
    print(f"Page 1 items: {page1.items}")
    print(f"Page 1 has next: {page1.paging.has_next}")
    print(f"Page 1 next bookmark: {page1.paging.bookmark_next}")

    # Get the second page using the bookmark from the first page
    if page1.paging.has_next:
        page2 = select_page(session, q, per_page=2, bookmark=page1.paging.bookmark_next)
        print(f"Page 2 items: {page2.items}")
        print(f"Page 2 has next: {page2.paging.has_next}")
        print(f"Page 2 next bookmark: {page2.paging.bookmark_next}")

view raw JSON →