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