use serde::{Deserialize, Serialize};
#[cfg(feature = "openapi")]
use utoipa::ToSchema;
#[derive(Debug, Clone, Copy, Deserialize)]
#[cfg_attr(feature = "openapi", derive(ToSchema, utoipa::IntoParams))]
pub struct PageRequest {
#[serde(default = "default_page")]
pub page: u32,
#[serde(default = "default_size")]
pub size: u32,
}
fn default_page() -> u32 {
1
}
fn default_size() -> u32 {
10
}
impl Default for PageRequest {
fn default() -> Self {
Self {
page: default_page(),
size: default_size(),
}
}
}
impl PageRequest {
pub fn normalized(self, max_page_size: u32) -> Self {
let size = self.size.clamp(1, max_page_size.max(1));
let page = self.page.max(1);
Self { page, size }
}
pub fn offset_limit(self) -> (u32, u32) {
let page = self.page.max(1);
let size = self.size.max(1);
let offset = (page - 1).saturating_mul(size);
(offset, size)
}
}
#[derive(Debug, Clone, Serialize)]
#[cfg_attr(feature = "openapi", derive(ToSchema))]
pub struct Paged<T> {
pub items: Vec<T>,
pub total_items: u64,
pub page: u32,
pub size: u32,
pub total_pages: u32,
}
impl<T> Paged<T> {
pub fn new(items: Vec<T>, total_items: u64, page: u32, size: u32) -> Self {
let size = size.max(1);
let total_pages = if total_items == 0 {
0
} else {
((total_items + size as u64 - 1) / size as u64) as u32
};
Self {
items,
total_items,
page: page.max(1),
size,
total_pages,
}
}
}