Skip to main content

No project description provided

Project description

sqlalchemy-relay-pagination

Python package that make setting up relay-style pagination with SQLAlchemy easy.

Quickstart

Installation

uv add sqlalchemy-relay-pagination

Schema

Define your connection types in SDL:

type Query {
  users(first: Int, last: Int, after: String, before: String): UserConnection!
}

type UserConnection {
  edges: [UserEdge!]!
  pageInfo: PageInfo!
}

type UserEdge {
  node: User!
  cursor: String!
}

type PageInfo {
  hasNextPage: Boolean!
  hasPreviousPage: Boolean!
  startCursor: String
  endCursor: String
  totalCount: Int
}

type User {
  id: Int!
  name: String!
  posts(first: Int, last: Int, after: String, before: String): PostConnection!
}

type PostConnection {
  edges: [PostEdge!]!
  pageInfo: PageInfo!
}

type PostEdge {
  node: Post!
  cursor: String!
}

type Post {
  id: Int!
  title: String!
}

Resolver

from ariadne import QueryType
from sqlalchemy import select
from sqlalchemy_relay_pagination import paginate
from sqlalchemy_relay_pagination.graphql import extract_requested_fields

query_type = QueryType()

@query_type.field("users")
async def resolve_users(_, info, first=None, last=None, after=None, before=None):
    session = info.context["session"]
    return await paginate(
        session,
        select(User),
        order_by=User.id,
        first=first,
        last=last,
        after=after,
        before=before,
        requested_fields=extract_requested_fields(info),
    )

extract_requested_fields inspects the GraphQL selection set and tells paginate which fields the client actually requested — skipping the COUNT(*) query when totalCount is absent, and skipping the extra-row fetch when neither hasNextPage nor hasPreviousPage is selected.

Batch-loading nested connections (avoiding N+1)

For nested paginated fields (e.g. User.posts), use paginate_many inside a dataloader to fetch all parents' children in a single query:

from aiodataloader import DataLoader
from ariadne import ObjectType
from sqlalchemy_relay_pagination import paginate_many

user_type = ObjectType("User")

class UserPostsLoader(DataLoader):
    def __init__(self, session, first, last, fields):
        super().__init__()
        self._session = session
        self._first = first
        self._last = last
        self._fields = fields

    async def batch_load_fn(self, user_ids):
        results = await paginate_many(
            self._session,
            select(Post),
            model=Post,
            partition_by=Post.user_id,
            order_by=Post.id,
            keys=list(user_ids),
            first=self._first,
            last=self._last,
            requested_fields=self._fields,
        )
        return [results[uid] for uid in user_ids]

@user_type.field("posts")
async def resolve_user_posts(user, info, first=None, last=None):
    session = info.context["session"]
    loaders = info.context["loaders"]

    loader_key = (first, last)
    if loader_key not in loaders:
        loaders[loader_key] = UserPostsLoader(
            session, first, last, extract_requested_fields(info)
        )

    return await loaders[loader_key].load(user.id)

Note: when after or before cursors are provided, paginate_many falls back to one query per parent key instead of a single batched query, because each parent may be at a different cursor position. Results are still correct; only the single-query optimisation is lost.

Global configuration

Call configure() once at application startup:

from sqlalchemy_relay_pagination import configure, PaginationConfig

configure(PaginationConfig(default_page_size=20, max_page_size=100))

Settings can also be provided via environment variables:

SQLALCHEMY_RELAY_PAGINATION_DEFAULT_PAGE_SIZE=20
SQLALCHEMY_RELAY_PAGINATION_MAX_PAGE_SIZE=100

Resources

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

sqlalchemy_relay_pagination-0.1.0rc2.tar.gz (99.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

sqlalchemy_relay_pagination-0.1.0rc2-py3-none-any.whl (19.5 kB view details)

Uploaded Python 3

File details

Details for the file sqlalchemy_relay_pagination-0.1.0rc2.tar.gz.

File metadata

File hashes

Hashes for sqlalchemy_relay_pagination-0.1.0rc2.tar.gz
Algorithm Hash digest
SHA256 1a68dc51f833c5d3f39be84e89a6dbbb3911ad9bc539d77f869c7044fb77b980
MD5 d77d85c1e59792378083f0fbc4b3ca4c
BLAKE2b-256 410cb64fb3558ab0c1b76018a0cfb636a31478898c0205bd86d2768262819f70

See more details on using hashes here.

Provenance

The following attestation bundles were made for sqlalchemy_relay_pagination-0.1.0rc2.tar.gz:

Publisher: publish-package.yaml on fedirz/sqlalchemy-relay-pagination

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file sqlalchemy_relay_pagination-0.1.0rc2-py3-none-any.whl.

File metadata

File hashes

Hashes for sqlalchemy_relay_pagination-0.1.0rc2-py3-none-any.whl
Algorithm Hash digest
SHA256 3f92677aff68d63b785a97e6d8df0e47c02dd774baf72e921f683774a0af1b79
MD5 e7bd89fc0ffa5d4a91293f7529931577
BLAKE2b-256 0bbc0eafef5ab1a8c49031c9c3598ccad01953d9b3593f1b7ee85e268babda6d

See more details on using hashes here.

Provenance

The following attestation bundles were made for sqlalchemy_relay_pagination-0.1.0rc2-py3-none-any.whl:

Publisher: publish-package.yaml on fedirz/sqlalchemy-relay-pagination

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page