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