icydb_core/db/response/
mod.rs

1mod ext;
2
3pub use ext::*;
4
5use crate::{Error, Key, ThisError, db::DbError, traits::EntityKind};
6
7///
8/// ResponseError
9/// Errors related to interpreting a materialized response.
10///
11
12#[derive(Debug, ThisError)]
13pub enum ResponseError {
14    #[error("expected exactly one row, found 0 (entity {entity})")]
15    NotFound { entity: &'static str },
16
17    #[error("expected exactly one row, found {count} (entity {entity})")]
18    NotUnique { entity: &'static str, count: u32 },
19}
20
21impl From<ResponseError> for Error {
22    fn from(err: ResponseError) -> Self {
23        DbError::from(err).into()
24    }
25}
26
27///
28/// Response
29/// Materialized query result: ordered `(Key, Entity)` pairs.
30///
31
32#[derive(Debug)]
33pub struct Response<E: EntityKind>(pub Vec<(Key, E)>);
34
35impl<E: EntityKind> Response<E> {
36    // ======================================================================
37    // Cardinality (introspection only)
38    // ======================================================================
39
40    /// Number of rows in the response, truncated to `u32`.
41    #[must_use]
42    #[allow(clippy::cast_possible_truncation)]
43    pub const fn count(&self) -> u32 {
44        self.0.len() as u32
45    }
46
47    /// True when no rows were returned.
48    #[must_use]
49    pub const fn is_empty(&self) -> bool {
50        self.0.is_empty()
51    }
52
53    // ======================================================================
54    // Cardinality guards (non-consuming)
55    // ======================================================================
56
57    /// Require exactly one row.
58    pub fn require_one(&self) -> Result<(), Error> {
59        match self.count() {
60            1 => Ok(()),
61            0 => Err(ResponseError::NotFound { entity: E::PATH }.into()),
62            n => Err(ResponseError::NotUnique {
63                entity: E::PATH,
64                count: n,
65            }
66            .into()),
67        }
68    }
69
70    /// Require at least one row.
71    pub fn require_some(&self) -> Result<(), Error> {
72        match self.count() {
73            0 => Err(ResponseError::NotFound { entity: E::PATH }.into()),
74            _ => Ok(()),
75        }
76    }
77
78    /// Require exactly `expected` rows.
79    pub fn require_len(&self, expected: u32) -> Result<(), Error> {
80        let actual = self.count();
81        if actual == expected {
82            Ok(())
83        } else if actual == 0 {
84            Err(ResponseError::NotFound { entity: E::PATH }.into())
85        } else {
86            Err(ResponseError::NotUnique {
87                entity: E::PATH,
88                count: actual,
89            }
90            .into())
91        }
92    }
93
94    // ======================================================================
95    // Row extractors (consume self)
96    // ======================================================================
97
98    /// Require exactly one row and return it.
99    pub fn one(self) -> Result<(Key, E), Error> {
100        self.require_one()?;
101        Ok(self.0.into_iter().next().unwrap())
102    }
103
104    /// Require at most one row and return it.
105    pub fn one_opt(self) -> Result<Option<(Key, E)>, Error> {
106        match self.count() {
107            0 => Ok(None),
108            1 => Ok(Some(self.0.into_iter().next().unwrap())),
109            n => Err(ResponseError::NotUnique {
110                entity: E::PATH,
111                count: n,
112            }
113            .into()),
114        }
115    }
116
117    // ======================================================================
118    // Key extractors
119    // ======================================================================
120
121    /// First key in the response, if present.
122    #[must_use]
123    pub fn key(&self) -> Option<Key> {
124        self.0.first().map(|(k, _)| *k)
125    }
126
127    /// Collect all keys in order.
128    #[must_use]
129    pub fn keys(&self) -> Vec<Key> {
130        self.0.iter().map(|(k, _)| *k).collect()
131    }
132
133    /// Require exactly one row and return its key.
134    pub fn one_key(self) -> Result<Key, Error> {
135        self.one().map(|(k, _)| k)
136    }
137
138    /// Require at most one row and return its key.
139    pub fn one_opt_key(self) -> Result<Option<Key>, Error> {
140        Ok(self.one_opt()?.map(|(k, _)| k))
141    }
142
143    #[must_use]
144    pub fn contains_key(&self, key: &Key) -> bool {
145        self.0.iter().any(|(k, _)| k == key)
146    }
147
148    // ======================================================================
149    // Entity extractors
150    // ======================================================================
151
152    /// Consume the response and return the first entity, if any.
153    #[must_use]
154    pub fn entity(self) -> Option<E> {
155        self.0.into_iter().next().map(|(_, e)| e)
156    }
157
158    /// Consume the response and collect all entities.
159    #[must_use]
160    pub fn entities(self) -> Vec<E> {
161        self.0.into_iter().map(|(_, e)| e).collect()
162    }
163
164    /// Require exactly one entity.
165    pub fn one_entity(self) -> Result<E, Error> {
166        self.one().map(|(_, e)| e)
167    }
168
169    /// Require at most one entity.
170    pub fn one_opt_entity(self) -> Result<Option<E>, Error> {
171        Ok(self.one_opt()?.map(|(_, e)| e))
172    }
173
174    // ======================================================================
175    // Primary key extractors
176    // ======================================================================
177
178    /// First primary key in the response, if present.
179    #[must_use]
180    pub fn pk(&self) -> Option<E::PrimaryKey> {
181        self.0.first().map(|(_, e)| e.primary_key())
182    }
183
184    /// Collect all primary keys in order.
185    #[must_use]
186    pub fn pks(&self) -> Vec<E::PrimaryKey> {
187        self.0.iter().map(|(_, e)| e.primary_key()).collect()
188    }
189
190    /// Require exactly one primary key.
191    pub fn one_pk(self) -> Result<E::PrimaryKey, Error> {
192        self.one_entity().map(|e| e.primary_key())
193    }
194
195    /// Require at most one primary key.
196    pub fn one_opt_pk(self) -> Result<Option<E::PrimaryKey>, Error> {
197        Ok(self.one_opt_entity()?.map(|e| e.primary_key()))
198    }
199
200    // ======================================================================
201    // View extractors
202    // ======================================================================
203
204    /// Convert the first entity to its view type, if present.
205    #[must_use]
206    pub fn view(self) -> Option<E::ViewType> {
207        self.entity().map(|e| e.to_view())
208    }
209
210    /// Require exactly one view.
211    pub fn one_view(self) -> Result<E::ViewType, Error> {
212        self.one_entity().map(|e| e.to_view())
213    }
214
215    /// Require at most one view.
216    pub fn one_opt_view(self) -> Result<Option<E::ViewType>, Error> {
217        Ok(self.one_opt_entity()?.map(|e| e.to_view()))
218    }
219
220    /// Convert all entities to their view types.
221    #[must_use]
222    pub fn views(self) -> Vec<E::ViewType> {
223        self.entities().into_iter().map(|e| e.to_view()).collect()
224    }
225
226    // ======================================================================
227    // Arbitrary row access (no cardinality guarantees)
228    // ======================================================================
229
230    /// Return the first row in the response, if any.
231    ///
232    /// This does NOT enforce cardinality. Use only when row order is
233    /// well-defined and uniqueness is irrelevant.
234    #[must_use]
235    pub fn first(self) -> Option<(Key, E)> {
236        self.0.into_iter().next()
237    }
238
239    /// Return the first entity in the response, if any.
240    ///
241    /// This does NOT enforce cardinality. Use only when row order is
242    /// well-defined and uniqueness is irrelevant.
243    #[must_use]
244    pub fn first_entity(self) -> Option<E> {
245        self.first().map(|(_, e)| e)
246    }
247
248    /// Return the first primary key in the response, if any.
249    ///
250    /// This does NOT enforce cardinality.
251    #[must_use]
252    pub fn first_pk(self) -> Option<E::PrimaryKey> {
253        self.first_entity().map(|e| e.primary_key())
254    }
255}
256
257impl<E: EntityKind> IntoIterator for Response<E> {
258    type Item = (Key, E);
259    type IntoIter = std::vec::IntoIter<Self::Item>;
260
261    fn into_iter(self) -> Self::IntoIter {
262        self.0.into_iter()
263    }
264}