1pub const DEFAULT_PER_PAGE: u64 = 100;
5pub const MAX_PER_PAGE: u64 = 1000;
6
7#[derive(Debug, Clone, Copy, PartialEq, Eq)]
10pub struct Pagination {
11 pub page: u64,
13 pub per_page: u64,
14}
15
16impl Pagination {
17 pub fn from_raw(page: Option<u64>, per_page: Option<u64>) -> Self {
20 let page = page.unwrap_or(1).max(1);
21 let per_page = per_page.unwrap_or(DEFAULT_PER_PAGE).clamp(1, MAX_PER_PAGE);
22 Self { page, per_page }
23 }
24}
25
26#[derive(Debug, Clone, serde::Serialize)]
28pub struct PagedResult<M> {
29 pub items: Vec<M>,
30 pub page: u64,
31 pub per_page: u64,
32 pub total_items: u64,
33 pub total_pages: u64,
34}
35
36#[cfg(test)]
37mod tests {
38 use super::*;
39
40 #[test]
41 fn defaults_when_absent() {
42 let p = Pagination::from_raw(None, None);
43 assert_eq!(p.page, 1);
44 assert_eq!(p.per_page, DEFAULT_PER_PAGE);
45 }
46
47 #[test]
48 fn per_page_clamped_to_max() {
49 let p = Pagination::from_raw(None, Some(50_000));
50 assert_eq!(p.per_page, MAX_PER_PAGE);
51 }
52
53 #[test]
54 fn per_page_clamped_to_min() {
55 let p = Pagination::from_raw(None, Some(0));
56 assert_eq!(p.per_page, 1);
57 }
58
59 #[test]
60 fn page_clamped_to_min() {
61 let p = Pagination::from_raw(Some(0), None);
62 assert_eq!(p.page, 1);
63 }
64}