geekorm_core/queries/
pages.rs

1//! # GeekORM Pages
2
3/// Default limit for max page size
4const DEFAULT_LIMIT: u32 = 100;
5
6/// Page struct for pagination.
7///
8/// This is a simple struct to handle pagination for queries.
9///
10/// ```rust
11/// # use geekorm::prelude::*;
12///
13/// #[derive(Table, Debug, Default, Clone, serde::Serialize, serde::Deserialize)]
14/// pub struct Users {
15///     pub id: PrimaryKeyInteger,
16///     pub username: String,
17///     pub age: i32,
18///     pub postcode: Option<String>,
19/// }
20///
21/// # fn main() {
22/// // Create a new Page instance
23/// let mut page = Page::new();
24/// # assert_eq!(page.limit(), 100);
25/// # assert_eq!(page.offset(), 0);
26///
27/// // Update the page to the next page
28/// page.next();
29/// # assert_eq!(page.page(), 1);
30/// # assert_eq!(page.limit(), 100);
31/// # assert_eq!(page.offset(), 100);
32///
33/// # page.next();
34/// # assert_eq!(page.offset(), 200);
35/// # page.prev();
36///
37/// // Build a query to select rows from the table
38/// let select_query = Users::query_select()
39///     .where_eq("username", "geekmasher")
40///     .page(&page)
41///     .order_by("age", QueryOrder::Asc)
42///     .build()
43///     .expect("Failed to build select query");
44/// # assert_eq!(
45/// #     select_query.query,
46/// #     "SELECT id, username, age, postcode FROM Users WHERE username = ? ORDER BY age ASC LIMIT 100 OFFSET 100;"
47/// # );
48///
49/// let page_max = Page::from((1, 10_000));
50/// # assert_eq!(page_max.limit(), 100);
51///
52/// let option_page = Page::from((Some(5), Some(10)));
53/// # assert_eq!(option_page.page(), 5);
54/// # assert_eq!(option_page.limit(), 10);
55/// # assert_eq!(option_page.offset(), 50);
56///
57/// # }
58/// ```
59#[derive(Debug)]
60pub struct Page {
61    pub(crate) page: u32,
62    pub(crate) limit: u32,
63    pub(crate) total: u32,
64}
65
66impl Page {
67    /// Create a new Page instance
68    pub fn new() -> Self {
69        Page {
70            page: 0,
71            limit: DEFAULT_LIMIT,
72            total: 0,
73        }
74    }
75    /// Update current page to the next page
76    pub fn next(&mut self) {
77        // Don't overflow the page number, reset to 0
78        if self.page == u32::MAX {
79            self.page = 0;
80        } else {
81            self.page += 1;
82        }
83    }
84    /// Update current page to the previous page
85    pub fn prev(&mut self) {
86        if self.page > 0 {
87            self.page -= 1;
88        }
89    }
90    /// Page number
91    pub fn page(&self) -> u32 {
92        self.page
93    }
94    /// Limit the rows accessed
95    pub fn limit(&self) -> u32 {
96        self.limit
97    }
98    /// Offset for the query
99    pub fn offset(&self) -> u32 {
100        if self.page == u32::MAX {
101            0
102        } else {
103            self.page * self.limit
104        }
105    }
106    /// Total number of pages
107    pub fn pages(&self) -> u32 {
108        if self.total == 0 {
109            0
110        } else {
111            (self.total as f64 / self.limit as f64).ceil() as u32
112        }
113    }
114    /// Get total number of rows
115    pub fn total(&self) -> u32 {
116        self.total
117    }
118    /// Set the total number of rows
119    pub fn set_total(&mut self, total: u32) {
120        self.total = total;
121    }
122
123    /// Get the maximum number of pages based on the total number of rows
124    pub fn max(&self) -> u32 {
125        if self.total == 0 {
126            0
127        } else {
128            (self.total as f64 / self.limit as f64).ceil() as u32
129        }
130    }
131}
132
133impl Default for Page {
134    fn default() -> Self {
135        Page {
136            page: u32::MAX,
137            limit: DEFAULT_LIMIT,
138            total: 0,
139        }
140    }
141}
142
143impl From<(u32, u32)> for Page {
144    fn from(p: (u32, u32)) -> Self {
145        let limit = if p.1 > DEFAULT_LIMIT {
146            DEFAULT_LIMIT
147        } else {
148            p.1
149        };
150        Page {
151            page: p.0,
152            limit,
153            ..Default::default()
154        }
155    }
156}
157
158impl From<(Option<u32>, Option<u32>)> for Page {
159    fn from(value: (Option<u32>, Option<u32>)) -> Self {
160        let mut page = Page::new();
161        if let Some(p) = value.0 {
162            page.page = p;
163        }
164        if let Some(l) = value.1 {
165            if l > DEFAULT_LIMIT {
166                page.limit = DEFAULT_LIMIT;
167            } else {
168                page.limit = l;
169            }
170        }
171        page
172    }
173}
174
175/// Implement From for Page (page, limit, total)
176impl From<(Option<u32>, Option<u32>, u32)> for Page {
177    fn from(value: (Option<u32>, Option<u32>, u32)) -> Self {
178        let mut page = Page::new();
179        if let Some(p) = value.0 {
180            page.page = p;
181        }
182        if let Some(l) = value.1 {
183            if l > DEFAULT_LIMIT {
184                page.limit = DEFAULT_LIMIT;
185            } else {
186                page.limit = l;
187            }
188        }
189        page.total = value.2;
190        page
191    }
192}
193
194impl From<u32> for Page {
195    fn from(value: u32) -> Self {
196        Page {
197            page: value,
198            limit: DEFAULT_LIMIT,
199            ..Default::default()
200        }
201    }
202}