1use std::cmp::Ordering;
2
3use candid::CandidType;
4use serde::{Deserialize, Serialize};
5
6#[derive(Debug, Clone, Serialize, Deserialize, CandidType)]
10pub struct QueryPage {
11 pub page: u64,
13 pub size: u32,
15}
16
17#[derive(Debug, Clone, Serialize, Deserialize, CandidType)]
19pub enum QueryPageError {
20 WrongPage, WrongSize {
25 size: u32,
27 max: u32,
29 }, }
31impl std::fmt::Display for QueryPageError {
32 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
33 match self {
34 QueryPageError::WrongPage => write!(f, "page can not be 0"),
35 QueryPageError::WrongSize { size, max } => {
36 if *size == 0 {
37 write!(f, "size can not be 0")
38 } else {
39 write!(f, "max({max}) < size({size})")
40 }
41 }
42 }
43 }
44}
45impl std::error::Error for QueryPageError {}
46
47#[derive(Debug, Clone, Serialize, Deserialize, CandidType)]
49pub struct PageData<T> {
50 pub page: u64,
52 pub size: u32,
54 pub total: u64,
56 pub data: Vec<T>,
58}
59
60impl<T: Clone> From<PageData<&T>> for PageData<T> {
61 fn from(value: PageData<&T>) -> Self {
62 PageData {
63 page: value.page,
64 size: value.size,
65 total: value.total,
66 data: value.data.into_iter().cloned().collect(),
67 }
68 }
69}
70
71impl QueryPage {
73 #[inline]
75 pub fn empty<T>(&self) -> PageData<T> {
76 PageData {
77 page: self.page,
78 size: self.size,
79 total: 0,
80 data: Vec::new(),
81 }
82 }
83
84 #[inline]
86 pub fn check(&self, max: u32) -> Result<(), QueryPageError> {
87 if self.page == 0 {
88 return Err(QueryPageError::WrongPage);
89 }
90 if self.size == 0 || max < self.size {
91 return Err(QueryPageError::WrongSize {
92 size: self.size,
93 max,
94 });
95 }
96 Ok(())
97 }
98
99 #[inline]
101 pub fn from_data<T>(&self, total: u64, data: Vec<T>) -> PageData<T> {
102 PageData {
103 page: self.page,
104 size: self.size,
105 total,
106 data,
107 }
108 }
109
110 #[inline]
111 fn inner_query_by_list<'a, T>(
112 &self,
113 list: &'a [T],
114 max: u32,
115 ) -> Result<Vec<&'a T>, QueryPageError> {
116 self.check(max)?;
117
118 if list.is_empty() {
119 return Ok(Vec::new());
120 }
121
122 let mut data = Vec::with_capacity(self.size as usize);
123
124 let start = ((self.page - 1) * self.size as u64) as usize;
126 let end = ((self.page) * self.size as u64) as usize;
127
128 if end < list.len() {
129 data = list[start..end].iter().collect();
130 } else if start < list.len() {
131 data = list[start..].iter().collect();
132 }
133
134 Ok(data)
135 }
136
137 #[inline]
139 pub fn query_by_list<'a, T>(
140 &self,
141 list: &'a [T],
142 max: u32,
143 ) -> Result<PageData<&'a T>, QueryPageError> {
144 let total = list.len() as u64;
145
146 let data = self.inner_query_by_list(list, max)?;
147
148 Ok(self.from_data(total, data))
149 }
150
151 #[inline]
153 pub fn query_desc_by_list<'a, T>(
154 &self,
155 list: &'a [T],
156 max: u32,
157 ) -> Result<PageData<&'a T>, QueryPageError> {
158 let index_list: Vec<usize> = (0..list.len()).rev().collect();
160
161 let total = index_list.len() as u64;
162
163 let data = self.inner_query_by_list(&index_list, max)?;
164
165 let data = data.into_iter().map(|i| &list[*i]).collect::<Vec<_>>();
166
167 Ok(self.from_data(total, data))
168 }
169
170 #[inline]
172 pub fn query_desc_by_list_and_filter<'a, T, F>(
173 &self,
174 list: &'a [T],
175 max: u32,
176 filter: F, ) -> Result<PageData<&'a T>, QueryPageError>
178 where
179 F: Fn(&T) -> bool,
180 {
181 let index_list: Vec<usize> = (0..list.len())
183 .filter(|i| filter(&list[*i]))
184 .rev()
185 .collect();
186
187 let total = index_list.len() as u64;
188
189 let data = self.inner_query_by_list(&index_list, max)?;
190
191 let data = data.into_iter().map(|i| &list[*i]).collect::<Vec<_>>();
192
193 Ok(self.from_data(total, data))
194 }
195
196 #[inline]
198 pub fn custom_query_by_list<T, R, Filter, Compare, Transform>(
199 &self,
200 list: &[T],
201 max: u32,
202 filter: Filter, compare: Compare, transform: Transform, ) -> Result<PageData<R>, QueryPageError>
206 where
207 Filter: Fn(&T) -> bool,
208 Compare: Fn(&T, &T) -> Ordering,
209 Transform: Fn(&T) -> R,
210 {
211 let mut list: Vec<&T> = list.iter().filter(|&item| filter(item)).collect();
213
214 list.sort_by(|&a, &b| compare(a, b));
216
217 let total = list.len() as u64;
218
219 let data = self.inner_query_by_list(&list, max)?;
220
221 let data = data.into_iter().map(|t| transform(t)).collect::<Vec<_>>();
222
223 Ok(self.from_data(total, data))
224 }
225}