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    /// - Empty input yields a no-op delete
63    #[must_use]
64    pub fn many<I>(mut self, keys: I) -> Self
65    where
66        I: IntoIterator<Item = E::PrimaryKey>,
67    {
68        self.query = self.query.by_keys(keys.into_iter().map(Into::into));
69        self
70    }
71
72    /// Add a predicate, implicitly AND-ing with any existing predicate.
73    #[must_use]
74    pub fn filter(mut self, predicate: Predicate) -> Self {
75        self.query = self.query.filter(predicate);
76        self
77    }
78
79    /// Apply a dynamic filter expression.
80    pub fn filter_expr(mut self, expr: FilterExpr) -> Result<Self, QueryError> {
81        self.query = self.query.filter_expr(expr)?;
82
83        Ok(self)
84    }
85
86    /// Apply a dynamic sort expression.
87    pub fn sort_expr(mut self, expr: SortExpr) -> Result<Self, QueryError> {
88        self.query = self.query.sort_expr(expr)?;
89
90        Ok(self)
91    }
92
93    /// Append an ascending sort key.
94    #[must_use]
95    pub fn order_by(mut self, field: impl AsRef<str>) -> Self {
96        self.query = self.query.order_by(field);
97        self
98    }
99
100    /// Append a descending sort key.
101    #[must_use]
102    pub fn order_by_desc(mut self, field: impl AsRef<str>) -> Self {
103        self.query = self.query.order_by_desc(field);
104        self
105    }
106
107    /// Apply a delete limit to bound mutation size.
108    #[must_use]
109    pub fn limit(mut self, limit: u32) -> Self {
110        self.query = self.query.limit(limit);
111        self
112    }
113
114    // ------------------------------------------------------------------
115    // Planning / diagnostics
116    // ------------------------------------------------------------------
117
118    /// Explain this query without executing it.
119    pub fn explain(&self) -> Result<ExplainPlan, QueryError> {
120        self.query.explain()
121    }
122
123    /// Plan this query into an executor-ready plan.
124    pub fn plan(&self) -> Result<ExecutablePlan<E>, QueryError> {
125        self.query.plan()
126    }
127
128    // ------------------------------------------------------------------
129    // Execution
130    // ------------------------------------------------------------------
131
132    /// Execute this delete using the session's policy settings.
133    pub fn execute(&self) -> Result<Response<E>, QueryError> {
134        self.execute_raw()
135    }
136
137    /// Execute and return whether the response is empty.
138    pub fn is_empty(&self) -> Result<bool, QueryError> {
139        Ok(self.execute()?.is_empty())
140    }
141
142    /// Execute and return the number of affected rows.
143    pub fn count(&self) -> Result<u32, QueryError> {
144        Ok(self.execute()?.count())
145    }
146
147    /// Execute and require exactly one row.
148    pub fn require_one(&self) -> Result<(), QueryError> {
149        self.execute()?.require_one().map_err(QueryError::Response)
150    }
151
152    /// Execute and require at least one row.
153    pub fn require_some(&self) -> Result<(), QueryError> {
154        self.execute()?.require_some().map_err(QueryError::Response)
155    }
156
157    /// Execute and return the single row.
158    pub fn row(&self) -> Result<Row<E>, QueryError> {
159        self.execute()?.row().map_err(QueryError::Response)
160    }
161
162    /// Execute and return zero or one row.
163    pub fn try_row(&self) -> Result<Option<Row<E>>, QueryError> {
164        self.execute()?.try_row().map_err(QueryError::Response)
165    }
166
167    /// Execute and return all rows.
168    pub fn rows(&self) -> Result<Vec<Row<E>>, QueryError> {
169        Ok(self.execute()?.rows())
170    }
171
172    /// Execute and return the single entity.
173    pub fn entity(&self) -> Result<E, QueryError> {
174        self.execute()?.entity().map_err(QueryError::Response)
175    }
176
177    /// Execute and return zero or one entity.
178    pub fn try_entity(&self) -> Result<Option<E>, QueryError> {
179        self.execute()?.try_entity().map_err(QueryError::Response)
180    }
181
182    /// Execute and return all entities.
183    pub fn entities(&self) -> Result<Vec<E>, QueryError> {
184        Ok(self.execute()?.entities())
185    }
186
187    /// Execute and return the first store key, if any.
188    pub fn key(&self) -> Result<Option<Key>, QueryError> {
189        Ok(self.execute()?.key())
190    }
191
192    /// Execute and require exactly one store key.
193    pub fn key_strict(&self) -> Result<Key, QueryError> {
194        self.execute()?.key_strict().map_err(QueryError::Response)
195    }
196
197    /// Execute and return zero or one store key.
198    pub fn try_key(&self) -> Result<Option<Key>, QueryError> {
199        self.execute()?.try_key().map_err(QueryError::Response)
200    }
201
202    /// Execute and return all store keys.
203    pub fn keys(&self) -> Result<Vec<Key>, QueryError> {
204        Ok(self.execute()?.keys())
205    }
206
207    /// Execute and check whether the response contains the provided key.
208    pub fn contains_key(&self, key: &Key) -> Result<bool, QueryError> {
209        Ok(self.execute()?.contains_key(key))
210    }
211
212    /// Execute and require exactly one primary key.
213    pub fn primary_key(&self) -> Result<E::PrimaryKey, QueryError> {
214        self.execute()?.primary_key().map_err(QueryError::Response)
215    }
216
217    /// Execute and return zero or one primary key.
218    pub fn try_primary_key(&self) -> Result<Option<E::PrimaryKey>, QueryError> {
219        self.execute()?
220            .try_primary_key()
221            .map_err(QueryError::Response)
222    }
223
224    /// Execute and return all primary keys.
225    pub fn primary_keys(&self) -> Result<Vec<E::PrimaryKey>, QueryError> {
226        Ok(self.execute()?.primary_keys())
227    }
228
229    /// Execute and return the single view.
230    pub fn view(&self) -> Result<View<E>, QueryError> {
231        self.execute()?.view().map_err(QueryError::Response)
232    }
233
234    /// Execute and return zero or one view.
235    pub fn view_opt(&self) -> Result<Option<View<E>>, QueryError> {
236        self.execute()?.view_opt().map_err(QueryError::Response)
237    }
238
239    /// Execute and return all views.
240    pub fn views(&self) -> Result<Vec<View<E>>, QueryError> {
241        Ok(self.execute()?.views())
242    }
243
244    /// Execute a delete query and return the deleted rows.
245    pub fn delete_rows(&self) -> Result<Response<E>, QueryError> {
246        self.execute()
247    }
248
249    /// Execute the delete intent without facade-level cardinality handling.
250    fn execute_raw(&self) -> Result<Response<E>, QueryError> {
251        self.session.execute_query(self.query())
252    }
253}
254
255impl<C: CanisterKind, E: EntityKind<Canister = C>> SessionDeleteQuery<'_, C, E>
256where
257    E::PrimaryKey: UnitKey,
258{
259    /// Delete the singleton entity identified by the unit primary key `()`.
260    ///
261    /// Semantics:
262    /// - Equivalent to `DELETE … WHERE pk = ()`
263    /// - Uses key-based access (ByKey)
264    /// - MissingOk mode is idempotent
265    /// - Strict mode treats missing row as corruption
266    #[must_use]
267    pub fn only(mut self) -> Self {
268        self.query = self.query.only();
269        self
270    }
271}