icydb_core/db/response/
mod.rs1mod ext;
2
3pub use ext::*;
4
5use crate::{Error, Key, ThisError, db::DbError, traits::EntityKind};
6
7pub struct Page<T> {
12 pub items: Vec<T>,
13 pub has_more: bool,
14}
15
16impl<T> Page<T> {
17 #[must_use]
18 pub const fn is_empty(&self) -> bool {
19 self.items.is_empty()
20 }
21
22 #[must_use]
23 pub const fn len(&self) -> usize {
24 self.items.len()
25 }
26}
27
28pub type Row<E> = (Key, E);
33
34#[derive(Debug, ThisError)]
40pub enum ResponseError {
41 #[error("expected exactly one row, found 0 (entity {entity})")]
42 NotFound { entity: &'static str },
43
44 #[error("expected exactly one row, found {count} (entity {entity})")]
45 NotUnique { entity: &'static str, count: u32 },
46}
47
48impl From<ResponseError> for Error {
49 fn from(err: ResponseError) -> Self {
50 DbError::from(err).into()
51 }
52}
53
54#[derive(Debug)]
60pub struct Response<E: EntityKind>(pub Vec<Row<E>>);
61
62impl<E: EntityKind> Response<E> {
63 #[must_use]
69 #[allow(clippy::cast_possible_truncation)]
70 pub const fn count(&self) -> u32 {
71 self.0.len() as u32
72 }
73
74 #[must_use]
76 pub const fn is_empty(&self) -> bool {
77 self.0.is_empty()
78 }
79
80 pub fn require_one(&self) -> Result<(), Error> {
86 match self.count() {
87 1 => Ok(()),
88 0 => Err(ResponseError::NotFound { entity: E::PATH }.into()),
89 n => Err(ResponseError::NotUnique {
90 entity: E::PATH,
91 count: n,
92 }
93 .into()),
94 }
95 }
96
97 pub fn require_some(&self) -> Result<(), Error> {
99 match self.count() {
100 0 => Err(ResponseError::NotFound { entity: E::PATH }.into()),
101 _ => Ok(()),
102 }
103 }
104
105 pub fn require_len(&self, expected: u32) -> Result<(), Error> {
107 let actual = self.count();
108 if actual == expected {
109 Ok(())
110 } else if actual == 0 {
111 Err(ResponseError::NotFound { entity: E::PATH }.into())
112 } else {
113 Err(ResponseError::NotUnique {
114 entity: E::PATH,
115 count: actual,
116 }
117 .into())
118 }
119 }
120
121 pub fn one(self) -> Result<Row<E>, Error> {
127 self.require_one()?;
128 Ok(self.0.into_iter().next().unwrap())
129 }
130
131 #[allow(clippy::cast_possible_truncation)]
133 pub fn one_opt(self) -> Result<Option<Row<E>>, Error> {
134 match self.0.len() {
135 0 => Ok(None),
136 1 => Ok(Some(self.0.into_iter().next().unwrap())),
137 n => Err(ResponseError::NotUnique {
138 entity: E::PATH,
139 count: n as u32,
140 }
141 .into()),
142 }
143 }
144
145 #[must_use]
154 pub fn into_page(self, limit: usize) -> Page<E> {
155 let mut iter = self.0.into_iter();
156
157 let mut items = Vec::with_capacity(limit);
158 for _ in 0..limit {
159 if let Some((_, entity)) = iter.next() {
160 items.push(entity);
161 } else {
162 return Page {
163 items,
164 has_more: false,
165 };
166 }
167 }
168
169 Page {
170 items,
171 has_more: iter.next().is_some(),
172 }
173 }
174
175 #[must_use]
181 pub fn key(&self) -> Option<Key> {
182 self.0.first().map(|(k, _)| *k)
183 }
184
185 #[must_use]
187 pub fn keys(&self) -> Vec<Key> {
188 self.0.iter().map(|(k, _)| *k).collect()
189 }
190
191 pub fn one_key(self) -> Result<Key, Error> {
193 self.one().map(|(k, _)| k)
194 }
195
196 pub fn one_opt_key(self) -> Result<Option<Key>, Error> {
198 Ok(self.one_opt()?.map(|(k, _)| k))
199 }
200
201 #[must_use]
202 pub fn contains_key(&self, key: &Key) -> bool {
203 self.0.iter().any(|(k, _)| k == key)
204 }
205
206 #[must_use]
212 pub fn entity(self) -> Option<E> {
213 self.0.into_iter().next().map(|(_, e)| e)
214 }
215
216 #[must_use]
218 pub fn entities(self) -> Vec<E> {
219 self.0.into_iter().map(|(_, e)| e).collect()
220 }
221
222 pub fn one_entity(self) -> Result<E, Error> {
224 self.one().map(|(_, e)| e)
225 }
226
227 pub fn one_opt_entity(self) -> Result<Option<E>, Error> {
229 Ok(self.one_opt()?.map(|(_, e)| e))
230 }
231
232 #[must_use]
238 pub fn pk(&self) -> Option<E::PrimaryKey> {
239 self.0.first().map(|(_, e)| e.primary_key())
240 }
241
242 #[must_use]
244 pub fn pks(&self) -> Vec<E::PrimaryKey> {
245 self.0.iter().map(|(_, e)| e.primary_key()).collect()
246 }
247
248 pub fn one_pk(self) -> Result<E::PrimaryKey, Error> {
250 self.one_entity().map(|e| e.primary_key())
251 }
252
253 pub fn one_opt_pk(self) -> Result<Option<E::PrimaryKey>, Error> {
255 Ok(self.one_opt_entity()?.map(|e| e.primary_key()))
256 }
257
258 #[must_use]
264 pub fn view(self) -> Option<E::ViewType> {
265 self.entity().map(|e| e.to_view())
266 }
267
268 pub fn one_view(self) -> Result<E::ViewType, Error> {
270 self.one_entity().map(|e| e.to_view())
271 }
272
273 pub fn one_opt_view(self) -> Result<Option<E::ViewType>, Error> {
275 Ok(self.one_opt_entity()?.map(|e| e.to_view()))
276 }
277
278 #[must_use]
280 pub fn views(self) -> Vec<E::ViewType> {
281 self.entities().into_iter().map(|e| e.to_view()).collect()
282 }
283
284 #[must_use]
293 pub fn first(self) -> Option<Row<E>> {
294 self.0.into_iter().next()
295 }
296
297 #[must_use]
302 pub fn first_entity(self) -> Option<E> {
303 self.first().map(|(_, e)| e)
304 }
305
306 #[must_use]
310 pub fn first_pk(self) -> Option<E::PrimaryKey> {
311 self.first_entity().map(|e| e.primary_key())
312 }
313}
314
315impl<E: EntityKind> IntoIterator for Response<E> {
316 type Item = Row<E>;
317 type IntoIter = std::vec::IntoIter<Self::Item>;
318
319 fn into_iter(self) -> Self::IntoIter {
320 self.0.into_iter()
321 }
322}