use serde::{Deserialize, Serialize};
pub const DEFAULT_PER_PAGE: u64 = 20;
pub const MAX_PER_PAGE: u64 = 1000;
#[derive(Debug, Clone, Serialize, Deserialize)]
#[cfg_attr(feature = "openapi", derive(utoipa::IntoParams))]
pub struct PaginationParams {
pub page: Option<u64>,
pub per_page: Option<u64>,
}
#[derive(Debug, Clone, Copy)]
pub struct ResolvedPagination {
pub page: u64,
pub per_page: u64,
}
impl PaginationParams {
pub fn resolve(&self) -> ResolvedPagination {
let page = self.page.unwrap_or(1).max(1);
let per_page = self
.per_page
.unwrap_or(DEFAULT_PER_PAGE)
.clamp(1, MAX_PER_PAGE);
ResolvedPagination { page, per_page }
}
}
impl ResolvedPagination {
pub fn offset(&self) -> u64 {
(self.page - 1) * self.per_page
}
pub fn total_pages(&self, total: u64) -> u64 {
total.div_ceil(self.per_page)
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
pub struct PaginatedResponse<T> {
pub items: Vec<T>,
pub total: u64,
pub page: u64,
pub per_page: u64,
pub total_pages: u64,
}
impl<T> PaginatedResponse<T> {
pub fn new(items: Vec<T>, total: u64, pagination: ResolvedPagination) -> Self {
Self {
items,
total,
page: pagination.page,
per_page: pagination.per_page,
total_pages: pagination.total_pages(total),
}
}
}