1#[cfg(feature = "sql")]
7use crate::db::query::plan::expr::ProjectionSelection;
8use crate::{
9 db::{
10 executor::{
11 BytesByProjectionMode, PreparedExecutionPlan, SharedPreparedExecutionPlan,
12 assemble_aggregate_terminal_execution_descriptor,
13 assemble_load_execution_node_descriptor, assemble_load_execution_verbose_diagnostics,
14 planning::route::AggregateRouteShape,
15 },
16 predicate::{CoercionId, CompareOp, MissingRowPolicy, Predicate},
17 query::{
18 builder::{
19 AggregateExpr, PreparedFluentAggregateExplainStrategy,
20 PreparedFluentProjectionStrategy,
21 },
22 explain::{
23 ExplainAccessPath, ExplainAggregateTerminalPlan, ExplainExecutionNodeDescriptor,
24 ExplainExecutionNodeType, ExplainOrderPushdown, ExplainPlan, ExplainPredicate,
25 },
26 expr::FilterExpr,
27 expr::OrderTerm as FluentOrderTerm,
28 intent::{
29 QueryError,
30 model::{PreparedScalarPlanningState, QueryModel},
31 },
32 plan::{
33 AccessPlannedQuery, LoadSpec, OrderSpec, QueryMode, VisibleIndexes, expr::Expr,
34 },
35 },
36 },
37 traits::{EntityKind, EntityValue, FieldValue, SingletonEntity},
38 value::Value,
39};
40use core::marker::PhantomData;
41
42#[derive(Clone, Debug)]
51pub(in crate::db) struct StructuralQuery {
52 intent: QueryModel<'static, Value>,
53}
54
55impl StructuralQuery {
56 #[must_use]
57 pub(in crate::db) const fn new(
58 model: &'static crate::model::entity::EntityModel,
59 consistency: MissingRowPolicy,
60 ) -> Self {
61 Self {
62 intent: QueryModel::new(model, consistency),
63 }
64 }
65
66 const fn from_intent(intent: QueryModel<'static, Value>) -> Self {
70 Self { intent }
71 }
72
73 fn map_intent(
76 self,
77 map: impl FnOnce(QueryModel<'static, Value>) -> QueryModel<'static, Value>,
78 ) -> Self {
79 Self::from_intent(map(self.intent))
80 }
81
82 fn try_map_intent(
85 self,
86 map: impl FnOnce(QueryModel<'static, Value>) -> Result<QueryModel<'static, Value>, QueryError>,
87 ) -> Result<Self, QueryError> {
88 map(self.intent).map(Self::from_intent)
89 }
90
91 #[must_use]
92 const fn mode(&self) -> QueryMode {
93 self.intent.mode()
94 }
95
96 #[must_use]
97 fn has_explicit_order(&self) -> bool {
98 self.intent.has_explicit_order()
99 }
100
101 #[must_use]
102 pub(in crate::db) const fn has_grouping(&self) -> bool {
103 self.intent.has_grouping()
104 }
105
106 #[must_use]
107 const fn load_spec(&self) -> Option<LoadSpec> {
108 match self.intent.mode() {
109 QueryMode::Load(spec) => Some(spec),
110 QueryMode::Delete(_) => None,
111 }
112 }
113
114 #[must_use]
115 pub(in crate::db) fn filter_predicate(mut self, predicate: Predicate) -> Self {
116 self.intent = self.intent.filter_predicate(predicate);
117 self
118 }
119
120 #[must_use]
121 pub(in crate::db) fn filter(mut self, expr: impl Into<FilterExpr>) -> Self {
122 self.intent = self.intent.filter(expr.into());
123 self
124 }
125
126 #[must_use]
127 pub(in crate::db) fn filter_expr_with_normalized_predicate(
128 mut self,
129 expr: Expr,
130 predicate: Predicate,
131 ) -> Self {
132 self.intent = self
133 .intent
134 .filter_expr_with_normalized_predicate(expr, predicate);
135 self
136 }
137 pub(in crate::db) fn order_term(mut self, term: FluentOrderTerm) -> Self {
138 self.intent = self.intent.order_term(term);
139 self
140 }
141
142 #[must_use]
143 pub(in crate::db) fn order_spec(mut self, order: OrderSpec) -> Self {
144 self.intent = self.intent.order_spec(order);
145 self
146 }
147
148 #[must_use]
149 pub(in crate::db) fn distinct(mut self) -> Self {
150 self.intent = self.intent.distinct();
151 self
152 }
153
154 #[cfg(feature = "sql")]
155 #[must_use]
156 pub(in crate::db) fn select_fields<I, S>(mut self, fields: I) -> Self
157 where
158 I: IntoIterator<Item = S>,
159 S: Into<String>,
160 {
161 self.intent = self.intent.select_fields(fields);
162 self
163 }
164
165 #[cfg(feature = "sql")]
166 #[must_use]
167 pub(in crate::db) fn projection_selection(mut self, selection: ProjectionSelection) -> Self {
168 self.intent = self.intent.projection_selection(selection);
169 self
170 }
171
172 pub(in crate::db) fn group_by(self, field: impl AsRef<str>) -> Result<Self, QueryError> {
173 self.try_map_intent(|intent| intent.push_group_field(field.as_ref()))
174 }
175
176 #[must_use]
177 pub(in crate::db) fn aggregate(mut self, aggregate: AggregateExpr) -> Self {
178 self.intent = self.intent.push_group_aggregate(aggregate);
179 self
180 }
181
182 #[must_use]
183 fn grouped_limits(mut self, max_groups: u64, max_group_bytes: u64) -> Self {
184 self.intent = self.intent.grouped_limits(max_groups, max_group_bytes);
185 self
186 }
187
188 pub(in crate::db) fn having_group(
189 self,
190 field: impl AsRef<str>,
191 op: CompareOp,
192 value: Value,
193 ) -> Result<Self, QueryError> {
194 let field = field.as_ref().to_owned();
195 self.try_map_intent(|intent| intent.push_having_group_clause(&field, op, value))
196 }
197
198 pub(in crate::db) fn having_aggregate(
199 self,
200 aggregate_index: usize,
201 op: CompareOp,
202 value: Value,
203 ) -> Result<Self, QueryError> {
204 self.try_map_intent(|intent| {
205 intent.push_having_aggregate_clause(aggregate_index, op, value)
206 })
207 }
208
209 pub(in crate::db) fn having_expr(self, expr: Expr) -> Result<Self, QueryError> {
210 self.try_map_intent(|intent| intent.push_having_expr(expr))
211 }
212
213 #[must_use]
214 fn by_id(self, id: Value) -> Self {
215 self.map_intent(|intent| intent.by_id(id))
216 }
217
218 #[must_use]
219 fn by_ids<I>(self, ids: I) -> Self
220 where
221 I: IntoIterator<Item = Value>,
222 {
223 self.map_intent(|intent| intent.by_ids(ids))
224 }
225
226 #[must_use]
227 fn only(self, id: Value) -> Self {
228 self.map_intent(|intent| intent.only(id))
229 }
230
231 #[must_use]
232 pub(in crate::db) fn delete(mut self) -> Self {
233 self.intent = self.intent.delete();
234 self
235 }
236
237 #[must_use]
238 pub(in crate::db) fn limit(mut self, limit: u32) -> Self {
239 self.intent = self.intent.limit(limit);
240 self
241 }
242
243 #[must_use]
244 pub(in crate::db) fn offset(mut self, offset: u32) -> Self {
245 self.intent = self.intent.offset(offset);
246 self
247 }
248
249 pub(in crate::db) fn build_plan(&self) -> Result<AccessPlannedQuery, QueryError> {
250 self.intent.build_plan_model()
251 }
252
253 pub(in crate::db) fn build_plan_with_visible_indexes(
254 &self,
255 visible_indexes: &VisibleIndexes<'_>,
256 ) -> Result<AccessPlannedQuery, QueryError> {
257 self.intent.build_plan_model_with_indexes(visible_indexes)
258 }
259
260 pub(in crate::db) fn prepare_scalar_planning_state(
261 &self,
262 ) -> Result<PreparedScalarPlanningState<'_>, QueryError> {
263 self.intent.prepare_scalar_planning_state()
264 }
265
266 pub(in crate::db) fn build_plan_with_visible_indexes_from_scalar_planning_state(
267 &self,
268 visible_indexes: &VisibleIndexes<'_>,
269 planning_state: PreparedScalarPlanningState<'_>,
270 ) -> Result<AccessPlannedQuery, QueryError> {
271 self.intent
272 .build_plan_model_with_indexes_from_scalar_planning_state(
273 visible_indexes,
274 planning_state,
275 )
276 }
277
278 #[must_use]
279 #[cfg(test)]
280 pub(in crate::db) fn structural_cache_key(
281 &self,
282 ) -> crate::db::query::intent::StructuralQueryCacheKey {
283 crate::db::query::intent::StructuralQueryCacheKey::from_query_model(&self.intent)
284 }
285
286 #[must_use]
287 pub(in crate::db) fn structural_cache_key_with_normalized_predicate_fingerprint(
288 &self,
289 predicate_fingerprint: Option<[u8; 32]>,
290 ) -> crate::db::query::intent::StructuralQueryCacheKey {
291 self.intent
292 .structural_cache_key_with_normalized_predicate_fingerprint(predicate_fingerprint)
293 }
294
295 fn build_plan_for_visibility(
298 &self,
299 visible_indexes: Option<&VisibleIndexes<'_>>,
300 ) -> Result<AccessPlannedQuery, QueryError> {
301 match visible_indexes {
302 Some(visible_indexes) => self.build_plan_with_visible_indexes(visible_indexes),
303 None => self.build_plan(),
304 }
305 }
306
307 fn explain_execution_descriptor_from_plan(
310 &self,
311 plan: &AccessPlannedQuery,
312 ) -> Result<ExplainExecutionNodeDescriptor, QueryError> {
313 assemble_load_execution_node_descriptor(
314 self.intent.model().fields(),
315 self.intent.model().primary_key().name(),
316 plan,
317 )
318 .map_err(QueryError::execute)
319 }
320
321 fn explain_execution_verbose_from_plan(
323 &self,
324 plan: &AccessPlannedQuery,
325 ) -> Result<String, QueryError> {
326 let descriptor = self.explain_execution_descriptor_from_plan(plan)?;
327 let route_diagnostics = assemble_load_execution_verbose_diagnostics(
328 self.intent.model().fields(),
329 self.intent.model().primary_key().name(),
330 plan,
331 )
332 .map_err(QueryError::execute)?;
333 let explain = plan.explain();
334
335 let mut lines = vec![descriptor.render_text_tree_verbose()];
337 lines.extend(route_diagnostics);
338
339 lines.push(format!(
341 "diag.d.has_top_n_seek={}",
342 contains_execution_node_type(&descriptor, ExplainExecutionNodeType::TopNSeek)
343 ));
344 lines.push(format!(
345 "diag.d.has_index_range_limit_pushdown={}",
346 contains_execution_node_type(
347 &descriptor,
348 ExplainExecutionNodeType::IndexRangeLimitPushdown,
349 )
350 ));
351 lines.push(format!(
352 "diag.d.has_index_predicate_prefilter={}",
353 contains_execution_node_type(
354 &descriptor,
355 ExplainExecutionNodeType::IndexPredicatePrefilter,
356 )
357 ));
358 lines.push(format!(
359 "diag.d.has_residual_filter={}",
360 contains_execution_node_type(
361 &descriptor,
362 ExplainExecutionNodeType::ResidualPredicateFilter,
363 )
364 ));
365
366 lines.push(format!("diag.p.mode={:?}", explain.mode()));
368 lines.push(format!(
369 "diag.p.order_pushdown={}",
370 plan_order_pushdown_label(explain.order_pushdown())
371 ));
372 lines.push(format!(
373 "diag.p.predicate_pushdown={}",
374 plan_predicate_pushdown_label(explain.predicate(), explain.access())
375 ));
376 lines.push(format!("diag.p.distinct={}", explain.distinct()));
377 lines.push(format!("diag.p.page={:?}", explain.page()));
378 lines.push(format!("diag.p.consistency={:?}", explain.consistency()));
379
380 Ok(lines.join("\n"))
381 }
382
383 fn finalize_explain_access_choice_for_visibility(
386 &self,
387 plan: &mut AccessPlannedQuery,
388 visible_indexes: Option<&VisibleIndexes<'_>>,
389 ) {
390 let visible_indexes = match visible_indexes {
391 Some(visible_indexes) => visible_indexes.as_slice(),
392 None => self.intent.model().indexes(),
393 };
394
395 plan.finalize_access_choice_for_model_with_indexes(self.intent.model(), visible_indexes);
396 }
397
398 fn explain_execution_descriptor_for_visibility(
401 &self,
402 visible_indexes: Option<&VisibleIndexes<'_>>,
403 ) -> Result<ExplainExecutionNodeDescriptor, QueryError> {
404 let mut plan = self.build_plan_for_visibility(visible_indexes)?;
405 self.finalize_explain_access_choice_for_visibility(&mut plan, visible_indexes);
406
407 self.explain_execution_descriptor_from_plan(&plan)
408 }
409
410 fn explain_execution_verbose_for_visibility(
413 &self,
414 visible_indexes: Option<&VisibleIndexes<'_>>,
415 ) -> Result<String, QueryError> {
416 let mut plan = self.build_plan_for_visibility(visible_indexes)?;
417 self.finalize_explain_access_choice_for_visibility(&mut plan, visible_indexes);
418
419 self.explain_execution_verbose_from_plan(&plan)
420 }
421
422 #[cfg(feature = "sql")]
423 #[must_use]
424 pub(in crate::db) const fn model(&self) -> &'static crate::model::entity::EntityModel {
425 self.intent.model()
426 }
427
428 #[inline(never)]
429 pub(in crate::db) fn explain_execution_with_visible_indexes(
430 &self,
431 visible_indexes: &VisibleIndexes<'_>,
432 ) -> Result<ExplainExecutionNodeDescriptor, QueryError> {
433 self.explain_execution_descriptor_for_visibility(Some(visible_indexes))
434 }
435
436 #[inline(never)]
438 pub(in crate::db) fn explain_execution(
439 &self,
440 ) -> Result<ExplainExecutionNodeDescriptor, QueryError> {
441 self.explain_execution_descriptor_for_visibility(None)
442 }
443
444 #[inline(never)]
447 pub(in crate::db) fn explain_execution_verbose(&self) -> Result<String, QueryError> {
448 self.explain_execution_verbose_for_visibility(None)
449 }
450
451 #[inline(never)]
452 pub(in crate::db) fn explain_execution_verbose_with_visible_indexes(
453 &self,
454 visible_indexes: &VisibleIndexes<'_>,
455 ) -> Result<String, QueryError> {
456 self.explain_execution_verbose_for_visibility(Some(visible_indexes))
457 }
458
459 #[inline(never)]
460 pub(in crate::db) fn explain_aggregate_terminal_with_visible_indexes(
461 &self,
462 visible_indexes: &VisibleIndexes<'_>,
463 aggregate: AggregateRouteShape<'_>,
464 ) -> Result<ExplainAggregateTerminalPlan, QueryError> {
465 let plan = self.build_plan_with_visible_indexes(visible_indexes)?;
466 let query_explain = plan.explain();
467 let terminal = aggregate.kind();
468 let execution = assemble_aggregate_terminal_execution_descriptor(&plan, aggregate);
469
470 Ok(ExplainAggregateTerminalPlan::new(
471 query_explain,
472 terminal,
473 execution,
474 ))
475 }
476
477 #[inline(never)]
478 pub(in crate::db) fn explain_prepared_aggregate_terminal_with_visible_indexes<S>(
479 &self,
480 visible_indexes: &VisibleIndexes<'_>,
481 strategy: &S,
482 ) -> Result<ExplainAggregateTerminalPlan, QueryError>
483 where
484 S: PreparedFluentAggregateExplainStrategy,
485 {
486 let Some(kind) = strategy.explain_aggregate_kind() else {
487 return Err(QueryError::invariant(
488 "prepared fluent aggregate explain requires an explain-visible aggregate kind",
489 ));
490 };
491 let aggregate = AggregateRouteShape::new_from_fields(
492 kind,
493 strategy.explain_projected_field(),
494 self.intent.model().fields(),
495 self.intent.model().primary_key().name(),
496 );
497
498 self.explain_aggregate_terminal_with_visible_indexes(visible_indexes, aggregate)
499 }
500}
501
502#[derive(Clone, Debug)]
512enum QueryPlanHandle {
513 Plan(Box<AccessPlannedQuery>),
514 Prepared(SharedPreparedExecutionPlan),
515}
516
517impl QueryPlanHandle {
518 #[must_use]
519 fn from_plan(plan: AccessPlannedQuery) -> Self {
520 Self::Plan(Box::new(plan))
521 }
522
523 #[must_use]
524 const fn from_prepared(prepared_plan: SharedPreparedExecutionPlan) -> Self {
525 Self::Prepared(prepared_plan)
526 }
527
528 #[must_use]
529 fn logical_plan(&self) -> &AccessPlannedQuery {
530 match self {
531 Self::Plan(plan) => plan,
532 Self::Prepared(prepared_plan) => prepared_plan.logical_plan(),
533 }
534 }
535
536 fn into_prepared_execution_plan<E: EntityKind>(self) -> PreparedExecutionPlan<E> {
537 match self {
538 Self::Plan(plan) => PreparedExecutionPlan::new(*plan),
539 Self::Prepared(prepared_plan) => prepared_plan.typed_clone::<E>(),
540 }
541 }
542
543 #[must_use]
544 #[cfg(test)]
545 fn into_inner(self) -> AccessPlannedQuery {
546 match self {
547 Self::Plan(plan) => *plan,
548 Self::Prepared(prepared_plan) => prepared_plan.logical_plan().clone(),
549 }
550 }
551}
552
553#[derive(Debug)]
561pub struct PlannedQuery<E: EntityKind> {
562 plan: QueryPlanHandle,
563 _marker: PhantomData<E>,
564}
565
566impl<E: EntityKind> PlannedQuery<E> {
567 #[must_use]
568 fn from_plan(plan: AccessPlannedQuery) -> Self {
569 Self {
570 plan: QueryPlanHandle::from_plan(plan),
571 _marker: PhantomData,
572 }
573 }
574
575 #[must_use]
576 pub(in crate::db) const fn from_prepared_plan(
577 prepared_plan: SharedPreparedExecutionPlan,
578 ) -> Self {
579 Self {
580 plan: QueryPlanHandle::from_prepared(prepared_plan),
581 _marker: PhantomData,
582 }
583 }
584
585 #[must_use]
586 pub fn explain(&self) -> ExplainPlan {
587 self.plan.logical_plan().explain()
588 }
589
590 #[must_use]
592 pub fn plan_hash_hex(&self) -> String {
593 self.plan.logical_plan().fingerprint().to_string()
594 }
595}
596
597#[derive(Clone, Debug)]
607pub struct CompiledQuery<E: EntityKind> {
608 plan: QueryPlanHandle,
609 _marker: PhantomData<E>,
610}
611
612impl<E: EntityKind> CompiledQuery<E> {
613 #[must_use]
614 fn from_plan(plan: AccessPlannedQuery) -> Self {
615 Self {
616 plan: QueryPlanHandle::from_plan(plan),
617 _marker: PhantomData,
618 }
619 }
620
621 #[must_use]
622 pub(in crate::db) const fn from_prepared_plan(
623 prepared_plan: SharedPreparedExecutionPlan,
624 ) -> Self {
625 Self {
626 plan: QueryPlanHandle::from_prepared(prepared_plan),
627 _marker: PhantomData,
628 }
629 }
630
631 #[must_use]
632 pub fn explain(&self) -> ExplainPlan {
633 self.plan.logical_plan().explain()
634 }
635
636 #[must_use]
638 pub fn plan_hash_hex(&self) -> String {
639 self.plan.logical_plan().fingerprint().to_string()
640 }
641
642 #[must_use]
643 #[cfg(test)]
644 pub(in crate::db) fn projection_spec(&self) -> crate::db::query::plan::expr::ProjectionSpec {
645 self.plan.logical_plan().projection_spec(E::MODEL)
646 }
647
648 pub(in crate::db) fn into_prepared_execution_plan(
650 self,
651 ) -> crate::db::executor::PreparedExecutionPlan<E> {
652 self.plan.into_prepared_execution_plan::<E>()
653 }
654
655 #[must_use]
656 #[cfg(test)]
657 pub(in crate::db) fn into_inner(self) -> AccessPlannedQuery {
658 self.plan.into_inner()
659 }
660}
661
662#[derive(Debug)]
674pub struct Query<E: EntityKind> {
675 inner: StructuralQuery,
676 _marker: PhantomData<E>,
677}
678
679impl<E: EntityKind> Query<E> {
680 pub(in crate::db) const fn from_inner(inner: StructuralQuery) -> Self {
682 Self {
683 inner,
684 _marker: PhantomData,
685 }
686 }
687
688 #[must_use]
692 pub const fn new(consistency: MissingRowPolicy) -> Self {
693 Self::from_inner(StructuralQuery::new(E::MODEL, consistency))
694 }
695
696 #[must_use]
698 pub const fn mode(&self) -> QueryMode {
699 self.inner.mode()
700 }
701
702 pub(in crate::db) fn explain_with_visible_indexes(
703 &self,
704 visible_indexes: &VisibleIndexes<'_>,
705 ) -> Result<ExplainPlan, QueryError> {
706 let plan = self.build_plan_for_visibility(Some(visible_indexes))?;
707
708 Ok(plan.explain())
709 }
710
711 pub(in crate::db) fn plan_hash_hex_with_visible_indexes(
712 &self,
713 visible_indexes: &VisibleIndexes<'_>,
714 ) -> Result<String, QueryError> {
715 let plan = self.build_plan_for_visibility(Some(visible_indexes))?;
716
717 Ok(plan.fingerprint().to_string())
718 }
719
720 fn build_plan_for_visibility(
723 &self,
724 visible_indexes: Option<&VisibleIndexes<'_>>,
725 ) -> Result<AccessPlannedQuery, QueryError> {
726 self.inner.build_plan_for_visibility(visible_indexes)
727 }
728
729 fn map_plan_for_visibility<T>(
733 &self,
734 visible_indexes: Option<&VisibleIndexes<'_>>,
735 map: impl FnOnce(AccessPlannedQuery) -> T,
736 ) -> Result<T, QueryError> {
737 let plan = self.build_plan_for_visibility(visible_indexes)?;
738
739 Ok(map(plan))
740 }
741
742 fn prepared_execution_plan_for_visibility(
746 &self,
747 visible_indexes: Option<&VisibleIndexes<'_>>,
748 ) -> Result<PreparedExecutionPlan<E>, QueryError> {
749 self.map_plan_for_visibility(visible_indexes, PreparedExecutionPlan::<E>::new)
750 }
751
752 pub(in crate::db) fn planned_query_from_plan(plan: AccessPlannedQuery) -> PlannedQuery<E> {
754 PlannedQuery::from_plan(plan)
755 }
756
757 pub(in crate::db) fn compiled_query_from_plan(plan: AccessPlannedQuery) -> CompiledQuery<E> {
759 CompiledQuery::from_plan(plan)
760 }
761
762 #[must_use]
763 pub(crate) fn has_explicit_order(&self) -> bool {
764 self.inner.has_explicit_order()
765 }
766
767 #[must_use]
768 pub(in crate::db) const fn structural(&self) -> &StructuralQuery {
769 &self.inner
770 }
771
772 #[must_use]
773 pub const fn has_grouping(&self) -> bool {
774 self.inner.has_grouping()
775 }
776
777 #[must_use]
778 pub(crate) const fn load_spec(&self) -> Option<LoadSpec> {
779 self.inner.load_spec()
780 }
781
782 #[must_use]
784 pub fn filter(mut self, expr: impl Into<FilterExpr>) -> Self {
785 self.inner = self.inner.filter(expr);
786 self
787 }
788
789 #[must_use]
790 pub(in crate::db) fn filter_predicate(mut self, predicate: Predicate) -> Self {
791 self.inner = self.inner.filter_predicate(predicate);
792 self
793 }
794
795 #[must_use]
797 pub fn order_term(mut self, term: FluentOrderTerm) -> Self {
798 self.inner = self.inner.order_term(term);
799 self
800 }
801
802 #[must_use]
804 pub fn order_terms<I>(mut self, terms: I) -> Self
805 where
806 I: IntoIterator<Item = FluentOrderTerm>,
807 {
808 for term in terms {
809 self.inner = self.inner.order_term(term);
810 }
811
812 self
813 }
814
815 #[must_use]
817 pub fn distinct(mut self) -> Self {
818 self.inner = self.inner.distinct();
819 self
820 }
821
822 #[cfg(all(test, feature = "sql"))]
825 #[must_use]
826 pub(in crate::db) fn select_fields<I, S>(mut self, fields: I) -> Self
827 where
828 I: IntoIterator<Item = S>,
829 S: Into<String>,
830 {
831 self.inner = self.inner.select_fields(fields);
832 self
833 }
834
835 pub fn group_by(self, field: impl AsRef<str>) -> Result<Self, QueryError> {
837 let Self { inner, .. } = self;
838 let inner = inner.group_by(field)?;
839
840 Ok(Self::from_inner(inner))
841 }
842
843 #[must_use]
845 pub fn aggregate(mut self, aggregate: AggregateExpr) -> Self {
846 self.inner = self.inner.aggregate(aggregate);
847 self
848 }
849
850 #[must_use]
852 pub fn grouped_limits(mut self, max_groups: u64, max_group_bytes: u64) -> Self {
853 self.inner = self.inner.grouped_limits(max_groups, max_group_bytes);
854 self
855 }
856
857 pub fn having_group(
859 self,
860 field: impl AsRef<str>,
861 op: CompareOp,
862 value: Value,
863 ) -> Result<Self, QueryError> {
864 let Self { inner, .. } = self;
865 let inner = inner.having_group(field, op, value)?;
866
867 Ok(Self::from_inner(inner))
868 }
869
870 pub fn having_aggregate(
872 self,
873 aggregate_index: usize,
874 op: CompareOp,
875 value: Value,
876 ) -> Result<Self, QueryError> {
877 let Self { inner, .. } = self;
878 let inner = inner.having_aggregate(aggregate_index, op, value)?;
879
880 Ok(Self::from_inner(inner))
881 }
882
883 pub(crate) fn by_id(self, id: E::Key) -> Self {
885 let Self { inner, .. } = self;
886
887 Self::from_inner(inner.by_id(id.to_value()))
888 }
889
890 pub(crate) fn by_ids<I>(self, ids: I) -> Self
892 where
893 I: IntoIterator<Item = E::Key>,
894 {
895 let Self { inner, .. } = self;
896
897 Self::from_inner(inner.by_ids(ids.into_iter().map(|id| id.to_value())))
898 }
899
900 #[must_use]
902 pub fn delete(mut self) -> Self {
903 self.inner = self.inner.delete();
904 self
905 }
906
907 #[must_use]
914 pub fn limit(mut self, limit: u32) -> Self {
915 self.inner = self.inner.limit(limit);
916 self
917 }
918
919 #[must_use]
925 pub fn offset(mut self, offset: u32) -> Self {
926 self.inner = self.inner.offset(offset);
927 self
928 }
929
930 pub fn explain(&self) -> Result<ExplainPlan, QueryError> {
932 let plan = self.planned()?;
933
934 Ok(plan.explain())
935 }
936
937 pub fn plan_hash_hex(&self) -> Result<String, QueryError> {
942 let plan = self.inner.build_plan()?;
943
944 Ok(plan.fingerprint().to_string())
945 }
946
947 fn explain_execution_descriptor_for_visibility(
950 &self,
951 visible_indexes: Option<&VisibleIndexes<'_>>,
952 ) -> Result<ExplainExecutionNodeDescriptor, QueryError>
953 where
954 E: EntityValue,
955 {
956 match visible_indexes {
957 Some(visible_indexes) => self
958 .inner
959 .explain_execution_with_visible_indexes(visible_indexes),
960 None => self.inner.explain_execution(),
961 }
962 }
963
964 fn render_execution_descriptor_for_visibility(
967 &self,
968 visible_indexes: Option<&VisibleIndexes<'_>>,
969 render: impl FnOnce(ExplainExecutionNodeDescriptor) -> String,
970 ) -> Result<String, QueryError>
971 where
972 E: EntityValue,
973 {
974 let descriptor = self.explain_execution_descriptor_for_visibility(visible_indexes)?;
975
976 Ok(render(descriptor))
977 }
978
979 fn explain_execution_verbose_for_visibility(
982 &self,
983 visible_indexes: Option<&VisibleIndexes<'_>>,
984 ) -> Result<String, QueryError>
985 where
986 E: EntityValue,
987 {
988 match visible_indexes {
989 Some(visible_indexes) => self
990 .inner
991 .explain_execution_verbose_with_visible_indexes(visible_indexes),
992 None => self.inner.explain_execution_verbose(),
993 }
994 }
995
996 pub fn explain_execution(&self) -> Result<ExplainExecutionNodeDescriptor, QueryError>
998 where
999 E: EntityValue,
1000 {
1001 self.explain_execution_descriptor_for_visibility(None)
1002 }
1003
1004 pub(in crate::db) fn explain_execution_with_visible_indexes(
1005 &self,
1006 visible_indexes: &VisibleIndexes<'_>,
1007 ) -> Result<ExplainExecutionNodeDescriptor, QueryError>
1008 where
1009 E: EntityValue,
1010 {
1011 self.explain_execution_descriptor_for_visibility(Some(visible_indexes))
1012 }
1013
1014 pub fn explain_execution_text(&self) -> Result<String, QueryError>
1016 where
1017 E: EntityValue,
1018 {
1019 self.render_execution_descriptor_for_visibility(None, |descriptor| {
1020 descriptor.render_text_tree()
1021 })
1022 }
1023
1024 pub fn explain_execution_json(&self) -> Result<String, QueryError>
1026 where
1027 E: EntityValue,
1028 {
1029 self.render_execution_descriptor_for_visibility(None, |descriptor| {
1030 descriptor.render_json_canonical()
1031 })
1032 }
1033
1034 #[inline(never)]
1036 pub fn explain_execution_verbose(&self) -> Result<String, QueryError>
1037 where
1038 E: EntityValue,
1039 {
1040 self.explain_execution_verbose_for_visibility(None)
1041 }
1042
1043 pub(in crate::db) fn explain_execution_verbose_with_visible_indexes(
1044 &self,
1045 visible_indexes: &VisibleIndexes<'_>,
1046 ) -> Result<String, QueryError>
1047 where
1048 E: EntityValue,
1049 {
1050 self.explain_execution_verbose_for_visibility(Some(visible_indexes))
1051 }
1052
1053 #[cfg(test)]
1055 #[inline(never)]
1056 pub(in crate::db) fn explain_aggregate_terminal(
1057 &self,
1058 aggregate: AggregateExpr,
1059 ) -> Result<ExplainAggregateTerminalPlan, QueryError>
1060 where
1061 E: EntityValue,
1062 {
1063 self.inner.explain_aggregate_terminal_with_visible_indexes(
1064 &VisibleIndexes::schema_owned(E::MODEL.indexes()),
1065 AggregateRouteShape::new_from_fields(
1066 aggregate.kind(),
1067 aggregate.target_field(),
1068 E::MODEL.fields(),
1069 E::MODEL.primary_key().name(),
1070 ),
1071 )
1072 }
1073
1074 pub(in crate::db) fn explain_prepared_aggregate_terminal_with_visible_indexes<S>(
1075 &self,
1076 visible_indexes: &VisibleIndexes<'_>,
1077 strategy: &S,
1078 ) -> Result<ExplainAggregateTerminalPlan, QueryError>
1079 where
1080 E: EntityValue,
1081 S: PreparedFluentAggregateExplainStrategy,
1082 {
1083 self.inner
1084 .explain_prepared_aggregate_terminal_with_visible_indexes(visible_indexes, strategy)
1085 }
1086
1087 pub(in crate::db) fn explain_bytes_by_with_visible_indexes(
1088 &self,
1089 visible_indexes: &VisibleIndexes<'_>,
1090 target_field: &str,
1091 ) -> Result<ExplainExecutionNodeDescriptor, QueryError>
1092 where
1093 E: EntityValue,
1094 {
1095 let executable = self.prepared_execution_plan_for_visibility(Some(visible_indexes))?;
1096 let mut descriptor = executable
1097 .explain_load_execution_node_descriptor()
1098 .map_err(QueryError::execute)?;
1099 let projection_mode = executable.bytes_by_projection_mode(target_field);
1100 let projection_mode_label =
1101 PreparedExecutionPlan::<E>::bytes_by_projection_mode_label(projection_mode);
1102
1103 descriptor
1104 .node_properties
1105 .insert("terminal", Value::from("bytes_by"));
1106 descriptor
1107 .node_properties
1108 .insert("terminal_field", Value::from(target_field.to_string()));
1109 descriptor.node_properties.insert(
1110 "terminal_projection_mode",
1111 Value::from(projection_mode_label),
1112 );
1113 descriptor.node_properties.insert(
1114 "terminal_index_only",
1115 Value::from(matches!(
1116 projection_mode,
1117 BytesByProjectionMode::CoveringIndex | BytesByProjectionMode::CoveringConstant
1118 )),
1119 );
1120
1121 Ok(descriptor)
1122 }
1123
1124 pub(in crate::db) fn explain_prepared_projection_terminal_with_visible_indexes(
1125 &self,
1126 visible_indexes: &VisibleIndexes<'_>,
1127 strategy: &PreparedFluentProjectionStrategy,
1128 ) -> Result<ExplainExecutionNodeDescriptor, QueryError>
1129 where
1130 E: EntityValue,
1131 {
1132 let executable = self.prepared_execution_plan_for_visibility(Some(visible_indexes))?;
1133 let mut descriptor = executable
1134 .explain_load_execution_node_descriptor()
1135 .map_err(QueryError::execute)?;
1136 let projection_descriptor = strategy.explain_descriptor();
1137
1138 descriptor.node_properties.insert(
1139 "terminal",
1140 Value::from(projection_descriptor.terminal_label()),
1141 );
1142 descriptor.node_properties.insert(
1143 "terminal_field",
1144 Value::from(projection_descriptor.field_label().to_string()),
1145 );
1146 descriptor.node_properties.insert(
1147 "terminal_output",
1148 Value::from(projection_descriptor.output_label()),
1149 );
1150
1151 Ok(descriptor)
1152 }
1153
1154 pub fn planned(&self) -> Result<PlannedQuery<E>, QueryError> {
1156 self.map_plan_for_visibility(None, Self::planned_query_from_plan)
1157 }
1158
1159 pub fn plan(&self) -> Result<CompiledQuery<E>, QueryError> {
1163 self.map_plan_for_visibility(None, Self::compiled_query_from_plan)
1164 }
1165
1166 #[cfg(test)]
1167 pub(in crate::db) fn plan_with_visible_indexes(
1168 &self,
1169 visible_indexes: &VisibleIndexes<'_>,
1170 ) -> Result<CompiledQuery<E>, QueryError> {
1171 self.map_plan_for_visibility(Some(visible_indexes), Self::compiled_query_from_plan)
1172 }
1173}
1174
1175fn contains_execution_node_type(
1176 descriptor: &ExplainExecutionNodeDescriptor,
1177 target: ExplainExecutionNodeType,
1178) -> bool {
1179 descriptor.node_type() == target
1180 || descriptor
1181 .children()
1182 .iter()
1183 .any(|child| contains_execution_node_type(child, target))
1184}
1185
1186fn plan_order_pushdown_label(order_pushdown: &ExplainOrderPushdown) -> String {
1187 match order_pushdown {
1188 ExplainOrderPushdown::MissingModelContext => "missing_model_context".to_string(),
1189 ExplainOrderPushdown::EligibleSecondaryIndex { index, prefix_len } => {
1190 format!("eligible(index={index},prefix_len={prefix_len})",)
1191 }
1192 ExplainOrderPushdown::Rejected(reason) => format!("rejected({reason:?})"),
1193 }
1194}
1195
1196fn plan_predicate_pushdown_label(
1197 predicate: &ExplainPredicate,
1198 access: &ExplainAccessPath,
1199) -> String {
1200 let access_label = match access {
1201 ExplainAccessPath::ByKey { .. } => "by_key",
1202 ExplainAccessPath::ByKeys { keys } if keys.is_empty() => "empty_access_contract",
1203 ExplainAccessPath::ByKeys { .. } => "by_keys",
1204 ExplainAccessPath::KeyRange { .. } => "key_range",
1205 ExplainAccessPath::IndexPrefix { .. } => "index_prefix",
1206 ExplainAccessPath::IndexMultiLookup { .. } => "index_multi_lookup",
1207 ExplainAccessPath::IndexRange { .. } => "index_range",
1208 ExplainAccessPath::FullScan => "full_scan",
1209 ExplainAccessPath::Union(_) => "union",
1210 ExplainAccessPath::Intersection(_) => "intersection",
1211 };
1212 if matches!(predicate, ExplainPredicate::None) {
1213 return "none".to_string();
1214 }
1215 if matches!(access, ExplainAccessPath::FullScan) {
1216 if explain_predicate_contains_non_strict_compare(predicate) {
1217 return "fallback(non_strict_compare_coercion)".to_string();
1218 }
1219 if explain_predicate_contains_empty_prefix_starts_with(predicate) {
1220 return "fallback(starts_with_empty_prefix)".to_string();
1221 }
1222 if explain_predicate_contains_is_null(predicate) {
1223 return "fallback(is_null_full_scan)".to_string();
1224 }
1225 if explain_predicate_contains_text_scan_operator(predicate) {
1226 return "fallback(text_operator_full_scan)".to_string();
1227 }
1228
1229 return format!("fallback({access_label})");
1230 }
1231
1232 format!("applied({access_label})")
1233}
1234
1235fn explain_predicate_contains_non_strict_compare(predicate: &ExplainPredicate) -> bool {
1236 match predicate {
1237 ExplainPredicate::Compare { coercion, .. }
1238 | ExplainPredicate::CompareFields { coercion, .. } => coercion.id != CoercionId::Strict,
1239 ExplainPredicate::And(children) | ExplainPredicate::Or(children) => children
1240 .iter()
1241 .any(explain_predicate_contains_non_strict_compare),
1242 ExplainPredicate::Not(inner) => explain_predicate_contains_non_strict_compare(inner),
1243 ExplainPredicate::None
1244 | ExplainPredicate::True
1245 | ExplainPredicate::False
1246 | ExplainPredicate::IsNull { .. }
1247 | ExplainPredicate::IsNotNull { .. }
1248 | ExplainPredicate::IsMissing { .. }
1249 | ExplainPredicate::IsEmpty { .. }
1250 | ExplainPredicate::IsNotEmpty { .. }
1251 | ExplainPredicate::TextContains { .. }
1252 | ExplainPredicate::TextContainsCi { .. } => false,
1253 }
1254}
1255
1256fn explain_predicate_contains_is_null(predicate: &ExplainPredicate) -> bool {
1257 match predicate {
1258 ExplainPredicate::IsNull { .. } => true,
1259 ExplainPredicate::And(children) | ExplainPredicate::Or(children) => {
1260 children.iter().any(explain_predicate_contains_is_null)
1261 }
1262 ExplainPredicate::Not(inner) => explain_predicate_contains_is_null(inner),
1263 ExplainPredicate::None
1264 | ExplainPredicate::True
1265 | ExplainPredicate::False
1266 | ExplainPredicate::Compare { .. }
1267 | ExplainPredicate::CompareFields { .. }
1268 | ExplainPredicate::IsNotNull { .. }
1269 | ExplainPredicate::IsMissing { .. }
1270 | ExplainPredicate::IsEmpty { .. }
1271 | ExplainPredicate::IsNotEmpty { .. }
1272 | ExplainPredicate::TextContains { .. }
1273 | ExplainPredicate::TextContainsCi { .. } => false,
1274 }
1275}
1276
1277fn explain_predicate_contains_empty_prefix_starts_with(predicate: &ExplainPredicate) -> bool {
1278 match predicate {
1279 ExplainPredicate::Compare {
1280 op: CompareOp::StartsWith,
1281 value: Value::Text(prefix),
1282 ..
1283 } => prefix.is_empty(),
1284 ExplainPredicate::And(children) | ExplainPredicate::Or(children) => children
1285 .iter()
1286 .any(explain_predicate_contains_empty_prefix_starts_with),
1287 ExplainPredicate::Not(inner) => explain_predicate_contains_empty_prefix_starts_with(inner),
1288 ExplainPredicate::None
1289 | ExplainPredicate::True
1290 | ExplainPredicate::False
1291 | ExplainPredicate::Compare { .. }
1292 | ExplainPredicate::CompareFields { .. }
1293 | ExplainPredicate::IsNull { .. }
1294 | ExplainPredicate::IsNotNull { .. }
1295 | ExplainPredicate::IsMissing { .. }
1296 | ExplainPredicate::IsEmpty { .. }
1297 | ExplainPredicate::IsNotEmpty { .. }
1298 | ExplainPredicate::TextContains { .. }
1299 | ExplainPredicate::TextContainsCi { .. } => false,
1300 }
1301}
1302
1303fn explain_predicate_contains_text_scan_operator(predicate: &ExplainPredicate) -> bool {
1304 match predicate {
1305 ExplainPredicate::Compare {
1306 op: CompareOp::EndsWith,
1307 ..
1308 }
1309 | ExplainPredicate::TextContains { .. }
1310 | ExplainPredicate::TextContainsCi { .. } => true,
1311 ExplainPredicate::And(children) | ExplainPredicate::Or(children) => children
1312 .iter()
1313 .any(explain_predicate_contains_text_scan_operator),
1314 ExplainPredicate::Not(inner) => explain_predicate_contains_text_scan_operator(inner),
1315 ExplainPredicate::Compare { .. }
1316 | ExplainPredicate::CompareFields { .. }
1317 | ExplainPredicate::None
1318 | ExplainPredicate::True
1319 | ExplainPredicate::False
1320 | ExplainPredicate::IsNull { .. }
1321 | ExplainPredicate::IsNotNull { .. }
1322 | ExplainPredicate::IsMissing { .. }
1323 | ExplainPredicate::IsEmpty { .. }
1324 | ExplainPredicate::IsNotEmpty { .. } => false,
1325 }
1326}
1327
1328impl<E> Query<E>
1329where
1330 E: EntityKind + SingletonEntity,
1331 E::Key: Default,
1332{
1333 pub(crate) fn only(self) -> Self {
1335 let Self { inner, .. } = self;
1336
1337 Self::from_inner(inner.only(E::Key::default().to_value()))
1338 }
1339}