Skip to main content

icydb_core/db/query/session/
delete.rs

1use crate::{
2    db::{
3        DbSession,
4        query::{
5            Query, QueryError,
6            expr::{FilterExpr, SortExpr},
7            plan::{ExecutablePlan, ExplainPlan},
8            predicate::Predicate,
9        },
10        response::{Response, Row},
11    },
12    key::Key,
13    traits::{CanisterKind, EntityKind, UnitKey},
14    view::View,
15};
16
17///
18/// SessionDeleteQuery
19///
20/// Fluent, session-bound delete query wrapper that keeps query intent pure
21/// while routing execution through the `DbSession` boundary.
22///
23
24pub struct SessionDeleteQuery<'a, C: CanisterKind, E: EntityKind<Canister = C>> {
25    session: &'a DbSession<C>,
26    query: Query<E>,
27}
28
29impl<'a, C: CanisterKind, E: EntityKind<Canister = C>> SessionDeleteQuery<'a, C, E> {
30    pub(crate) const fn new(session: &'a DbSession<C>, query: Query<E>) -> Self {
31        Self { session, query }
32    }
33
34    // ------------------------------------------------------------------
35    // Intent inspection
36    // ------------------------------------------------------------------
37
38    /// Return a reference to the underlying query intent.
39    #[must_use]
40    pub const fn query(&self) -> &Query<E> {
41        &self.query
42    }
43
44    // ------------------------------------------------------------------
45    // Intent builders
46    // ------------------------------------------------------------------
47
48    /// Delete by primary key.
49    #[must_use]
50    pub fn by_key(mut self, key: impl Into<Key>) -> Self {
51        self.query = self.query.by_key(key.into());
52        self
53    }
54
55    /// Delete multiple entities by primary key.
56    ///
57    /// Semantics:
58    /// - Equivalent to `WHERE pk IN (…)`
59    /// - Uses key-based access (ByKey / ByKeys)
60    /// - Missing keys are ignored in MissingOk mode
61    /// - Strict mode treats missing rows as corruption
62    #[must_use]
63    pub fn many<I>(mut self, keys: I) -> Self
64    where
65        I: IntoIterator<Item = E::PrimaryKey>,
66    {
67        self.query = self.query.by_keys(keys.into_iter().map(Into::into));
68        self
69    }
70
71    /// Add a predicate, implicitly AND-ing with any existing predicate.
72    #[must_use]
73    pub fn filter(mut self, predicate: Predicate) -> Self {
74        self.query = self.query.filter(predicate);
75        self
76    }
77
78    /// Apply a dynamic filter expression.
79    pub fn filter_expr(mut self, expr: FilterExpr) -> Result<Self, QueryError> {
80        self.query = self.query.filter_expr(expr)?;
81
82        Ok(self)
83    }
84
85    /// Apply a dynamic sort expression.
86    pub fn sort_expr(mut self, expr: SortExpr) -> Result<Self, QueryError> {
87        self.query = self.query.sort_expr(expr)?;
88
89        Ok(self)
90    }
91
92    /// Append an ascending sort key.
93    #[must_use]
94    pub fn order_by(mut self, field: impl AsRef<str>) -> Self {
95        self.query = self.query.order_by(field);
96        self
97    }
98
99    /// Append a descending sort key.
100    #[must_use]
101    pub fn order_by_desc(mut self, field: impl AsRef<str>) -> Self {
102        self.query = self.query.order_by_desc(field);
103        self
104    }
105
106    /// Apply a delete limit to bound mutation size.
107    #[must_use]
108    pub fn limit(mut self, limit: u32) -> Self {
109        self.query = self.query.limit(limit);
110        self
111    }
112
113    // ------------------------------------------------------------------
114    // Planning / diagnostics
115    // ------------------------------------------------------------------
116
117    /// Explain this query without executing it.
118    pub fn explain(&self) -> Result<ExplainPlan, QueryError> {
119        self.query.explain()
120    }
121
122    /// Plan this query into an executor-ready plan.
123    pub fn plan(&self) -> Result<ExecutablePlan<E>, QueryError> {
124        self.query.plan()
125    }
126
127    // ------------------------------------------------------------------
128    // Execution
129    // ------------------------------------------------------------------
130
131    /// Execute this delete using the session's policy settings.
132    pub fn execute(&self) -> Result<Response<E>, QueryError> {
133        self.execute_raw()
134    }
135
136    /// Execute and return whether the response is empty.
137    pub fn is_empty(&self) -> Result<bool, QueryError> {
138        Ok(self.execute()?.is_empty())
139    }
140
141    /// Execute and return the number of affected rows.
142    pub fn count(&self) -> Result<u32, QueryError> {
143        Ok(self.execute()?.count())
144    }
145
146    /// Execute and require exactly one row.
147    pub fn require_one(&self) -> Result<(), QueryError> {
148        self.execute()?.require_one().map_err(QueryError::Response)
149    }
150
151    /// Execute and require at least one row.
152    pub fn require_some(&self) -> Result<(), QueryError> {
153        self.execute()?.require_some().map_err(QueryError::Response)
154    }
155
156    /// Execute and return the single row.
157    pub fn row(&self) -> Result<Row<E>, QueryError> {
158        self.execute()?.row().map_err(QueryError::Response)
159    }
160
161    /// Execute and return zero or one row.
162    pub fn try_row(&self) -> Result<Option<Row<E>>, QueryError> {
163        self.execute()?.try_row().map_err(QueryError::Response)
164    }
165
166    /// Execute and return all rows.
167    pub fn rows(&self) -> Result<Vec<Row<E>>, QueryError> {
168        Ok(self.execute()?.rows())
169    }
170
171    /// Execute and return the single entity.
172    pub fn entity(&self) -> Result<E, QueryError> {
173        self.execute()?.entity().map_err(QueryError::Response)
174    }
175
176    /// Execute and return zero or one entity.
177    pub fn try_entity(&self) -> Result<Option<E>, QueryError> {
178        self.execute()?.try_entity().map_err(QueryError::Response)
179    }
180
181    /// Execute and return all entities.
182    pub fn entities(&self) -> Result<Vec<E>, QueryError> {
183        Ok(self.execute()?.entities())
184    }
185
186    /// Execute and return the first store key, if any.
187    pub fn key(&self) -> Result<Option<Key>, QueryError> {
188        Ok(self.execute()?.key())
189    }
190
191    /// Execute and require exactly one store key.
192    pub fn key_strict(&self) -> Result<Key, QueryError> {
193        self.execute()?.key_strict().map_err(QueryError::Response)
194    }
195
196    /// Execute and return zero or one store key.
197    pub fn try_key(&self) -> Result<Option<Key>, QueryError> {
198        self.execute()?.try_key().map_err(QueryError::Response)
199    }
200
201    /// Execute and return all store keys.
202    pub fn keys(&self) -> Result<Vec<Key>, QueryError> {
203        Ok(self.execute()?.keys())
204    }
205
206    /// Execute and check whether the response contains the provided key.
207    pub fn contains_key(&self, key: &Key) -> Result<bool, QueryError> {
208        Ok(self.execute()?.contains_key(key))
209    }
210
211    /// Execute and require exactly one primary key.
212    pub fn primary_key(&self) -> Result<E::PrimaryKey, QueryError> {
213        self.execute()?.primary_key().map_err(QueryError::Response)
214    }
215
216    /// Execute and return zero or one primary key.
217    pub fn try_primary_key(&self) -> Result<Option<E::PrimaryKey>, QueryError> {
218        self.execute()?
219            .try_primary_key()
220            .map_err(QueryError::Response)
221    }
222
223    /// Execute and return all primary keys.
224    pub fn primary_keys(&self) -> Result<Vec<E::PrimaryKey>, QueryError> {
225        Ok(self.execute()?.primary_keys())
226    }
227
228    /// Execute and return the single view.
229    pub fn view(&self) -> Result<View<E>, QueryError> {
230        self.execute()?.view().map_err(QueryError::Response)
231    }
232
233    /// Execute and return zero or one view.
234    pub fn view_opt(&self) -> Result<Option<View<E>>, QueryError> {
235        self.execute()?.view_opt().map_err(QueryError::Response)
236    }
237
238    /// Execute and return all views.
239    pub fn views(&self) -> Result<Vec<View<E>>, QueryError> {
240        Ok(self.execute()?.views())
241    }
242
243    /// Execute a delete query and return the deleted rows.
244    pub fn delete_rows(&self) -> Result<Response<E>, QueryError> {
245        self.execute()
246    }
247
248    /// Execute the delete intent without facade-level cardinality handling.
249    fn execute_raw(&self) -> Result<Response<E>, QueryError> {
250        self.session.execute_query(self.query())
251    }
252}
253
254impl<C: CanisterKind, E: EntityKind<Canister = C>> SessionDeleteQuery<'_, C, E>
255where
256    E::PrimaryKey: UnitKey,
257{
258    /// Delete the singleton entity identified by the unit primary key `()`.
259    ///
260    /// Semantics:
261    /// - Equivalent to `DELETE … WHERE pk = ()`
262    /// - Uses key-based access (ByKey)
263    /// - MissingOk mode is idempotent
264    /// - Strict mode treats missing row as corruption
265    #[must_use]
266    pub fn only(mut self) -> Self {
267        self.query = self.query.only();
268        self
269    }
270}