icydb_core/db/response/
mod.rs1mod grouped;
10mod paged;
11
12mod private {
18 pub trait Sealed {}
19}
20
21use crate::{
22 prelude::*,
23 traits::{AsView, EntityValue},
24 types::Id,
25 value::Value,
26};
27use thiserror::Error as ThisError;
28
29pub use grouped::{GroupedRow, PagedGroupedExecution, PagedGroupedExecutionWithTrace};
30pub use paged::{PagedLoadExecution, PagedLoadExecutionWithTrace};
31
32pub trait ResponseRow: private::Sealed {}
40
41impl ResponseRow for GroupedRow {}
42
43impl private::Sealed for GroupedRow {}
44
45#[derive(Clone, Debug, Eq, PartialEq)]
52pub struct Row<E: EntityKind> {
53 id: Id<E>,
54 entity: E,
55}
56
57impl<E: EntityKind> Row<E> {
58 #[must_use]
60 #[inline]
61 pub const fn new(id: Id<E>, entity: E) -> Self {
62 Self { id, entity }
63 }
64
65 #[must_use]
67 #[inline]
68 pub const fn id(&self) -> Id<E> {
69 self.id
70 }
71
72 #[must_use]
74 #[inline]
75 pub fn entity(self) -> E {
76 self.entity
77 }
78
79 #[must_use]
81 #[inline]
82 pub const fn entity_ref(&self) -> &E {
83 &self.entity
84 }
85
86 #[must_use]
88 #[inline]
89 pub fn into_parts(self) -> (Id<E>, E) {
90 (self.id, self.entity)
91 }
92}
93
94impl<E: EntityKind> From<(Id<E>, E)> for Row<E> {
95 fn from(value: (Id<E>, E)) -> Self {
96 Self::new(value.0, value.1)
97 }
98}
99
100impl<E: EntityKind> private::Sealed for Row<E> {}
101
102impl<E: EntityKind> ResponseRow for Row<E> {}
103
104#[derive(Clone, Debug, Eq, PartialEq)]
112pub struct ProjectedRow<E: EntityKind> {
113 id: Id<E>,
114 values: Vec<Value>,
115}
116
117impl<E: EntityKind> ProjectedRow<E> {
118 #[must_use]
120 #[inline]
121 pub const fn new(id: Id<E>, values: Vec<Value>) -> Self {
122 Self { id, values }
123 }
124
125 #[must_use]
127 #[inline]
128 pub const fn id(&self) -> Id<E> {
129 self.id
130 }
131
132 #[must_use]
134 #[inline]
135 pub const fn values(&self) -> &[Value] {
136 self.values.as_slice()
137 }
138
139 #[must_use]
141 #[inline]
142 pub fn into_parts(self) -> (Id<E>, Vec<Value>) {
143 (self.id, self.values)
144 }
145}
146
147impl<E: EntityKind> private::Sealed for ProjectedRow<E> {}
148
149impl<E: EntityKind> ResponseRow for ProjectedRow<E> {}
150
151#[derive(Debug, ThisError)]
156pub enum ResponseError {
157 #[error("expected exactly one row, found 0 (entity {entity})")]
158 NotFound { entity: &'static str },
159
160 #[error("expected exactly one row, found {count} (entity {entity})")]
161 NotUnique { entity: &'static str, count: u32 },
162}
163
164#[derive(Debug)]
171pub struct Response<R: ResponseRow>(Vec<R>);
172
173pub type EntityResponse<E> = Response<Row<E>>;
180
181pub type ProjectionResponse<E> = Response<ProjectedRow<E>>;
188
189impl<R: ResponseRow> Response<R> {
190 #[must_use]
192 pub const fn new(rows: Vec<R>) -> Self {
193 Self(rows)
194 }
195
196 #[must_use]
198 pub fn from_rows<T>(rows: Vec<T>) -> Self
199 where
200 T: Into<R>,
201 {
202 Self(rows.into_iter().map(Into::into).collect())
203 }
204
205 #[must_use]
207 pub const fn len(&self) -> usize {
208 self.0.len()
209 }
210
211 #[must_use]
213 #[expect(clippy::cast_possible_truncation)]
214 pub const fn count(&self) -> u32 {
215 self.0.len() as u32
216 }
217
218 #[must_use]
220 pub const fn is_empty(&self) -> bool {
221 self.0.is_empty()
222 }
223
224 #[must_use]
226 pub fn rows(self) -> Vec<R> {
227 self.0
228 }
229
230 pub fn iter(&self) -> std::slice::Iter<'_, R> {
232 self.0.iter()
233 }
234}
235
236impl<R: ResponseRow> AsRef<[R]> for Response<R> {
237 fn as_ref(&self) -> &[R] {
238 self.0.as_slice()
239 }
240}
241
242impl<R: ResponseRow> std::ops::Deref for Response<R> {
243 type Target = [R];
244
245 fn deref(&self) -> &Self::Target {
246 self.0.as_slice()
247 }
248}
249
250impl<E: EntityKind> Response<Row<E>> {
251 #[must_use]
253 pub fn id(&self) -> Option<Id<E>> {
254 self.0.first().map(Row::id)
255 }
256
257 #[must_use]
259 pub fn entities(self) -> Vec<E> {
260 self.0.into_iter().map(Row::entity).collect()
261 }
262
263 pub fn ids(&self) -> impl Iterator<Item = Id<E>> + '_ {
265 self.0.iter().map(Row::id)
266 }
267
268 pub fn contains_id(&self, id: &Id<E>) -> bool {
270 self.0.iter().any(|row| row.id() == *id)
271 }
272
273 pub fn views(&self) -> impl Iterator<Item = <E as AsView>::ViewType> + '_ {
275 self.0.iter().map(|row| row.entity_ref().as_view())
276 }
277}
278
279impl<R: ResponseRow> IntoIterator for Response<R> {
280 type Item = R;
281 type IntoIter = std::vec::IntoIter<Self::Item>;
282
283 fn into_iter(self) -> Self::IntoIter {
284 self.0.into_iter()
285 }
286}
287
288impl<'a, R: ResponseRow> IntoIterator for &'a Response<R> {
289 type Item = &'a R;
290 type IntoIter = std::slice::Iter<'a, R>;
291
292 fn into_iter(self) -> Self::IntoIter {
293 self.iter()
294 }
295}
296
297#[derive(Debug)]
305pub struct WriteBatchResponse<E> {
306 entities: Vec<E>,
307}
308
309impl<E> WriteBatchResponse<E> {
310 #[must_use]
312 pub const fn new(entities: Vec<E>) -> Self {
313 Self { entities }
314 }
315
316 #[must_use]
318 pub const fn len(&self) -> usize {
319 self.entities.len()
320 }
321
322 #[must_use]
324 pub const fn is_empty(&self) -> bool {
325 self.entities.is_empty()
326 }
327
328 #[must_use]
330 pub fn entities(self) -> Vec<E> {
331 self.entities
332 }
333
334 pub fn ids(&self) -> impl Iterator<Item = Id<E>> + '_
336 where
337 E: EntityValue,
338 {
339 self.entities.iter().map(EntityValue::id)
340 }
341
342 pub fn views(&self) -> impl Iterator<Item = <E as AsView>::ViewType> + '_
344 where
345 E: AsView,
346 {
347 self.entities.iter().map(AsView::as_view)
348 }
349
350 pub fn iter(&self) -> std::slice::Iter<'_, E> {
352 self.entities.iter()
353 }
354}
355
356impl<E> IntoIterator for WriteBatchResponse<E> {
357 type Item = E;
358 type IntoIter = std::vec::IntoIter<E>;
359
360 fn into_iter(self) -> Self::IntoIter {
361 self.entities.into_iter()
362 }
363}
364
365impl<'a, E> IntoIterator for &'a WriteBatchResponse<E> {
366 type Item = &'a E;
367 type IntoIter = std::slice::Iter<'a, E>;
368
369 fn into_iter(self) -> Self::IntoIter {
370 self.iter()
371 }
372}