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