1#[cfg(feature = "sql")]
7use crate::db::query::plan::expr::ProjectionSelection;
8use crate::{
9 db::{
10 predicate::{CompareOp, MissingRowPolicy, Predicate},
11 query::{
12 builder::AggregateExpr,
13 explain::ExplainPlan,
14 expr::FilterExpr,
15 expr::OrderTerm as FluentOrderTerm,
16 intent::{QueryError, QueryModel},
17 plan::{
18 AccessPlannedQuery, LoadSpec, OrderSpec, PreparedScalarPlanningState, QueryMode,
19 VisibleIndexes, expr::Expr,
20 },
21 },
22 schema::SchemaInfo,
23 },
24 traits::{EntityKind, KeyValueCodec, SingletonEntity},
25 value::{InputValue, Value},
26};
27use core::marker::PhantomData;
28
29#[derive(Clone, Debug)]
38pub(in crate::db) struct StructuralQuery {
39 intent: QueryModel<'static, Value>,
40}
41
42impl StructuralQuery {
43 #[must_use]
44 pub(in crate::db) const fn new(
45 model: &'static crate::model::entity::EntityModel,
46 consistency: MissingRowPolicy,
47 ) -> Self {
48 Self {
49 intent: QueryModel::new(model, consistency),
50 }
51 }
52
53 const fn from_intent(intent: QueryModel<'static, Value>) -> Self {
57 Self { intent }
58 }
59
60 fn map_intent(
63 self,
64 map: impl FnOnce(QueryModel<'static, Value>) -> QueryModel<'static, Value>,
65 ) -> Self {
66 Self::from_intent(map(self.intent))
67 }
68
69 fn try_map_intent(
72 self,
73 map: impl FnOnce(QueryModel<'static, Value>) -> Result<QueryModel<'static, Value>, QueryError>,
74 ) -> Result<Self, QueryError> {
75 map(self.intent).map(Self::from_intent)
76 }
77
78 #[must_use]
79 const fn mode(&self) -> QueryMode {
80 self.intent.mode()
81 }
82
83 #[must_use]
84 fn has_explicit_order(&self) -> bool {
85 self.intent.has_explicit_order()
86 }
87
88 #[must_use]
89 pub(in crate::db) const fn has_grouping(&self) -> bool {
90 self.intent.has_grouping()
91 }
92
93 #[must_use]
94 const fn load_spec(&self) -> Option<LoadSpec> {
95 match self.intent.mode() {
96 QueryMode::Load(spec) => Some(spec),
97 QueryMode::Delete(_) => None,
98 }
99 }
100
101 #[must_use]
102 pub(in crate::db) fn filter_predicate(mut self, predicate: Predicate) -> Self {
103 self.intent = self.intent.filter_predicate(predicate);
104 self
105 }
106
107 #[must_use]
108 pub(in crate::db) fn filter(mut self, expr: impl Into<FilterExpr>) -> Self {
109 self.intent = self.intent.filter(expr.into());
110 self
111 }
112
113 #[must_use]
114 pub(in crate::db) fn filter_expr_with_normalized_predicate(
115 mut self,
116 expr: Expr,
117 predicate: Predicate,
118 ) -> Self {
119 self.intent = self
120 .intent
121 .filter_expr_with_normalized_predicate(expr, predicate);
122 self
123 }
124 pub(in crate::db) fn order_term(mut self, term: FluentOrderTerm) -> Self {
125 self.intent = self.intent.order_term(term);
126 self
127 }
128
129 #[must_use]
133 pub(in crate::db) fn filter_expr(mut self, expr: Expr) -> Self {
134 self.intent = self.intent.filter_expr(expr);
135 self
136 }
137
138 #[must_use]
139 pub(in crate::db) fn order_spec(mut self, order: OrderSpec) -> Self {
140 self.intent = self.intent.order_spec(order);
141 self
142 }
143
144 #[must_use]
145 pub(in crate::db) fn distinct(mut self) -> Self {
146 self.intent = self.intent.distinct();
147 self
148 }
149
150 #[cfg(all(test, feature = "sql"))]
151 #[must_use]
152 pub(in crate::db) fn select_fields<I, S>(mut self, fields: I) -> Self
153 where
154 I: IntoIterator<Item = S>,
155 S: Into<String>,
156 {
157 self.intent = self.intent.select_fields(fields);
158 self
159 }
160
161 #[cfg(feature = "sql")]
162 #[must_use]
163 pub(in crate::db) fn projection_selection(mut self, selection: ProjectionSelection) -> Self {
164 self.intent = self.intent.projection_selection(selection);
165 self
166 }
167
168 pub(in crate::db) fn group_by(self, field: impl AsRef<str>) -> Result<Self, QueryError> {
169 self.try_map_intent(|intent| intent.push_group_field(field.as_ref()))
170 }
171
172 #[must_use]
173 pub(in crate::db) fn aggregate(mut self, aggregate: AggregateExpr) -> Self {
174 self.intent = self.intent.push_group_aggregate(aggregate);
175 self
176 }
177
178 #[must_use]
179 fn grouped_limits(mut self, max_groups: u64, max_group_bytes: u64) -> Self {
180 self.intent = self.intent.grouped_limits(max_groups, max_group_bytes);
181 self
182 }
183
184 pub(in crate::db) fn having_group(
185 self,
186 field: impl AsRef<str>,
187 op: CompareOp,
188 value: Value,
189 ) -> Result<Self, QueryError> {
190 let field = field.as_ref().to_owned();
191 self.try_map_intent(|intent| intent.push_having_group_clause(&field, op, value))
192 }
193
194 pub(in crate::db) fn having_aggregate(
195 self,
196 aggregate_index: usize,
197 op: CompareOp,
198 value: Value,
199 ) -> Result<Self, QueryError> {
200 self.try_map_intent(|intent| {
201 intent.push_having_aggregate_clause(aggregate_index, op, value)
202 })
203 }
204
205 #[cfg(test)]
206 pub(in crate::db) fn having_expr(self, expr: Expr) -> Result<Self, QueryError> {
207 self.try_map_intent(|intent| intent.push_having_expr(expr))
208 }
209
210 pub(in crate::db) fn having_expr_preserving_shape(
211 self,
212 expr: Expr,
213 ) -> Result<Self, QueryError> {
214 self.try_map_intent(|intent| intent.push_having_expr_preserving_shape(expr))
215 }
216
217 #[must_use]
218 fn by_id(self, id: Value) -> Self {
219 self.map_intent(|intent| intent.by_id(id))
220 }
221
222 #[must_use]
223 fn by_ids<I>(self, ids: I) -> Self
224 where
225 I: IntoIterator<Item = Value>,
226 {
227 self.map_intent(|intent| intent.by_ids(ids))
228 }
229
230 #[must_use]
231 fn only(self, id: Value) -> Self {
232 self.map_intent(|intent| intent.only(id))
233 }
234
235 #[must_use]
236 pub(in crate::db) fn delete(mut self) -> Self {
237 self.intent = self.intent.delete();
238 self
239 }
240
241 #[must_use]
242 pub(in crate::db) fn limit(mut self, limit: u32) -> Self {
243 self.intent = self.intent.limit(limit);
244 self
245 }
246
247 #[must_use]
248 pub(in crate::db) fn offset(mut self, offset: u32) -> Self {
249 self.intent = self.intent.offset(offset);
250 self
251 }
252
253 pub(in crate::db) fn build_plan(&self) -> Result<AccessPlannedQuery, QueryError> {
254 self.intent.build_plan_model()
255 }
256
257 pub(in crate::db) fn build_plan_with_visible_indexes(
258 &self,
259 visible_indexes: &VisibleIndexes<'_>,
260 ) -> Result<AccessPlannedQuery, QueryError> {
261 self.intent.build_plan_model_with_indexes(visible_indexes)
262 }
263
264 pub(in crate::db) fn prepare_scalar_planning_state_with_schema_info(
265 &self,
266 schema_info: SchemaInfo,
267 ) -> Result<PreparedScalarPlanningState<'_>, QueryError> {
268 self.intent
269 .prepare_scalar_planning_state_with_schema_info(schema_info)
270 }
271
272 pub(in crate::db) fn build_plan_with_visible_indexes_from_scalar_planning_state(
273 &self,
274 visible_indexes: &VisibleIndexes<'_>,
275 planning_state: PreparedScalarPlanningState<'_>,
276 ) -> Result<AccessPlannedQuery, QueryError> {
277 self.intent
278 .build_plan_model_with_indexes_from_scalar_planning_state(
279 visible_indexes,
280 planning_state,
281 )
282 }
283
284 pub(in crate::db) fn try_build_trivial_scalar_load_plan(
285 &self,
286 ) -> Result<Option<AccessPlannedQuery>, QueryError> {
287 self.intent.try_build_trivial_scalar_load_plan()
288 }
289
290 #[must_use]
291 pub(in crate::db) fn trivial_scalar_load_fast_path_eligible(&self) -> bool {
292 self.intent.trivial_scalar_load_fast_path_eligible()
293 }
294
295 #[must_use]
296 #[cfg(test)]
297 pub(in crate::db) fn structural_cache_key(
298 &self,
299 ) -> crate::db::query::intent::StructuralQueryCacheKey {
300 crate::db::query::intent::StructuralQueryCacheKey::from_query_model(&self.intent)
301 }
302
303 #[must_use]
304 pub(in crate::db) fn structural_cache_key_with_normalized_predicate_fingerprint(
305 &self,
306 predicate_fingerprint: Option<[u8; 32]>,
307 ) -> crate::db::query::intent::StructuralQueryCacheKey {
308 self.intent
309 .structural_cache_key_with_normalized_predicate_fingerprint(predicate_fingerprint)
310 }
311
312 fn build_plan_for_visibility(
315 &self,
316 visible_indexes: Option<&VisibleIndexes<'_>>,
317 ) -> Result<AccessPlannedQuery, QueryError> {
318 match visible_indexes {
319 Some(visible_indexes) => self.build_plan_with_visible_indexes(visible_indexes),
320 None => self.build_plan(),
321 }
322 }
323
324 #[must_use]
325 pub(in crate::db) const fn model(&self) -> &'static crate::model::entity::EntityModel {
326 self.intent.model()
327 }
328}
329
330#[derive(Clone, Debug)]
339struct QueryPlanHandle {
340 plan: Box<AccessPlannedQuery>,
341}
342
343impl QueryPlanHandle {
344 #[must_use]
345 fn from_plan(plan: AccessPlannedQuery) -> Self {
346 Self {
347 plan: Box::new(plan),
348 }
349 }
350
351 #[must_use]
352 const fn logical_plan(&self) -> &AccessPlannedQuery {
353 &self.plan
354 }
355
356 #[must_use]
357 fn into_inner(self) -> AccessPlannedQuery {
358 *self.plan
359 }
360}
361
362#[derive(Debug)]
370pub struct PlannedQuery<E: EntityKind> {
371 plan: QueryPlanHandle,
372 _marker: PhantomData<E>,
373}
374
375impl<E: EntityKind> PlannedQuery<E> {
376 #[must_use]
377 pub(in crate::db) fn from_plan(plan: AccessPlannedQuery) -> Self {
378 Self {
379 plan: QueryPlanHandle::from_plan(plan),
380 _marker: PhantomData,
381 }
382 }
383
384 #[must_use]
385 pub fn explain(&self) -> ExplainPlan {
386 self.plan.logical_plan().explain()
387 }
388
389 #[must_use]
391 pub fn plan_hash_hex(&self) -> String {
392 self.plan.logical_plan().fingerprint().to_string()
393 }
394}
395
396#[derive(Clone, Debug)]
406pub struct CompiledQuery<E: EntityKind> {
407 plan: QueryPlanHandle,
408 _marker: PhantomData<E>,
409}
410
411impl<E: EntityKind> CompiledQuery<E> {
412 #[must_use]
413 pub(in crate::db) fn from_plan(plan: AccessPlannedQuery) -> Self {
414 Self {
415 plan: QueryPlanHandle::from_plan(plan),
416 _marker: PhantomData,
417 }
418 }
419
420 #[must_use]
421 pub fn explain(&self) -> ExplainPlan {
422 self.plan.logical_plan().explain()
423 }
424
425 #[must_use]
427 pub fn plan_hash_hex(&self) -> String {
428 self.plan.logical_plan().fingerprint().to_string()
429 }
430
431 #[must_use]
432 #[cfg(test)]
433 pub(in crate::db) fn projection_spec(&self) -> crate::db::query::plan::expr::ProjectionSpec {
434 self.plan.logical_plan().projection_spec(E::MODEL)
435 }
436
437 pub(in crate::db) fn into_plan(self) -> AccessPlannedQuery {
439 self.plan.into_inner()
440 }
441
442 #[must_use]
443 #[cfg(test)]
444 pub(in crate::db) fn into_inner(self) -> AccessPlannedQuery {
445 self.plan.into_inner()
446 }
447}
448
449#[derive(Debug)]
461pub struct Query<E: EntityKind> {
462 inner: StructuralQuery,
463 _marker: PhantomData<E>,
464}
465
466impl<E: EntityKind> Query<E> {
467 pub(in crate::db) const fn from_inner(inner: StructuralQuery) -> Self {
469 Self {
470 inner,
471 _marker: PhantomData,
472 }
473 }
474
475 #[must_use]
479 pub const fn new(consistency: MissingRowPolicy) -> Self {
480 Self::from_inner(StructuralQuery::new(E::MODEL, consistency))
481 }
482
483 #[must_use]
485 pub const fn mode(&self) -> QueryMode {
486 self.inner.mode()
487 }
488
489 #[cfg(test)]
490 pub(in crate::db) fn explain_with_visible_indexes(
491 &self,
492 visible_indexes: &VisibleIndexes<'_>,
493 ) -> Result<ExplainPlan, QueryError> {
494 let plan = self.build_plan_for_visibility(Some(visible_indexes))?;
495
496 Ok(plan.explain())
497 }
498
499 #[cfg(test)]
500 pub(in crate::db) fn plan_hash_hex_with_visible_indexes(
501 &self,
502 visible_indexes: &VisibleIndexes<'_>,
503 ) -> Result<String, QueryError> {
504 let plan = self.build_plan_for_visibility(Some(visible_indexes))?;
505
506 Ok(plan.fingerprint().to_string())
507 }
508
509 fn build_plan_for_visibility(
512 &self,
513 visible_indexes: Option<&VisibleIndexes<'_>>,
514 ) -> Result<AccessPlannedQuery, QueryError> {
515 self.inner.build_plan_for_visibility(visible_indexes)
516 }
517
518 fn map_plan_for_visibility<T>(
522 &self,
523 visible_indexes: Option<&VisibleIndexes<'_>>,
524 map: impl FnOnce(AccessPlannedQuery) -> T,
525 ) -> Result<T, QueryError> {
526 let plan = self.build_plan_for_visibility(visible_indexes)?;
527
528 Ok(map(plan))
529 }
530
531 pub(in crate::db) fn planned_query_from_plan(plan: AccessPlannedQuery) -> PlannedQuery<E> {
533 PlannedQuery::from_plan(plan)
534 }
535
536 pub(in crate::db) fn compiled_query_from_plan(plan: AccessPlannedQuery) -> CompiledQuery<E> {
538 CompiledQuery::from_plan(plan)
539 }
540
541 #[must_use]
542 pub(in crate::db::query) fn has_explicit_order(&self) -> bool {
543 self.inner.has_explicit_order()
544 }
545
546 #[must_use]
547 pub(in crate::db) const fn structural(&self) -> &StructuralQuery {
548 &self.inner
549 }
550
551 #[must_use]
552 pub const fn has_grouping(&self) -> bool {
553 self.inner.has_grouping()
554 }
555
556 #[must_use]
557 pub(in crate::db::query) const fn load_spec(&self) -> Option<LoadSpec> {
558 self.inner.load_spec()
559 }
560
561 #[must_use]
563 pub fn filter(mut self, expr: impl Into<FilterExpr>) -> Self {
564 self.inner = self.inner.filter(expr);
565 self
566 }
567
568 #[cfg(test)]
572 #[must_use]
573 pub(in crate::db) fn filter_expr(mut self, expr: Expr) -> Self {
574 self.inner = self.inner.filter_expr(expr);
575 self
576 }
577
578 #[cfg(test)]
582 #[must_use]
583 pub(in crate::db) fn filter_predicate(mut self, predicate: Predicate) -> Self {
584 self.inner = self.inner.filter_predicate(predicate);
585 self
586 }
587
588 #[must_use]
590 pub fn order_term(mut self, term: FluentOrderTerm) -> Self {
591 self.inner = self.inner.order_term(term);
592 self
593 }
594
595 #[must_use]
597 pub fn order_terms<I>(mut self, terms: I) -> Self
598 where
599 I: IntoIterator<Item = FluentOrderTerm>,
600 {
601 for term in terms {
602 self.inner = self.inner.order_term(term);
603 }
604
605 self
606 }
607
608 #[must_use]
610 pub fn distinct(mut self) -> Self {
611 self.inner = self.inner.distinct();
612 self
613 }
614
615 #[cfg(all(test, feature = "sql"))]
618 #[must_use]
619 pub(in crate::db) fn select_fields<I, S>(mut self, fields: I) -> Self
620 where
621 I: IntoIterator<Item = S>,
622 S: Into<String>,
623 {
624 self.inner = self.inner.select_fields(fields);
625 self
626 }
627
628 pub fn group_by(self, field: impl AsRef<str>) -> Result<Self, QueryError> {
630 let Self { inner, .. } = self;
631 let inner = inner.group_by(field)?;
632
633 Ok(Self::from_inner(inner))
634 }
635
636 #[must_use]
638 pub fn aggregate(mut self, aggregate: AggregateExpr) -> Self {
639 self.inner = self.inner.aggregate(aggregate);
640 self
641 }
642
643 #[must_use]
645 pub fn grouped_limits(mut self, max_groups: u64, max_group_bytes: u64) -> Self {
646 self.inner = self.inner.grouped_limits(max_groups, max_group_bytes);
647 self
648 }
649
650 pub fn having_group(
652 self,
653 field: impl AsRef<str>,
654 op: CompareOp,
655 value: InputValue,
656 ) -> Result<Self, QueryError> {
657 let Self { inner, .. } = self;
658 let inner = inner.having_group(field, op, value.into())?;
659
660 Ok(Self::from_inner(inner))
661 }
662
663 pub fn having_aggregate(
665 self,
666 aggregate_index: usize,
667 op: CompareOp,
668 value: InputValue,
669 ) -> Result<Self, QueryError> {
670 let Self { inner, .. } = self;
671 let inner = inner.having_aggregate(aggregate_index, op, value.into())?;
672
673 Ok(Self::from_inner(inner))
674 }
675
676 #[cfg(test)]
680 pub(in crate::db) fn having_expr(self, expr: Expr) -> Result<Self, QueryError> {
681 let Self { inner, .. } = self;
682 let inner = inner.having_expr(expr)?;
683
684 Ok(Self::from_inner(inner))
685 }
686
687 pub(in crate::db) fn by_id(self, id: E::Key) -> Self {
689 let Self { inner, .. } = self;
690
691 Self::from_inner(inner.by_id(id.to_key_value()))
692 }
693
694 pub(in crate::db) fn by_ids<I>(self, ids: I) -> Self
696 where
697 I: IntoIterator<Item = E::Key>,
698 {
699 let Self { inner, .. } = self;
700
701 Self::from_inner(inner.by_ids(ids.into_iter().map(|id| id.to_key_value())))
702 }
703
704 #[must_use]
706 pub fn delete(mut self) -> Self {
707 self.inner = self.inner.delete();
708 self
709 }
710
711 #[must_use]
718 pub fn limit(mut self, limit: u32) -> Self {
719 self.inner = self.inner.limit(limit);
720 self
721 }
722
723 #[must_use]
729 pub fn offset(mut self, offset: u32) -> Self {
730 self.inner = self.inner.offset(offset);
731 self
732 }
733
734 pub fn explain(&self) -> Result<ExplainPlan, QueryError> {
736 let plan = self.planned()?;
737
738 Ok(plan.explain())
739 }
740
741 pub fn plan_hash_hex(&self) -> Result<String, QueryError> {
746 let plan = self.inner.build_plan()?;
747
748 Ok(plan.fingerprint().to_string())
749 }
750
751 pub fn planned(&self) -> Result<PlannedQuery<E>, QueryError> {
753 self.map_plan_for_visibility(None, Self::planned_query_from_plan)
754 }
755
756 pub fn plan(&self) -> Result<CompiledQuery<E>, QueryError> {
760 self.map_plan_for_visibility(None, Self::compiled_query_from_plan)
761 }
762
763 #[cfg(test)]
764 pub(in crate::db) fn plan_with_visible_indexes(
765 &self,
766 visible_indexes: &VisibleIndexes<'_>,
767 ) -> Result<CompiledQuery<E>, QueryError> {
768 self.map_plan_for_visibility(Some(visible_indexes), Self::compiled_query_from_plan)
769 }
770}
771
772impl<E> Query<E>
773where
774 E: EntityKind + SingletonEntity,
775 E::Key: Default,
776{
777 pub(in crate::db) fn only(self) -> Self {
779 let Self { inner, .. } = self;
780
781 Self::from_inner(inner.only(E::Key::default().to_key_value()))
782 }
783}