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(crate) const fn new(session: &'a DbSession<E::Canister>, query: Query<E>) -> Self {
43 Self { session, query }
44 }
45
46 #[must_use]
52 pub const fn query(&self) -> &Query<E> {
53 &self.query
54 }
55
56 fn map_query(mut self, map: impl FnOnce(Query<E>) -> Query<E>) -> Self {
57 self.query = map(self.query);
58 self
59 }
60
61 fn map_session_query_output<T>(
65 &self,
66 map: impl FnOnce(&DbSession<E::Canister>, &Query<E>) -> Result<T, QueryError>,
67 ) -> Result<T, QueryError> {
68 map(self.session, self.query())
69 }
70
71 #[must_use]
79 pub fn by_id(self, id: Id<E>) -> Self {
80 self.map_query(|query| query.by_id(id.key()))
81 }
82
83 #[must_use]
87 pub fn by_ids<I>(self, ids: I) -> Self
88 where
89 I: IntoIterator<Item = Id<E>>,
90 {
91 self.map_query(|query| query.by_ids(ids.into_iter().map(|id| id.key())))
92 }
93
94 #[must_use]
100 pub fn filter(self, expr: impl Into<FilterExpr>) -> Self {
101 self.map_query(|query| query.filter(expr))
102 }
103
104 #[must_use]
106 pub fn order_term(self, term: OrderTerm) -> Self {
107 self.map_query(|query| query.order_term(term))
108 }
109
110 #[must_use]
112 pub fn order_terms<I>(self, terms: I) -> Self
113 where
114 I: IntoIterator<Item = OrderTerm>,
115 {
116 self.map_query(|query| query.order_terms(terms))
117 }
118
119 #[must_use]
121 pub fn limit(self, limit: u32) -> Self {
122 self.map_query(|query| query.limit(limit))
123 }
124
125 pub fn explain(&self) -> Result<ExplainPlan, QueryError> {
131 self.map_session_query_output(DbSession::explain_query_with_visible_indexes)
132 }
133
134 pub fn plan_hash_hex(&self) -> Result<String, QueryError> {
136 self.map_session_query_output(DbSession::query_plan_hash_hex_with_visible_indexes)
137 }
138
139 pub fn trace(&self) -> Result<QueryTracePlan, QueryError> {
141 self.map_session_query_output(DbSession::trace_query)
142 }
143
144 pub fn planned(&self) -> Result<PlannedQuery<E>, QueryError> {
146 self.map_session_query_output(DbSession::planned_query_with_visible_indexes)
147 }
148
149 pub fn plan(&self) -> Result<CompiledQuery<E>, QueryError> {
151 self.map_session_query_output(DbSession::compile_query_with_visible_indexes)
152 }
153
154 pub fn execute(&self) -> Result<u32, QueryError>
160 where
161 E: EntityValue,
162 {
163 self.session.execute_delete_count(self.query())
164 }
165
166 pub fn execute_rows(&self) -> Result<EntityResponse<E>, QueryError>
169 where
170 E: EntityValue,
171 {
172 self.session.execute_query(self.query())
173 }
174
175 pub fn is_empty(&self) -> Result<bool, QueryError>
177 where
178 E: EntityValue,
179 {
180 Ok(self.execute()? == 0)
181 }
182
183 pub fn count(&self) -> Result<u32, QueryError>
185 where
186 E: EntityValue,
187 {
188 self.execute()
189 }
190
191 pub fn require_one(&self) -> Result<(), QueryError>
193 where
194 E: EntityValue,
195 {
196 match self.execute()? {
197 1 => Ok(()),
198 0 => Err(ResponseError::not_found(E::PATH).into()),
199 count => Err(ResponseError::not_unique(E::PATH, count).into()),
200 }
201 }
202
203 pub fn require_some(&self) -> Result<(), QueryError>
205 where
206 E: EntityValue,
207 {
208 if self.execute()? == 0 {
209 return Err(ResponseError::not_found(E::PATH).into());
210 }
211
212 Ok(())
213 }
214}
215
216impl<E> FluentDeleteQuery<'_, E>
217where
218 E: PersistedRow + SingletonEntity,
219 E::Key: Default,
220{
221 #[must_use]
223 pub fn only(self) -> Self {
224 self.map_query(Query::only)
225 }
226}