icydb_core/db/response/
mod.rs

1use crate::{Error, Key, ThisError, db::DbError, traits::EntityKind};
2
3///
4/// ResponseError
5/// Errors related to interpreting a materialized response.
6///
7
8#[derive(Debug, ThisError)]
9pub enum ResponseError {
10    #[error("expected exactly one row, found 0 (entity {entity})")]
11    NotFound { entity: &'static str },
12
13    #[error("expected exactly one row, found {count} (entity {entity})")]
14    NotUnique { entity: &'static str, count: u32 },
15}
16
17impl From<ResponseError> for Error {
18    fn from(err: ResponseError) -> Self {
19        DbError::from(err).into()
20    }
21}
22
23///
24/// Response
25/// Materialized query result: ordered `(Key, Entity)` pairs.
26///
27
28#[derive(Debug)]
29pub struct Response<E: EntityKind>(pub Vec<(Key, E)>);
30
31impl<E: EntityKind> Response<E> {
32    //
33    // Cardinality
34    //
35
36    #[must_use]
37    /// Number of rows in the response, truncated to `u32`.
38    #[allow(clippy::cast_possible_truncation)]
39    pub const fn count(&self) -> u32 {
40        self.0.len() as u32
41    }
42
43    #[must_use]
44    /// True when no rows were returned.
45    pub const fn is_empty(&self) -> bool {
46        self.0.is_empty()
47    }
48
49    //
50    // Exact cardinality helpers
51    //
52
53    /// Require exactly one row.
54    pub fn one(self) -> Result<(Key, E), Error> {
55        let count = self.count();
56
57        match count {
58            0 => Err(ResponseError::NotFound { entity: E::PATH }.into()),
59            1 => Ok(self.0.into_iter().next().unwrap()),
60            _ => Err(ResponseError::NotUnique {
61                entity: E::PATH,
62                count,
63            }
64            .into()),
65        }
66    }
67
68    /// Require exactly one entity.
69    pub fn one_entity(self) -> Result<E, Error> {
70        self.one().map(|(_, e)| e)
71    }
72
73    /// Require at most one row.
74    pub fn one_opt(self) -> Result<Option<(Key, E)>, Error> {
75        let count = self.count();
76
77        match count {
78            0 => Ok(None),
79            1 => Ok(Some(self.0.into_iter().next().unwrap())),
80            _ => Err(ResponseError::NotUnique {
81                entity: E::PATH,
82                count,
83            }
84            .into()),
85        }
86    }
87
88    /// Require at most one entity.
89    pub fn one_opt_entity(self) -> Result<Option<E>, Error> {
90        Ok(self.one_opt()?.map(|(_, e)| e))
91    }
92
93    //
94    // Keys
95    //
96
97    #[must_use]
98    /// First key in the response, if present.
99    pub fn key(&self) -> Option<Key> {
100        self.0.first().map(|(key, _)| *key)
101    }
102
103    #[must_use]
104    /// Collect all keys in order.
105    pub fn keys(&self) -> Vec<Key> {
106        self.0.iter().map(|(key, _)| *key).collect()
107    }
108
109    /// Iterate keys without cloning entities.
110    pub fn keys_iter(self) -> impl Iterator<Item = Key> {
111        self.0.into_iter().map(|(key, _)| key)
112    }
113
114    /// Require exactly one row and return its key.
115    pub fn one_key(self) -> Result<Key, Error> {
116        self.one().map(|(key, _)| key)
117    }
118
119    /// Require at most one row and return its key.
120    pub fn one_opt_key(self) -> Result<Option<Key>, Error> {
121        Ok(self.one_opt()?.map(|(key, _)| key))
122    }
123
124    #[must_use]
125    pub fn contains_key(&self, key: &Key) -> bool {
126        self.0.iter().any(|(k, _)| k == key)
127    }
128
129    //
130    // Primary keys
131    //
132
133    #[must_use]
134    /// First primary key in the response, if present.
135    pub fn pk(&self) -> Option<E::PrimaryKey> {
136        self.0.first().map(|(_, e)| e.primary_key())
137    }
138
139    #[must_use]
140    /// Collect all primary keys in order.
141    pub fn pks(&self) -> Vec<E::PrimaryKey> {
142        self.0.iter().map(|(_, e)| e.primary_key()).collect()
143    }
144
145    /// Iterate primary keys without cloning entities.
146    pub fn pks_iter(self) -> impl Iterator<Item = E::PrimaryKey> {
147        self.0.into_iter().map(|(_, e)| e.primary_key())
148    }
149
150    pub fn one_pk(self) -> Result<E::PrimaryKey, Error> {
151        self.one_entity().map(|e| e.primary_key())
152    }
153
154    pub fn one_opt_pk(self) -> Result<Option<E::PrimaryKey>, Error> {
155        Ok(self.one_opt_entity()?.map(|e| e.primary_key()))
156    }
157
158    //
159    // Entities
160    //
161
162    #[must_use]
163    /// Consume the response and return the first entity, if any.
164    pub fn entity(self) -> Option<E> {
165        self.0.into_iter().next().map(|(_, e)| e)
166    }
167
168    #[must_use]
169    /// Consume the response and collect all entities.
170    pub fn entities(self) -> Vec<E> {
171        self.0.into_iter().map(|(_, e)| e).collect()
172    }
173
174    /// Iterate entities without materializing a `Vec`.
175    pub fn entities_iter(self) -> impl Iterator<Item = E> {
176        self.0.into_iter().map(|(_, e)| e)
177    }
178
179    //
180    // Views
181    //
182
183    #[must_use]
184    /// Convert the first entity to its view type, if present.
185    pub fn view(self) -> Option<E::ViewType> {
186        self.entity().map(|e| e.to_view())
187    }
188
189    /// Require exactly one view.
190    pub fn one_view(self) -> Result<E::ViewType, Error> {
191        self.one_entity().map(|e| e.to_view())
192    }
193
194    /// Require at most one view.
195    pub fn one_opt_view(self) -> Result<Option<E::ViewType>, Error> {
196        Ok(self.one_opt_entity()?.map(|e| e.to_view()))
197    }
198
199    #[must_use]
200    /// Convert all entities to their view types and collect them.
201    pub fn views(self) -> Vec<E::ViewType> {
202        self.entities().into_iter().map(|e| e.to_view()).collect()
203    }
204
205    /// Iterate over view types without cloning entities.
206    pub fn views_iter(self) -> impl Iterator<Item = E::ViewType> {
207        self.entities().into_iter().map(|e| e.to_view())
208    }
209}
210
211impl<E: EntityKind> IntoIterator for Response<E> {
212    type Item = (Key, E);
213    type IntoIter = std::vec::IntoIter<Self::Item>;
214
215    fn into_iter(self) -> Self::IntoIter {
216        self.0.into_iter()
217    }
218}