sqlx-record/src/pagination.rs

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)
}
}