icydb_core/db/query/fluent/
delete.rs1use crate::{
7 db::{
8 DbSession, EntityResponse, PersistedRow,
9 query::{
10 explain::ExplainPlan,
11 expr::{FilterExpr, OrderTerm},
12 intent::{CompiledQuery, PlannedQuery, Query, QueryError},
13 trace::QueryTracePlan,
14 },
15 response::ResponseError,
16 },
17 traits::{EntityKind, EntityValue, SingletonEntity},
18 types::Id,
19};
20
21pub struct FluentDeleteQuery<'a, E>
31where
32 E: EntityKind,
33{
34 session: &'a DbSession<E::Canister>,
35 query: Query<E>,
36}
37
38impl<'a, E> FluentDeleteQuery<'a, E>
39where
40 E: PersistedRow,
41{
42 pub(in crate::db) const fn new(session: &'a DbSession<E::Canister>, query: Query<E>) -> Self {
43 Self { session, query }
44 }
45
46 #[doc(hidden)]
52 #[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 map_session_query_output<T>(
66 &self,
67 map: impl FnOnce(&DbSession<E::Canister>, &Query<E>) -> Result<T, QueryError>,
68 ) -> Result<T, QueryError> {
69 map(self.session, self.query())
70 }
71
72 #[must_use]
80 pub fn by_id(self, id: Id<E>) -> Self {
81 self.map_query(|query| query.by_id(id.key()))
82 }
83
84 #[must_use]
88 pub fn by_ids<I>(self, ids: I) -> Self
89 where
90 I: IntoIterator<Item = Id<E>>,
91 {
92 self.map_query(|query| query.by_ids(ids.into_iter().map(|id| id.key())))
93 }
94
95 #[must_use]
101 pub fn filter(self, expr: impl Into<FilterExpr>) -> Self {
102 self.map_query(|query| query.filter(expr))
103 }
104
105 #[must_use]
107 pub fn order_term(self, term: OrderTerm) -> Self {
108 self.map_query(|query| query.order_term(term))
109 }
110
111 #[must_use]
113 pub fn order_terms<I>(self, terms: I) -> Self
114 where
115 I: IntoIterator<Item = OrderTerm>,
116 {
117 self.map_query(|query| query.order_terms(terms))
118 }
119
120 #[must_use]
122 pub fn max_affected(self, limit: u32) -> Self {
123 self.map_query(|query| query.limit(limit))
124 }
125
126 pub fn explain(&self) -> Result<ExplainPlan, QueryError> {
132 self.map_session_query_output(DbSession::explain_query_with_visible_indexes)
133 }
134
135 pub fn plan_hash_hex(&self) -> Result<String, QueryError> {
137 self.map_session_query_output(DbSession::query_plan_hash_hex_with_visible_indexes)
138 }
139
140 pub fn trace(&self) -> Result<QueryTracePlan, QueryError> {
142 self.map_session_query_output(DbSession::trace_query)
143 }
144
145 pub fn planned(&self) -> Result<PlannedQuery<E>, QueryError> {
147 self.map_session_query_output(DbSession::planned_query_with_visible_indexes)
148 }
149
150 pub fn plan(&self) -> Result<CompiledQuery<E>, QueryError> {
152 self.map_session_query_output(DbSession::compile_query_with_visible_indexes)
153 }
154
155 pub fn execute(&self) -> Result<u32, QueryError>
161 where
162 E: EntityValue,
163 {
164 self.session.execute_delete_count(self.query())
165 }
166
167 pub fn execute_rows(&self) -> Result<EntityResponse<E>, QueryError>
170 where
171 E: EntityValue,
172 {
173 self.session.execute_delete_rows(self.query())
174 }
175
176 pub fn is_empty(&self) -> Result<bool, QueryError>
178 where
179 E: EntityValue,
180 {
181 Ok(self.execute()? == 0)
182 }
183
184 pub fn count(&self) -> Result<u32, QueryError>
186 where
187 E: EntityValue,
188 {
189 self.execute()
190 }
191
192 pub fn require_one(&self) -> Result<(), QueryError>
194 where
195 E: EntityValue,
196 {
197 match self.execute()? {
198 1 => Ok(()),
199 0 => Err(ResponseError::not_found(E::PATH).into()),
200 count => Err(ResponseError::not_unique(E::PATH, count).into()),
201 }
202 }
203
204 pub fn require_some(&self) -> Result<(), QueryError>
206 where
207 E: EntityValue,
208 {
209 if self.execute()? == 0 {
210 return Err(ResponseError::not_found(E::PATH).into());
211 }
212
213 Ok(())
214 }
215}
216
217impl<E> FluentDeleteQuery<'_, E>
218where
219 E: PersistedRow + SingletonEntity,
220 E::Key: Default,
221{
222 #[must_use]
224 pub fn singleton(self) -> Self {
225 self.map_query(Query::singleton)
226 }
227}