use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct PageRequest {
pub page: u64,
pub per_page: u64,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Page<T> {
pub items: Vec<T>,
pub total: u64,
pub page: u64,
pub per_page: u64,
}
impl<T> Page<T> {
pub fn total_pages(&self) -> u64 {
if self.per_page == 0 {
return 0;
}
self.total.div_ceil(self.per_page)
}
pub fn has_next_page(&self) -> bool {
self.page < self.total_pages()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn page_total_pages_exact_division() {
let page: Page<i32> = Page {
items: vec![1, 2],
total: 10,
page: 1,
per_page: 5,
};
assert_eq!(page.total_pages(), 2);
}
#[test]
fn page_total_pages_with_remainder() {
let page: Page<i32> = Page {
items: vec![1, 2, 3],
total: 7,
page: 1,
per_page: 3,
};
assert_eq!(page.total_pages(), 3);
}
#[test]
fn page_total_pages_zero_per_page() {
let page: Page<i32> = Page {
items: vec![],
total: 10,
page: 1,
per_page: 0,
};
assert_eq!(page.total_pages(), 0);
}
#[test]
fn page_total_pages_zero_total() {
let page: Page<i32> = Page {
items: vec![],
total: 0,
page: 1,
per_page: 10,
};
assert_eq!(page.total_pages(), 0);
}
#[test]
fn has_next_page_true() {
let page: Page<i32> = Page {
items: vec![1, 2],
total: 10,
page: 1,
per_page: 5,
};
assert!(page.has_next_page());
}
#[test]
fn has_next_page_false_on_last_page() {
let page: Page<i32> = Page {
items: vec![1],
total: 10,
page: 2,
per_page: 5,
};
assert!(!page.has_next_page());
}
#[test]
fn has_next_page_false_when_empty() {
let page: Page<i32> = Page {
items: vec![],
total: 0,
page: 1,
per_page: 10,
};
assert!(!page.has_next_page());
}
#[test]
fn page_request_construction() {
let req = PageRequest {
page: 2,
per_page: 25,
};
assert_eq!(req.page, 2);
assert_eq!(req.per_page, 25);
}
#[test]
fn page_request_clone_and_eq() {
let req = PageRequest {
page: 1,
per_page: 10,
};
let cloned = req.clone();
assert_eq!(req, cloned);
}
}