109 lines
2.5 KiB
Rust
109 lines
2.5 KiB
Rust
/// Paginated result container
|
|
#[derive(Debug, Clone)]
|
|
pub struct Page<T> {
|
|
/// Items for this page
|
|
pub items: Vec<T>,
|
|
/// Total count of all matching items
|
|
pub total_count: u64,
|
|
/// Current page number (1-indexed)
|
|
pub page: u32,
|
|
/// Items per page
|
|
pub page_size: u32,
|
|
}
|
|
|
|
impl<T> Page<T> {
|
|
pub fn new(items: Vec<T>, total_count: u64, page: u32, page_size: u32) -> Self {
|
|
Self { items, total_count, page, page_size }
|
|
}
|
|
|
|
/// Total number of pages
|
|
pub fn total_pages(&self) -> u32 {
|
|
if self.page_size == 0 {
|
|
return 0;
|
|
}
|
|
((self.total_count as f64) / (self.page_size as f64)).ceil() as u32
|
|
}
|
|
|
|
/// Whether there is a next page
|
|
pub fn has_next(&self) -> bool {
|
|
self.page < self.total_pages()
|
|
}
|
|
|
|
/// Whether there is a previous page
|
|
pub fn has_prev(&self) -> bool {
|
|
self.page > 1
|
|
}
|
|
|
|
/// Check if page is empty
|
|
pub fn is_empty(&self) -> bool {
|
|
self.items.is_empty()
|
|
}
|
|
|
|
/// Number of items on this page
|
|
pub fn len(&self) -> usize {
|
|
self.items.len()
|
|
}
|
|
|
|
/// Map items to a different type
|
|
pub fn map<U, F: FnMut(T) -> U>(self, f: F) -> Page<U> {
|
|
Page {
|
|
items: self.items.into_iter().map(f).collect(),
|
|
total_count: self.total_count,
|
|
page: self.page,
|
|
page_size: self.page_size,
|
|
}
|
|
}
|
|
|
|
/// Iterator over items
|
|
pub fn iter(&self) -> impl Iterator<Item = &T> {
|
|
self.items.iter()
|
|
}
|
|
|
|
/// Take ownership of items
|
|
pub fn into_items(self) -> Vec<T> {
|
|
self.items
|
|
}
|
|
}
|
|
|
|
impl<T> IntoIterator for Page<T> {
|
|
type Item = T;
|
|
type IntoIter = std::vec::IntoIter<T>;
|
|
|
|
fn into_iter(self) -> Self::IntoIter {
|
|
self.items.into_iter()
|
|
}
|
|
}
|
|
|
|
/// Pagination request options
|
|
#[derive(Debug, Clone, Default)]
|
|
pub struct PageRequest {
|
|
/// Page number (1-indexed, minimum 1)
|
|
pub page: u32,
|
|
/// Items per page
|
|
pub page_size: u32,
|
|
}
|
|
|
|
impl PageRequest {
|
|
pub fn new(page: u32, page_size: u32) -> Self {
|
|
Self {
|
|
page: page.max(1),
|
|
page_size,
|
|
}
|
|
}
|
|
|
|
/// Calculate SQL OFFSET (0-indexed)
|
|
pub fn offset(&self) -> u32 {
|
|
if self.page <= 1 { 0 } else { (self.page - 1) * self.page_size }
|
|
}
|
|
|
|
/// Calculate SQL LIMIT
|
|
pub fn limit(&self) -> u32 {
|
|
self.page_size
|
|
}
|
|
|
|
/// First page
|
|
pub fn first(page_size: u32) -> Self {
|
|
Self::new(1, page_size)
|
|
}
|
|
}
|