---
import DocsLayout from '../../layouts/DocsLayout.astro';
import CodeBlock from '../../components/CodeBlock.astro';
const offsetPagination = `// Skip and take (offset pagination)
let page = 2;
let page_size = 20;
let users = client
.user()
.find_many()
.skip((page - 1) * page_size)
.take(page_size)
.exec()
.await?;
// Get total count for pagination UI
let total = client
.user()
.count()
.exec()
.await?;
let total_pages = (total + page_size - 1) / page_size;`;
const cursorPagination = `use prax_query::pagination::Cursor;
// Cursor-based pagination (more efficient for large datasets)
let users = client
.user()
.find_many()
.cursor(Cursor::after("id", last_id))
.take(20)
.exec()
.await?;
// Fetch the previous page instead with Cursor::before("id", first_id)
// Get the cursor for the next page
let next_cursor = users.last().map(|u| u.id);`;
const sorting = `use prax_query::types::{NullsOrder, OrderByField};
// Single field sort
let users = client
.user()
.find_many()
.order_by(OrderByField::desc("created_at"))
.exec()
.await?;
// Multiple field sort — pass a field list to one .order_by() call
// (a second .order_by() call replaces the first)
let users = client
.user()
.find_many()
.order_by(vec![
OrderByField::asc("last_name"),
OrderByField::asc("first_name"),
])
.exec()
.await?;
// Nulls first/last
let users = client
.user()
.find_many()
.order_by(OrderByField::desc("deleted_at").nulls(NullsOrder::First))
.exec()
.await?;`;
const distinct = `// Get distinct values
let cities = client
.user()
.find_many()
.distinct(["city"])
.exec()
.await?;
// Distinct on multiple fields
let locations = client
.user()
.find_many()
.distinct(["country", "city"])
.exec()
.await?;
// Generated field modules also expose the column name as a const:
// .distinct([user::city::COLUMN])`;
---
<DocsLayout title="Pagination & Sorting - Prax ORM">
<article class="max-w-4xl mx-auto px-6 py-12">
<header class="mb-12">
<h1 class="text-4xl font-bold mb-4">Pagination & Sorting</h1>
<p class="text-xl text-muted">
Paginate results and order them efficiently.
</p>
</header>
<div class="space-y-12">
<section>
<h2 class="text-2xl font-semibold mb-4">Offset Pagination</h2>
<CodeBlock code={offsetPagination} lang="rust" />
</section>
<section>
<h2 class="text-2xl font-semibold mb-4">Cursor Pagination</h2>
<p class="text-muted mb-4">
With a cursor and no explicit <code class="text-primary-400">.order_by(...)</code>, the query
automatically orders by the cursor column (<code>Cursor::after</code> → ASC,
<code>Cursor::before</code> → DESC) so keyset pagination stays deterministic;
an explicit <code class="text-primary-400">.order_by(...)</code> takes precedence.
</p>
<CodeBlock code={cursorPagination} lang="rust" />
</section>
<section>
<h2 class="text-2xl font-semibold mb-4">Sorting</h2>
<CodeBlock code={sorting} lang="rust" />
</section>
<section>
<h2 class="text-2xl font-semibold mb-4">Distinct</h2>
<p class="text-muted mb-4">
<code class="text-primary-400">.distinct(cols)</code> emits
<code>SELECT DISTINCT ON (cols)</code> on PostgreSQL. Other dialects fall back to plain
<code>SELECT DISTINCT</code>, which deduplicates whole rows — different semantics.
</p>
<CodeBlock code={distinct} lang="rust" />
</section>
</div>
</article>
</DocsLayout>