icydb_core/db/query/intent/
query.rs1use crate::{
2 db::{
3 predicate::{CompareOp, MissingRowPolicy, Predicate},
4 query::{
5 builder::aggregate::AggregateExpr,
6 explain::ExplainPlan,
7 expr::{FilterExpr, SortExpr},
8 intent::{QueryError, access_plan_to_entity_keys, model::QueryModel},
9 plan::{AccessPlannedQuery, LoadSpec, QueryMode},
10 },
11 },
12 traits::{EntityKind, SingletonEntity},
13 value::Value,
14};
15
16#[derive(Debug)]
28pub struct Query<E: EntityKind> {
29 intent: QueryModel<'static, E::Key>,
30}
31
32impl<E: EntityKind> Query<E> {
33 #[must_use]
37 pub const fn new(consistency: MissingRowPolicy) -> Self {
38 Self {
39 intent: QueryModel::new(E::MODEL, consistency),
40 }
41 }
42
43 #[must_use]
45 pub const fn mode(&self) -> QueryMode {
46 self.intent.mode()
47 }
48
49 #[must_use]
50 pub(crate) fn has_explicit_order(&self) -> bool {
51 self.intent.has_explicit_order()
52 }
53
54 #[must_use]
55 pub(crate) const fn has_grouping(&self) -> bool {
56 self.intent.has_grouping()
57 }
58
59 #[must_use]
60 pub(crate) const fn load_spec(&self) -> Option<LoadSpec> {
61 match self.intent.mode() {
62 QueryMode::Load(spec) => Some(spec),
63 QueryMode::Delete(_) => None,
64 }
65 }
66
67 #[must_use]
69 pub fn filter(mut self, predicate: Predicate) -> Self {
70 self.intent = self.intent.filter(predicate);
71 self
72 }
73
74 pub fn filter_expr(self, expr: FilterExpr) -> Result<Self, QueryError> {
76 let Self { intent } = self;
77 let intent = intent.filter_expr(expr)?;
78
79 Ok(Self { intent })
80 }
81
82 pub fn sort_expr(self, expr: SortExpr) -> Result<Self, QueryError> {
84 let Self { intent } = self;
85 let intent = intent.sort_expr(expr)?;
86
87 Ok(Self { intent })
88 }
89
90 #[must_use]
92 pub fn order_by(mut self, field: impl AsRef<str>) -> Self {
93 self.intent = self.intent.order_by(field);
94 self
95 }
96
97 #[must_use]
99 pub fn order_by_desc(mut self, field: impl AsRef<str>) -> Self {
100 self.intent = self.intent.order_by_desc(field);
101 self
102 }
103
104 #[must_use]
106 pub fn distinct(mut self) -> Self {
107 self.intent = self.intent.distinct();
108 self
109 }
110
111 pub fn group_by(self, field: impl AsRef<str>) -> Result<Self, QueryError> {
113 let Self { intent } = self;
114 let intent = intent.push_group_field(field.as_ref())?;
115
116 Ok(Self { intent })
117 }
118
119 #[must_use]
121 pub fn aggregate(mut self, aggregate: AggregateExpr) -> Self {
122 self.intent = self.intent.push_group_aggregate(aggregate);
123 self
124 }
125
126 #[must_use]
128 pub fn grouped_limits(mut self, max_groups: u64, max_group_bytes: u64) -> Self {
129 self.intent = self.intent.grouped_limits(max_groups, max_group_bytes);
130 self
131 }
132
133 pub fn having_group(
135 self,
136 field: impl AsRef<str>,
137 op: CompareOp,
138 value: Value,
139 ) -> Result<Self, QueryError> {
140 let field = field.as_ref().to_owned();
141 let Self { intent } = self;
142 let intent = intent.push_having_group_clause(&field, op, value)?;
143
144 Ok(Self { intent })
145 }
146
147 pub fn having_aggregate(
149 self,
150 aggregate_index: usize,
151 op: CompareOp,
152 value: Value,
153 ) -> Result<Self, QueryError> {
154 let Self { intent } = self;
155 let intent = intent.push_having_aggregate_clause(aggregate_index, op, value)?;
156
157 Ok(Self { intent })
158 }
159
160 pub(crate) fn by_id(self, id: E::Key) -> Self {
162 let Self { intent } = self;
163 Self {
164 intent: intent.by_id(id),
165 }
166 }
167
168 pub(crate) fn by_ids<I>(self, ids: I) -> Self
170 where
171 I: IntoIterator<Item = E::Key>,
172 {
173 let Self { intent } = self;
174 Self {
175 intent: intent.by_ids(ids),
176 }
177 }
178
179 #[must_use]
181 pub fn delete(mut self) -> Self {
182 self.intent = self.intent.delete();
183 self
184 }
185
186 #[must_use]
193 pub fn limit(mut self, limit: u32) -> Self {
194 self.intent = self.intent.limit(limit);
195 self
196 }
197
198 #[must_use]
204 pub fn offset(mut self, offset: u32) -> Self {
205 self.intent = self.intent.offset(offset);
206 self
207 }
208
209 pub fn explain(&self) -> Result<ExplainPlan, QueryError> {
211 let plan = self.planned()?;
212
213 Ok(plan.explain())
214 }
215
216 pub fn plan_hash_hex(&self) -> Result<String, QueryError> {
221 Ok(self.explain()?.fingerprint().to_string())
222 }
223
224 pub fn planned(&self) -> Result<PlannedQuery<E>, QueryError> {
226 let plan = self.build_plan()?;
227 let _projection = plan.projection_spec(E::MODEL);
228
229 Ok(PlannedQuery::new(plan))
230 }
231
232 pub fn plan(&self) -> Result<CompiledQuery<E>, QueryError> {
236 let plan = self.build_plan()?;
237 let _projection = plan.projection_spec(E::MODEL);
238
239 Ok(CompiledQuery::new(plan))
240 }
241
242 fn build_plan(&self) -> Result<AccessPlannedQuery<E::Key>, QueryError> {
244 let plan_value = self.intent.build_plan_model()?;
245 let (logical, access) = plan_value.into_parts();
246 let access = access_plan_to_entity_keys::<E>(E::MODEL, access)?;
247 let plan = AccessPlannedQuery::from_parts(logical, access);
248
249 Ok(plan)
250 }
251}
252
253impl<E> Query<E>
254where
255 E: EntityKind + SingletonEntity,
256 E::Key: Default,
257{
258 pub(crate) fn only(self) -> Self {
260 let Self { intent } = self;
261
262 Self {
263 intent: intent.only(E::Key::default()),
264 }
265 }
266}
267
268#[derive(Debug)]
276pub struct PlannedQuery<E: EntityKind> {
277 plan: AccessPlannedQuery<E::Key>,
278}
279
280impl<E: EntityKind> PlannedQuery<E> {
281 #[must_use]
282 pub(in crate::db) const fn new(plan: AccessPlannedQuery<E::Key>) -> Self {
283 Self { plan }
284 }
285
286 #[must_use]
287 pub fn explain(&self) -> ExplainPlan {
288 self.plan.explain_with_model(E::MODEL)
289 }
290
291 #[must_use]
293 pub fn plan_hash_hex(&self) -> String {
294 self.explain().fingerprint().to_string()
295 }
296}
297
298#[derive(Clone, Debug)]
307pub struct CompiledQuery<E: EntityKind> {
308 plan: AccessPlannedQuery<E::Key>,
309}
310
311impl<E: EntityKind> CompiledQuery<E> {
312 #[must_use]
313 pub(in crate::db) const fn new(plan: AccessPlannedQuery<E::Key>) -> Self {
314 Self { plan }
315 }
316
317 #[must_use]
318 pub fn explain(&self) -> ExplainPlan {
319 self.plan.explain_with_model(E::MODEL)
320 }
321
322 #[must_use]
324 pub fn plan_hash_hex(&self) -> String {
325 self.explain().fingerprint().to_string()
326 }
327
328 #[must_use]
330 #[cfg(test)]
331 pub(crate) fn projection_spec(&self) -> crate::db::query::plan::expr::ProjectionSpec {
332 self.plan.projection_spec(E::MODEL)
333 }
334
335 #[must_use]
336 pub(in crate::db) fn into_inner(self) -> AccessPlannedQuery<E::Key> {
337 self.plan
338 }
339}