icydb_core/db/query/fluent/
delete.rs1use crate::{
7 db::{
8 DbSession, EntityResponse, PersistedRow,
9 predicate::Predicate,
10 query::{
11 explain::ExplainPlan,
12 expr::{FilterExpr, OrderTerm},
13 intent::{CompiledQuery, PlannedQuery, Query, QueryError},
14 trace::QueryTracePlan,
15 },
16 response::ResponseError,
17 },
18 traits::{EntityKind, EntityValue, SingletonEntity},
19 types::Id,
20};
21
22pub struct FluentDeleteQuery<'a, E>
32where
33 E: EntityKind,
34{
35 session: &'a DbSession<E::Canister>,
36 query: Query<E>,
37}
38
39impl<'a, E> FluentDeleteQuery<'a, E>
40where
41 E: PersistedRow,
42{
43 pub(crate) const fn new(session: &'a DbSession<E::Canister>, query: Query<E>) -> Self {
44 Self { session, query }
45 }
46
47 #[must_use]
53 pub const fn query(&self) -> &Query<E> {
54 &self.query
55 }
56
57 fn map_query(mut self, map: impl FnOnce(Query<E>) -> Query<E>) -> Self {
58 self.query = map(self.query);
59 self
60 }
61
62 fn try_map_query(
63 mut self,
64 map: impl FnOnce(Query<E>) -> Result<Query<E>, QueryError>,
65 ) -> Result<Self, QueryError> {
66 self.query = map(self.query)?;
67 Ok(self)
68 }
69
70 fn map_session_query_output<T>(
74 &self,
75 map: impl FnOnce(&DbSession<E::Canister>, &Query<E>) -> Result<T, QueryError>,
76 ) -> Result<T, QueryError> {
77 map(self.session, self.query())
78 }
79
80 #[must_use]
88 pub fn by_id(self, id: Id<E>) -> Self {
89 self.map_query(|query| query.by_id(id.key()))
90 }
91
92 #[must_use]
96 pub fn by_ids<I>(self, ids: I) -> Self
97 where
98 I: IntoIterator<Item = Id<E>>,
99 {
100 self.map_query(|query| query.by_ids(ids.into_iter().map(|id| id.key())))
101 }
102
103 #[must_use]
109 pub fn filter(self, predicate: Predicate) -> Self {
110 self.map_query(|query| query.filter(predicate))
111 }
112
113 pub fn filter_expr(self, expr: FilterExpr) -> Result<Self, QueryError> {
115 self.try_map_query(|query| query.filter_expr(expr))
116 }
117
118 #[must_use]
120 pub fn order_term(self, term: OrderTerm) -> Self {
121 self.map_query(|query| query.order_term(term))
122 }
123
124 #[must_use]
126 pub fn order_terms<I>(self, terms: I) -> Self
127 where
128 I: IntoIterator<Item = OrderTerm>,
129 {
130 self.map_query(|query| query.order_terms(terms))
131 }
132
133 #[must_use]
135 pub fn limit(self, limit: u32) -> Self {
136 self.map_query(|query| query.limit(limit))
137 }
138
139 pub fn explain(&self) -> Result<ExplainPlan, QueryError> {
145 self.map_session_query_output(DbSession::explain_query_with_visible_indexes)
146 }
147
148 pub fn plan_hash_hex(&self) -> Result<String, QueryError> {
150 self.map_session_query_output(DbSession::query_plan_hash_hex_with_visible_indexes)
151 }
152
153 pub fn trace(&self) -> Result<QueryTracePlan, QueryError> {
155 self.map_session_query_output(DbSession::trace_query)
156 }
157
158 pub fn planned(&self) -> Result<PlannedQuery<E>, QueryError> {
160 self.map_session_query_output(DbSession::planned_query_with_visible_indexes)
161 }
162
163 pub fn plan(&self) -> Result<CompiledQuery<E>, QueryError> {
165 self.map_session_query_output(DbSession::compile_query_with_visible_indexes)
166 }
167
168 pub fn execute(&self) -> Result<u32, QueryError>
174 where
175 E: EntityValue,
176 {
177 self.session.execute_delete_count(self.query())
178 }
179
180 pub fn execute_rows(&self) -> Result<EntityResponse<E>, QueryError>
183 where
184 E: EntityValue,
185 {
186 self.session.execute_query(self.query())
187 }
188
189 pub fn is_empty(&self) -> Result<bool, QueryError>
191 where
192 E: EntityValue,
193 {
194 Ok(self.execute()? == 0)
195 }
196
197 pub fn count(&self) -> Result<u32, QueryError>
199 where
200 E: EntityValue,
201 {
202 self.execute()
203 }
204
205 pub fn require_one(&self) -> Result<(), QueryError>
207 where
208 E: EntityValue,
209 {
210 match self.execute()? {
211 1 => Ok(()),
212 0 => Err(ResponseError::not_found(E::PATH).into()),
213 count => Err(ResponseError::not_unique(E::PATH, count).into()),
214 }
215 }
216
217 pub fn require_some(&self) -> Result<(), QueryError>
219 where
220 E: EntityValue,
221 {
222 if self.execute()? == 0 {
223 return Err(ResponseError::not_found(E::PATH).into());
224 }
225
226 Ok(())
227 }
228}
229
230impl<E> FluentDeleteQuery<'_, E>
231where
232 E: PersistedRow + SingletonEntity,
233 E::Key: Default,
234{
235 #[must_use]
237 pub fn only(self) -> Self {
238 self.map_query(Query::only)
239 }
240}