icydb_core/db/response/
mod.rs1mod grouped;
10mod paged;
11
12#[cfg(test)]
13use crate::value::Value;
14use crate::{prelude::*, traits::EntityValue, types::Id, value::OutputValue};
15use thiserror::Error as ThisError;
16
17mod private {
18 pub trait Sealed {}
25}
26
27pub(in crate::db) use grouped::RuntimeGroupedRow;
28pub use grouped::{GroupedRow, PagedGroupedExecution, PagedGroupedExecutionWithTrace};
29pub use paged::{PagedLoadExecution, PagedLoadExecutionWithTrace};
30
31pub trait ResponseRow: private::Sealed {}
39
40impl ResponseRow for GroupedRow {}
41
42impl private::Sealed for GroupedRow {}
43
44#[derive(Clone, Debug, Eq, PartialEq)]
51pub struct Row<E: EntityKind> {
52 id: Id<E>,
53 entity: E,
54}
55
56impl<E: EntityKind> Row<E> {
57 #[must_use]
59 pub const fn new(id: Id<E>, entity: E) -> Self {
60 Self { id, entity }
61 }
62
63 #[must_use]
65 pub const fn id(&self) -> Id<E> {
66 self.id
67 }
68
69 #[must_use]
71 pub fn entity(self) -> E {
72 self.entity
73 }
74
75 #[must_use]
77 pub const fn entity_ref(&self) -> &E {
78 &self.entity
79 }
80
81 #[must_use]
83 pub fn into_parts(self) -> (Id<E>, E) {
84 (self.id, self.entity)
85 }
86}
87
88impl<E: EntityKind> From<(Id<E>, E)> for Row<E> {
89 fn from(value: (Id<E>, E)) -> Self {
90 Self::new(value.0, value.1)
91 }
92}
93
94impl<E: EntityKind> private::Sealed for Row<E> {}
95
96impl<E: EntityKind> ResponseRow for Row<E> {}
97
98#[derive(Clone, Debug, Eq, PartialEq)]
106pub struct ProjectedRow<E: EntityKind> {
107 id: Id<E>,
108 values: Vec<OutputValue>,
109}
110
111impl<E: EntityKind> ProjectedRow<E> {
112 #[must_use]
114 pub const fn new(id: Id<E>, values: Vec<OutputValue>) -> Self {
115 Self { id, values }
116 }
117
118 #[cfg(test)]
120 #[must_use]
121 pub(in crate::db) fn from_runtime_values(id: Id<E>, values: Vec<Value>) -> Self {
122 Self::new(id, values.into_iter().map(OutputValue::from).collect())
123 }
124
125 #[must_use]
127 pub const fn id(&self) -> Id<E> {
128 self.id
129 }
130
131 #[must_use]
133 pub const fn values(&self) -> &[OutputValue] {
134 self.values.as_slice()
135 }
136
137 #[must_use]
139 pub fn into_parts(self) -> (Id<E>, Vec<OutputValue>) {
140 (self.id, self.values)
141 }
142}
143
144impl<E: EntityKind> private::Sealed for ProjectedRow<E> {}
145
146impl<E: EntityKind> ResponseRow for ProjectedRow<E> {}
147
148#[derive(Debug, ThisError)]
153pub enum ResponseError {
154 #[error("expected exactly one row, found 0 (entity {entity})")]
155 NotFound { entity: &'static str },
156
157 #[error("expected exactly one row, found {count} (entity {entity})")]
158 NotUnique { entity: &'static str, count: u32 },
159}
160
161impl ResponseError {
162 #[must_use]
164 pub const fn not_found(entity: &'static str) -> Self {
165 Self::NotFound { entity }
166 }
167
168 #[must_use]
170 pub const fn not_unique(entity: &'static str, count: u32) -> Self {
171 Self::NotUnique { entity, count }
172 }
173}
174
175#[derive(Debug)]
182pub struct Response<R: ResponseRow>(Vec<R>);
183
184pub type EntityResponse<E> = Response<Row<E>>;
191
192pub type ProjectionResponse<E> = Response<ProjectedRow<E>>;
199
200impl<R: ResponseRow> Response<R> {
201 #[must_use]
203 pub const fn new(rows: Vec<R>) -> Self {
204 Self(rows)
205 }
206
207 #[must_use]
209 pub fn from_rows<T>(rows: Vec<T>) -> Self
210 where
211 T: Into<R>,
212 {
213 Self(rows.into_iter().map(Into::into).collect())
214 }
215
216 #[must_use]
218 pub const fn len(&self) -> usize {
219 self.0.len()
220 }
221
222 #[must_use]
224 #[expect(clippy::cast_possible_truncation)]
225 pub const fn count(&self) -> u32 {
226 self.0.len() as u32
227 }
228
229 #[must_use]
231 pub const fn is_empty(&self) -> bool {
232 self.0.is_empty()
233 }
234
235 #[must_use]
237 pub fn rows(self) -> Vec<R> {
238 self.0
239 }
240
241 pub fn iter(&self) -> std::slice::Iter<'_, R> {
243 self.0.iter()
244 }
245}
246
247impl<R: ResponseRow> AsRef<[R]> for Response<R> {
248 fn as_ref(&self) -> &[R] {
249 self.0.as_slice()
250 }
251}
252
253impl<R: ResponseRow> std::ops::Deref for Response<R> {
254 type Target = [R];
255
256 fn deref(&self) -> &Self::Target {
257 self.0.as_slice()
258 }
259}
260
261impl<E: EntityKind> Response<Row<E>> {
262 #[must_use]
264 pub fn id(&self) -> Option<Id<E>> {
265 self.0.first().map(Row::id)
266 }
267
268 #[must_use]
270 pub fn entities(self) -> Vec<E> {
271 self.0.into_iter().map(Row::entity).collect()
272 }
273
274 pub fn ids(&self) -> impl Iterator<Item = Id<E>> + '_ {
276 self.0.iter().map(Row::id)
277 }
278
279 pub fn contains_id(&self, id: &Id<E>) -> bool {
281 self.0.iter().any(|row| row.id() == *id)
282 }
283}
284
285impl<R: ResponseRow> IntoIterator for Response<R> {
286 type Item = R;
287 type IntoIter = std::vec::IntoIter<Self::Item>;
288
289 fn into_iter(self) -> Self::IntoIter {
290 self.0.into_iter()
291 }
292}
293
294impl<'a, R: ResponseRow> IntoIterator for &'a Response<R> {
295 type Item = &'a R;
296 type IntoIter = std::slice::Iter<'a, R>;
297
298 fn into_iter(self) -> Self::IntoIter {
299 self.iter()
300 }
301}
302
303#[derive(Debug)]
311pub struct WriteBatchResponse<E> {
312 entities: Vec<E>,
313}
314
315impl<E> WriteBatchResponse<E> {
316 #[must_use]
318 pub const fn new(entities: Vec<E>) -> Self {
319 Self { entities }
320 }
321
322 #[must_use]
324 pub const fn len(&self) -> usize {
325 self.entities.len()
326 }
327
328 #[must_use]
330 pub const fn is_empty(&self) -> bool {
331 self.entities.is_empty()
332 }
333
334 #[must_use]
336 pub fn entities(self) -> Vec<E> {
337 self.entities
338 }
339
340 pub fn ids(&self) -> impl Iterator<Item = Id<E>> + '_
342 where
343 E: EntityValue,
344 {
345 self.entities.iter().map(EntityValue::id)
346 }
347
348 pub fn iter(&self) -> std::slice::Iter<'_, E> {
350 self.entities.iter()
351 }
352}
353
354impl<E> IntoIterator for WriteBatchResponse<E> {
355 type Item = E;
356 type IntoIter = std::vec::IntoIter<E>;
357
358 fn into_iter(self) -> Self::IntoIter {
359 self.entities.into_iter()
360 }
361}
362
363impl<'a, E> IntoIterator for &'a WriteBatchResponse<E> {
364 type Item = &'a E;
365 type IntoIter = std::slice::Iter<'a, E>;
366
367 fn into_iter(self) -> Self::IntoIter {
368 self.iter()
369 }
370}