icydb_core/db/
response.rs1use crate::{
2 error::{ErrorClass, ErrorOrigin, InternalError},
3 prelude::*,
4 view::View,
5};
6use thiserror::Error as ThisError;
7
8pub type Row<E> = (Key, E);
13
14#[derive(Debug, ThisError)]
20pub enum ResponseError {
21 #[error("expected exactly one row, found 0 (entity {entity})")]
22 NotFound { entity: &'static str },
23
24 #[error("expected exactly one row, found {count} (entity {entity})")]
25 NotUnique { entity: &'static str, count: u64 },
26}
27
28impl ResponseError {
29 pub(crate) const fn class(&self) -> ErrorClass {
30 match self {
31 Self::NotFound { .. } => ErrorClass::NotFound,
32 Self::NotUnique { .. } => ErrorClass::Conflict,
33 }
34 }
35}
36
37impl From<ResponseError> for InternalError {
38 fn from(err: ResponseError) -> Self {
39 Self::new(err.class(), ErrorOrigin::Response, err.to_string())
40 }
41}
42
43#[derive(Debug)]
49pub struct Response<E: EntityKind>(pub Vec<Row<E>>);
50
51impl<E: EntityKind> Response<E> {
52 #[must_use]
57 pub const fn count(&self) -> u64 {
58 self.0.len() as u64
59 }
60
61 #[must_use]
62 pub const fn is_empty(&self) -> bool {
63 self.0.is_empty()
64 }
65
66 pub fn require_one(&self) -> Result<(), InternalError> {
71 match self.count() {
72 1 => Ok(()),
73 0 => Err(ResponseError::NotFound { entity: E::PATH }.into()),
74 n => Err(ResponseError::NotUnique {
75 entity: E::PATH,
76 count: n,
77 }
78 .into()),
79 }
80 }
81
82 pub fn require_some(&self) -> Result<(), InternalError> {
83 if self.is_empty() {
84 Err(ResponseError::NotFound { entity: E::PATH }.into())
85 } else {
86 Ok(())
87 }
88 }
89
90 pub fn row(self) -> Result<Row<E>, InternalError> {
95 self.require_one()?;
96 Ok(self.0.into_iter().next().unwrap())
97 }
98
99 pub fn try_row(self) -> Result<Option<Row<E>>, InternalError> {
100 match self.count() {
101 0 => Ok(None),
102 1 => Ok(Some(self.0.into_iter().next().unwrap())),
103 n => Err(ResponseError::NotUnique {
104 entity: E::PATH,
105 count: n,
106 }
107 .into()),
108 }
109 }
110
111 #[must_use]
112 pub fn rows(self) -> Vec<Row<E>> {
113 self.0
114 }
115
116 pub fn entity(self) -> Result<E, InternalError> {
121 self.row().map(|(_, e)| e)
122 }
123
124 pub fn try_entity(self) -> Result<Option<E>, InternalError> {
125 Ok(self.try_row()?.map(|(_, e)| e))
126 }
127
128 #[must_use]
129 pub fn entities(self) -> Vec<E> {
130 self.0.into_iter().map(|(_, e)| e).collect()
131 }
132
133 #[must_use]
138 pub fn key(&self) -> Option<Key> {
139 self.0.first().map(|(k, _)| *k)
140 }
141
142 pub fn key_strict(self) -> Result<Key, InternalError> {
143 self.row().map(|(k, _)| k)
144 }
145
146 pub fn try_key(self) -> Result<Option<Key>, InternalError> {
147 Ok(self.try_row()?.map(|(k, _)| k))
148 }
149
150 #[must_use]
151 pub fn keys(&self) -> Vec<Key> {
152 self.0.iter().map(|(k, _)| *k).collect()
153 }
154
155 #[must_use]
156 pub fn contains_key(&self, key: &Key) -> bool {
157 self.0.iter().any(|(k, _)| k == key)
158 }
159
160 pub fn view(&self) -> Result<View<E>, InternalError> {
165 self.require_one()?;
166 Ok(self
167 .0
168 .first()
169 .expect("require_one guarantees a row")
170 .1
171 .to_view())
172 }
173
174 pub fn view_opt(&self) -> Result<Option<View<E>>, InternalError> {
175 match self.count() {
176 0 => Ok(None),
177 1 => Ok(Some(self.0[0].1.to_view())),
178 n => Err(ResponseError::NotUnique {
179 entity: E::PATH,
180 count: n,
181 }
182 .into()),
183 }
184 }
185
186 #[must_use]
187 pub fn views(&self) -> Vec<View<E>> {
188 self.0.iter().map(|(_, e)| e.to_view()).collect()
189 }
190
191 #[must_use]
197 pub fn first(self) -> Option<Row<E>> {
198 self.0.into_iter().next()
199 }
200
201 #[must_use]
202 pub fn first_entity(self) -> Option<E> {
203 self.first().map(|(_, e)| e)
204 }
205
206 #[must_use]
207 pub fn first_pk(self) -> Option<E::PrimaryKey> {
208 self.first_entity().map(|e| e.primary_key())
209 }
210}
211
212impl<E: EntityKind> IntoIterator for Response<E> {
213 type Item = Row<E>;
214 type IntoIter = std::vec::IntoIter<Self::Item>;
215
216 fn into_iter(self) -> Self::IntoIter {
217 self.0.into_iter()
218 }
219}