icydb_core/db/response/
mod.rs1mod ext;
2
3pub use ext::*;
4
5use crate::{
6 Key, ThisError,
7 runtime_error::{ErrorClass, ErrorOrigin, RuntimeError},
8 traits::EntityKind,
9};
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 { .. } | Self::NotUnique { .. } => ErrorClass::Unsupported,
56 }
57 }
58}
59
60impl From<ResponseError> for RuntimeError {
61 fn from(err: ResponseError) -> Self {
62 Self::new(err.class(), ErrorOrigin::Response, err.to_string())
63 }
64}
65
66#[derive(Debug)]
72pub struct Response<E: EntityKind>(pub Vec<Row<E>>);
73
74impl<E: EntityKind> Response<E> {
75 #[must_use]
81 #[allow(clippy::cast_possible_truncation)]
82 pub const fn count(&self) -> u32 {
83 self.0.len() as u32
84 }
85
86 #[must_use]
88 pub const fn is_empty(&self) -> bool {
89 self.0.is_empty()
90 }
91
92 pub fn require_one(&self) -> Result<(), RuntimeError> {
98 match self.count() {
99 1 => Ok(()),
100 0 => Err(ResponseError::NotFound { entity: E::PATH }.into()),
101 n => Err(ResponseError::NotUnique {
102 entity: E::PATH,
103 count: n,
104 }
105 .into()),
106 }
107 }
108
109 pub fn require_some(&self) -> Result<(), RuntimeError> {
111 match self.count() {
112 0 => Err(ResponseError::NotFound { entity: E::PATH }.into()),
113 _ => Ok(()),
114 }
115 }
116
117 pub fn require_len(&self, expected: u32) -> Result<(), RuntimeError> {
119 let actual = self.count();
120 if actual == expected {
121 Ok(())
122 } else if actual == 0 {
123 Err(ResponseError::NotFound { entity: E::PATH }.into())
124 } else {
125 Err(ResponseError::NotUnique {
126 entity: E::PATH,
127 count: actual,
128 }
129 .into())
130 }
131 }
132
133 pub fn one(self) -> Result<Row<E>, RuntimeError> {
139 self.require_one()?;
140 Ok(self.0.into_iter().next().unwrap())
141 }
142
143 #[allow(clippy::cast_possible_truncation)]
145 pub fn one_opt(self) -> Result<Option<Row<E>>, RuntimeError> {
146 match self.0.len() {
147 0 => Ok(None),
148 1 => Ok(Some(self.0.into_iter().next().unwrap())),
149 n => Err(ResponseError::NotUnique {
150 entity: E::PATH,
151 count: n as u32,
152 }
153 .into()),
154 }
155 }
156
157 #[must_use]
166 pub fn into_page(self, limit: usize) -> Page<E> {
167 let mut iter = self.0.into_iter();
168
169 let mut items = Vec::with_capacity(limit);
170 for _ in 0..limit {
171 if let Some((_, entity)) = iter.next() {
172 items.push(entity);
173 } else {
174 return Page {
175 items,
176 has_more: false,
177 };
178 }
179 }
180
181 Page {
182 items,
183 has_more: iter.next().is_some(),
184 }
185 }
186
187 #[must_use]
193 pub fn key(&self) -> Option<Key> {
194 self.0.first().map(|(k, _)| *k)
195 }
196
197 #[must_use]
199 pub fn keys(&self) -> Vec<Key> {
200 self.0.iter().map(|(k, _)| *k).collect()
201 }
202
203 pub fn one_key(self) -> Result<Key, RuntimeError> {
205 self.one().map(|(k, _)| k)
206 }
207
208 pub fn one_opt_key(self) -> Result<Option<Key>, RuntimeError> {
210 Ok(self.one_opt()?.map(|(k, _)| k))
211 }
212
213 #[must_use]
214 pub fn contains_key(&self, key: &Key) -> bool {
215 self.0.iter().any(|(k, _)| k == key)
216 }
217
218 #[must_use]
224 pub fn entity(self) -> Option<E> {
225 self.0.into_iter().next().map(|(_, e)| e)
226 }
227
228 #[must_use]
230 pub fn entities(self) -> Vec<E> {
231 self.0.into_iter().map(|(_, e)| e).collect()
232 }
233
234 pub fn one_entity(self) -> Result<E, RuntimeError> {
236 self.one().map(|(_, e)| e)
237 }
238
239 pub fn one_opt_entity(self) -> Result<Option<E>, RuntimeError> {
241 Ok(self.one_opt()?.map(|(_, e)| e))
242 }
243
244 #[must_use]
250 pub fn pk(&self) -> Option<E::PrimaryKey> {
251 self.0.first().map(|(_, e)| e.primary_key())
252 }
253
254 #[must_use]
256 pub fn pks(&self) -> Vec<E::PrimaryKey> {
257 self.0.iter().map(|(_, e)| e.primary_key()).collect()
258 }
259
260 pub fn one_pk(self) -> Result<E::PrimaryKey, RuntimeError> {
262 self.one_entity().map(|e| e.primary_key())
263 }
264
265 pub fn one_opt_pk(self) -> Result<Option<E::PrimaryKey>, RuntimeError> {
267 Ok(self.one_opt_entity()?.map(|e| e.primary_key()))
268 }
269
270 #[must_use]
276 pub fn view(self) -> Option<E::ViewType> {
277 self.entity().map(|e| e.to_view())
278 }
279
280 pub fn one_view(self) -> Result<E::ViewType, RuntimeError> {
282 self.one_entity().map(|e| e.to_view())
283 }
284
285 pub fn one_opt_view(self) -> Result<Option<E::ViewType>, RuntimeError> {
287 Ok(self.one_opt_entity()?.map(|e| e.to_view()))
288 }
289
290 #[must_use]
292 pub fn views(self) -> Vec<E::ViewType> {
293 self.entities().into_iter().map(|e| e.to_view()).collect()
294 }
295
296 #[must_use]
305 pub fn first(self) -> Option<Row<E>> {
306 self.0.into_iter().next()
307 }
308
309 #[must_use]
314 pub fn first_entity(self) -> Option<E> {
315 self.first().map(|(_, e)| e)
316 }
317
318 #[must_use]
322 pub fn first_pk(self) -> Option<E::PrimaryKey> {
323 self.first_entity().map(|e| e.primary_key())
324 }
325}
326
327impl<E: EntityKind> IntoIterator for Response<E> {
328 type Item = Row<E>;
329 type IntoIter = std::vec::IntoIter<Self::Item>;
330
331 fn into_iter(self) -> Self::IntoIter {
332 self.0.into_iter()
333 }
334}