icydb_core/db/response/
mod.rs1mod grouped;
10mod paged;
11
12use crate::{prelude::*, traits::EntityValue, types::Id, value::Value};
13use thiserror::Error as ThisError;
14
15mod private {
16 pub trait Sealed {}
23}
24
25pub use grouped::{GroupedRow, PagedGroupedExecution, PagedGroupedExecutionWithTrace};
26pub use paged::{PagedLoadExecution, PagedLoadExecutionWithTrace};
27
28pub trait ResponseRow: private::Sealed {}
36
37impl ResponseRow for GroupedRow {}
38
39impl private::Sealed for GroupedRow {}
40
41#[derive(Clone, Debug, Eq, PartialEq)]
48pub struct Row<E: EntityKind> {
49 id: Id<E>,
50 entity: E,
51}
52
53impl<E: EntityKind> Row<E> {
54 #[must_use]
56 pub const fn new(id: Id<E>, entity: E) -> Self {
57 Self { id, entity }
58 }
59
60 #[must_use]
62 pub const fn id(&self) -> Id<E> {
63 self.id
64 }
65
66 #[must_use]
68 pub fn entity(self) -> E {
69 self.entity
70 }
71
72 #[must_use]
74 pub const fn entity_ref(&self) -> &E {
75 &self.entity
76 }
77
78 #[must_use]
80 pub fn into_parts(self) -> (Id<E>, E) {
81 (self.id, self.entity)
82 }
83}
84
85impl<E: EntityKind> From<(Id<E>, E)> for Row<E> {
86 fn from(value: (Id<E>, E)) -> Self {
87 Self::new(value.0, value.1)
88 }
89}
90
91impl<E: EntityKind> private::Sealed for Row<E> {}
92
93impl<E: EntityKind> ResponseRow for Row<E> {}
94
95#[derive(Clone, Debug, Eq, PartialEq)]
103pub struct ProjectedRow<E: EntityKind> {
104 id: Id<E>,
105 values: Vec<Value>,
106}
107
108impl<E: EntityKind> ProjectedRow<E> {
109 #[must_use]
111 pub const fn new(id: Id<E>, values: Vec<Value>) -> Self {
112 Self { id, values }
113 }
114
115 #[must_use]
117 pub const fn id(&self) -> Id<E> {
118 self.id
119 }
120
121 #[must_use]
123 pub const fn values(&self) -> &[Value] {
124 self.values.as_slice()
125 }
126
127 #[must_use]
129 pub fn into_parts(self) -> (Id<E>, Vec<Value>) {
130 (self.id, self.values)
131 }
132}
133
134impl<E: EntityKind> private::Sealed for ProjectedRow<E> {}
135
136impl<E: EntityKind> ResponseRow for ProjectedRow<E> {}
137
138#[derive(Debug, ThisError)]
143pub enum ResponseError {
144 #[error("expected exactly one row, found 0 (entity {entity})")]
145 NotFound { entity: &'static str },
146
147 #[error("expected exactly one row, found {count} (entity {entity})")]
148 NotUnique { entity: &'static str, count: u32 },
149}
150
151impl ResponseError {
152 #[must_use]
154 pub const fn not_found(entity: &'static str) -> Self {
155 Self::NotFound { entity }
156 }
157
158 #[must_use]
160 pub const fn not_unique(entity: &'static str, count: u32) -> Self {
161 Self::NotUnique { entity, count }
162 }
163}
164
165#[derive(Debug)]
172pub struct Response<R: ResponseRow>(Vec<R>);
173
174pub type EntityResponse<E> = Response<Row<E>>;
181
182pub type ProjectionResponse<E> = Response<ProjectedRow<E>>;
189
190impl<R: ResponseRow> Response<R> {
191 #[must_use]
193 pub const fn new(rows: Vec<R>) -> Self {
194 Self(rows)
195 }
196
197 #[must_use]
199 pub fn from_rows<T>(rows: Vec<T>) -> Self
200 where
201 T: Into<R>,
202 {
203 Self(rows.into_iter().map(Into::into).collect())
204 }
205
206 #[must_use]
208 pub const fn len(&self) -> usize {
209 self.0.len()
210 }
211
212 #[must_use]
214 #[expect(clippy::cast_possible_truncation)]
215 pub const fn count(&self) -> u32 {
216 self.0.len() as u32
217 }
218
219 #[must_use]
221 pub const fn is_empty(&self) -> bool {
222 self.0.is_empty()
223 }
224
225 #[must_use]
227 pub fn rows(self) -> Vec<R> {
228 self.0
229 }
230
231 pub fn iter(&self) -> std::slice::Iter<'_, R> {
233 self.0.iter()
234 }
235}
236
237impl<R: ResponseRow> AsRef<[R]> for Response<R> {
238 fn as_ref(&self) -> &[R] {
239 self.0.as_slice()
240 }
241}
242
243impl<R: ResponseRow> std::ops::Deref for Response<R> {
244 type Target = [R];
245
246 fn deref(&self) -> &Self::Target {
247 self.0.as_slice()
248 }
249}
250
251impl<E: EntityKind> Response<Row<E>> {
252 #[must_use]
254 pub fn id(&self) -> Option<Id<E>> {
255 self.0.first().map(Row::id)
256 }
257
258 #[must_use]
260 pub fn entities(self) -> Vec<E> {
261 self.0.into_iter().map(Row::entity).collect()
262 }
263
264 pub fn ids(&self) -> impl Iterator<Item = Id<E>> + '_ {
266 self.0.iter().map(Row::id)
267 }
268
269 pub fn contains_id(&self, id: &Id<E>) -> bool {
271 self.0.iter().any(|row| row.id() == *id)
272 }
273}
274
275impl<R: ResponseRow> IntoIterator for Response<R> {
276 type Item = R;
277 type IntoIter = std::vec::IntoIter<Self::Item>;
278
279 fn into_iter(self) -> Self::IntoIter {
280 self.0.into_iter()
281 }
282}
283
284impl<'a, R: ResponseRow> IntoIterator for &'a Response<R> {
285 type Item = &'a R;
286 type IntoIter = std::slice::Iter<'a, R>;
287
288 fn into_iter(self) -> Self::IntoIter {
289 self.iter()
290 }
291}
292
293#[derive(Debug)]
301pub struct WriteBatchResponse<E> {
302 entities: Vec<E>,
303}
304
305impl<E> WriteBatchResponse<E> {
306 #[must_use]
308 pub const fn new(entities: Vec<E>) -> Self {
309 Self { entities }
310 }
311
312 #[must_use]
314 pub const fn len(&self) -> usize {
315 self.entities.len()
316 }
317
318 #[must_use]
320 pub const fn is_empty(&self) -> bool {
321 self.entities.is_empty()
322 }
323
324 #[must_use]
326 pub fn entities(self) -> Vec<E> {
327 self.entities
328 }
329
330 pub fn ids(&self) -> impl Iterator<Item = Id<E>> + '_
332 where
333 E: EntityValue,
334 {
335 self.entities.iter().map(EntityValue::id)
336 }
337
338 pub fn iter(&self) -> std::slice::Iter<'_, E> {
340 self.entities.iter()
341 }
342}
343
344impl<E> IntoIterator for WriteBatchResponse<E> {
345 type Item = E;
346 type IntoIter = std::vec::IntoIter<E>;
347
348 fn into_iter(self) -> Self::IntoIter {
349 self.entities.into_iter()
350 }
351}
352
353impl<'a, E> IntoIterator for &'a WriteBatchResponse<E> {
354 type Item = &'a E;
355 type IntoIter = std::slice::Iter<'a, E>;
356
357 fn into_iter(self) -> Self::IntoIter {
358 self.iter()
359 }
360}