klauthed_data/pagination/mod.rs
1//! Pagination — offset, cursor, and keyset strategies.
2//!
3//! Three complementary strategies are provided:
4//!
5//! - **Offset** (`OffsetPageRequest` / `Page<T>`) — classic `LIMIT … OFFSET …`,
6//! suitable for UI pages with a known total count.
7//! - **Cursor** (`CursorPageRequest` / `CursorPage<T>`) — opaque, base64-encoded
8//! position tokens; ideal for feeds and activity streams.
9//! - **Keyset** (`KeysetPageRequest` / `KeysetPage<T>`) — compound column comparison
10//! (`WHERE (col1, col2) > (v1, v2)`); most efficient for large sorted tables.
11//!
12//! Optional SQL helpers live in the `sql` sub-module (feature = `"sql"`).
13
14#[cfg(feature = "sql")]
15pub mod sql;
16
17pub mod cursor;
18pub mod keyset;
19pub mod offset;
20
21pub use cursor::{Cursor, CursorPage, CursorPageRequest};
22pub use keyset::{KeysetPage, KeysetPageRequest, KeysetPosition};
23pub use offset::{OffsetPageRequest, Page};
24
25use serde::{Deserialize, Serialize};
26
27// ── Constants ─────────────────────────────────────────────────────────────────
28
29/// Default number of items per page when no explicit `per_page` is supplied.
30pub const DEFAULT_PAGE_SIZE: u32 = 20;
31
32/// Hard upper limit on items per page — requests for more are silently capped.
33pub const MAX_PAGE_SIZE: u32 = 100;
34
35// ── Shared types ──────────────────────────────────────────────────────────────
36
37/// Sort direction for a single sort key.
38#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Serialize, Deserialize)]
39#[serde(rename_all = "lowercase")]
40pub enum SortOrder {
41 /// Ascending order (smallest first). This is the default.
42 #[default]
43 Asc,
44 /// Descending order (largest first).
45 Desc,
46}
47
48/// One sort criterion — a field name together with a direction.
49#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
50pub struct SortKey {
51 /// The field (column) name to sort on.
52 pub field: String,
53 /// The direction of the sort.
54 pub order: SortOrder,
55}
56
57impl SortKey {
58 /// Create an ascending sort key for `field`.
59 pub fn asc(field: impl Into<String>) -> Self {
60 SortKey { field: field.into(), order: SortOrder::Asc }
61 }
62
63 /// Create a descending sort key for `field`.
64 pub fn desc(field: impl Into<String>) -> Self {
65 SortKey { field: field.into(), order: SortOrder::Desc }
66 }
67}
68
69/// SQL parameter placeholder dialect for keyset and offset pagination helpers.
70///
71/// Pass this to [`sql::keyset_where_clause`]
72/// to select between positional (`$1`, `$2`, …) and question-mark (`?`, `?`, …)
73/// parameter styles.
74#[derive(Debug, Clone, Copy, PartialEq, Eq)]
75pub enum KeysetDialect {
76 /// PostgreSQL-style positional parameters: `$1`, `$2`, …
77 Positional,
78 /// MySQL / SQLite-style question-mark parameters: `?`, `?`, …
79 Question,
80}