mas_storage/
pagination.rs1use thiserror::Error;
10use ulid::Ulid;
11
12#[derive(Debug, Error)]
14#[error("Either 'first' or 'last' must be specified")]
15pub struct InvalidPagination;
16
17#[derive(Debug, Clone, Copy, PartialEq, Eq)]
19pub struct Pagination {
20 pub before: Option<Ulid>,
22
23 pub after: Option<Ulid>,
25
26 pub count: usize,
28
29 pub direction: PaginationDirection,
31}
32
33#[derive(Debug, Clone, Copy, PartialEq, Eq)]
35pub enum PaginationDirection {
36 Forward,
38
39 Backward,
41}
42
43impl Pagination {
44 pub const fn try_new(
51 before: Option<Ulid>,
52 after: Option<Ulid>,
53 first: Option<usize>,
54 last: Option<usize>,
55 ) -> Result<Self, InvalidPagination> {
56 let (direction, count) = match (first, last) {
57 (Some(first), _) => (PaginationDirection::Forward, first),
58 (_, Some(last)) => (PaginationDirection::Backward, last),
59 (None, None) => return Err(InvalidPagination),
60 };
61
62 Ok(Self {
63 before,
64 after,
65 count,
66 direction,
67 })
68 }
69
70 #[must_use]
72 pub const fn first(first: usize) -> Self {
73 Self {
74 before: None,
75 after: None,
76 count: first,
77 direction: PaginationDirection::Forward,
78 }
79 }
80
81 #[must_use]
83 pub const fn last(last: usize) -> Self {
84 Self {
85 before: None,
86 after: None,
87 count: last,
88 direction: PaginationDirection::Backward,
89 }
90 }
91
92 #[must_use]
94 pub const fn before(mut self, id: Ulid) -> Self {
95 self.before = Some(id);
96 self
97 }
98
99 #[must_use]
101 pub const fn clear_before(mut self) -> Self {
102 self.before = None;
103 self
104 }
105
106 #[must_use]
108 pub const fn after(mut self, id: Ulid) -> Self {
109 self.after = Some(id);
110 self
111 }
112
113 #[must_use]
115 pub const fn clear_after(mut self) -> Self {
116 self.after = None;
117 self
118 }
119
120 #[must_use]
122 pub fn process<T>(&self, mut edges: Vec<T>) -> Page<T> {
123 let is_full = edges.len() == (self.count + 1);
124 if is_full {
125 edges.pop();
126 }
127
128 let (has_previous_page, has_next_page) = match self.direction {
129 PaginationDirection::Forward => (false, is_full),
130 PaginationDirection::Backward => {
131 edges.reverse();
133 (is_full, false)
134 }
135 };
136
137 Page {
138 has_next_page,
139 has_previous_page,
140 edges,
141 }
142 }
143}
144
145#[derive(Debug, Clone, PartialEq, Eq)]
147pub struct Page<T> {
148 pub has_next_page: bool,
150
151 pub has_previous_page: bool,
153
154 pub edges: Vec<T>,
156}
157
158impl<T> Page<T> {
159 #[must_use]
165 pub fn map<F, T2>(self, f: F) -> Page<T2>
166 where
167 F: FnMut(T) -> T2,
168 {
169 let edges = self.edges.into_iter().map(f).collect();
170 Page {
171 has_next_page: self.has_next_page,
172 has_previous_page: self.has_previous_page,
173 edges,
174 }
175 }
176
177 pub fn try_map<F, E, T2>(self, f: F) -> Result<Page<T2>, E>
187 where
188 F: FnMut(T) -> Result<T2, E>,
189 {
190 let edges: Result<Vec<T2>, E> = self.edges.into_iter().map(f).collect();
191 Ok(Page {
192 has_next_page: self.has_next_page,
193 has_previous_page: self.has_previous_page,
194 edges: edges?,
195 })
196 }
197}