icydb_core/db/response/
mod.rs1mod grouped;
10mod paged;
11mod private;
12
13use crate::{
14 prelude::*,
15 traits::{AsView, EntityValue},
16 types::Id,
17 value::Value,
18};
19use thiserror::Error as ThisError;
20
21pub use grouped::{GroupedRow, PagedGroupedExecution, PagedGroupedExecutionWithTrace};
22pub use paged::{PagedLoadExecution, PagedLoadExecutionWithTrace};
23
24pub trait ResponseRow: private::Sealed {}
32
33impl ResponseRow for GroupedRow {}
34
35impl private::Sealed for GroupedRow {}
36
37#[derive(Clone, Debug, Eq, PartialEq)]
44pub struct Row<E: EntityKind> {
45 id: Id<E>,
46 entity: E,
47}
48
49impl<E: EntityKind> Row<E> {
50 #[must_use]
52 pub const fn new(id: Id<E>, entity: E) -> Self {
53 Self { id, entity }
54 }
55
56 #[must_use]
58 pub const fn id(&self) -> Id<E> {
59 self.id
60 }
61
62 #[must_use]
64 pub fn entity(self) -> E {
65 self.entity
66 }
67
68 #[must_use]
70 pub const fn entity_ref(&self) -> &E {
71 &self.entity
72 }
73
74 #[must_use]
76 pub fn into_parts(self) -> (Id<E>, E) {
77 (self.id, self.entity)
78 }
79}
80
81impl<E: EntityKind> From<(Id<E>, E)> for Row<E> {
82 fn from(value: (Id<E>, E)) -> Self {
83 Self::new(value.0, value.1)
84 }
85}
86
87impl<E: EntityKind> private::Sealed for Row<E> {}
88
89impl<E: EntityKind> ResponseRow for Row<E> {}
90
91#[derive(Clone, Debug, Eq, PartialEq)]
99pub struct ProjectedRow<E: EntityKind> {
100 id: Id<E>,
101 values: Vec<Value>,
102}
103
104impl<E: EntityKind> ProjectedRow<E> {
105 #[must_use]
107 pub const fn new(id: Id<E>, values: Vec<Value>) -> Self {
108 Self { id, values }
109 }
110
111 #[must_use]
113 pub const fn id(&self) -> Id<E> {
114 self.id
115 }
116
117 #[must_use]
119 pub const fn values(&self) -> &[Value] {
120 self.values.as_slice()
121 }
122
123 #[must_use]
125 pub fn into_parts(self) -> (Id<E>, Vec<Value>) {
126 (self.id, self.values)
127 }
128}
129
130impl<E: EntityKind> private::Sealed for ProjectedRow<E> {}
131
132impl<E: EntityKind> ResponseRow for ProjectedRow<E> {}
133
134#[derive(Debug, ThisError)]
139pub enum ResponseError {
140 #[error("expected exactly one row, found 0 (entity {entity})")]
141 NotFound { entity: &'static str },
142
143 #[error("expected exactly one row, found {count} (entity {entity})")]
144 NotUnique { entity: &'static str, count: u32 },
145}
146
147#[derive(Debug)]
154pub struct Response<R: ResponseRow>(Vec<R>);
155
156pub type EntityResponse<E> = Response<Row<E>>;
163
164pub type ProjectionResponse<E> = Response<ProjectedRow<E>>;
171
172impl<R: ResponseRow> Response<R> {
173 #[must_use]
175 pub const fn new(rows: Vec<R>) -> Self {
176 Self(rows)
177 }
178
179 #[must_use]
181 pub fn from_rows<T>(rows: Vec<T>) -> Self
182 where
183 T: Into<R>,
184 {
185 Self(rows.into_iter().map(Into::into).collect())
186 }
187
188 #[must_use]
190 pub const fn len(&self) -> usize {
191 self.0.len()
192 }
193
194 #[must_use]
196 #[expect(clippy::cast_possible_truncation)]
197 pub const fn count(&self) -> u32 {
198 self.0.len() as u32
199 }
200
201 #[must_use]
203 pub const fn is_empty(&self) -> bool {
204 self.0.is_empty()
205 }
206
207 #[must_use]
209 pub fn rows(self) -> Vec<R> {
210 self.0
211 }
212
213 pub fn iter(&self) -> std::slice::Iter<'_, R> {
215 self.0.iter()
216 }
217}
218
219impl<R: ResponseRow> AsRef<[R]> for Response<R> {
220 fn as_ref(&self) -> &[R] {
221 self.0.as_slice()
222 }
223}
224
225impl<R: ResponseRow> std::ops::Deref for Response<R> {
226 type Target = [R];
227
228 fn deref(&self) -> &Self::Target {
229 self.0.as_slice()
230 }
231}
232
233impl<E: EntityKind> Response<Row<E>> {
234 #[must_use]
236 pub fn id(&self) -> Option<Id<E>> {
237 self.0.first().map(Row::id)
238 }
239
240 #[must_use]
242 pub fn entities(self) -> Vec<E> {
243 self.0.into_iter().map(Row::entity).collect()
244 }
245
246 pub fn ids(&self) -> impl Iterator<Item = Id<E>> + '_ {
248 self.0.iter().map(Row::id)
249 }
250
251 pub fn contains_id(&self, id: &Id<E>) -> bool {
253 self.0.iter().any(|row| row.id() == *id)
254 }
255
256 pub fn views(&self) -> impl Iterator<Item = <E as AsView>::ViewType> + '_ {
258 self.0.iter().map(|row| row.entity_ref().as_view())
259 }
260}
261
262impl<R: ResponseRow> IntoIterator for Response<R> {
263 type Item = R;
264 type IntoIter = std::vec::IntoIter<Self::Item>;
265
266 fn into_iter(self) -> Self::IntoIter {
267 self.0.into_iter()
268 }
269}
270
271impl<'a, R: ResponseRow> IntoIterator for &'a Response<R> {
272 type Item = &'a R;
273 type IntoIter = std::slice::Iter<'a, R>;
274
275 fn into_iter(self) -> Self::IntoIter {
276 self.iter()
277 }
278}
279
280#[derive(Debug)]
288pub struct WriteBatchResponse<E> {
289 entities: Vec<E>,
290}
291
292impl<E> WriteBatchResponse<E> {
293 #[must_use]
295 pub const fn new(entities: Vec<E>) -> Self {
296 Self { entities }
297 }
298
299 #[must_use]
301 pub const fn len(&self) -> usize {
302 self.entities.len()
303 }
304
305 #[must_use]
307 pub const fn is_empty(&self) -> bool {
308 self.entities.is_empty()
309 }
310
311 #[must_use]
313 pub fn entities(self) -> Vec<E> {
314 self.entities
315 }
316
317 pub fn ids(&self) -> impl Iterator<Item = Id<E>> + '_
319 where
320 E: EntityValue,
321 {
322 self.entities.iter().map(EntityValue::id)
323 }
324
325 pub fn views(&self) -> impl Iterator<Item = <E as AsView>::ViewType> + '_
327 where
328 E: AsView,
329 {
330 self.entities.iter().map(AsView::as_view)
331 }
332
333 pub fn iter(&self) -> std::slice::Iter<'_, E> {
335 self.entities.iter()
336 }
337}
338
339impl<E> IntoIterator for WriteBatchResponse<E> {
340 type Item = E;
341 type IntoIter = std::vec::IntoIter<E>;
342
343 fn into_iter(self) -> Self::IntoIter {
344 self.entities.into_iter()
345 }
346}
347
348impl<'a, E> IntoIterator for &'a WriteBatchResponse<E> {
349 type Item = &'a E;
350 type IntoIter = std::slice::Iter<'a, E>;
351
352 fn into_iter(self) -> Self::IntoIter {
353 self.iter()
354 }
355}