icydb_core/db/
response.rs1use crate::{
2 error::{ErrorClass, ErrorOrigin, InternalError},
3 prelude::*,
4};
5use thiserror::Error as ThisError;
6
7pub type Row<E> = (Key, E);
12
13#[derive(Debug, ThisError)]
19pub enum ResponseError {
20 #[error("expected exactly one row, found 0 (entity {entity})")]
21 NotFound { entity: &'static str },
22
23 #[error("expected exactly one row, found {count} (entity {entity})")]
24 NotUnique { entity: &'static str, count: u32 },
25}
26
27impl ResponseError {
28 pub(crate) const fn class(&self) -> ErrorClass {
29 match self {
30 Self::NotFound { .. } => ErrorClass::NotFound,
31 Self::NotUnique { .. } => ErrorClass::Conflict,
32 }
33 }
34}
35
36impl From<ResponseError> for InternalError {
37 fn from(err: ResponseError) -> Self {
38 Self::new(err.class(), ErrorOrigin::Response, err.to_string())
39 }
40}
41
42#[derive(Debug)]
50pub struct Response<E: EntityKind>(pub Vec<Row<E>>);
51
52impl<E: EntityKind> Response<E> {
53 #[must_use]
58 #[allow(clippy::cast_possible_truncation)]
59 pub const fn count(&self) -> u32 {
60 self.0.len() as u32
61 }
62
63 #[must_use]
64 pub const fn is_empty(&self) -> bool {
65 self.0.is_empty()
66 }
67
68 pub fn require_one(&self) -> Result<(), InternalError> {
73 match self.count() {
74 1 => Ok(()),
75 0 => Err(ResponseError::NotFound { entity: E::PATH }.into()),
76 n => Err(ResponseError::NotUnique {
77 entity: E::PATH,
78 count: n,
79 }
80 .into()),
81 }
82 }
83
84 pub fn require_some(&self) -> Result<(), InternalError> {
85 if self.is_empty() {
86 Err(ResponseError::NotFound { entity: E::PATH }.into())
87 } else {
88 Ok(())
89 }
90 }
91
92 pub fn row(self) -> Result<Row<E>, InternalError> {
97 self.require_one()?;
98 Ok(self.0.into_iter().next().unwrap())
99 }
100
101 #[allow(clippy::cast_possible_truncation)]
102 pub fn try_row(self) -> Result<Option<Row<E>>, InternalError> {
103 match self.0.len() {
104 0 => Ok(None),
105 1 => Ok(Some(self.0.into_iter().next().unwrap())),
106 n => Err(ResponseError::NotUnique {
107 entity: E::PATH,
108 count: n as u32,
109 }
110 .into()),
111 }
112 }
113
114 #[must_use]
115 pub fn rows(self) -> Vec<Row<E>> {
116 self.0
117 }
118
119 pub fn entity(self) -> Result<E, InternalError> {
124 self.row().map(|(_, e)| e)
125 }
126
127 pub fn try_entity(self) -> Result<Option<E>, InternalError> {
128 Ok(self.try_row()?.map(|(_, e)| e))
129 }
130
131 #[must_use]
132 pub fn entities(self) -> Vec<E> {
133 self.0.into_iter().map(|(_, e)| e).collect()
134 }
135
136 #[must_use]
141 pub fn key(&self) -> Option<Key> {
142 self.0.first().map(|(k, _)| *k)
143 }
144
145 pub fn key_strict(self) -> Result<Key, InternalError> {
146 self.row().map(|(k, _)| k)
147 }
148
149 pub fn try_key(self) -> Result<Option<Key>, InternalError> {
150 Ok(self.try_row()?.map(|(k, _)| k))
151 }
152
153 #[must_use]
154 pub fn keys(&self) -> Vec<Key> {
155 self.0.iter().map(|(k, _)| *k).collect()
156 }
157
158 #[must_use]
159 pub fn contains_key(&self, key: &Key) -> bool {
160 self.0.iter().any(|(k, _)| k == key)
161 }
162
163 pub fn view(self) -> Result<E::ViewType, InternalError> {
168 self.entity().map(|e| e.to_view())
169 }
170
171 pub fn try_view(self) -> Result<Option<E::ViewType>, InternalError> {
172 Ok(self.try_entity()?.map(|e| e.to_view()))
173 }
174
175 #[must_use]
176 pub fn views(self) -> Vec<E::ViewType> {
177 self.entities().into_iter().map(|e| e.to_view()).collect()
178 }
179
180 #[must_use]
185 pub fn first(self) -> Option<Row<E>> {
186 self.0.into_iter().next()
187 }
188
189 #[must_use]
190 pub fn first_entity(self) -> Option<E> {
191 self.first().map(|(_, e)| e)
192 }
193
194 #[must_use]
195 pub fn first_pk(self) -> Option<E::PrimaryKey> {
196 self.first_entity().map(|e| e.primary_key())
197 }
198}
199
200impl<E: EntityKind> IntoIterator for Response<E> {
201 type Item = Row<E>;
202 type IntoIter = std::vec::IntoIter<Self::Item>;
203
204 fn into_iter(self) -> Self::IntoIter {
205 self.0.into_iter()
206 }
207}
208
209pub trait ResponseExt<E: EntityKind> {
218 fn entities(self) -> Result<Vec<E>, InternalError>;
221 fn entity(self) -> Result<E, InternalError>;
222 fn try_entity(self) -> Result<Option<E>, InternalError>;
223
224 fn count(self) -> Result<u32, InternalError>;
227}
228
229impl<E: EntityKind> ResponseExt<E> for Result<Response<E>, InternalError> {
230 fn entities(self) -> Result<Vec<E>, InternalError> {
231 Ok(self?.entities())
232 }
233
234 fn entity(self) -> Result<E, InternalError> {
235 self?.entity()
236 }
237
238 fn try_entity(self) -> Result<Option<E>, InternalError> {
239 self?.try_entity()
240 }
241
242 fn count(self) -> Result<u32, InternalError> {
243 Ok(self?.count())
244 }
245}