icydb_core/db/response/
mod.rs1mod write;
2
3use crate::{prelude::*, traits::AsView, types::Id};
4use thiserror::Error as ThisError;
5
6pub use write::*;
8
9pub type Row<E> = (Id<E>, E);
14
15#[derive(Debug, ThisError)]
20pub enum ResponseError {
21 #[error("expected exactly one row, found 0 (entity {entity})")]
22 NotFound { entity: &'static str },
23
24 #[error("expected exactly one row, found {count} (entity {entity})")]
25 NotUnique { entity: &'static str, count: u32 },
26}
27
28impl ResponseError {
29 const fn not_found<E: EntityKind>() -> Self {
30 Self::NotFound { entity: E::PATH }
31 }
32
33 const fn not_unique<E: EntityKind>(count: u32) -> Self {
34 Self::NotUnique {
35 entity: E::PATH,
36 count,
37 }
38 }
39}
40
41#[derive(Debug)]
50pub struct Response<E: EntityKind>(pub Vec<Row<E>>);
51
52impl<E: EntityKind> Response<E> {
53 #[must_use]
58 #[expect(clippy::cast_possible_truncation)]
59 pub const fn count(&self) -> u32 {
60 self.0.len() as u32
61 }
62
63 #[must_use]
64 pub const fn is_empty(&self) -> bool {
65 self.0.is_empty()
66 }
67
68 pub const fn require_one(&self) -> Result<(), ResponseError> {
73 match self.count() {
74 1 => Ok(()),
75 0 => Err(ResponseError::not_found::<E>()),
76 n => Err(ResponseError::not_unique::<E>(n)),
77 }
78 }
79
80 pub const fn require_some(&self) -> Result<(), ResponseError> {
81 if self.is_empty() {
82 Err(ResponseError::not_found::<E>())
83 } else {
84 Ok(())
85 }
86 }
87
88 #[expect(clippy::cast_possible_truncation)]
93 pub fn try_row(self) -> Result<Option<Row<E>>, ResponseError> {
94 match self.0.len() {
95 0 => Ok(None),
96 1 => Ok(Some(self.0.into_iter().next().unwrap())),
97 n => Err(ResponseError::not_unique::<E>(n as u32)),
98 }
99 }
100
101 pub fn row(self) -> Result<Row<E>, ResponseError> {
102 self.try_row()?.ok_or_else(ResponseError::not_found::<E>)
103 }
104
105 #[must_use]
106 pub fn rows(self) -> Vec<Row<E>> {
107 self.0
108 }
109
110 pub fn try_entity(self) -> Result<Option<E>, ResponseError> {
115 Ok(self.try_row()?.map(|(_, e)| e))
116 }
117
118 pub fn entity(self) -> Result<E, ResponseError> {
119 self.row().map(|(_, e)| e)
120 }
121
122 #[must_use]
123 pub fn entities(self) -> Vec<E> {
124 self.0.into_iter().map(|(_, e)| e).collect()
125 }
126
127 #[must_use]
135 pub fn id(&self) -> Option<Id<E>> {
136 self.0.first().map(|(id, _)| *id)
137 }
138
139 pub fn require_id(self) -> Result<Id<E>, ResponseError> {
141 self.row().map(|(id, _)| id)
142 }
143
144 #[must_use]
146 pub fn ids(&self) -> Vec<Id<E>> {
147 self.0.iter().map(|(id, _)| *id).collect()
148 }
149
150 pub fn contains_id(&self, id: &Id<E>) -> bool {
152 self.0.iter().any(|(k, _)| k == id)
153 }
154
155 pub fn view(&self) -> Result<<E as AsView>::ViewType, ResponseError> {
160 self.require_one()?;
161 Ok(self.0[0].1.as_view())
162 }
163
164 pub fn view_opt(&self) -> Result<Option<<E as AsView>::ViewType>, ResponseError> {
165 match self.count() {
166 0 => Ok(None),
167 1 => Ok(Some(self.0[0].1.as_view())),
168 n => Err(ResponseError::not_unique::<E>(n)),
169 }
170 }
171
172 #[must_use]
173 pub fn views(&self) -> Vec<<E as AsView>::ViewType> {
174 self.0.iter().map(|(_, e)| e.as_view()).collect()
175 }
176}
177
178impl<E: EntityKind> IntoIterator for Response<E> {
179 type Item = Row<E>;
180 type IntoIter = std::vec::IntoIter<Self::Item>;
181
182 fn into_iter(self) -> Self::IntoIter {
183 self.0.into_iter()
184 }
185}