icydb_core/db/response/
mod.rs1mod ext;
2
3pub use ext::*;
4
5use crate::{
6 error::{ErrorClass, ErrorOrigin, InternalError},
7 prelude::*,
8};
9use thiserror::Error as ThisError;
10
11pub struct Page<T> {
16 pub items: Vec<T>,
17 pub has_more: bool,
18}
19
20impl<T> Page<T> {
21 #[must_use]
22 pub const fn is_empty(&self) -> bool {
23 self.items.is_empty()
24 }
25
26 #[must_use]
27 pub const fn len(&self) -> usize {
28 self.items.len()
29 }
30}
31
32pub type Row<E> = (Key, E);
37
38#[derive(Debug, ThisError)]
44pub enum ResponseError {
45 #[error("expected exactly one row, found 0 (entity {entity})")]
46 NotFound { entity: &'static str },
47
48 #[error("expected exactly one row, found {count} (entity {entity})")]
49 NotUnique { entity: &'static str, count: u32 },
50}
51
52impl ResponseError {
53 pub(crate) const fn class(&self) -> ErrorClass {
54 match self {
55 Self::NotFound { .. } => ErrorClass::NotFound,
56 Self::NotUnique { .. } => ErrorClass::Unsupported,
57 }
58 }
59}
60
61impl From<ResponseError> for InternalError {
62 fn from(err: ResponseError) -> Self {
63 Self::new(err.class(), ErrorOrigin::Response, err.to_string())
64 }
65}
66
67#[derive(Debug)]
73pub struct Response<E: EntityKind>(pub Vec<Row<E>>);
74
75impl<E: EntityKind> Response<E> {
76 #[must_use]
82 #[allow(clippy::cast_possible_truncation)]
83 pub const fn count(&self) -> u32 {
84 self.0.len() as u32
85 }
86
87 #[must_use]
89 pub const fn is_empty(&self) -> bool {
90 self.0.is_empty()
91 }
92
93 pub fn require_one(&self) -> Result<(), InternalError> {
99 match self.count() {
100 1 => Ok(()),
101 0 => Err(ResponseError::NotFound { entity: E::PATH }.into()),
102 n => Err(ResponseError::NotUnique {
103 entity: E::PATH,
104 count: n,
105 }
106 .into()),
107 }
108 }
109
110 pub fn require_some(&self) -> Result<(), InternalError> {
112 match self.count() {
113 0 => Err(ResponseError::NotFound { entity: E::PATH }.into()),
114 _ => Ok(()),
115 }
116 }
117
118 pub fn require_len(&self, expected: u32) -> Result<(), InternalError> {
120 let actual = self.count();
121 if actual == expected {
122 Ok(())
123 } else if actual == 0 {
124 Err(ResponseError::NotFound { entity: E::PATH }.into())
125 } else {
126 Err(ResponseError::NotUnique {
127 entity: E::PATH,
128 count: actual,
129 }
130 .into())
131 }
132 }
133
134 pub fn one(self) -> Result<Row<E>, InternalError> {
140 self.require_one()?;
141 Ok(self.0.into_iter().next().unwrap())
142 }
143
144 #[allow(clippy::cast_possible_truncation)]
146 pub fn one_opt(self) -> Result<Option<Row<E>>, InternalError> {
147 match self.0.len() {
148 0 => Ok(None),
149 1 => Ok(Some(self.0.into_iter().next().unwrap())),
150 n => Err(ResponseError::NotUnique {
151 entity: E::PATH,
152 count: n as u32,
153 }
154 .into()),
155 }
156 }
157
158 #[must_use]
167 pub fn into_page(self, limit: usize) -> Page<E> {
168 let mut iter = self.0.into_iter();
169
170 let mut items = Vec::with_capacity(limit);
171 for _ in 0..limit {
172 if let Some((_, entity)) = iter.next() {
173 items.push(entity);
174 } else {
175 return Page {
176 items,
177 has_more: false,
178 };
179 }
180 }
181
182 Page {
183 items,
184 has_more: iter.next().is_some(),
185 }
186 }
187
188 #[must_use]
194 pub fn key(&self) -> Option<Key> {
195 self.0.first().map(|(k, _)| *k)
196 }
197
198 #[must_use]
200 pub fn keys(&self) -> Vec<Key> {
201 self.0.iter().map(|(k, _)| *k).collect()
202 }
203
204 pub fn one_key(self) -> Result<Key, InternalError> {
206 self.one().map(|(k, _)| k)
207 }
208
209 pub fn one_opt_key(self) -> Result<Option<Key>, InternalError> {
211 Ok(self.one_opt()?.map(|(k, _)| k))
212 }
213
214 #[must_use]
215 pub fn contains_key(&self, key: &Key) -> bool {
216 self.0.iter().any(|(k, _)| k == key)
217 }
218
219 #[must_use]
225 pub fn entity(self) -> Option<E> {
226 self.0.into_iter().next().map(|(_, e)| e)
227 }
228
229 #[must_use]
231 pub fn entities(self) -> Vec<E> {
232 self.0.into_iter().map(|(_, e)| e).collect()
233 }
234
235 pub fn one_entity(self) -> Result<E, InternalError> {
237 self.one().map(|(_, e)| e)
238 }
239
240 pub fn one_opt_entity(self) -> Result<Option<E>, InternalError> {
242 Ok(self.one_opt()?.map(|(_, e)| e))
243 }
244
245 #[must_use]
251 pub fn pk(&self) -> Option<E::PrimaryKey> {
252 self.0.first().map(|(_, e)| e.primary_key())
253 }
254
255 #[must_use]
257 pub fn pks(&self) -> Vec<E::PrimaryKey> {
258 self.0.iter().map(|(_, e)| e.primary_key()).collect()
259 }
260
261 pub fn one_pk(self) -> Result<E::PrimaryKey, InternalError> {
263 self.one_entity().map(|e| e.primary_key())
264 }
265
266 pub fn one_opt_pk(self) -> Result<Option<E::PrimaryKey>, InternalError> {
268 Ok(self.one_opt_entity()?.map(|e| e.primary_key()))
269 }
270
271 #[must_use]
277 pub fn view(self) -> Option<E::ViewType> {
278 self.entity().map(|e| e.to_view())
279 }
280
281 pub fn one_view(self) -> Result<E::ViewType, InternalError> {
283 self.one_entity().map(|e| e.to_view())
284 }
285
286 pub fn one_opt_view(self) -> Result<Option<E::ViewType>, InternalError> {
288 Ok(self.one_opt_entity()?.map(|e| e.to_view()))
289 }
290
291 #[must_use]
293 pub fn views(self) -> Vec<E::ViewType> {
294 self.entities().into_iter().map(|e| e.to_view()).collect()
295 }
296
297 #[must_use]
306 pub fn first(self) -> Option<Row<E>> {
307 self.0.into_iter().next()
308 }
309
310 #[must_use]
315 pub fn first_entity(self) -> Option<E> {
316 self.first().map(|(_, e)| e)
317 }
318
319 #[must_use]
323 pub fn first_pk(self) -> Option<E::PrimaryKey> {
324 self.first_entity().map(|e| e.primary_key())
325 }
326}
327
328impl<E: EntityKind> IntoIterator for Response<E> {
329 type Item = Row<E>;
330 type IntoIter = std::vec::IntoIter<Self::Item>;
331
332 fn into_iter(self) -> Self::IntoIter {
333 self.0.into_iter()
334 }
335}