Skip to main content

ic_canister_kit/common/
pages.rs

1use std::cmp::Ordering;
2
3use candid::CandidType;
4use serde::{Deserialize, Serialize};
5
6// ============= 分页查询 =============
7
8/// 分页对象
9#[derive(Debug, Clone, Serialize, Deserialize, CandidType)]
10pub struct QueryPage {
11    /// 当前页码 1 开始计数
12    pub page: u64,
13    /// 每页大小
14    pub size: u32,
15}
16
17/// 分页查询错误
18#[derive(Debug, Clone, Serialize, Deserialize, CandidType)]
19pub enum QueryPageError {
20    /// 错误的页码,不能为 0
21    WrongPage, // page can not be 0
22
23    /// 错误的页面大小
24    WrongSize {
25        /// 页面大小
26        size: u32,
27        /// 最大页面大小
28        max: u32,
29    }, // size can not be 0 and has max value
30}
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/// 分页查询结果
48#[derive(Debug, Clone, Serialize, Deserialize, CandidType)]
49pub struct PageData<T> {
50    /// 请求的页码
51    pub page: u64,
52    /// 请求的页面大小
53    pub size: u32,
54    /// 总个数
55    pub total: u64,
56    /// 查到的分页数据
57    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
71// 空结果
72impl QueryPage {
73    /// 空结果
74    #[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    /// 检查分页选项是否有效
85    #[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    /// 分页数据对象
100    #[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        // 偏移序号
125        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    /// 对所有数据进行分页查询
138    #[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    /// 对所有数据进行倒序分页查询
152    #[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        // 取出倒序索引
159        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    /// 倒序过滤分页查询
171    #[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, // 过滤条件
177    ) -> Result<PageData<&'a T>, QueryPageError>
178    where
179        F: Fn(&T) -> bool,
180    {
181        // 取出过滤后的倒序索引
182        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    /// 按条件分页查询
197    #[inline]
198    pub fn custom_query_by_list<T, R, Filter, Compare, Transform>(
199        &self,
200        list: &[T],
201        max: u32,
202        filter: Filter,       // 过滤条件
203        compare: Compare,     // 排序方法
204        transform: Transform, // 变形方法
205    ) -> Result<PageData<R>, QueryPageError>
206    where
207        Filter: Fn(&T) -> bool,
208        Compare: Fn(&T, &T) -> Ordering,
209        Transform: Fn(&T) -> R,
210    {
211        // 1. 过滤有效的结果
212        let mut list: Vec<&T> = list.iter().filter(|&item| filter(item)).collect();
213
214        // 2. 进行排序
215        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}