icydb_core/db/response/
mod.rs1mod write;
2
3use crate::{prelude::*, view::View};
4use thiserror::Error as ThisError;
5
6pub use write::*;
8
9pub type Row<E> = (<E as EntityIdentity>::Id, 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)]
48pub struct Response<E: EntityKind>(pub Vec<Row<E>>);
49
50impl<E: EntityKind> Response<E> {
51 #[must_use]
56 #[expect(clippy::cast_possible_truncation)]
57 pub const fn count(&self) -> u32 {
58 self.0.len() as u32
59 }
60
61 #[must_use]
62 pub const fn is_empty(&self) -> bool {
63 self.0.is_empty()
64 }
65
66 pub const fn require_one(&self) -> Result<(), ResponseError> {
71 match self.count() {
72 1 => Ok(()),
73 0 => Err(ResponseError::not_found::<E>()),
74 n => Err(ResponseError::not_unique::<E>(n)),
75 }
76 }
77
78 pub const fn require_some(&self) -> Result<(), ResponseError> {
79 if self.is_empty() {
80 Err(ResponseError::not_found::<E>())
81 } else {
82 Ok(())
83 }
84 }
85
86 #[expect(clippy::cast_possible_truncation)]
91 pub fn try_row(self) -> Result<Option<Row<E>>, ResponseError> {
92 match self.0.len() {
93 0 => Ok(None),
94 1 => Ok(Some(self.0.into_iter().next().unwrap())),
95 n => Err(ResponseError::not_unique::<E>(n as u32)),
96 }
97 }
98
99 pub fn row(self) -> Result<Row<E>, ResponseError> {
100 self.try_row()?.ok_or_else(ResponseError::not_found::<E>)
101 }
102
103 #[must_use]
104 pub fn rows(self) -> Vec<Row<E>> {
105 self.0
106 }
107
108 pub fn try_entity(self) -> Result<Option<E>, ResponseError> {
113 Ok(self.try_row()?.map(|(_, e)| e))
114 }
115
116 pub fn entity(self) -> Result<E, ResponseError> {
117 self.row().map(|(_, e)| e)
118 }
119
120 #[must_use]
121 pub fn entities(self) -> Vec<E> {
122 self.0.into_iter().map(|(_, e)| e).collect()
123 }
124
125 #[must_use]
130 pub fn id(&self) -> Option<E::Id> {
131 self.0.first().map(|(id, _)| *id)
132 }
133
134 pub fn require_id(self) -> Result<E::Id, ResponseError> {
135 self.row().map(|(id, _)| id)
136 }
137
138 #[must_use]
139 pub fn ids(&self) -> Vec<E::Id> {
140 self.0.iter().map(|(id, _)| *id).collect()
141 }
142
143 pub fn contains_id(&self, id: &E::Id) -> bool {
144 self.0.iter().any(|(k, _)| k == id)
145 }
146
147 pub fn view(&self) -> Result<View<E>, ResponseError> {
152 self.require_one()?;
153 Ok(self.0[0].1.to_view())
154 }
155
156 pub fn view_opt(&self) -> Result<Option<View<E>>, ResponseError> {
157 match self.count() {
158 0 => Ok(None),
159 1 => Ok(Some(self.0[0].1.to_view())),
160 n => Err(ResponseError::not_unique::<E>(n)),
161 }
162 }
163
164 #[must_use]
165 pub fn views(&self) -> Vec<View<E>> {
166 self.0.iter().map(|(_, e)| e.to_view()).collect()
167 }
168}
169
170impl<E: EntityKind> IntoIterator for Response<E> {
171 type Item = Row<E>;
172 type IntoIter = std::vec::IntoIter<Self::Item>;
173
174 fn into_iter(self) -> Self::IntoIter {
175 self.0.into_iter()
176 }
177}