api_tools/value_objects/
pagination.rs

1//! Pagination value object representation
2
3/// Pagination min limit
4pub const PAGINATION_MIN_LIMIT: u32 = 50;
5
6/// Pagination max limit
7pub const PAGINATION_MAX_LIMIT: u32 = 500;
8
9/// Pagination default limit
10pub const PAGINATION_DEFAULT_LIMIT: u32 = 200;
11
12#[derive(Debug, Clone, PartialEq, Eq)]
13pub struct Pagination {
14    page: u32,
15    limit: u32,
16    max_limit: Option<u32>,
17}
18
19impl Pagination {
20    /// Create new pagination
21    ///
22    /// `max_limit` is optional and will be clamped between `PAGINATION_MIN_LIMIT` and `PAGINATION_MAX_LIMIT`
23    ///
24    /// # Examples
25    ///
26    /// ```
27    /// use api_tools::value_objects::pagination::{Pagination, PAGINATION_MAX_LIMIT, PAGINATION_MIN_LIMIT};
28    ///
29    /// let pagination = Pagination::new(1, 100, None);
30    /// assert_eq!(pagination.page(), 1);
31    /// assert_eq!(pagination.limit(), 100);
32    ///
33    /// // Invalid page
34    /// let pagination = Pagination::new(0, 100, None);
35    /// assert_eq!(pagination.page(), 1);
36    /// assert_eq!(pagination.limit(), 100);
37    ///
38    /// // Limit too small
39    /// let pagination = Pagination::new(2, 10, None);
40    /// assert_eq!(pagination.page(), 2);
41    /// assert_eq!(pagination.limit(), PAGINATION_MIN_LIMIT);
42    ///
43    /// // Limit too big
44    /// let pagination = Pagination::new(2, 1_000, None);
45    /// assert_eq!(pagination.page(), 2);
46    /// assert_eq!(pagination.limit(), PAGINATION_MAX_LIMIT);
47    ///
48    /// // Limit too big and max limit greater than max
49    /// let pagination = Pagination::new(2, 1_000, Some(800));
50    /// assert_eq!(pagination.page(), 2);
51    /// assert_eq!(pagination.limit(), PAGINATION_MAX_LIMIT);
52    /// ```
53    pub fn new(page: u32, limit: u32, max_limit: Option<u32>) -> Self {
54        let page = if page == 0 { 1 } else { page };
55
56        let mut max = max_limit.unwrap_or(PAGINATION_MAX_LIMIT);
57
58        if max > PAGINATION_MAX_LIMIT {
59            max = PAGINATION_MAX_LIMIT;
60        }
61
62        let limit = if limit > max {
63            max
64        } else if limit < PAGINATION_MIN_LIMIT {
65            PAGINATION_MIN_LIMIT
66        } else {
67            limit
68        };
69
70        Self { page, limit, max_limit }
71    }
72
73    /// Get page
74    pub fn page(&self) -> u32 {
75        self.page
76    }
77
78    /// Get limit
79    pub fn limit(&self) -> u32 {
80        self.limit
81    }
82
83    /// Set a max limit (between `PAGINATION_MIN_LIMIT` and `PAGINATION_MAX_LIMIT`)
84    pub fn set_max_limit(&mut self, max_limit: u32) {
85        let max_limit = max_limit.clamp(PAGINATION_MIN_LIMIT, PAGINATION_MAX_LIMIT);
86        self.max_limit = Some(max_limit);
87    }
88}
89
90impl Default for Pagination {
91    /// Default pagination
92    fn default() -> Self {
93        let default = if PAGINATION_DEFAULT_LIMIT > PAGINATION_MAX_LIMIT {
94            PAGINATION_MAX_LIMIT
95        } else {
96            PAGINATION_DEFAULT_LIMIT
97        };
98        Self::new(1, default, None)
99    }
100}
101
102/// Pagination for response
103#[derive(Debug, Clone, PartialEq)]
104
105pub struct PaginationResponse {
106    pub page: u32,
107    pub limit: u32,
108    pub total: i64,
109}
110
111impl PaginationResponse {
112    /// Create a new pagination response
113    pub fn new(page: u32, limit: u32, total: i64) -> Self {
114        Self { page, limit, total }
115    }
116}
117
118#[cfg(test)]
119mod test {
120    use super::*;
121
122    #[test]
123    fn test_set_max_limit() {
124        let mut pagination = Pagination::default();
125        assert_eq!(pagination.max_limit, None);
126
127        pagination.set_max_limit(100);
128        assert_eq!(pagination.max_limit, Some(100));
129
130        pagination.set_max_limit(300);
131        assert_eq!(pagination.max_limit, Some(300));
132
133        pagination.set_max_limit(20);
134        assert_eq!(pagination.max_limit, Some(PAGINATION_MIN_LIMIT));
135
136        pagination.set_max_limit(600);
137        assert_eq!(pagination.max_limit, Some(PAGINATION_MAX_LIMIT));
138    }
139
140    #[test]
141    fn test_default() {
142        let pagination = Pagination::default();
143        assert_eq!(pagination.page(), 1);
144        assert_eq!(pagination.limit(), PAGINATION_DEFAULT_LIMIT);
145        assert_eq!(pagination.max_limit, None);
146    }
147}