icydb_core/db/response/
mod.rs1mod paged;
6
7use crate::{
8 prelude::*,
9 traits::{AsView, EntityValue},
10 types::Id,
11 value::Value,
12};
13use thiserror::Error as ThisError;
14
15pub use paged::{PagedLoadExecution, PagedLoadExecutionWithTrace};
17
18pub type Row<E> = (Id<E>, E);
23
24#[derive(Clone, Debug, Eq, PartialEq)]
32pub struct ProjectedRow<E: EntityKind> {
33 id: Id<E>,
34 values: Vec<Value>,
35}
36
37impl<E: EntityKind> ProjectedRow<E> {
38 #[must_use]
40 pub const fn new(id: Id<E>, values: Vec<Value>) -> Self {
41 Self { id, values }
42 }
43
44 #[must_use]
46 pub const fn id(&self) -> Id<E> {
47 self.id
48 }
49
50 #[must_use]
52 pub const fn values(&self) -> &[Value] {
53 self.values.as_slice()
54 }
55
56 #[must_use]
58 pub fn into_parts(self) -> (Id<E>, Vec<Value>) {
59 (self.id, self.values)
60 }
61}
62
63#[derive(Debug, ThisError)]
68pub enum ResponseError {
69 #[error("expected exactly one row, found 0 (entity {entity})")]
70 NotFound { entity: &'static str },
71
72 #[error("expected exactly one row, found {count} (entity {entity})")]
73 NotUnique { entity: &'static str, count: u32 },
74}
75
76impl ResponseError {
77 const fn not_found<E: EntityKind>() -> Self {
78 Self::NotFound { entity: E::PATH }
79 }
80
81 const fn not_unique<E: EntityKind>(count: u32) -> Self {
82 Self::NotUnique {
83 entity: E::PATH,
84 count,
85 }
86 }
87}
88
89#[derive(Debug)]
100pub struct Response<E: EntityKind>(pub Vec<Row<E>>, Option<Vec<ProjectedRow<E>>>);
101
102impl<E: EntityKind> Response<E> {
103 #[must_use]
105 pub const fn from_rows(rows: Vec<Row<E>>) -> Self {
106 Self(rows, None)
107 }
108
109 #[must_use]
111 pub const fn from_rows_with_projection(
112 rows: Vec<Row<E>>,
113 projected_rows: Option<Vec<ProjectedRow<E>>>,
114 ) -> Self {
115 Self(rows, projected_rows)
116 }
117
118 #[must_use]
120 pub fn projected_rows(&self) -> Option<&[ProjectedRow<E>]> {
121 self.1.as_deref()
122 }
123
124 #[must_use]
126 pub fn into_projected_rows(self) -> Option<Vec<ProjectedRow<E>>> {
127 self.1
128 }
129
130 #[must_use]
136 #[expect(clippy::cast_possible_truncation)]
137 pub const fn count(&self) -> u32 {
138 self.0.len() as u32
139 }
140
141 #[must_use]
143 pub const fn is_empty(&self) -> bool {
144 self.0.is_empty()
145 }
146
147 pub const fn require_one(&self) -> Result<(), ResponseError> {
153 match self.count() {
154 1 => Ok(()),
155 0 => Err(ResponseError::not_found::<E>()),
156 n => Err(ResponseError::not_unique::<E>(n)),
157 }
158 }
159
160 pub const fn require_some(&self) -> Result<(), ResponseError> {
162 if self.is_empty() {
163 Err(ResponseError::not_found::<E>())
164 } else {
165 Ok(())
166 }
167 }
168
169 #[expect(clippy::cast_possible_truncation)]
175 pub fn try_row(self) -> Result<Option<Row<E>>, ResponseError> {
176 match self.0.len() {
177 0 => Ok(None),
178 1 => Ok(Some(self.0.into_iter().next().unwrap())),
179 n => Err(ResponseError::not_unique::<E>(n as u32)),
180 }
181 }
182
183 pub fn row(self) -> Result<Row<E>, ResponseError> {
185 self.try_row()?.ok_or_else(ResponseError::not_found::<E>)
186 }
187
188 #[must_use]
190 pub fn rows(self) -> Vec<Row<E>> {
191 self.0
192 }
193
194 pub fn try_entity(self) -> Result<Option<E>, ResponseError> {
200 Ok(self.try_row()?.map(|(_, e)| e))
201 }
202
203 pub fn entity(self) -> Result<E, ResponseError> {
205 self.row().map(|(_, e)| e)
206 }
207
208 #[must_use]
210 pub fn entities(self) -> Vec<E> {
211 self.0.into_iter().map(|(_, e)| e).collect()
212 }
213
214 #[must_use]
222 pub fn id(&self) -> Option<Id<E>> {
223 self.0.first().map(|(id, _)| *id)
224 }
225
226 pub fn require_id(self) -> Result<Id<E>, ResponseError> {
228 self.row().map(|(id, _)| id)
229 }
230
231 #[must_use]
233 pub fn ids(&self) -> Vec<Id<E>> {
234 self.0.iter().map(|(id, _)| *id).collect()
235 }
236
237 pub fn contains_id(&self, id: &Id<E>) -> bool {
239 self.0.iter().any(|(k, _)| k == id)
240 }
241
242 pub fn view(&self) -> Result<<E as AsView>::ViewType, ResponseError> {
248 self.require_one()?;
249 Ok(self.0[0].1.as_view())
250 }
251
252 pub fn view_opt(&self) -> Result<Option<<E as AsView>::ViewType>, ResponseError> {
254 match self.count() {
255 0 => Ok(None),
256 1 => Ok(Some(self.0[0].1.as_view())),
257 n => Err(ResponseError::not_unique::<E>(n)),
258 }
259 }
260
261 #[must_use]
263 pub fn views(&self) -> Vec<<E as AsView>::ViewType> {
264 self.0.iter().map(|(_, e)| e.as_view()).collect()
265 }
266}
267
268impl<E: EntityKind> IntoIterator for Response<E> {
269 type Item = Row<E>;
270 type IntoIter = std::vec::IntoIter<Self::Item>;
271
272 fn into_iter(self) -> Self::IntoIter {
273 self.0.into_iter()
274 }
275}
276
277#[derive(Debug)]
285pub struct WriteResponse<E> {
286 entity: E,
287}
288
289impl<E> WriteResponse<E> {
290 #[must_use]
292 pub const fn new(entity: E) -> Self {
293 Self { entity }
294 }
295
296 #[must_use]
298 pub fn entity(self) -> E {
299 self.entity
300 }
301
302 #[must_use]
304 pub fn id(&self) -> Id<E>
305 where
306 E: EntityValue,
307 {
308 self.entity.id()
309 }
310
311 #[must_use]
313 pub fn view(&self) -> <E as AsView>::ViewType
314 where
315 E: AsView,
316 {
317 self.entity.as_view()
318 }
319}
320
321#[derive(Debug)]
329pub struct WriteBatchResponse<E> {
330 entries: Vec<WriteResponse<E>>,
331}
332
333impl<E> WriteBatchResponse<E> {
334 #[must_use]
336 pub fn new(entities: Vec<E>) -> Self {
337 Self {
338 entries: entities.into_iter().map(WriteResponse::new).collect(),
339 }
340 }
341
342 #[must_use]
344 pub fn entries(&self) -> &[WriteResponse<E>] {
345 &self.entries
346 }
347
348 #[must_use]
350 pub const fn len(&self) -> usize {
351 self.entries.len()
352 }
353
354 #[must_use]
356 pub const fn is_empty(&self) -> bool {
357 self.entries.is_empty()
358 }
359
360 #[must_use]
362 pub fn entities(self) -> Vec<E> {
363 self.entries
364 .into_iter()
365 .map(WriteResponse::entity)
366 .collect()
367 }
368
369 #[must_use]
371 pub fn ids(&self) -> Vec<Id<E>>
372 where
373 E: EntityValue,
374 {
375 self.entries.iter().map(WriteResponse::id).collect()
376 }
377
378 #[must_use]
380 pub fn views(&self) -> Vec<<E as AsView>::ViewType>
381 where
382 E: AsView,
383 {
384 self.entries.iter().map(WriteResponse::view).collect()
385 }
386}
387
388impl<E> IntoIterator for WriteBatchResponse<E> {
389 type Item = WriteResponse<E>;
390 type IntoIter = std::vec::IntoIter<WriteResponse<E>>;
391
392 fn into_iter(self) -> Self::IntoIter {
393 self.entries.into_iter()
394 }
395}
396
397impl<E> WriteBatchResponse<E> {
398 pub fn iter(&self) -> std::slice::Iter<'_, WriteResponse<E>> {
400 self.entries.iter()
401 }
402}
403
404impl<'a, E> IntoIterator for &'a WriteBatchResponse<E> {
405 type Item = &'a WriteResponse<E>;
406 type IntoIter = std::slice::Iter<'a, WriteResponse<E>>;
407
408 fn into_iter(self) -> Self::IntoIter {
409 self.iter()
410 }
411}