road_runner_common/
pagination.rs1use serde::{Deserialize, Serialize};
2
3#[cfg(feature = "openapi")]
4use utoipa::ToSchema;
5
6#[derive(Debug, Clone, Copy, Deserialize)]
7#[cfg_attr(feature = "openapi", derive(ToSchema, utoipa::IntoParams))]
8pub struct PageRequest {
9 #[serde(default = "default_page")]
10 pub page: u32, #[serde(default = "default_size")]
13 pub size: u32,
14}
15
16fn default_page() -> u32 {
17 1
18}
19fn default_size() -> u32 {
20 10
21}
22
23impl Default for PageRequest {
24 fn default() -> Self {
25 Self {
26 page: default_page(),
27 size: default_size(),
28 }
29 }
30}
31
32impl PageRequest {
33 pub fn normalized(self, max_page_size: u32) -> Self {
34 let size = self.size.clamp(1, max_page_size.max(1));
35 let page = self.page.max(1);
36 Self { page, size }
37 }
38
39 pub fn offset_limit(self) -> (u32, u32) {
40 let page = self.page.max(1);
41 let size = self.size.max(1);
42 let offset = (page - 1).saturating_mul(size);
43 (offset, size)
44 }
45}
46
47#[derive(Debug, Clone, Serialize)]
48#[cfg_attr(feature = "openapi", derive(ToSchema))]
49pub struct Paged<T> {
50 pub items: Vec<T>,
51 pub total_items: u64,
52 pub page: u32,
53 pub size: u32,
54 pub total_pages: u32,
55}
56
57impl<T> Paged<T> {
58 pub fn new(items: Vec<T>, total_items: u64, page: u32, size: u32) -> Self {
59 let size = size.max(1);
60 let total_pages = if total_items == 0 {
61 0
62 } else {
63 ((total_items + size as u64 - 1) / size as u64) as u32
64 };
65
66 Self {
67 items,
68 total_items,
69 page: page.max(1),
70 size,
71 total_pages,
72 }
73 }
74}