karbon_framework/db/
pagination.rs1use serde::{Deserialize, Serialize};
2
3#[derive(Debug, Clone, Deserialize)]
5pub struct PaginationParams {
6 #[serde(default = "default_page")]
7 pub page: u32,
8 #[serde(default = "default_per_page")]
9 pub per_page: u32,
10 #[serde(default)]
11 pub sort: Option<String>,
12 #[serde(default = "default_order")]
13 pub order: String,
14 #[serde(default)]
15 pub search: Option<String>,
16}
17
18fn default_page() -> u32 {
19 1
20}
21fn default_per_page() -> u32 {
22 20
23}
24fn default_order() -> String {
25 "desc".to_string()
26}
27
28const MAX_PER_PAGE: u32 = 200;
30
31impl PaginationParams {
32 pub fn safe_per_page(&self) -> u32 {
34 self.per_page.min(MAX_PER_PAGE).max(1)
35 }
36
37 pub fn offset(&self) -> u32 {
39 (self.page.saturating_sub(1)) * self.safe_per_page()
40 }
41
42 pub fn order_direction(&self) -> &str {
44 match self.order.to_lowercase().as_str() {
45 "asc" => "ASC",
46 _ => "DESC",
47 }
48 }
49
50 pub fn sort_column<'a>(&'a self, allowed: &[&'a str], default: &'a str) -> &'a str {
52 match &self.sort {
53 Some(col) if allowed.contains(&col.as_str()) => col.as_str(),
54 _ => default,
55 }
56 }
57}
58
59#[derive(Debug, Serialize)]
61pub struct Paginated<T: Serialize> {
62 pub data: Vec<T>,
63 pub meta: PaginationMeta,
64}
65
66#[derive(Debug, Serialize)]
67pub struct PaginationMeta {
68 pub page: u32,
69 pub per_page: u32,
70 pub total: u64,
71 pub total_pages: u32,
72 pub has_next: bool,
73 pub has_prev: bool,
74}
75
76impl<T: Serialize> Paginated<T> {
77 pub fn new(data: Vec<T>, total: u64, params: &PaginationParams) -> Self {
79 let total_pages = ((total as f64) / (params.per_page as f64)).ceil() as u32;
80 Self {
81 data,
82 meta: PaginationMeta {
83 page: params.page,
84 per_page: params.per_page,
85 total,
86 total_pages,
87 has_next: params.page < total_pages,
88 has_prev: params.page > 1,
89 },
90 }
91 }
92}