icydb_core/db/query/api/
result_ext.rs1use crate::{
2 db::{EntityResponse, ResponseError, Row, query::api::private::SealedResponseCardinalityExt},
3 prelude::*,
4 types::Id,
5};
6
7pub trait ResponseCardinalityExt<E: EntityKind>: SealedResponseCardinalityExt<E> {
16 fn require_one(&self) -> Result<(), ResponseError>;
18
19 fn require_some(&self) -> Result<(), ResponseError>;
21
22 fn try_row(self) -> Result<Option<Row<E>>, ResponseError>;
24
25 fn row(self) -> Result<Row<E>, ResponseError>;
27
28 fn try_entity(self) -> Result<Option<E>, ResponseError>;
30
31 fn entity(self) -> Result<E, ResponseError>;
33
34 fn require_id(self) -> Result<Id<E>, ResponseError>;
36}
37
38impl<E: EntityKind> ResponseCardinalityExt<E> for EntityResponse<E> {
39 fn require_one(&self) -> Result<(), ResponseError> {
40 match self.count() {
41 1 => Ok(()),
42 0 => Err(ResponseError::NotFound { entity: E::PATH }),
43 n => Err(ResponseError::NotUnique {
44 entity: E::PATH,
45 count: n,
46 }),
47 }
48 }
49
50 fn require_some(&self) -> Result<(), ResponseError> {
51 if self.is_empty() {
52 Err(ResponseError::NotFound { entity: E::PATH })
53 } else {
54 Ok(())
55 }
56 }
57
58 #[expect(clippy::cast_possible_truncation)]
59 fn try_row(self) -> Result<Option<Row<E>>, ResponseError> {
60 let mut rows = self.rows();
61
62 match rows.len() {
63 0 => Ok(None),
64 1 => Ok(rows.pop()),
65 n => Err(ResponseError::NotUnique {
66 entity: E::PATH,
67 count: n as u32,
68 }),
69 }
70 }
71
72 fn row(self) -> Result<Row<E>, ResponseError> {
73 self.try_row()?
74 .ok_or(ResponseError::NotFound { entity: E::PATH })
75 }
76
77 fn try_entity(self) -> Result<Option<E>, ResponseError> {
78 Ok(self.try_row()?.map(Row::entity))
79 }
80
81 fn entity(self) -> Result<E, ResponseError> {
82 self.try_entity()?
83 .ok_or(ResponseError::NotFound { entity: E::PATH })
84 }
85
86 fn require_id(self) -> Result<Id<E>, ResponseError> {
87 self.row().map(|row| row.id())
88 }
89}