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(in crate::db) use grouped::GroupedTextCursorPageWithTrace;
26pub use grouped::{GroupedRow, PagedGroupedExecution, PagedGroupedExecutionWithTrace};
27pub use paged::{PagedLoadExecution, PagedLoadExecutionWithTrace};
28
29pub trait ResponseRow: private::Sealed {}
37
38impl ResponseRow for GroupedRow {}
39
40impl private::Sealed for GroupedRow {}
41
42#[derive(Clone, Debug, Eq, PartialEq)]
49pub struct Row<E: EntityKind> {
50 id: Id<E>,
51 entity: E,
52}
53
54impl<E: EntityKind> Row<E> {
55 #[must_use]
57 pub const fn new(id: Id<E>, entity: E) -> Self {
58 Self { id, entity }
59 }
60
61 #[must_use]
63 pub const fn id(&self) -> Id<E> {
64 self.id
65 }
66
67 #[must_use]
69 pub fn entity(self) -> E {
70 self.entity
71 }
72
73 #[must_use]
75 pub const fn entity_ref(&self) -> &E {
76 &self.entity
77 }
78
79 #[must_use]
81 pub fn into_parts(self) -> (Id<E>, E) {
82 (self.id, self.entity)
83 }
84}
85
86impl<E: EntityKind> From<(Id<E>, E)> for Row<E> {
87 fn from(value: (Id<E>, E)) -> Self {
88 Self::new(value.0, value.1)
89 }
90}
91
92impl<E: EntityKind> private::Sealed for Row<E> {}
93
94impl<E: EntityKind> ResponseRow for Row<E> {}
95
96#[derive(Clone, Debug, Eq, PartialEq)]
104pub struct ProjectedRow<E: EntityKind> {
105 id: Id<E>,
106 values: Vec<Value>,
107}
108
109impl<E: EntityKind> ProjectedRow<E> {
110 #[must_use]
112 pub const fn new(id: Id<E>, values: Vec<Value>) -> Self {
113 Self { id, values }
114 }
115
116 #[must_use]
118 pub const fn id(&self) -> Id<E> {
119 self.id
120 }
121
122 #[must_use]
124 pub const fn values(&self) -> &[Value] {
125 self.values.as_slice()
126 }
127
128 #[must_use]
130 pub fn into_parts(self) -> (Id<E>, Vec<Value>) {
131 (self.id, self.values)
132 }
133}
134
135impl<E: EntityKind> private::Sealed for ProjectedRow<E> {}
136
137impl<E: EntityKind> ResponseRow for ProjectedRow<E> {}
138
139#[derive(Debug, ThisError)]
144pub enum ResponseError {
145 #[error("expected exactly one row, found 0 (entity {entity})")]
146 NotFound { entity: &'static str },
147
148 #[error("expected exactly one row, found {count} (entity {entity})")]
149 NotUnique { entity: &'static str, count: u32 },
150}
151
152impl ResponseError {
153 #[must_use]
155 pub const fn not_found(entity: &'static str) -> Self {
156 Self::NotFound { entity }
157 }
158
159 #[must_use]
161 pub const fn not_unique(entity: &'static str, count: u32) -> Self {
162 Self::NotUnique { entity, count }
163 }
164}
165
166#[derive(Debug)]
173pub struct Response<R: ResponseRow>(Vec<R>);
174
175pub type EntityResponse<E> = Response<Row<E>>;
182
183pub type ProjectionResponse<E> = Response<ProjectedRow<E>>;
190
191impl<R: ResponseRow> Response<R> {
192 #[must_use]
194 pub const fn new(rows: Vec<R>) -> Self {
195 Self(rows)
196 }
197
198 #[must_use]
200 pub fn from_rows<T>(rows: Vec<T>) -> Self
201 where
202 T: Into<R>,
203 {
204 Self(rows.into_iter().map(Into::into).collect())
205 }
206
207 #[must_use]
209 pub const fn len(&self) -> usize {
210 self.0.len()
211 }
212
213 #[must_use]
215 #[expect(clippy::cast_possible_truncation)]
216 pub const fn count(&self) -> u32 {
217 self.0.len() as u32
218 }
219
220 #[must_use]
222 pub const fn is_empty(&self) -> bool {
223 self.0.is_empty()
224 }
225
226 #[must_use]
228 pub fn rows(self) -> Vec<R> {
229 self.0
230 }
231
232 pub fn iter(&self) -> std::slice::Iter<'_, R> {
234 self.0.iter()
235 }
236}
237
238impl<R: ResponseRow> AsRef<[R]> for Response<R> {
239 fn as_ref(&self) -> &[R] {
240 self.0.as_slice()
241 }
242}
243
244impl<R: ResponseRow> std::ops::Deref for Response<R> {
245 type Target = [R];
246
247 fn deref(&self) -> &Self::Target {
248 self.0.as_slice()
249 }
250}
251
252impl<E: EntityKind> Response<Row<E>> {
253 #[must_use]
255 pub fn id(&self) -> Option<Id<E>> {
256 self.0.first().map(Row::id)
257 }
258
259 #[must_use]
261 pub fn entities(self) -> Vec<E> {
262 self.0.into_iter().map(Row::entity).collect()
263 }
264
265 pub fn ids(&self) -> impl Iterator<Item = Id<E>> + '_ {
267 self.0.iter().map(Row::id)
268 }
269
270 pub fn contains_id(&self, id: &Id<E>) -> bool {
272 self.0.iter().any(|row| row.id() == *id)
273 }
274}
275
276impl<R: ResponseRow> IntoIterator for Response<R> {
277 type Item = R;
278 type IntoIter = std::vec::IntoIter<Self::Item>;
279
280 fn into_iter(self) -> Self::IntoIter {
281 self.0.into_iter()
282 }
283}
284
285impl<'a, R: ResponseRow> IntoIterator for &'a Response<R> {
286 type Item = &'a R;
287 type IntoIter = std::slice::Iter<'a, R>;
288
289 fn into_iter(self) -> Self::IntoIter {
290 self.iter()
291 }
292}
293
294#[derive(Debug)]
302pub struct WriteBatchResponse<E> {
303 entities: Vec<E>,
304}
305
306impl<E> WriteBatchResponse<E> {
307 #[must_use]
309 pub const fn new(entities: Vec<E>) -> Self {
310 Self { entities }
311 }
312
313 #[must_use]
315 pub const fn len(&self) -> usize {
316 self.entities.len()
317 }
318
319 #[must_use]
321 pub const fn is_empty(&self) -> bool {
322 self.entities.is_empty()
323 }
324
325 #[must_use]
327 pub fn entities(self) -> Vec<E> {
328 self.entities
329 }
330
331 pub fn ids(&self) -> impl Iterator<Item = Id<E>> + '_
333 where
334 E: EntityValue,
335 {
336 self.entities.iter().map(EntityValue::id)
337 }
338
339 pub fn iter(&self) -> std::slice::Iter<'_, E> {
341 self.entities.iter()
342 }
343}
344
345impl<E> IntoIterator for WriteBatchResponse<E> {
346 type Item = E;
347 type IntoIter = std::vec::IntoIter<E>;
348
349 fn into_iter(self) -> Self::IntoIter {
350 self.entities.into_iter()
351 }
352}
353
354impl<'a, E> IntoIterator for &'a WriteBatchResponse<E> {
355 type Item = &'a E;
356 type IntoIter = std::slice::Iter<'a, E>;
357
358 fn into_iter(self) -> Self::IntoIter {
359 self.iter()
360 }
361}