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 use grouped::{GroupedRow, PagedGroupedExecution, PagedGroupedExecutionWithTrace};
28pub use paged::{PagedLoadExecution, PagedLoadExecutionWithTrace};
29
30pub trait ResponseRow: private::Sealed {}
38
39impl ResponseRow for GroupedRow {}
40
41impl private::Sealed for GroupedRow {}
42
43#[derive(Clone, Debug, Eq, PartialEq)]
50pub struct Row<E: EntityKind> {
51 id: Id<E>,
52 entity: E,
53}
54
55impl<E: EntityKind> Row<E> {
56 #[must_use]
58 pub const fn new(id: Id<E>, entity: E) -> Self {
59 Self { id, entity }
60 }
61
62 #[must_use]
64 pub const fn id(&self) -> Id<E> {
65 self.id
66 }
67
68 #[must_use]
70 pub fn entity(self) -> E {
71 self.entity
72 }
73
74 #[must_use]
76 pub const fn entity_ref(&self) -> &E {
77 &self.entity
78 }
79
80 #[must_use]
82 pub fn into_parts(self) -> (Id<E>, E) {
83 (self.id, self.entity)
84 }
85}
86
87impl<E: EntityKind> From<(Id<E>, E)> for Row<E> {
88 fn from(value: (Id<E>, E)) -> Self {
89 Self::new(value.0, value.1)
90 }
91}
92
93impl<E: EntityKind> private::Sealed for Row<E> {}
94
95impl<E: EntityKind> ResponseRow for Row<E> {}
96
97#[derive(Clone, Debug, Eq, PartialEq)]
105pub struct ProjectedRow<E: EntityKind> {
106 id: Id<E>,
107 values: Vec<OutputValue>,
108}
109
110impl<E: EntityKind> ProjectedRow<E> {
111 #[must_use]
113 pub const fn new(id: Id<E>, values: Vec<OutputValue>) -> Self {
114 Self { id, values }
115 }
116
117 #[cfg(test)]
119 #[must_use]
120 pub(in crate::db) fn from_runtime_values(id: Id<E>, values: Vec<Value>) -> Self {
121 Self::new(id, values.into_iter().map(OutputValue::from).collect())
122 }
123
124 #[must_use]
126 pub const fn id(&self) -> Id<E> {
127 self.id
128 }
129
130 #[must_use]
132 pub const fn values(&self) -> &[OutputValue] {
133 self.values.as_slice()
134 }
135
136 #[must_use]
138 pub fn into_parts(self) -> (Id<E>, Vec<OutputValue>) {
139 (self.id, self.values)
140 }
141}
142
143impl<E: EntityKind> private::Sealed for ProjectedRow<E> {}
144
145impl<E: EntityKind> ResponseRow for ProjectedRow<E> {}
146
147#[derive(Debug, ThisError)]
152pub enum ResponseError {
153 #[error("expected exactly one row, found 0 (entity {entity})")]
154 NotFound { entity: &'static str },
155
156 #[error("expected exactly one row, found {count} (entity {entity})")]
157 NotUnique { entity: &'static str, count: u32 },
158}
159
160impl ResponseError {
161 #[must_use]
163 pub const fn not_found(entity: &'static str) -> Self {
164 Self::NotFound { entity }
165 }
166
167 #[must_use]
169 pub const fn not_unique(entity: &'static str, count: u32) -> Self {
170 Self::NotUnique { entity, count }
171 }
172}
173
174#[derive(Debug)]
181pub struct Response<R: ResponseRow>(Vec<R>);
182
183pub type EntityResponse<E> = Response<Row<E>>;
190
191pub type ProjectionResponse<E> = Response<ProjectedRow<E>>;
198
199impl<R: ResponseRow> Response<R> {
200 #[must_use]
202 pub const fn new(rows: Vec<R>) -> Self {
203 Self(rows)
204 }
205
206 #[must_use]
208 pub fn from_rows<T>(rows: Vec<T>) -> Self
209 where
210 T: Into<R>,
211 {
212 Self(rows.into_iter().map(Into::into).collect())
213 }
214
215 #[must_use]
217 pub const fn len(&self) -> usize {
218 self.0.len()
219 }
220
221 #[must_use]
223 #[expect(clippy::cast_possible_truncation)]
224 pub const fn count(&self) -> u32 {
225 self.0.len() as u32
226 }
227
228 #[must_use]
230 pub const fn is_empty(&self) -> bool {
231 self.0.is_empty()
232 }
233
234 #[must_use]
236 pub fn rows(self) -> Vec<R> {
237 self.0
238 }
239
240 pub fn iter(&self) -> std::slice::Iter<'_, R> {
242 self.0.iter()
243 }
244}
245
246impl<R: ResponseRow> AsRef<[R]> for Response<R> {
247 fn as_ref(&self) -> &[R] {
248 self.0.as_slice()
249 }
250}
251
252impl<R: ResponseRow> std::ops::Deref for Response<R> {
253 type Target = [R];
254
255 fn deref(&self) -> &Self::Target {
256 self.0.as_slice()
257 }
258}
259
260impl<E: EntityKind> Response<Row<E>> {
261 #[must_use]
263 pub fn id(&self) -> Option<Id<E>> {
264 self.0.first().map(Row::id)
265 }
266
267 #[must_use]
269 pub fn entities(self) -> Vec<E> {
270 self.0.into_iter().map(Row::entity).collect()
271 }
272
273 pub fn ids(&self) -> impl Iterator<Item = Id<E>> + '_ {
275 self.0.iter().map(Row::id)
276 }
277
278 pub fn contains_id(&self, id: &Id<E>) -> bool {
280 self.0.iter().any(|row| row.id() == *id)
281 }
282}
283
284impl<R: ResponseRow> IntoIterator for Response<R> {
285 type Item = R;
286 type IntoIter = std::vec::IntoIter<Self::Item>;
287
288 fn into_iter(self) -> Self::IntoIter {
289 self.0.into_iter()
290 }
291}
292
293impl<'a, R: ResponseRow> IntoIterator for &'a Response<R> {
294 type Item = &'a R;
295 type IntoIter = std::slice::Iter<'a, R>;
296
297 fn into_iter(self) -> Self::IntoIter {
298 self.iter()
299 }
300}
301
302#[derive(Debug)]
310pub struct WriteBatchResponse<E> {
311 entities: Vec<E>,
312}
313
314impl<E> WriteBatchResponse<E> {
315 #[must_use]
317 pub const fn new(entities: Vec<E>) -> Self {
318 Self { entities }
319 }
320
321 #[must_use]
323 pub const fn len(&self) -> usize {
324 self.entities.len()
325 }
326
327 #[must_use]
329 pub const fn is_empty(&self) -> bool {
330 self.entities.is_empty()
331 }
332
333 #[must_use]
335 pub fn entities(self) -> Vec<E> {
336 self.entities
337 }
338
339 pub fn ids(&self) -> impl Iterator<Item = Id<E>> + '_
341 where
342 E: EntityValue,
343 {
344 self.entities.iter().map(EntityValue::id)
345 }
346
347 pub fn iter(&self) -> std::slice::Iter<'_, E> {
349 self.entities.iter()
350 }
351}
352
353impl<E> IntoIterator for WriteBatchResponse<E> {
354 type Item = E;
355 type IntoIter = std::vec::IntoIter<E>;
356
357 fn into_iter(self) -> Self::IntoIter {
358 self.entities.into_iter()
359 }
360}
361
362impl<'a, E> IntoIterator for &'a WriteBatchResponse<E> {
363 type Item = &'a E;
364 type IntoIter = std::slice::Iter<'a, E>;
365
366 fn into_iter(self) -> Self::IntoIter {
367 self.iter()
368 }
369}