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 value::OutputValue,
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 #[doc(hidden)]
46 pub fn project_entity_output_values(
47 &self,
48 entity: &E,
49 slots: &[usize],
50 ) -> Result<Vec<OutputValue>, crate::error::InternalError>
51 where
52 E: EntityValue,
53 {
54 self.session.project_entity_output_values(entity, slots)
55 }
56
57 pub(in crate::db) const fn new(session: &'a DbSession<E::Canister>, query: Query<E>) -> Self {
58 Self { session, query }
59 }
60
61 #[doc(hidden)]
67 #[must_use]
68 pub const fn query(&self) -> &Query<E> {
69 &self.query
70 }
71
72 fn map_query(mut self, map: impl FnOnce(Query<E>) -> Query<E>) -> Self {
73 self.query = map(self.query);
74 self
75 }
76
77 fn map_session_query_output<T>(
81 &self,
82 map: impl FnOnce(&DbSession<E::Canister>, &Query<E>) -> Result<T, QueryError>,
83 ) -> Result<T, QueryError> {
84 map(self.session, self.query())
85 }
86
87 #[must_use]
95 pub fn by_id(self, id: Id<E>) -> Self {
96 self.map_query(|query| query.by_id(id.key()))
97 }
98
99 #[must_use]
103 pub fn by_ids<I>(self, ids: I) -> Self
104 where
105 I: IntoIterator<Item = Id<E>>,
106 {
107 self.map_query(|query| query.by_ids(ids.into_iter().map(|id| id.key())))
108 }
109
110 #[must_use]
116 pub fn filter(self, expr: impl Into<FilterExpr>) -> Self {
117 self.map_query(|query| query.filter(expr))
118 }
119
120 #[must_use]
122 pub fn order_term(self, term: OrderTerm) -> Self {
123 self.map_query(|query| query.order_term(term))
124 }
125
126 #[must_use]
128 pub fn order_terms<I>(self, terms: I) -> Self
129 where
130 I: IntoIterator<Item = OrderTerm>,
131 {
132 self.map_query(|query| query.order_terms(terms))
133 }
134
135 #[must_use]
137 pub fn max_affected(self, limit: u32) -> Self {
138 self.map_query(|query| query.limit(limit))
139 }
140
141 pub fn explain(&self) -> Result<ExplainPlan, QueryError> {
147 self.map_session_query_output(DbSession::explain_query_with_visible_indexes)
148 }
149
150 pub fn plan_hash_hex(&self) -> Result<String, QueryError> {
152 self.map_session_query_output(DbSession::query_plan_hash_hex_with_visible_indexes)
153 }
154
155 pub fn trace(&self) -> Result<QueryTracePlan, QueryError> {
157 self.map_session_query_output(DbSession::trace_query)
158 }
159
160 pub fn planned(&self) -> Result<PlannedQuery<E>, QueryError> {
162 self.map_session_query_output(DbSession::planned_query_with_visible_indexes)
163 }
164
165 pub fn plan(&self) -> Result<CompiledQuery<E>, QueryError> {
167 self.map_session_query_output(DbSession::compile_query_with_visible_indexes)
168 }
169
170 pub fn execute(&self) -> Result<u32, QueryError>
176 where
177 E: EntityValue,
178 {
179 self.session.execute_delete_count(self.query())
180 }
181
182 pub fn execute_rows(&self) -> Result<EntityResponse<E>, QueryError>
185 where
186 E: EntityValue,
187 {
188 self.session.execute_delete_rows(self.query())
189 }
190
191 pub fn is_empty(&self) -> Result<bool, QueryError>
193 where
194 E: EntityValue,
195 {
196 Ok(self.execute()? == 0)
197 }
198
199 pub fn count(&self) -> Result<u32, QueryError>
201 where
202 E: EntityValue,
203 {
204 self.execute()
205 }
206
207 pub fn require_one(&self) -> Result<(), QueryError>
209 where
210 E: EntityValue,
211 {
212 match self.execute()? {
213 1 => Ok(()),
214 0 => Err(ResponseError::not_found(E::PATH).into()),
215 count => Err(ResponseError::not_unique(E::PATH, count).into()),
216 }
217 }
218
219 pub fn require_some(&self) -> Result<(), QueryError>
221 where
222 E: EntityValue,
223 {
224 if self.execute()? == 0 {
225 return Err(ResponseError::not_found(E::PATH).into());
226 }
227
228 Ok(())
229 }
230}
231
232impl<E> FluentDeleteQuery<'_, E>
233where
234 E: PersistedRow + SingletonEntity,
235 E::Key: Default,
236{
237 #[must_use]
239 pub fn singleton(self) -> Self {
240 self.map_query(Query::singleton)
241 }
242}