1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
// Pagination support
use serde::{Deserialize, Serialize};
// Pagination parameters for queries
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Pagination {
/// Page number (1-based)
pub page: u32,
/// Number of items per page
pub per_page: u32,
/// Total number of items (set after query execution)
pub total: Option<u64>,
/// Total number of pages (calculated)
pub total_pages: Option<u32>,
}
impl Pagination {
/// Create a new pagination instance
pub fn new(page: u32, per_page: u32) -> Self {
Self {
page,
per_page,
total: None,
total_pages: None,
}
}
/// Get the offset for SQL LIMIT/OFFSET
pub fn offset(&self) -> u32 {
(self.page - 1) * self.per_page
}
/// Get the limit for SQL LIMIT/OFFSET
pub fn limit(&self) -> u32 {
self.per_page
}
/// Set the total count and calculate total pages
pub fn set_total(&mut self, total: u64) {
self.total = Some(total);
self.total_pages = Some(((total as f64) / (self.per_page as f64)).ceil() as u32);
}
/// Check if there's a next page
pub fn has_next(&self) -> bool {
if let (Some(total_pages), Some(current_page)) = (self.total_pages, Some(self.page)) {
current_page < total_pages
} else {
false
}
}
/// Check if there's a previous page
pub fn has_prev(&self) -> bool {
self.page > 1
}
/// Get the start item number for the current page
pub fn start_item(&self) -> u32 {
(self.page - 1) * self.per_page + 1
}
/// Get the end item number for the current page
pub fn end_item(&self) -> u32 {
self.page * self.per_page
}
/// Get the next page number
pub fn next_page(&self) -> Option<u32> {
if self.has_next() {
Some(self.page + 1)
} else {
None
}
}
/// Get the previous page number
pub fn prev_page(&self) -> Option<u32> {
if self.has_prev() {
Some(self.page - 1)
} else {
None
}
}
}
impl Default for Pagination {
fn default() -> Self {
Self::new(1, 20)
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PaginatedResult<T> {
/// The data items for the current page
pub data: Vec<T>,
/// Pagination metadata
pub pagination: Pagination,
}
impl<T> PaginatedResult<T> {
/// Create a new paginated result
pub fn new(data: Vec<T>, pagination: Pagination) -> Self {
Self { data, pagination }
}
/// Create a paginated result with total count
pub fn with_total(data: Vec<T>, mut pagination: Pagination, total: u64) -> Self {
pagination.set_total(total);
Self { data, pagination }
}
/// Get the data items
pub fn data(&self) -> &[T] {
&self.data
}
/// Get the pagination metadata
pub fn pagination(&self) -> &Pagination {
&self.pagination
}
/// Get the number of items in the current page
pub fn len(&self) -> usize {
self.data.len()
}
/// Check if the current page is empty
pub fn is_empty(&self) -> bool {
self.data.is_empty()
}
/// Map the data items to a new type
pub fn map<U, F>(self, f: F) -> PaginatedResult<U>
where
F: FnMut(T) -> U,
{
PaginatedResult {
data: self.data.into_iter().map(f).collect(),
pagination: self.pagination,
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CursorPagination {
/// Cursor for the next page
pub cursor: Option<String>,
/// Number of items per page
pub limit: u32,
/// Whether to include the cursor item in results
pub include_cursor: bool,
/// Whether there are more items
pub has_next: bool,
/// Whether there are previous items
pub has_prev: bool,
/// Cursor for the next page
pub next_cursor: Option<String>,
/// Cursor for the previous page
pub prev_cursor: Option<String>,
/// Total number of items
pub total: Option<u64>,
}
impl CursorPagination {
/// Create a new cursor pagination instance
pub fn new(limit: u32) -> Self {
Self {
cursor: None,
limit,
include_cursor: false,
has_next: false,
has_prev: false,
next_cursor: None,
prev_cursor: None,
total: None,
}
}
/// Create with a specific cursor
pub fn with_cursor(limit: u32, cursor: Option<String>) -> Self {
let has_prev = cursor.is_some();
Self {
cursor,
limit,
include_cursor: false,
has_next: false,
has_prev,
next_cursor: None,
prev_cursor: None,
total: None,
}
}
/// Create with a specific cursor (deprecated, use with_cursor(limit, cursor) instead)
pub fn with_cursor_old(cursor: String, limit: u32) -> Self {
Self {
cursor: Some(cursor),
limit,
include_cursor: false,
has_next: false,
has_prev: true,
next_cursor: None,
prev_cursor: None,
total: None,
}
}
/// Set the cursor
pub fn set_cursor(&mut self, cursor: Option<String>) {
self.cursor = cursor;
}
/// Get the limit for SQL queries
pub fn limit(&self) -> u32 {
self.limit
}
}
impl Default for CursorPagination {
fn default() -> Self {
Self::new(20)
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CursorPaginatedResult<T> {
/// The data items
pub data: Vec<T>,
/// Pagination metadata
pub pagination: CursorPagination,
}
impl<T> CursorPaginatedResult<T> {
/// Create a new cursor paginated result
pub fn new(data: Vec<T>, pagination: CursorPagination) -> Self {
Self { data, pagination }
}
/// Get the data items
pub fn data(&self) -> &[T] {
&self.data
}
/// Get the pagination metadata
pub fn pagination(&self) -> &CursorPagination {
&self.pagination
}
}