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