pub const PAGINATION_MIN_LIMIT: u32 = 10;
pub const PAGINATION_MAX_LIMIT: u32 = 500;
pub const PAGINATION_DEFAULT_LIMIT: u32 = 200;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Pagination {
page: u32,
limit: u32,
max_limit: Option<u32>,
}
impl Pagination {
pub fn new(page: u32, limit: u32, max_limit: Option<u32>) -> Self {
let page = if page == 0 { 1 } else { page };
let mut max = max_limit.unwrap_or(PAGINATION_MAX_LIMIT);
if max > PAGINATION_MAX_LIMIT {
max = PAGINATION_MAX_LIMIT;
}
let limit = if limit > max {
max
} else if limit < PAGINATION_MIN_LIMIT {
PAGINATION_MIN_LIMIT
} else {
limit
};
Self { page, limit, max_limit }
}
pub fn page(&self) -> u32 {
self.page
}
pub fn limit(&self) -> u32 {
self.limit
}
pub fn set_max_limit(&mut self, max_limit: u32) {
let max_limit = max_limit.clamp(PAGINATION_MIN_LIMIT, PAGINATION_MAX_LIMIT);
self.max_limit = Some(max_limit);
}
}
impl Default for Pagination {
fn default() -> Self {
let default = if PAGINATION_DEFAULT_LIMIT > PAGINATION_MAX_LIMIT {
PAGINATION_MAX_LIMIT
} else {
PAGINATION_DEFAULT_LIMIT
};
Self::new(1, default, None)
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct PaginationResponse {
pub page: u32,
pub limit: u32,
pub total: i64,
}
impl PaginationResponse {
pub fn new(page: u32, limit: u32, total: i64) -> Self {
Self { page, limit, total }
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test_set_max_limit() {
let mut pagination = Pagination::default();
assert_eq!(pagination.max_limit, None);
pagination.set_max_limit(100);
assert_eq!(pagination.max_limit, Some(100));
pagination.set_max_limit(300);
assert_eq!(pagination.max_limit, Some(300));
pagination.set_max_limit(5);
assert_eq!(pagination.max_limit, Some(PAGINATION_MIN_LIMIT));
pagination.set_max_limit(600);
assert_eq!(pagination.max_limit, Some(PAGINATION_MAX_LIMIT));
}
#[test]
fn test_default() {
let pagination = Pagination::default();
assert_eq!(pagination.page(), 1);
assert_eq!(pagination.limit(), PAGINATION_DEFAULT_LIMIT);
assert_eq!(pagination.max_limit, None);
}
#[test]
fn new_clamps_zero_page_to_one() {
let p = Pagination::new(0, 100, None);
assert_eq!(p.page(), 1);
}
#[test]
fn new_clamps_limit_below_min_to_pagination_min_limit() {
let p = Pagination::new(1, 1, None);
assert_eq!(p.limit(), PAGINATION_MIN_LIMIT);
}
#[test]
fn new_clamps_limit_above_max_to_pagination_max_limit() {
let p = Pagination::new(1, PAGINATION_MAX_LIMIT + 100, None);
assert_eq!(p.limit(), PAGINATION_MAX_LIMIT);
}
#[test]
fn new_caps_max_limit_argument_at_pagination_max_limit() {
let p = Pagination::new(1, 10_000, Some(10_000));
assert_eq!(p.limit(), PAGINATION_MAX_LIMIT);
}
#[test]
fn new_respects_a_smaller_custom_max_limit() {
let p = Pagination::new(1, 1_000, Some(100));
assert_eq!(p.limit(), 100);
}
#[test]
fn pagination_response_new_stores_all_fields() {
let r = PaginationResponse::new(2, 50, 1_234);
assert_eq!(r.page, 2);
assert_eq!(r.limit, 50);
assert_eq!(r.total, 1_234);
}
}