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