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