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}