1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
use vantage_expressions::traits::selectable::Selectable;
/// Pagination configuration for tables
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Pagination {
page: i64,
items_per_page: i64,
/// Explicit skip for a random-access `[offset, offset+limit)` window. When
/// set, `skip()` returns it verbatim instead of deriving it from `page` —
/// so the offset need not be a multiple of the page size.
offset: Option<i64>,
}
impl Pagination {
/// Create new pagination with page number and items per page
pub fn new(page: i64, items_per_page: i64) -> Self {
Self {
page: page.max(1),
items_per_page: items_per_page.max(1),
offset: None,
}
}
/// Create pagination for an explicit `[offset, offset + limit)` window
/// (random access). Unlike [`new`](Self::new), the offset is independent of
/// the page size, so any absolute row range maps directly onto a query.
pub fn window(offset: i64, limit: i64) -> Self {
Self {
page: 1,
items_per_page: limit.max(1),
offset: Some(offset.max(0)),
}
}
/// Set the current page number (1-based)
pub fn set_page(&mut self, page: i64) {
self.page = page.max(1);
}
/// Set items per page
/// When changing page size, adjusts current page to keep focused item visible
pub fn set_ipp(&mut self, items_per_page: i64) {
let items_per_page = items_per_page.max(1);
let first_item_index = (self.page - 1) * self.items_per_page;
self.page = (first_item_index / items_per_page) + 1;
self.items_per_page = items_per_page;
}
/// Get the current page number (1-based)
pub fn get_page(&self) -> i64 {
self.page
}
/// Get items per page
pub fn get_ipp(&self) -> i64 {
self.items_per_page
}
/// Calculate limit value for queries
pub fn limit(&self) -> i64 {
self.items_per_page
}
/// Calculate skip/offset value for queries
pub fn skip(&self) -> i64 {
self.offset.unwrap_or((self.page - 1) * self.items_per_page)
}
/// Apply pagination to a select query
pub fn apply_on_select<S, E>(&self, select: &mut S)
where
S: Selectable<E>,
{
select.set_limit(Some(self.limit()), Some(self.skip()));
}
}
impl Default for Pagination {
fn default() -> Self {
Self {
page: 1,
items_per_page: 50,
offset: None,
}
}
}