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