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(&descriptor, ExplainExecutionNodeType::ResidualFilter,)
361 ));
362
363 lines.push(format!("diag.p.mode={:?}", explain.mode()));
365 lines.push(format!(
366 "diag.p.order_pushdown={}",
367 plan_order_pushdown_label(explain.order_pushdown())
368 ));
369 lines.push(format!(
370 "diag.p.predicate_pushdown={}",
371 plan_predicate_pushdown_label(explain.predicate(), explain.access())
372 ));
373 lines.push(format!("diag.p.distinct={}", explain.distinct()));
374 lines.push(format!("diag.p.page={:?}", explain.page()));
375 lines.push(format!("diag.p.consistency={:?}", explain.consistency()));
376
377 Ok(lines.join("\n"))
378 }
379
380 fn finalize_explain_access_choice_for_visibility(
383 &self,
384 plan: &mut AccessPlannedQuery,
385 visible_indexes: Option<&VisibleIndexes<'_>>,
386 ) {
387 let visible_indexes = match visible_indexes {
388 Some(visible_indexes) => visible_indexes.as_slice(),
389 None => self.intent.model().indexes(),
390 };
391
392 plan.finalize_access_choice_for_model_with_indexes(self.intent.model(), visible_indexes);
393 }
394
395 fn explain_execution_descriptor_for_visibility(
398 &self,
399 visible_indexes: Option<&VisibleIndexes<'_>>,
400 ) -> Result<ExplainExecutionNodeDescriptor, QueryError> {
401 let mut plan = self.build_plan_for_visibility(visible_indexes)?;
402 self.finalize_explain_access_choice_for_visibility(&mut plan, visible_indexes);
403
404 self.explain_execution_descriptor_from_plan(&plan)
405 }
406
407 fn explain_execution_verbose_for_visibility(
410 &self,
411 visible_indexes: Option<&VisibleIndexes<'_>>,
412 ) -> Result<String, QueryError> {
413 let mut plan = self.build_plan_for_visibility(visible_indexes)?;
414 self.finalize_explain_access_choice_for_visibility(&mut plan, visible_indexes);
415
416 self.explain_execution_verbose_from_plan(&plan)
417 }
418
419 #[cfg(feature = "sql")]
420 #[must_use]
421 pub(in crate::db) const fn model(&self) -> &'static crate::model::entity::EntityModel {
422 self.intent.model()
423 }
424
425 #[inline(never)]
426 pub(in crate::db) fn explain_execution_with_visible_indexes(
427 &self,
428 visible_indexes: &VisibleIndexes<'_>,
429 ) -> Result<ExplainExecutionNodeDescriptor, QueryError> {
430 self.explain_execution_descriptor_for_visibility(Some(visible_indexes))
431 }
432
433 #[inline(never)]
435 pub(in crate::db) fn explain_execution(
436 &self,
437 ) -> Result<ExplainExecutionNodeDescriptor, QueryError> {
438 self.explain_execution_descriptor_for_visibility(None)
439 }
440
441 #[inline(never)]
444 pub(in crate::db) fn explain_execution_verbose(&self) -> Result<String, QueryError> {
445 self.explain_execution_verbose_for_visibility(None)
446 }
447
448 #[inline(never)]
449 pub(in crate::db) fn explain_execution_verbose_with_visible_indexes(
450 &self,
451 visible_indexes: &VisibleIndexes<'_>,
452 ) -> Result<String, QueryError> {
453 self.explain_execution_verbose_for_visibility(Some(visible_indexes))
454 }
455
456 #[inline(never)]
457 pub(in crate::db) fn explain_aggregate_terminal_with_visible_indexes(
458 &self,
459 visible_indexes: &VisibleIndexes<'_>,
460 aggregate: AggregateRouteShape<'_>,
461 ) -> Result<ExplainAggregateTerminalPlan, QueryError> {
462 let plan = self.build_plan_with_visible_indexes(visible_indexes)?;
463 let query_explain = plan.explain();
464 let terminal = aggregate.kind();
465 let execution = assemble_aggregate_terminal_execution_descriptor(&plan, aggregate);
466
467 Ok(ExplainAggregateTerminalPlan::new(
468 query_explain,
469 terminal,
470 execution,
471 ))
472 }
473
474 #[inline(never)]
475 pub(in crate::db) fn explain_prepared_aggregate_terminal_with_visible_indexes<S>(
476 &self,
477 visible_indexes: &VisibleIndexes<'_>,
478 strategy: &S,
479 ) -> Result<ExplainAggregateTerminalPlan, QueryError>
480 where
481 S: PreparedFluentAggregateExplainStrategy,
482 {
483 let Some(kind) = strategy.explain_aggregate_kind() else {
484 return Err(QueryError::invariant(
485 "prepared fluent aggregate explain requires an explain-visible aggregate kind",
486 ));
487 };
488 let aggregate = AggregateRouteShape::new_from_fields(
489 kind,
490 strategy.explain_projected_field(),
491 self.intent.model().fields(),
492 self.intent.model().primary_key().name(),
493 );
494
495 self.explain_aggregate_terminal_with_visible_indexes(visible_indexes, aggregate)
496 }
497}
498
499#[derive(Clone, Debug)]
509enum QueryPlanHandle {
510 Plan(Box<AccessPlannedQuery>),
511 Prepared(SharedPreparedExecutionPlan),
512}
513
514impl QueryPlanHandle {
515 #[must_use]
516 fn from_plan(plan: AccessPlannedQuery) -> Self {
517 Self::Plan(Box::new(plan))
518 }
519
520 #[must_use]
521 const fn from_prepared(prepared_plan: SharedPreparedExecutionPlan) -> Self {
522 Self::Prepared(prepared_plan)
523 }
524
525 #[must_use]
526 fn logical_plan(&self) -> &AccessPlannedQuery {
527 match self {
528 Self::Plan(plan) => plan,
529 Self::Prepared(prepared_plan) => prepared_plan.logical_plan(),
530 }
531 }
532
533 fn into_prepared_execution_plan<E: EntityKind>(self) -> PreparedExecutionPlan<E> {
534 match self {
535 Self::Plan(plan) => PreparedExecutionPlan::new(*plan),
536 Self::Prepared(prepared_plan) => prepared_plan.typed_clone::<E>(),
537 }
538 }
539
540 #[must_use]
541 #[cfg(test)]
542 fn into_inner(self) -> AccessPlannedQuery {
543 match self {
544 Self::Plan(plan) => *plan,
545 Self::Prepared(prepared_plan) => prepared_plan.logical_plan().clone(),
546 }
547 }
548}
549
550#[derive(Debug)]
558pub struct PlannedQuery<E: EntityKind> {
559 plan: QueryPlanHandle,
560 _marker: PhantomData<E>,
561}
562
563impl<E: EntityKind> PlannedQuery<E> {
564 #[must_use]
565 fn from_plan(plan: AccessPlannedQuery) -> Self {
566 Self {
567 plan: QueryPlanHandle::from_plan(plan),
568 _marker: PhantomData,
569 }
570 }
571
572 #[must_use]
573 pub(in crate::db) const fn from_prepared_plan(
574 prepared_plan: SharedPreparedExecutionPlan,
575 ) -> Self {
576 Self {
577 plan: QueryPlanHandle::from_prepared(prepared_plan),
578 _marker: PhantomData,
579 }
580 }
581
582 #[must_use]
583 pub fn explain(&self) -> ExplainPlan {
584 self.plan.logical_plan().explain()
585 }
586
587 #[must_use]
589 pub fn plan_hash_hex(&self) -> String {
590 self.plan.logical_plan().fingerprint().to_string()
591 }
592}
593
594#[derive(Clone, Debug)]
604pub struct CompiledQuery<E: EntityKind> {
605 plan: QueryPlanHandle,
606 _marker: PhantomData<E>,
607}
608
609impl<E: EntityKind> CompiledQuery<E> {
610 #[must_use]
611 fn from_plan(plan: AccessPlannedQuery) -> Self {
612 Self {
613 plan: QueryPlanHandle::from_plan(plan),
614 _marker: PhantomData,
615 }
616 }
617
618 #[must_use]
619 pub(in crate::db) const fn from_prepared_plan(
620 prepared_plan: SharedPreparedExecutionPlan,
621 ) -> Self {
622 Self {
623 plan: QueryPlanHandle::from_prepared(prepared_plan),
624 _marker: PhantomData,
625 }
626 }
627
628 #[must_use]
629 pub fn explain(&self) -> ExplainPlan {
630 self.plan.logical_plan().explain()
631 }
632
633 #[must_use]
635 pub fn plan_hash_hex(&self) -> String {
636 self.plan.logical_plan().fingerprint().to_string()
637 }
638
639 #[must_use]
640 #[cfg(test)]
641 pub(in crate::db) fn projection_spec(&self) -> crate::db::query::plan::expr::ProjectionSpec {
642 self.plan.logical_plan().projection_spec(E::MODEL)
643 }
644
645 pub(in crate::db) fn into_prepared_execution_plan(
647 self,
648 ) -> crate::db::executor::PreparedExecutionPlan<E> {
649 self.plan.into_prepared_execution_plan::<E>()
650 }
651
652 #[must_use]
653 #[cfg(test)]
654 pub(in crate::db) fn into_inner(self) -> AccessPlannedQuery {
655 self.plan.into_inner()
656 }
657}
658
659#[derive(Debug)]
671pub struct Query<E: EntityKind> {
672 inner: StructuralQuery,
673 _marker: PhantomData<E>,
674}
675
676impl<E: EntityKind> Query<E> {
677 pub(in crate::db) const fn from_inner(inner: StructuralQuery) -> Self {
679 Self {
680 inner,
681 _marker: PhantomData,
682 }
683 }
684
685 #[must_use]
689 pub const fn new(consistency: MissingRowPolicy) -> Self {
690 Self::from_inner(StructuralQuery::new(E::MODEL, consistency))
691 }
692
693 #[must_use]
695 pub const fn mode(&self) -> QueryMode {
696 self.inner.mode()
697 }
698
699 pub(in crate::db) fn explain_with_visible_indexes(
700 &self,
701 visible_indexes: &VisibleIndexes<'_>,
702 ) -> Result<ExplainPlan, QueryError> {
703 let plan = self.build_plan_for_visibility(Some(visible_indexes))?;
704
705 Ok(plan.explain())
706 }
707
708 pub(in crate::db) fn plan_hash_hex_with_visible_indexes(
709 &self,
710 visible_indexes: &VisibleIndexes<'_>,
711 ) -> Result<String, QueryError> {
712 let plan = self.build_plan_for_visibility(Some(visible_indexes))?;
713
714 Ok(plan.fingerprint().to_string())
715 }
716
717 fn build_plan_for_visibility(
720 &self,
721 visible_indexes: Option<&VisibleIndexes<'_>>,
722 ) -> Result<AccessPlannedQuery, QueryError> {
723 self.inner.build_plan_for_visibility(visible_indexes)
724 }
725
726 fn map_plan_for_visibility<T>(
730 &self,
731 visible_indexes: Option<&VisibleIndexes<'_>>,
732 map: impl FnOnce(AccessPlannedQuery) -> T,
733 ) -> Result<T, QueryError> {
734 let plan = self.build_plan_for_visibility(visible_indexes)?;
735
736 Ok(map(plan))
737 }
738
739 fn prepared_execution_plan_for_visibility(
743 &self,
744 visible_indexes: Option<&VisibleIndexes<'_>>,
745 ) -> Result<PreparedExecutionPlan<E>, QueryError> {
746 self.map_plan_for_visibility(visible_indexes, PreparedExecutionPlan::<E>::new)
747 }
748
749 pub(in crate::db) fn planned_query_from_plan(plan: AccessPlannedQuery) -> PlannedQuery<E> {
751 PlannedQuery::from_plan(plan)
752 }
753
754 pub(in crate::db) fn compiled_query_from_plan(plan: AccessPlannedQuery) -> CompiledQuery<E> {
756 CompiledQuery::from_plan(plan)
757 }
758
759 #[must_use]
760 pub(crate) fn has_explicit_order(&self) -> bool {
761 self.inner.has_explicit_order()
762 }
763
764 #[must_use]
765 pub(in crate::db) const fn structural(&self) -> &StructuralQuery {
766 &self.inner
767 }
768
769 #[must_use]
770 pub const fn has_grouping(&self) -> bool {
771 self.inner.has_grouping()
772 }
773
774 #[must_use]
775 pub(crate) const fn load_spec(&self) -> Option<LoadSpec> {
776 self.inner.load_spec()
777 }
778
779 #[must_use]
781 pub fn filter(mut self, expr: impl Into<FilterExpr>) -> Self {
782 self.inner = self.inner.filter(expr);
783 self
784 }
785
786 #[must_use]
787 pub(in crate::db) fn filter_predicate(mut self, predicate: Predicate) -> Self {
788 self.inner = self.inner.filter_predicate(predicate);
789 self
790 }
791
792 #[must_use]
794 pub fn order_term(mut self, term: FluentOrderTerm) -> Self {
795 self.inner = self.inner.order_term(term);
796 self
797 }
798
799 #[must_use]
801 pub fn order_terms<I>(mut self, terms: I) -> Self
802 where
803 I: IntoIterator<Item = FluentOrderTerm>,
804 {
805 for term in terms {
806 self.inner = self.inner.order_term(term);
807 }
808
809 self
810 }
811
812 #[must_use]
814 pub fn distinct(mut self) -> Self {
815 self.inner = self.inner.distinct();
816 self
817 }
818
819 #[cfg(all(test, feature = "sql"))]
822 #[must_use]
823 pub(in crate::db) fn select_fields<I, S>(mut self, fields: I) -> Self
824 where
825 I: IntoIterator<Item = S>,
826 S: Into<String>,
827 {
828 self.inner = self.inner.select_fields(fields);
829 self
830 }
831
832 pub fn group_by(self, field: impl AsRef<str>) -> Result<Self, QueryError> {
834 let Self { inner, .. } = self;
835 let inner = inner.group_by(field)?;
836
837 Ok(Self::from_inner(inner))
838 }
839
840 #[must_use]
842 pub fn aggregate(mut self, aggregate: AggregateExpr) -> Self {
843 self.inner = self.inner.aggregate(aggregate);
844 self
845 }
846
847 #[must_use]
849 pub fn grouped_limits(mut self, max_groups: u64, max_group_bytes: u64) -> Self {
850 self.inner = self.inner.grouped_limits(max_groups, max_group_bytes);
851 self
852 }
853
854 pub fn having_group(
856 self,
857 field: impl AsRef<str>,
858 op: CompareOp,
859 value: Value,
860 ) -> Result<Self, QueryError> {
861 let Self { inner, .. } = self;
862 let inner = inner.having_group(field, op, value)?;
863
864 Ok(Self::from_inner(inner))
865 }
866
867 pub fn having_aggregate(
869 self,
870 aggregate_index: usize,
871 op: CompareOp,
872 value: Value,
873 ) -> Result<Self, QueryError> {
874 let Self { inner, .. } = self;
875 let inner = inner.having_aggregate(aggregate_index, op, value)?;
876
877 Ok(Self::from_inner(inner))
878 }
879
880 pub(crate) fn by_id(self, id: E::Key) -> Self {
882 let Self { inner, .. } = self;
883
884 Self::from_inner(inner.by_id(id.to_value()))
885 }
886
887 pub(crate) fn by_ids<I>(self, ids: I) -> Self
889 where
890 I: IntoIterator<Item = E::Key>,
891 {
892 let Self { inner, .. } = self;
893
894 Self::from_inner(inner.by_ids(ids.into_iter().map(|id| id.to_value())))
895 }
896
897 #[must_use]
899 pub fn delete(mut self) -> Self {
900 self.inner = self.inner.delete();
901 self
902 }
903
904 #[must_use]
911 pub fn limit(mut self, limit: u32) -> Self {
912 self.inner = self.inner.limit(limit);
913 self
914 }
915
916 #[must_use]
922 pub fn offset(mut self, offset: u32) -> Self {
923 self.inner = self.inner.offset(offset);
924 self
925 }
926
927 pub fn explain(&self) -> Result<ExplainPlan, QueryError> {
929 let plan = self.planned()?;
930
931 Ok(plan.explain())
932 }
933
934 pub fn plan_hash_hex(&self) -> Result<String, QueryError> {
939 let plan = self.inner.build_plan()?;
940
941 Ok(plan.fingerprint().to_string())
942 }
943
944 fn explain_execution_descriptor_for_visibility(
947 &self,
948 visible_indexes: Option<&VisibleIndexes<'_>>,
949 ) -> Result<ExplainExecutionNodeDescriptor, QueryError>
950 where
951 E: EntityValue,
952 {
953 match visible_indexes {
954 Some(visible_indexes) => self
955 .inner
956 .explain_execution_with_visible_indexes(visible_indexes),
957 None => self.inner.explain_execution(),
958 }
959 }
960
961 fn render_execution_descriptor_for_visibility(
964 &self,
965 visible_indexes: Option<&VisibleIndexes<'_>>,
966 render: impl FnOnce(ExplainExecutionNodeDescriptor) -> String,
967 ) -> Result<String, QueryError>
968 where
969 E: EntityValue,
970 {
971 let descriptor = self.explain_execution_descriptor_for_visibility(visible_indexes)?;
972
973 Ok(render(descriptor))
974 }
975
976 fn explain_execution_verbose_for_visibility(
979 &self,
980 visible_indexes: Option<&VisibleIndexes<'_>>,
981 ) -> Result<String, QueryError>
982 where
983 E: EntityValue,
984 {
985 match visible_indexes {
986 Some(visible_indexes) => self
987 .inner
988 .explain_execution_verbose_with_visible_indexes(visible_indexes),
989 None => self.inner.explain_execution_verbose(),
990 }
991 }
992
993 pub fn explain_execution(&self) -> Result<ExplainExecutionNodeDescriptor, QueryError>
995 where
996 E: EntityValue,
997 {
998 self.explain_execution_descriptor_for_visibility(None)
999 }
1000
1001 pub(in crate::db) fn explain_execution_with_visible_indexes(
1002 &self,
1003 visible_indexes: &VisibleIndexes<'_>,
1004 ) -> Result<ExplainExecutionNodeDescriptor, QueryError>
1005 where
1006 E: EntityValue,
1007 {
1008 self.explain_execution_descriptor_for_visibility(Some(visible_indexes))
1009 }
1010
1011 pub fn explain_execution_text(&self) -> Result<String, QueryError>
1013 where
1014 E: EntityValue,
1015 {
1016 self.render_execution_descriptor_for_visibility(None, |descriptor| {
1017 descriptor.render_text_tree()
1018 })
1019 }
1020
1021 pub fn explain_execution_json(&self) -> Result<String, QueryError>
1023 where
1024 E: EntityValue,
1025 {
1026 self.render_execution_descriptor_for_visibility(None, |descriptor| {
1027 descriptor.render_json_canonical()
1028 })
1029 }
1030
1031 #[inline(never)]
1033 pub fn explain_execution_verbose(&self) -> Result<String, QueryError>
1034 where
1035 E: EntityValue,
1036 {
1037 self.explain_execution_verbose_for_visibility(None)
1038 }
1039
1040 pub(in crate::db) fn explain_execution_verbose_with_visible_indexes(
1041 &self,
1042 visible_indexes: &VisibleIndexes<'_>,
1043 ) -> Result<String, QueryError>
1044 where
1045 E: EntityValue,
1046 {
1047 self.explain_execution_verbose_for_visibility(Some(visible_indexes))
1048 }
1049
1050 #[cfg(test)]
1052 #[inline(never)]
1053 pub(in crate::db) fn explain_aggregate_terminal(
1054 &self,
1055 aggregate: AggregateExpr,
1056 ) -> Result<ExplainAggregateTerminalPlan, QueryError>
1057 where
1058 E: EntityValue,
1059 {
1060 self.inner.explain_aggregate_terminal_with_visible_indexes(
1061 &VisibleIndexes::schema_owned(E::MODEL.indexes()),
1062 AggregateRouteShape::new_from_fields(
1063 aggregate.kind(),
1064 aggregate.target_field(),
1065 E::MODEL.fields(),
1066 E::MODEL.primary_key().name(),
1067 ),
1068 )
1069 }
1070
1071 pub(in crate::db) fn explain_prepared_aggregate_terminal_with_visible_indexes<S>(
1072 &self,
1073 visible_indexes: &VisibleIndexes<'_>,
1074 strategy: &S,
1075 ) -> Result<ExplainAggregateTerminalPlan, QueryError>
1076 where
1077 E: EntityValue,
1078 S: PreparedFluentAggregateExplainStrategy,
1079 {
1080 self.inner
1081 .explain_prepared_aggregate_terminal_with_visible_indexes(visible_indexes, strategy)
1082 }
1083
1084 pub(in crate::db) fn explain_bytes_by_with_visible_indexes(
1085 &self,
1086 visible_indexes: &VisibleIndexes<'_>,
1087 target_field: &str,
1088 ) -> Result<ExplainExecutionNodeDescriptor, QueryError>
1089 where
1090 E: EntityValue,
1091 {
1092 let executable = self.prepared_execution_plan_for_visibility(Some(visible_indexes))?;
1093 let mut descriptor = executable
1094 .explain_load_execution_node_descriptor()
1095 .map_err(QueryError::execute)?;
1096 let projection_mode = executable.bytes_by_projection_mode(target_field);
1097 let projection_mode_label =
1098 PreparedExecutionPlan::<E>::bytes_by_projection_mode_label(projection_mode);
1099
1100 descriptor
1101 .node_properties
1102 .insert("terminal", Value::from("bytes_by"));
1103 descriptor
1104 .node_properties
1105 .insert("terminal_field", Value::from(target_field.to_string()));
1106 descriptor.node_properties.insert(
1107 "terminal_projection_mode",
1108 Value::from(projection_mode_label),
1109 );
1110 descriptor.node_properties.insert(
1111 "terminal_index_only",
1112 Value::from(matches!(
1113 projection_mode,
1114 BytesByProjectionMode::CoveringIndex | BytesByProjectionMode::CoveringConstant
1115 )),
1116 );
1117
1118 Ok(descriptor)
1119 }
1120
1121 pub(in crate::db) fn explain_prepared_projection_terminal_with_visible_indexes(
1122 &self,
1123 visible_indexes: &VisibleIndexes<'_>,
1124 strategy: &PreparedFluentProjectionStrategy,
1125 ) -> Result<ExplainExecutionNodeDescriptor, QueryError>
1126 where
1127 E: EntityValue,
1128 {
1129 let executable = self.prepared_execution_plan_for_visibility(Some(visible_indexes))?;
1130 let mut descriptor = executable
1131 .explain_load_execution_node_descriptor()
1132 .map_err(QueryError::execute)?;
1133 let projection_descriptor = strategy.explain_descriptor();
1134
1135 descriptor.node_properties.insert(
1136 "terminal",
1137 Value::from(projection_descriptor.terminal_label()),
1138 );
1139 descriptor.node_properties.insert(
1140 "terminal_field",
1141 Value::from(projection_descriptor.field_label().to_string()),
1142 );
1143 descriptor.node_properties.insert(
1144 "terminal_output",
1145 Value::from(projection_descriptor.output_label()),
1146 );
1147
1148 Ok(descriptor)
1149 }
1150
1151 pub fn planned(&self) -> Result<PlannedQuery<E>, QueryError> {
1153 self.map_plan_for_visibility(None, Self::planned_query_from_plan)
1154 }
1155
1156 pub fn plan(&self) -> Result<CompiledQuery<E>, QueryError> {
1160 self.map_plan_for_visibility(None, Self::compiled_query_from_plan)
1161 }
1162
1163 #[cfg(test)]
1164 pub(in crate::db) fn plan_with_visible_indexes(
1165 &self,
1166 visible_indexes: &VisibleIndexes<'_>,
1167 ) -> Result<CompiledQuery<E>, QueryError> {
1168 self.map_plan_for_visibility(Some(visible_indexes), Self::compiled_query_from_plan)
1169 }
1170}
1171
1172fn contains_execution_node_type(
1173 descriptor: &ExplainExecutionNodeDescriptor,
1174 target: ExplainExecutionNodeType,
1175) -> bool {
1176 descriptor.node_type() == target
1177 || descriptor
1178 .children()
1179 .iter()
1180 .any(|child| contains_execution_node_type(child, target))
1181}
1182
1183fn plan_order_pushdown_label(order_pushdown: &ExplainOrderPushdown) -> String {
1184 match order_pushdown {
1185 ExplainOrderPushdown::MissingModelContext => "missing_model_context".to_string(),
1186 ExplainOrderPushdown::EligibleSecondaryIndex { index, prefix_len } => {
1187 format!("eligible(index={index},prefix_len={prefix_len})",)
1188 }
1189 ExplainOrderPushdown::Rejected(reason) => format!("rejected({reason:?})"),
1190 }
1191}
1192
1193fn plan_predicate_pushdown_label(
1194 predicate: &ExplainPredicate,
1195 access: &ExplainAccessPath,
1196) -> String {
1197 let access_label = match access {
1198 ExplainAccessPath::ByKey { .. } => "by_key",
1199 ExplainAccessPath::ByKeys { keys } if keys.is_empty() => "empty_access_contract",
1200 ExplainAccessPath::ByKeys { .. } => "by_keys",
1201 ExplainAccessPath::KeyRange { .. } => "key_range",
1202 ExplainAccessPath::IndexPrefix { .. } => "index_prefix",
1203 ExplainAccessPath::IndexMultiLookup { .. } => "index_multi_lookup",
1204 ExplainAccessPath::IndexRange { .. } => "index_range",
1205 ExplainAccessPath::FullScan => "full_scan",
1206 ExplainAccessPath::Union(_) => "union",
1207 ExplainAccessPath::Intersection(_) => "intersection",
1208 };
1209 if matches!(predicate, ExplainPredicate::None) {
1210 return "none".to_string();
1211 }
1212 if matches!(access, ExplainAccessPath::FullScan) {
1213 if explain_predicate_contains_non_strict_compare(predicate) {
1214 return "fallback(non_strict_compare_coercion)".to_string();
1215 }
1216 if explain_predicate_contains_empty_prefix_starts_with(predicate) {
1217 return "fallback(starts_with_empty_prefix)".to_string();
1218 }
1219 if explain_predicate_contains_is_null(predicate) {
1220 return "fallback(is_null_full_scan)".to_string();
1221 }
1222 if explain_predicate_contains_text_scan_operator(predicate) {
1223 return "fallback(text_operator_full_scan)".to_string();
1224 }
1225
1226 return format!("fallback({access_label})");
1227 }
1228
1229 format!("applied({access_label})")
1230}
1231
1232fn explain_predicate_contains_non_strict_compare(predicate: &ExplainPredicate) -> bool {
1233 match predicate {
1234 ExplainPredicate::Compare { coercion, .. }
1235 | ExplainPredicate::CompareFields { coercion, .. } => coercion.id != CoercionId::Strict,
1236 ExplainPredicate::And(children) | ExplainPredicate::Or(children) => children
1237 .iter()
1238 .any(explain_predicate_contains_non_strict_compare),
1239 ExplainPredicate::Not(inner) => explain_predicate_contains_non_strict_compare(inner),
1240 ExplainPredicate::None
1241 | ExplainPredicate::True
1242 | ExplainPredicate::False
1243 | ExplainPredicate::IsNull { .. }
1244 | ExplainPredicate::IsNotNull { .. }
1245 | ExplainPredicate::IsMissing { .. }
1246 | ExplainPredicate::IsEmpty { .. }
1247 | ExplainPredicate::IsNotEmpty { .. }
1248 | ExplainPredicate::TextContains { .. }
1249 | ExplainPredicate::TextContainsCi { .. } => false,
1250 }
1251}
1252
1253fn explain_predicate_contains_is_null(predicate: &ExplainPredicate) -> bool {
1254 match predicate {
1255 ExplainPredicate::IsNull { .. } => true,
1256 ExplainPredicate::And(children) | ExplainPredicate::Or(children) => {
1257 children.iter().any(explain_predicate_contains_is_null)
1258 }
1259 ExplainPredicate::Not(inner) => explain_predicate_contains_is_null(inner),
1260 ExplainPredicate::None
1261 | ExplainPredicate::True
1262 | ExplainPredicate::False
1263 | ExplainPredicate::Compare { .. }
1264 | ExplainPredicate::CompareFields { .. }
1265 | ExplainPredicate::IsNotNull { .. }
1266 | ExplainPredicate::IsMissing { .. }
1267 | ExplainPredicate::IsEmpty { .. }
1268 | ExplainPredicate::IsNotEmpty { .. }
1269 | ExplainPredicate::TextContains { .. }
1270 | ExplainPredicate::TextContainsCi { .. } => false,
1271 }
1272}
1273
1274fn explain_predicate_contains_empty_prefix_starts_with(predicate: &ExplainPredicate) -> bool {
1275 match predicate {
1276 ExplainPredicate::Compare {
1277 op: CompareOp::StartsWith,
1278 value: Value::Text(prefix),
1279 ..
1280 } => prefix.is_empty(),
1281 ExplainPredicate::And(children) | ExplainPredicate::Or(children) => children
1282 .iter()
1283 .any(explain_predicate_contains_empty_prefix_starts_with),
1284 ExplainPredicate::Not(inner) => explain_predicate_contains_empty_prefix_starts_with(inner),
1285 ExplainPredicate::None
1286 | ExplainPredicate::True
1287 | ExplainPredicate::False
1288 | ExplainPredicate::Compare { .. }
1289 | ExplainPredicate::CompareFields { .. }
1290 | ExplainPredicate::IsNull { .. }
1291 | ExplainPredicate::IsNotNull { .. }
1292 | ExplainPredicate::IsMissing { .. }
1293 | ExplainPredicate::IsEmpty { .. }
1294 | ExplainPredicate::IsNotEmpty { .. }
1295 | ExplainPredicate::TextContains { .. }
1296 | ExplainPredicate::TextContainsCi { .. } => false,
1297 }
1298}
1299
1300fn explain_predicate_contains_text_scan_operator(predicate: &ExplainPredicate) -> bool {
1301 match predicate {
1302 ExplainPredicate::Compare {
1303 op: CompareOp::EndsWith,
1304 ..
1305 }
1306 | ExplainPredicate::TextContains { .. }
1307 | ExplainPredicate::TextContainsCi { .. } => true,
1308 ExplainPredicate::And(children) | ExplainPredicate::Or(children) => children
1309 .iter()
1310 .any(explain_predicate_contains_text_scan_operator),
1311 ExplainPredicate::Not(inner) => explain_predicate_contains_text_scan_operator(inner),
1312 ExplainPredicate::Compare { .. }
1313 | ExplainPredicate::CompareFields { .. }
1314 | ExplainPredicate::None
1315 | ExplainPredicate::True
1316 | ExplainPredicate::False
1317 | ExplainPredicate::IsNull { .. }
1318 | ExplainPredicate::IsNotNull { .. }
1319 | ExplainPredicate::IsMissing { .. }
1320 | ExplainPredicate::IsEmpty { .. }
1321 | ExplainPredicate::IsNotEmpty { .. } => false,
1322 }
1323}
1324
1325impl<E> Query<E>
1326where
1327 E: EntityKind + SingletonEntity,
1328 E::Key: Default,
1329{
1330 pub(crate) fn only(self) -> Self {
1332 let Self { inner, .. } = self;
1333
1334 Self::from_inner(inner.only(E::Key::default().to_value()))
1335 }
1336}