Querying
Pagination
Use paginate() for offset pages and cursor() for cursor navigation.
paginate() is the offset helper. cursor() is the cursor helper. Both return
{ data, pagination }, but the metadata is specific to the strategy.
Offset pagination
Use limit with skip (or take) when the consumer needs totals and page
numbers:
const page = await client.users.paginate({
limit: 20,
skip: 40,
orderBy: [{ id: 'asc' }],
where: { active: true },
});
page.data; // User[]
page.pagination.type; // "offset"
page.pagination.page;
page.pagination.perPage;
page.pagination.total;
page.pagination.pageCount;
page.pagination.hasNext;
page.pagination.hasPrevious;Cursor pagination
Use cursor() for feed-style navigation:
const first = await client.users.cursor({
limit: 2,
orderBy: [{ id: 'asc' }],
});
const second = await client.users.cursor({
limit: 2,
orderBy: [{ id: 'asc' }],
after: first.pagination.nextCursor as { id: number },
});Navigating backwards
Pass before to move backwards. cursor() accepts before or after, never
both.
const previous = await client.users.cursor({
limit: 2,
orderBy: [{ id: 'asc' }],
before: { id: 4 },
});Cursor pagination needs a stable order
Always pass a deterministic orderBy (typically including a unique column
like the primary key) when paginating by cursor, or pages can overlap or skip
rows.
Pagination with projection
Both helpers accept the same select / include as a normal read:
const page = await client.posts.paginate({
limit: 10,
orderBy: [{ id: 'desc' }],
include: { author: true },
});
const feed = await client.posts.cursor({
limit: 10,
orderBy: [{ id: 'desc' }],
include: { author: true },
});Choosing offset vs cursor
| Strategy | Good for | Trade-off |
|---|---|---|
| Offset | admin tables, reporting, simple lists | easy to reason about; weaker on very large, changing datasets |
| Cursor | feeds, timelines, large mutable datasets | needs stable ordering and cursor discipline |