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 normalized_with_default(self, default_size: u32, max_page_size: u32) -> Self {
40 let max_size = max_page_size.max(1);
41 let default_size = default_size.clamp(1, max_size);
42 let size = if self.size == 0 {
43 default_size
44 } else {
45 self.size.clamp(1, max_size)
46 };
47 let page = self.page.max(1);
48 Self { page, size }
49 }
50
51 pub fn offset_limit(self) -> (u32, u32) {
52 let page = self.page.max(1);
53 let size = self.size.max(1);
54 let offset = (page - 1).saturating_mul(size);
55 (offset, size)
56 }
57}
58
59#[derive(Debug, Clone, Serialize)]
60#[cfg_attr(feature = "openapi", derive(ToSchema))]
61pub struct Paged<T> {
62 pub items: Vec<T>,
63 pub total_items: u64,
64 pub page: u32,
65 pub size: u32,
66 pub total_pages: u32,
67}
68
69impl<T> Paged<T> {
70 pub fn new(items: Vec<T>, total_items: u64, page: u32, size: u32) -> Self {
71 let size = size.max(1);
72 let total_pages = if total_items == 0 {
73 0
74 } else {
75 ((total_items + size as u64 - 1) / size as u64) as u32
76 };
77
78 Self {
79 items,
80 total_items,
81 page: page.max(1),
82 size,
83 total_pages,
84 }
85 }
86}