icydb_core/db/response/
mod.rs1mod paged;
9mod write;
10
11use crate::{prelude::*, traits::AsView, types::Id};
12use thiserror::Error as ThisError;
13
14pub use paged::{PagedLoadExecution, PagedLoadExecutionWithTrace};
16pub use write::{WriteBatchResponse, WriteResponse};
17
18pub type Row<E> = (Id<E>, E);
23
24#[derive(Debug, ThisError)]
29pub enum ResponseError {
30 #[error("expected exactly one row, found 0 (entity {entity})")]
31 NotFound { entity: &'static str },
32
33 #[error("expected exactly one row, found {count} (entity {entity})")]
34 NotUnique { entity: &'static str, count: u32 },
35}
36
37impl ResponseError {
38 const fn not_found<E: EntityKind>() -> Self {
39 Self::NotFound { entity: E::PATH }
40 }
41
42 const fn not_unique<E: EntityKind>(count: u32) -> Self {
43 Self::NotUnique {
44 entity: E::PATH,
45 count,
46 }
47 }
48}
49
50#[derive(Debug)]
59pub struct Response<E: EntityKind>(pub Vec<Row<E>>);
60
61impl<E: EntityKind> Response<E> {
62 #[must_use]
67 #[expect(clippy::cast_possible_truncation)]
68 pub const fn count(&self) -> u32 {
69 self.0.len() as u32
70 }
71
72 #[must_use]
73 pub const fn is_empty(&self) -> bool {
74 self.0.is_empty()
75 }
76
77 pub const fn require_one(&self) -> Result<(), ResponseError> {
82 match self.count() {
83 1 => Ok(()),
84 0 => Err(ResponseError::not_found::<E>()),
85 n => Err(ResponseError::not_unique::<E>(n)),
86 }
87 }
88
89 pub const fn require_some(&self) -> Result<(), ResponseError> {
90 if self.is_empty() {
91 Err(ResponseError::not_found::<E>())
92 } else {
93 Ok(())
94 }
95 }
96
97 #[expect(clippy::cast_possible_truncation)]
102 pub fn try_row(self) -> Result<Option<Row<E>>, ResponseError> {
103 match self.0.len() {
104 0 => Ok(None),
105 1 => Ok(Some(self.0.into_iter().next().unwrap())),
106 n => Err(ResponseError::not_unique::<E>(n as u32)),
107 }
108 }
109
110 pub fn row(self) -> Result<Row<E>, ResponseError> {
111 self.try_row()?.ok_or_else(ResponseError::not_found::<E>)
112 }
113
114 #[must_use]
115 pub fn rows(self) -> Vec<Row<E>> {
116 self.0
117 }
118
119 pub fn try_entity(self) -> Result<Option<E>, ResponseError> {
124 Ok(self.try_row()?.map(|(_, e)| e))
125 }
126
127 pub fn entity(self) -> Result<E, ResponseError> {
128 self.row().map(|(_, e)| e)
129 }
130
131 #[must_use]
132 pub fn entities(self) -> Vec<E> {
133 self.0.into_iter().map(|(_, e)| e).collect()
134 }
135
136 #[must_use]
144 pub fn id(&self) -> Option<Id<E>> {
145 self.0.first().map(|(id, _)| *id)
146 }
147
148 pub fn require_id(self) -> Result<Id<E>, ResponseError> {
150 self.row().map(|(id, _)| id)
151 }
152
153 #[must_use]
155 pub fn ids(&self) -> Vec<Id<E>> {
156 self.0.iter().map(|(id, _)| *id).collect()
157 }
158
159 pub fn contains_id(&self, id: &Id<E>) -> bool {
161 self.0.iter().any(|(k, _)| k == id)
162 }
163
164 pub fn view(&self) -> Result<<E as AsView>::ViewType, ResponseError> {
169 self.require_one()?;
170 Ok(self.0[0].1.as_view())
171 }
172
173 pub fn view_opt(&self) -> Result<Option<<E as AsView>::ViewType>, ResponseError> {
174 match self.count() {
175 0 => Ok(None),
176 1 => Ok(Some(self.0[0].1.as_view())),
177 n => Err(ResponseError::not_unique::<E>(n)),
178 }
179 }
180
181 #[must_use]
182 pub fn views(&self) -> Vec<<E as AsView>::ViewType> {
183 self.0.iter().map(|(_, e)| e.as_view()).collect()
184 }
185}
186
187impl<E: EntityKind> IntoIterator for Response<E> {
188 type Item = Row<E>;
189 type IntoIter = std::vec::IntoIter<Self::Item>;
190
191 fn into_iter(self) -> Self::IntoIter {
192 self.0.into_iter()
193 }
194}