Skip to main content

paginator_utils/
params.rs

1use crate::cursor::Cursor;
2use crate::filter::Filter;
3use crate::search::SearchParams;
4use serde::{Deserialize, Serialize};
5
6#[derive(Clone, Copy, Debug, Serialize, Deserialize, PartialEq, Eq)]
7#[serde(rename_all = "lowercase")]
8pub enum SortDirection {
9    Asc,
10    Desc,
11}
12
13impl SortDirection {
14    pub fn reversed(self) -> Self {
15        match self {
16            SortDirection::Asc => SortDirection::Desc,
17            SortDirection::Desc => SortDirection::Asc,
18        }
19    }
20}
21
22#[derive(Clone, Debug, Serialize, Deserialize)]
23pub struct PaginationParams {
24    pub page: u32,
25    pub per_page: u32,
26    pub sort_by: Option<String>,
27    pub sort_direction: Option<SortDirection>,
28    #[serde(default)]
29    pub filters: Vec<Filter>,
30    pub search: Option<SearchParams>,
31    #[serde(default)]
32    pub disable_total_count: bool,
33    pub cursor: Option<Cursor>,
34}
35
36impl Default for PaginationParams {
37    fn default() -> Self {
38        Self {
39            page: 1,
40            per_page: 20,
41            sort_by: None,
42            sort_direction: None,
43            filters: Vec::new(),
44            search: None,
45            disable_total_count: false,
46            cursor: None,
47        }
48    }
49}
50
51impl PaginationParams {
52    pub fn new(page: u32, per_page: u32) -> Self {
53        Self {
54            page: page.max(1),
55            per_page: per_page.clamp(1, 100),
56            sort_by: None,
57            sort_direction: None,
58            filters: Vec::new(),
59            search: None,
60            disable_total_count: false,
61            cursor: None,
62        }
63    }
64
65    pub fn with_sort(mut self, field: impl Into<String>) -> Self {
66        self.sort_by = Some(field.into());
67        self
68    }
69
70    pub fn with_direction(mut self, direction: SortDirection) -> Self {
71        self.sort_direction = Some(direction);
72        self
73    }
74
75    pub fn with_filter(mut self, filter: Filter) -> Self {
76        self.filters.push(filter);
77        self
78    }
79
80    pub fn with_filters(mut self, filters: Vec<Filter>) -> Self {
81        self.filters.extend(filters);
82        self
83    }
84
85    pub fn with_search(mut self, search: SearchParams) -> Self {
86        self.search = Some(search);
87        self
88    }
89
90    pub fn offset(&self) -> u32 {
91        (self.page - 1) * self.per_page
92    }
93
94    pub fn limit(&self) -> u32 {
95        self.per_page
96    }
97
98    pub fn to_sql_where(&self) -> Option<String> {
99        let mut conditions = Vec::new();
100
101        for filter in &self.filters {
102            conditions.push(filter.to_sql_where());
103        }
104
105        if let Some(ref search) = self.search {
106            conditions.push(search.to_sql_where());
107        }
108
109        if conditions.is_empty() {
110            None
111        } else {
112            Some(conditions.join(" AND "))
113        }
114    }
115
116    pub fn to_surrealql_where(&self) -> Option<String> {
117        let mut conditions = Vec::new();
118
119        for filter in &self.filters {
120            conditions.push(filter.to_surrealql_where());
121        }
122
123        if let Some(ref search) = self.search {
124            let search_conditions: Vec<String> = search
125                .fields
126                .iter()
127                .map(|field| {
128                    let pattern = if search.exact_match {
129                        format!("'{}'", search.query.replace('\'', "''"))
130                    } else {
131                        format!("'%{}%'", search.query.replace('\'', "''"))
132                    };
133                    format!("{} ~ {}", field, pattern)
134                })
135                .collect();
136            conditions.push(format!("({})", search_conditions.join(" OR ")));
137        }
138
139        if conditions.is_empty() {
140            None
141        } else {
142            Some(conditions.join(" AND "))
143        }
144    }
145}