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, SortExpr},
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 fn execute_delete_count(&self) -> Result<u32, QueryError>
83 where
84 E: EntityValue,
85 {
86 self.session.execute_delete_count(self.query())
87 }
88
89 fn require_delete_row_count(&self, expected: u32) -> Result<(), QueryError>
92 where
93 E: EntityValue,
94 {
95 let row_count = self.execute_delete_count()?;
96
97 match row_count {
98 count if count == expected => Ok(()),
99 0 => Err(ResponseError::not_found(E::PATH).into()),
100 count => Err(ResponseError::not_unique(E::PATH, count).into()),
101 }
102 }
103
104 #[must_use]
112 pub fn by_id(self, id: Id<E>) -> Self {
113 self.map_query(|query| query.by_id(id.key()))
114 }
115
116 #[must_use]
120 pub fn by_ids<I>(self, ids: I) -> Self
121 where
122 I: IntoIterator<Item = Id<E>>,
123 {
124 self.map_query(|query| query.by_ids(ids.into_iter().map(|id| id.key())))
125 }
126
127 #[must_use]
133 pub fn filter(self, predicate: Predicate) -> Self {
134 self.map_query(|query| query.filter(predicate))
135 }
136
137 pub fn filter_expr(self, expr: FilterExpr) -> Result<Self, QueryError> {
139 self.try_map_query(|query| query.filter_expr(expr))
140 }
141
142 pub fn sort_expr(self, expr: SortExpr) -> Result<Self, QueryError> {
144 self.try_map_query(|query| query.sort_expr(expr))
145 }
146
147 #[must_use]
149 pub fn order_by(self, field: impl AsRef<str>) -> Self {
150 self.map_query(|query| query.order_by(field))
151 }
152
153 #[must_use]
155 pub fn order_by_desc(self, field: impl AsRef<str>) -> Self {
156 self.map_query(|query| query.order_by_desc(field))
157 }
158
159 #[must_use]
161 pub fn limit(self, limit: u32) -> Self {
162 self.map_query(|query| query.limit(limit))
163 }
164
165 pub fn explain(&self) -> Result<ExplainPlan, QueryError> {
171 self.map_session_query_output(DbSession::explain_query_with_visible_indexes)
172 }
173
174 pub fn plan_hash_hex(&self) -> Result<String, QueryError> {
176 self.map_session_query_output(DbSession::query_plan_hash_hex_with_visible_indexes)
177 }
178
179 pub fn trace(&self) -> Result<QueryTracePlan, QueryError> {
181 self.map_session_query_output(DbSession::trace_query)
182 }
183
184 pub fn planned(&self) -> Result<PlannedQuery<E>, QueryError> {
186 self.map_session_query_output(DbSession::planned_query_with_visible_indexes)
187 }
188
189 pub fn plan(&self) -> Result<CompiledQuery<E>, QueryError> {
191 self.map_session_query_output(DbSession::compile_query_with_visible_indexes)
192 }
193
194 pub fn execute(&self) -> Result<u32, QueryError>
200 where
201 E: EntityValue,
202 {
203 self.execute_delete_count()
204 }
205
206 pub fn execute_rows(&self) -> Result<EntityResponse<E>, QueryError>
209 where
210 E: EntityValue,
211 {
212 self.session.execute_query(self.query())
213 }
214
215 pub fn is_empty(&self) -> Result<bool, QueryError>
217 where
218 E: EntityValue,
219 {
220 Ok(self.execute()? == 0)
221 }
222
223 pub fn count(&self) -> Result<u32, QueryError>
225 where
226 E: EntityValue,
227 {
228 self.execute_delete_count()
229 }
230
231 pub fn require_one(&self) -> Result<(), QueryError>
233 where
234 E: EntityValue,
235 {
236 self.require_delete_row_count(1)
237 }
238
239 pub fn require_some(&self) -> Result<(), QueryError>
241 where
242 E: EntityValue,
243 {
244 if self.execute()? == 0 {
245 return Err(ResponseError::not_found(E::PATH).into());
246 }
247
248 Ok(())
249 }
250}
251
252impl<E> FluentDeleteQuery<'_, E>
253where
254 E: PersistedRow + SingletonEntity,
255 E::Key: Default,
256{
257 #[must_use]
259 pub fn only(self) -> Self {
260 self.map_query(Query::only)
261 }
262}