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_from_route_facts,
15 assemble_load_execution_verbose_diagnostics_from_route_facts,
16 freeze_load_execution_route_facts, planning::route::AggregateRouteShape,
17 },
18 predicate::{CoercionId, CompareOp, MissingRowPolicy, Predicate},
19 query::{
20 builder::{
21 AggregateExpr, PreparedFluentAggregateExplainStrategy,
22 PreparedFluentProjectionStrategy,
23 },
24 explain::{
25 ExplainAccessPath, ExplainAggregateTerminalPlan, ExplainExecutionNodeDescriptor,
26 ExplainExecutionNodeType, ExplainOrderPushdown, ExplainPlan, ExplainPredicate,
27 FinalizedQueryDiagnostics,
28 },
29 expr::FilterExpr,
30 expr::OrderTerm as FluentOrderTerm,
31 intent::{
32 QueryError,
33 model::{PreparedScalarPlanningState, QueryModel},
34 },
35 plan::{
36 AccessPlannedQuery, LoadSpec, OrderSpec, QueryMode, VisibleIndexes,
37 explain_access_kind_label, expr::Expr,
38 },
39 },
40 },
41 traits::{EntityKind, EntityValue, KeyValueCodec, SingletonEntity},
42 value::{InputValue, Value},
43};
44use core::marker::PhantomData;
45
46#[derive(Clone, Debug)]
55pub(in crate::db) struct StructuralQuery {
56 intent: QueryModel<'static, Value>,
57}
58
59impl StructuralQuery {
60 #[must_use]
61 pub(in crate::db) const fn new(
62 model: &'static crate::model::entity::EntityModel,
63 consistency: MissingRowPolicy,
64 ) -> Self {
65 Self {
66 intent: QueryModel::new(model, consistency),
67 }
68 }
69
70 const fn from_intent(intent: QueryModel<'static, Value>) -> Self {
74 Self { intent }
75 }
76
77 fn map_intent(
80 self,
81 map: impl FnOnce(QueryModel<'static, Value>) -> QueryModel<'static, Value>,
82 ) -> Self {
83 Self::from_intent(map(self.intent))
84 }
85
86 fn try_map_intent(
89 self,
90 map: impl FnOnce(QueryModel<'static, Value>) -> Result<QueryModel<'static, Value>, QueryError>,
91 ) -> Result<Self, QueryError> {
92 map(self.intent).map(Self::from_intent)
93 }
94
95 #[must_use]
96 const fn mode(&self) -> QueryMode {
97 self.intent.mode()
98 }
99
100 #[must_use]
101 fn has_explicit_order(&self) -> bool {
102 self.intent.has_explicit_order()
103 }
104
105 #[must_use]
106 pub(in crate::db) const fn has_grouping(&self) -> bool {
107 self.intent.has_grouping()
108 }
109
110 #[must_use]
111 const fn load_spec(&self) -> Option<LoadSpec> {
112 match self.intent.mode() {
113 QueryMode::Load(spec) => Some(spec),
114 QueryMode::Delete(_) => None,
115 }
116 }
117
118 #[must_use]
119 pub(in crate::db) fn filter_predicate(mut self, predicate: Predicate) -> Self {
120 self.intent = self.intent.filter_predicate(predicate);
121 self
122 }
123
124 #[must_use]
125 pub(in crate::db) fn filter(mut self, expr: impl Into<FilterExpr>) -> Self {
126 self.intent = self.intent.filter(expr.into());
127 self
128 }
129
130 #[must_use]
131 pub(in crate::db) fn filter_expr_with_normalized_predicate(
132 mut self,
133 expr: Expr,
134 predicate: Predicate,
135 ) -> Self {
136 self.intent = self
137 .intent
138 .filter_expr_with_normalized_predicate(expr, predicate);
139 self
140 }
141 pub(in crate::db) fn order_term(mut self, term: FluentOrderTerm) -> Self {
142 self.intent = self.intent.order_term(term);
143 self
144 }
145
146 #[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 let route_facts = freeze_load_execution_route_facts(
335 self.intent.model().fields(),
336 self.intent.model().primary_key().name(),
337 plan,
338 )
339 .map_err(QueryError::execute)?;
340
341 Ok(assemble_load_execution_node_descriptor_from_route_facts(
342 plan,
343 &route_facts,
344 ))
345 }
346
347 fn finalized_execution_diagnostics_from_plan(
351 &self,
352 plan: &AccessPlannedQuery,
353 reuse: Option<TraceReuseEvent>,
354 ) -> Result<FinalizedQueryDiagnostics, QueryError> {
355 let route_facts = freeze_load_execution_route_facts(
356 self.intent.model().fields(),
357 self.intent.model().primary_key().name(),
358 plan,
359 )
360 .map_err(QueryError::execute)?;
361 let descriptor =
362 assemble_load_execution_node_descriptor_from_route_facts(plan, &route_facts);
363 let route_diagnostics =
364 assemble_load_execution_verbose_diagnostics_from_route_facts(plan, &route_facts);
365 let explain = plan.explain();
366
367 let mut logical_diagnostics = Vec::new();
369 logical_diagnostics.push(format!(
370 "diag.d.has_top_n_seek={}",
371 descriptor.contains_type(ExplainExecutionNodeType::TopNSeek)
372 ));
373 logical_diagnostics.push(format!(
374 "diag.d.has_index_range_limit_pushdown={}",
375 descriptor.contains_type(ExplainExecutionNodeType::IndexRangeLimitPushdown)
376 ));
377 logical_diagnostics.push(format!(
378 "diag.d.has_index_predicate_prefilter={}",
379 descriptor.contains_type(ExplainExecutionNodeType::IndexPredicatePrefilter)
380 ));
381 logical_diagnostics.push(format!(
382 "diag.d.has_residual_filter={}",
383 descriptor.contains_type(ExplainExecutionNodeType::ResidualFilter)
384 ));
385
386 logical_diagnostics.push(format!("diag.p.mode={:?}", explain.mode()));
388 logical_diagnostics.push(format!(
389 "diag.p.order_pushdown={}",
390 plan_order_pushdown_label(explain.order_pushdown())
391 ));
392 logical_diagnostics.push(format!(
393 "diag.p.predicate_pushdown={}",
394 plan_predicate_pushdown_label(explain.predicate(), explain.access())
395 ));
396 logical_diagnostics.push(format!("diag.p.distinct={}", explain.distinct()));
397 logical_diagnostics.push(format!("diag.p.page={:?}", explain.page()));
398 logical_diagnostics.push(format!("diag.p.consistency={:?}", explain.consistency()));
399
400 Ok(FinalizedQueryDiagnostics::new(
401 descriptor,
402 route_diagnostics,
403 logical_diagnostics,
404 reuse,
405 ))
406 }
407
408 pub(in crate::db) fn finalized_execution_diagnostics_from_plan_with_descriptor_mutator(
411 &self,
412 plan: &AccessPlannedQuery,
413 reuse: Option<TraceReuseEvent>,
414 mutate_descriptor: impl FnOnce(&mut ExplainExecutionNodeDescriptor),
415 ) -> Result<FinalizedQueryDiagnostics, QueryError> {
416 let mut diagnostics = self.finalized_execution_diagnostics_from_plan(plan, reuse)?;
417 mutate_descriptor(&mut diagnostics.execution);
418
419 Ok(diagnostics)
420 }
421
422 fn explain_execution_verbose_from_plan(
425 &self,
426 plan: &AccessPlannedQuery,
427 ) -> Result<String, QueryError> {
428 self.finalized_execution_diagnostics_from_plan(plan, None)
429 .map(|diagnostics| diagnostics.render_text_verbose())
430 }
431
432 fn finalize_explain_access_choice_for_visibility(
435 &self,
436 plan: &mut AccessPlannedQuery,
437 visible_indexes: Option<&VisibleIndexes<'_>>,
438 ) {
439 let visible_indexes = match visible_indexes {
440 Some(visible_indexes) => visible_indexes.as_slice(),
441 None => self.intent.model().indexes(),
442 };
443
444 plan.finalize_access_choice_for_model_with_indexes(self.intent.model(), visible_indexes);
445 }
446
447 fn explain_execution_descriptor_for_visibility(
450 &self,
451 visible_indexes: Option<&VisibleIndexes<'_>>,
452 ) -> Result<ExplainExecutionNodeDescriptor, QueryError> {
453 let mut plan = self.build_plan_for_visibility(visible_indexes)?;
454 self.finalize_explain_access_choice_for_visibility(&mut plan, visible_indexes);
455
456 self.explain_execution_descriptor_from_plan(&plan)
457 }
458
459 fn explain_execution_verbose_for_visibility(
462 &self,
463 visible_indexes: Option<&VisibleIndexes<'_>>,
464 ) -> Result<String, QueryError> {
465 let mut plan = self.build_plan_for_visibility(visible_indexes)?;
466 self.finalize_explain_access_choice_for_visibility(&mut plan, visible_indexes);
467
468 self.explain_execution_verbose_from_plan(&plan)
469 }
470
471 #[cfg(feature = "sql")]
472 #[must_use]
473 pub(in crate::db) const fn model(&self) -> &'static crate::model::entity::EntityModel {
474 self.intent.model()
475 }
476
477 #[inline(never)]
478 pub(in crate::db) fn explain_execution_with_visible_indexes(
479 &self,
480 visible_indexes: &VisibleIndexes<'_>,
481 ) -> Result<ExplainExecutionNodeDescriptor, QueryError> {
482 self.explain_execution_descriptor_for_visibility(Some(visible_indexes))
483 }
484
485 #[inline(never)]
487 pub(in crate::db) fn explain_execution(
488 &self,
489 ) -> Result<ExplainExecutionNodeDescriptor, QueryError> {
490 self.explain_execution_descriptor_for_visibility(None)
491 }
492
493 #[inline(never)]
496 pub(in crate::db) fn explain_execution_verbose(&self) -> Result<String, QueryError> {
497 self.explain_execution_verbose_for_visibility(None)
498 }
499
500 #[inline(never)]
501 pub(in crate::db) fn explain_execution_verbose_with_visible_indexes(
502 &self,
503 visible_indexes: &VisibleIndexes<'_>,
504 ) -> Result<String, QueryError> {
505 self.explain_execution_verbose_for_visibility(Some(visible_indexes))
506 }
507
508 #[inline(never)]
509 pub(in crate::db) fn explain_aggregate_terminal_with_visible_indexes(
510 &self,
511 visible_indexes: &VisibleIndexes<'_>,
512 aggregate: AggregateRouteShape<'_>,
513 ) -> Result<ExplainAggregateTerminalPlan, QueryError> {
514 let plan = self.build_plan_with_visible_indexes(visible_indexes)?;
515 let query_explain = plan.explain();
516 let terminal = aggregate.kind();
517 let execution = assemble_aggregate_terminal_execution_descriptor(&plan, aggregate);
518
519 Ok(ExplainAggregateTerminalPlan::new(
520 query_explain,
521 terminal,
522 execution,
523 ))
524 }
525
526 #[inline(never)]
527 pub(in crate::db) fn explain_prepared_aggregate_terminal_with_visible_indexes<S>(
528 &self,
529 visible_indexes: &VisibleIndexes<'_>,
530 strategy: &S,
531 ) -> Result<ExplainAggregateTerminalPlan, QueryError>
532 where
533 S: PreparedFluentAggregateExplainStrategy,
534 {
535 let Some(kind) = strategy.explain_aggregate_kind() else {
536 return Err(QueryError::invariant(
537 "prepared fluent aggregate explain requires an explain-visible aggregate kind",
538 ));
539 };
540 let aggregate = AggregateRouteShape::new_from_fields(
541 kind,
542 strategy.explain_projected_field(),
543 self.intent.model().fields(),
544 self.intent.model().primary_key().name(),
545 );
546
547 self.explain_aggregate_terminal_with_visible_indexes(visible_indexes, aggregate)
548 }
549}
550
551#[derive(Clone, Debug)]
561enum QueryPlanHandle {
562 Plan(Box<AccessPlannedQuery>),
563 Prepared(SharedPreparedExecutionPlan),
564}
565
566impl QueryPlanHandle {
567 #[must_use]
568 fn from_plan(plan: AccessPlannedQuery) -> Self {
569 Self::Plan(Box::new(plan))
570 }
571
572 #[must_use]
573 const fn from_prepared(prepared_plan: SharedPreparedExecutionPlan) -> Self {
574 Self::Prepared(prepared_plan)
575 }
576
577 #[must_use]
578 fn logical_plan(&self) -> &AccessPlannedQuery {
579 match self {
580 Self::Plan(plan) => plan,
581 Self::Prepared(prepared_plan) => prepared_plan.logical_plan(),
582 }
583 }
584
585 fn into_prepared_execution_plan<E: EntityKind>(self) -> PreparedExecutionPlan<E> {
586 match self {
587 Self::Plan(plan) => PreparedExecutionPlan::new(*plan),
588 Self::Prepared(prepared_plan) => prepared_plan.typed_clone::<E>(),
589 }
590 }
591
592 #[must_use]
593 #[cfg(test)]
594 fn into_inner(self) -> AccessPlannedQuery {
595 match self {
596 Self::Plan(plan) => *plan,
597 Self::Prepared(prepared_plan) => prepared_plan.logical_plan().clone(),
598 }
599 }
600}
601
602#[derive(Debug)]
610pub struct PlannedQuery<E: EntityKind> {
611 plan: QueryPlanHandle,
612 _marker: PhantomData<E>,
613}
614
615impl<E: EntityKind> PlannedQuery<E> {
616 #[must_use]
617 fn from_plan(plan: AccessPlannedQuery) -> Self {
618 Self {
619 plan: QueryPlanHandle::from_plan(plan),
620 _marker: PhantomData,
621 }
622 }
623
624 #[must_use]
625 pub(in crate::db) const fn from_prepared_plan(
626 prepared_plan: SharedPreparedExecutionPlan,
627 ) -> Self {
628 Self {
629 plan: QueryPlanHandle::from_prepared(prepared_plan),
630 _marker: PhantomData,
631 }
632 }
633
634 #[must_use]
635 pub fn explain(&self) -> ExplainPlan {
636 self.plan.logical_plan().explain()
637 }
638
639 #[must_use]
641 pub fn plan_hash_hex(&self) -> String {
642 self.plan.logical_plan().fingerprint().to_string()
643 }
644}
645
646#[derive(Clone, Debug)]
656pub struct CompiledQuery<E: EntityKind> {
657 plan: QueryPlanHandle,
658 _marker: PhantomData<E>,
659}
660
661impl<E: EntityKind> CompiledQuery<E> {
662 #[must_use]
663 fn from_plan(plan: AccessPlannedQuery) -> Self {
664 Self {
665 plan: QueryPlanHandle::from_plan(plan),
666 _marker: PhantomData,
667 }
668 }
669
670 #[must_use]
671 pub(in crate::db) const fn from_prepared_plan(
672 prepared_plan: SharedPreparedExecutionPlan,
673 ) -> Self {
674 Self {
675 plan: QueryPlanHandle::from_prepared(prepared_plan),
676 _marker: PhantomData,
677 }
678 }
679
680 #[must_use]
681 pub fn explain(&self) -> ExplainPlan {
682 self.plan.logical_plan().explain()
683 }
684
685 #[must_use]
687 pub fn plan_hash_hex(&self) -> String {
688 self.plan.logical_plan().fingerprint().to_string()
689 }
690
691 #[must_use]
692 #[cfg(test)]
693 pub(in crate::db) fn projection_spec(&self) -> crate::db::query::plan::expr::ProjectionSpec {
694 self.plan.logical_plan().projection_spec(E::MODEL)
695 }
696
697 pub(in crate::db) fn into_prepared_execution_plan(
699 self,
700 ) -> crate::db::executor::PreparedExecutionPlan<E> {
701 self.plan.into_prepared_execution_plan::<E>()
702 }
703
704 #[must_use]
705 #[cfg(test)]
706 pub(in crate::db) fn into_inner(self) -> AccessPlannedQuery {
707 self.plan.into_inner()
708 }
709}
710
711#[derive(Debug)]
723pub struct Query<E: EntityKind> {
724 inner: StructuralQuery,
725 _marker: PhantomData<E>,
726}
727
728impl<E: EntityKind> Query<E> {
729 pub(in crate::db) const fn from_inner(inner: StructuralQuery) -> Self {
731 Self {
732 inner,
733 _marker: PhantomData,
734 }
735 }
736
737 #[must_use]
741 pub const fn new(consistency: MissingRowPolicy) -> Self {
742 Self::from_inner(StructuralQuery::new(E::MODEL, consistency))
743 }
744
745 #[must_use]
747 pub const fn mode(&self) -> QueryMode {
748 self.inner.mode()
749 }
750
751 pub(in crate::db) fn explain_with_visible_indexes(
752 &self,
753 visible_indexes: &VisibleIndexes<'_>,
754 ) -> Result<ExplainPlan, QueryError> {
755 let plan = self.build_plan_for_visibility(Some(visible_indexes))?;
756
757 Ok(plan.explain())
758 }
759
760 pub(in crate::db) fn plan_hash_hex_with_visible_indexes(
761 &self,
762 visible_indexes: &VisibleIndexes<'_>,
763 ) -> Result<String, QueryError> {
764 let plan = self.build_plan_for_visibility(Some(visible_indexes))?;
765
766 Ok(plan.fingerprint().to_string())
767 }
768
769 fn build_plan_for_visibility(
772 &self,
773 visible_indexes: Option<&VisibleIndexes<'_>>,
774 ) -> Result<AccessPlannedQuery, QueryError> {
775 self.inner.build_plan_for_visibility(visible_indexes)
776 }
777
778 fn map_plan_for_visibility<T>(
782 &self,
783 visible_indexes: Option<&VisibleIndexes<'_>>,
784 map: impl FnOnce(AccessPlannedQuery) -> T,
785 ) -> Result<T, QueryError> {
786 let plan = self.build_plan_for_visibility(visible_indexes)?;
787
788 Ok(map(plan))
789 }
790
791 fn prepared_execution_plan_for_visibility(
795 &self,
796 visible_indexes: Option<&VisibleIndexes<'_>>,
797 ) -> Result<PreparedExecutionPlan<E>, QueryError> {
798 self.map_plan_for_visibility(visible_indexes, PreparedExecutionPlan::<E>::new)
799 }
800
801 pub(in crate::db) fn planned_query_from_plan(plan: AccessPlannedQuery) -> PlannedQuery<E> {
803 PlannedQuery::from_plan(plan)
804 }
805
806 pub(in crate::db) fn compiled_query_from_plan(plan: AccessPlannedQuery) -> CompiledQuery<E> {
808 CompiledQuery::from_plan(plan)
809 }
810
811 #[must_use]
812 pub(crate) fn has_explicit_order(&self) -> bool {
813 self.inner.has_explicit_order()
814 }
815
816 #[must_use]
817 pub(in crate::db) const fn structural(&self) -> &StructuralQuery {
818 &self.inner
819 }
820
821 #[must_use]
822 pub const fn has_grouping(&self) -> bool {
823 self.inner.has_grouping()
824 }
825
826 #[must_use]
827 pub(crate) const fn load_spec(&self) -> Option<LoadSpec> {
828 self.inner.load_spec()
829 }
830
831 #[must_use]
833 pub fn filter(mut self, expr: impl Into<FilterExpr>) -> Self {
834 self.inner = self.inner.filter(expr);
835 self
836 }
837
838 #[cfg(test)]
842 #[must_use]
843 pub(in crate::db) fn filter_expr(mut self, expr: Expr) -> Self {
844 self.inner = self.inner.filter_expr(expr);
845 self
846 }
847
848 #[must_use]
849 pub(in crate::db) fn filter_predicate(mut self, predicate: Predicate) -> Self {
850 self.inner = self.inner.filter_predicate(predicate);
851 self
852 }
853
854 #[must_use]
856 pub fn order_term(mut self, term: FluentOrderTerm) -> Self {
857 self.inner = self.inner.order_term(term);
858 self
859 }
860
861 #[must_use]
863 pub fn order_terms<I>(mut self, terms: I) -> Self
864 where
865 I: IntoIterator<Item = FluentOrderTerm>,
866 {
867 for term in terms {
868 self.inner = self.inner.order_term(term);
869 }
870
871 self
872 }
873
874 #[must_use]
876 pub fn distinct(mut self) -> Self {
877 self.inner = self.inner.distinct();
878 self
879 }
880
881 #[cfg(all(test, feature = "sql"))]
884 #[must_use]
885 pub(in crate::db) fn select_fields<I, S>(mut self, fields: I) -> Self
886 where
887 I: IntoIterator<Item = S>,
888 S: Into<String>,
889 {
890 self.inner = self.inner.select_fields(fields);
891 self
892 }
893
894 pub fn group_by(self, field: impl AsRef<str>) -> Result<Self, QueryError> {
896 let Self { inner, .. } = self;
897 let inner = inner.group_by(field)?;
898
899 Ok(Self::from_inner(inner))
900 }
901
902 #[must_use]
904 pub fn aggregate(mut self, aggregate: AggregateExpr) -> Self {
905 self.inner = self.inner.aggregate(aggregate);
906 self
907 }
908
909 #[must_use]
911 pub fn grouped_limits(mut self, max_groups: u64, max_group_bytes: u64) -> Self {
912 self.inner = self.inner.grouped_limits(max_groups, max_group_bytes);
913 self
914 }
915
916 pub fn having_group(
918 self,
919 field: impl AsRef<str>,
920 op: CompareOp,
921 value: InputValue,
922 ) -> Result<Self, QueryError> {
923 let Self { inner, .. } = self;
924 let inner = inner.having_group(field, op, value.into())?;
925
926 Ok(Self::from_inner(inner))
927 }
928
929 pub fn having_aggregate(
931 self,
932 aggregate_index: usize,
933 op: CompareOp,
934 value: InputValue,
935 ) -> Result<Self, QueryError> {
936 let Self { inner, .. } = self;
937 let inner = inner.having_aggregate(aggregate_index, op, value.into())?;
938
939 Ok(Self::from_inner(inner))
940 }
941
942 #[cfg(test)]
946 pub(in crate::db) fn having_expr(self, expr: Expr) -> Result<Self, QueryError> {
947 let Self { inner, .. } = self;
948 let inner = inner.having_expr(expr)?;
949
950 Ok(Self::from_inner(inner))
951 }
952
953 pub(crate) fn by_id(self, id: E::Key) -> Self {
955 let Self { inner, .. } = self;
956
957 Self::from_inner(inner.by_id(id.to_key_value()))
958 }
959
960 pub(crate) fn by_ids<I>(self, ids: I) -> Self
962 where
963 I: IntoIterator<Item = E::Key>,
964 {
965 let Self { inner, .. } = self;
966
967 Self::from_inner(inner.by_ids(ids.into_iter().map(|id| id.to_key_value())))
968 }
969
970 #[must_use]
972 pub fn delete(mut self) -> Self {
973 self.inner = self.inner.delete();
974 self
975 }
976
977 #[must_use]
984 pub fn limit(mut self, limit: u32) -> Self {
985 self.inner = self.inner.limit(limit);
986 self
987 }
988
989 #[must_use]
995 pub fn offset(mut self, offset: u32) -> Self {
996 self.inner = self.inner.offset(offset);
997 self
998 }
999
1000 pub fn explain(&self) -> Result<ExplainPlan, QueryError> {
1002 let plan = self.planned()?;
1003
1004 Ok(plan.explain())
1005 }
1006
1007 pub fn plan_hash_hex(&self) -> Result<String, QueryError> {
1012 let plan = self.inner.build_plan()?;
1013
1014 Ok(plan.fingerprint().to_string())
1015 }
1016
1017 fn explain_execution_descriptor_for_visibility(
1020 &self,
1021 visible_indexes: Option<&VisibleIndexes<'_>>,
1022 ) -> Result<ExplainExecutionNodeDescriptor, QueryError>
1023 where
1024 E: EntityValue,
1025 {
1026 match visible_indexes {
1027 Some(visible_indexes) => self
1028 .inner
1029 .explain_execution_with_visible_indexes(visible_indexes),
1030 None => self.inner.explain_execution(),
1031 }
1032 }
1033
1034 fn render_execution_descriptor_for_visibility(
1037 &self,
1038 visible_indexes: Option<&VisibleIndexes<'_>>,
1039 render: impl FnOnce(ExplainExecutionNodeDescriptor) -> String,
1040 ) -> Result<String, QueryError>
1041 where
1042 E: EntityValue,
1043 {
1044 let descriptor = self.explain_execution_descriptor_for_visibility(visible_indexes)?;
1045
1046 Ok(render(descriptor))
1047 }
1048
1049 fn explain_execution_verbose_for_visibility(
1052 &self,
1053 visible_indexes: Option<&VisibleIndexes<'_>>,
1054 ) -> Result<String, QueryError>
1055 where
1056 E: EntityValue,
1057 {
1058 match visible_indexes {
1059 Some(visible_indexes) => self
1060 .inner
1061 .explain_execution_verbose_with_visible_indexes(visible_indexes),
1062 None => self.inner.explain_execution_verbose(),
1063 }
1064 }
1065
1066 pub fn explain_execution(&self) -> Result<ExplainExecutionNodeDescriptor, QueryError>
1068 where
1069 E: EntityValue,
1070 {
1071 self.explain_execution_descriptor_for_visibility(None)
1072 }
1073
1074 pub(in crate::db) fn explain_execution_with_visible_indexes(
1075 &self,
1076 visible_indexes: &VisibleIndexes<'_>,
1077 ) -> Result<ExplainExecutionNodeDescriptor, QueryError>
1078 where
1079 E: EntityValue,
1080 {
1081 self.explain_execution_descriptor_for_visibility(Some(visible_indexes))
1082 }
1083
1084 pub fn explain_execution_text(&self) -> Result<String, QueryError>
1086 where
1087 E: EntityValue,
1088 {
1089 self.render_execution_descriptor_for_visibility(None, |descriptor| {
1090 descriptor.render_text_tree()
1091 })
1092 }
1093
1094 pub fn explain_execution_json(&self) -> Result<String, QueryError>
1096 where
1097 E: EntityValue,
1098 {
1099 self.render_execution_descriptor_for_visibility(None, |descriptor| {
1100 descriptor.render_json_canonical()
1101 })
1102 }
1103
1104 #[inline(never)]
1106 pub fn explain_execution_verbose(&self) -> Result<String, QueryError>
1107 where
1108 E: EntityValue,
1109 {
1110 self.explain_execution_verbose_for_visibility(None)
1111 }
1112
1113 #[cfg(test)]
1115 #[inline(never)]
1116 pub(in crate::db) fn explain_aggregate_terminal(
1117 &self,
1118 aggregate: AggregateExpr,
1119 ) -> Result<ExplainAggregateTerminalPlan, QueryError>
1120 where
1121 E: EntityValue,
1122 {
1123 self.inner.explain_aggregate_terminal_with_visible_indexes(
1124 &VisibleIndexes::schema_owned(E::MODEL.indexes()),
1125 AggregateRouteShape::new_from_fields(
1126 aggregate.kind(),
1127 aggregate.target_field(),
1128 E::MODEL.fields(),
1129 E::MODEL.primary_key().name(),
1130 ),
1131 )
1132 }
1133
1134 pub(in crate::db) fn explain_prepared_aggregate_terminal_with_visible_indexes<S>(
1135 &self,
1136 visible_indexes: &VisibleIndexes<'_>,
1137 strategy: &S,
1138 ) -> Result<ExplainAggregateTerminalPlan, QueryError>
1139 where
1140 E: EntityValue,
1141 S: PreparedFluentAggregateExplainStrategy,
1142 {
1143 self.inner
1144 .explain_prepared_aggregate_terminal_with_visible_indexes(visible_indexes, strategy)
1145 }
1146
1147 pub(in crate::db) fn explain_bytes_by_with_visible_indexes(
1148 &self,
1149 visible_indexes: &VisibleIndexes<'_>,
1150 target_field: &str,
1151 ) -> Result<ExplainExecutionNodeDescriptor, QueryError>
1152 where
1153 E: EntityValue,
1154 {
1155 let executable = self.prepared_execution_plan_for_visibility(Some(visible_indexes))?;
1156 let mut descriptor = executable
1157 .explain_load_execution_node_descriptor()
1158 .map_err(QueryError::execute)?;
1159 let projection_mode = executable.bytes_by_projection_mode(target_field);
1160 let projection_mode_label =
1161 PreparedExecutionPlan::<E>::bytes_by_projection_mode_label(projection_mode);
1162
1163 descriptor
1164 .node_properties
1165 .insert("terminal", Value::from("bytes_by"));
1166 descriptor
1167 .node_properties
1168 .insert("terminal_field", Value::from(target_field.to_string()));
1169 descriptor.node_properties.insert(
1170 "terminal_projection_mode",
1171 Value::from(projection_mode_label),
1172 );
1173 descriptor.node_properties.insert(
1174 "terminal_index_only",
1175 Value::from(matches!(
1176 projection_mode,
1177 BytesByProjectionMode::CoveringIndex | BytesByProjectionMode::CoveringConstant
1178 )),
1179 );
1180
1181 Ok(descriptor)
1182 }
1183
1184 pub(in crate::db) fn explain_prepared_projection_terminal_with_visible_indexes(
1185 &self,
1186 visible_indexes: &VisibleIndexes<'_>,
1187 strategy: &PreparedFluentProjectionStrategy,
1188 ) -> Result<ExplainExecutionNodeDescriptor, QueryError>
1189 where
1190 E: EntityValue,
1191 {
1192 let executable = self.prepared_execution_plan_for_visibility(Some(visible_indexes))?;
1193 let mut descriptor = executable
1194 .explain_load_execution_node_descriptor()
1195 .map_err(QueryError::execute)?;
1196 let projection_descriptor = strategy.explain_descriptor();
1197
1198 descriptor.node_properties.insert(
1199 "terminal",
1200 Value::from(projection_descriptor.terminal_label()),
1201 );
1202 descriptor.node_properties.insert(
1203 "terminal_field",
1204 Value::from(projection_descriptor.field_label().to_string()),
1205 );
1206 descriptor.node_properties.insert(
1207 "terminal_output",
1208 Value::from(projection_descriptor.output_label()),
1209 );
1210
1211 Ok(descriptor)
1212 }
1213
1214 pub fn planned(&self) -> Result<PlannedQuery<E>, QueryError> {
1216 self.map_plan_for_visibility(None, Self::planned_query_from_plan)
1217 }
1218
1219 pub fn plan(&self) -> Result<CompiledQuery<E>, QueryError> {
1223 self.map_plan_for_visibility(None, Self::compiled_query_from_plan)
1224 }
1225
1226 #[cfg(test)]
1227 pub(in crate::db) fn plan_with_visible_indexes(
1228 &self,
1229 visible_indexes: &VisibleIndexes<'_>,
1230 ) -> Result<CompiledQuery<E>, QueryError> {
1231 self.map_plan_for_visibility(Some(visible_indexes), Self::compiled_query_from_plan)
1232 }
1233}
1234
1235fn plan_order_pushdown_label(order_pushdown: &ExplainOrderPushdown) -> String {
1236 match order_pushdown {
1237 ExplainOrderPushdown::MissingModelContext => "missing_model_context".to_string(),
1238 ExplainOrderPushdown::EligibleSecondaryIndex { index, prefix_len } => {
1239 format!("eligible(index={index},prefix_len={prefix_len})")
1240 }
1241 ExplainOrderPushdown::Rejected(reason) => format!("rejected({reason:?})"),
1242 }
1243}
1244
1245fn plan_predicate_pushdown_label(
1246 predicate: &ExplainPredicate,
1247 access: &ExplainAccessPath,
1248) -> String {
1249 let access_label = explain_access_kind_label(access);
1250 if matches!(predicate, ExplainPredicate::None) {
1251 return "none".to_string();
1252 }
1253 if access_label == "full_scan" {
1254 if explain_predicate_contains_non_strict_compare(predicate) {
1255 return "fallback(non_strict_compare_coercion)".to_string();
1256 }
1257 if explain_predicate_contains_empty_prefix_starts_with(predicate) {
1258 return "fallback(starts_with_empty_prefix)".to_string();
1259 }
1260 if explain_predicate_contains_is_null(predicate) {
1261 return "fallback(is_null_full_scan)".to_string();
1262 }
1263 if explain_predicate_contains_text_scan_operator(predicate) {
1264 return "fallback(text_operator_full_scan)".to_string();
1265 }
1266
1267 return format!("fallback({access_label})");
1268 }
1269
1270 format!("applied({access_label})")
1271}
1272
1273fn explain_predicate_contains_non_strict_compare(predicate: &ExplainPredicate) -> bool {
1274 match predicate {
1275 ExplainPredicate::Compare { coercion, .. }
1276 | ExplainPredicate::CompareFields { coercion, .. } => coercion.id != CoercionId::Strict,
1277 ExplainPredicate::And(children) | ExplainPredicate::Or(children) => children
1278 .iter()
1279 .any(explain_predicate_contains_non_strict_compare),
1280 ExplainPredicate::Not(inner) => explain_predicate_contains_non_strict_compare(inner),
1281 ExplainPredicate::None
1282 | ExplainPredicate::True
1283 | ExplainPredicate::False
1284 | ExplainPredicate::IsNull { .. }
1285 | ExplainPredicate::IsNotNull { .. }
1286 | ExplainPredicate::IsMissing { .. }
1287 | ExplainPredicate::IsEmpty { .. }
1288 | ExplainPredicate::IsNotEmpty { .. }
1289 | ExplainPredicate::TextContains { .. }
1290 | ExplainPredicate::TextContainsCi { .. } => false,
1291 }
1292}
1293
1294fn explain_predicate_contains_is_null(predicate: &ExplainPredicate) -> bool {
1295 match predicate {
1296 ExplainPredicate::IsNull { .. } => true,
1297 ExplainPredicate::And(children) | ExplainPredicate::Or(children) => {
1298 children.iter().any(explain_predicate_contains_is_null)
1299 }
1300 ExplainPredicate::Not(inner) => explain_predicate_contains_is_null(inner),
1301 ExplainPredicate::None
1302 | ExplainPredicate::True
1303 | ExplainPredicate::False
1304 | ExplainPredicate::Compare { .. }
1305 | ExplainPredicate::CompareFields { .. }
1306 | ExplainPredicate::IsNotNull { .. }
1307 | ExplainPredicate::IsMissing { .. }
1308 | ExplainPredicate::IsEmpty { .. }
1309 | ExplainPredicate::IsNotEmpty { .. }
1310 | ExplainPredicate::TextContains { .. }
1311 | ExplainPredicate::TextContainsCi { .. } => false,
1312 }
1313}
1314
1315fn explain_predicate_contains_empty_prefix_starts_with(predicate: &ExplainPredicate) -> bool {
1316 match predicate {
1317 ExplainPredicate::Compare {
1318 op: CompareOp::StartsWith,
1319 value: Value::Text(prefix),
1320 ..
1321 } => prefix.is_empty(),
1322 ExplainPredicate::And(children) | ExplainPredicate::Or(children) => children
1323 .iter()
1324 .any(explain_predicate_contains_empty_prefix_starts_with),
1325 ExplainPredicate::Not(inner) => explain_predicate_contains_empty_prefix_starts_with(inner),
1326 ExplainPredicate::None
1327 | ExplainPredicate::True
1328 | ExplainPredicate::False
1329 | ExplainPredicate::Compare { .. }
1330 | ExplainPredicate::CompareFields { .. }
1331 | ExplainPredicate::IsNull { .. }
1332 | ExplainPredicate::IsNotNull { .. }
1333 | ExplainPredicate::IsMissing { .. }
1334 | ExplainPredicate::IsEmpty { .. }
1335 | ExplainPredicate::IsNotEmpty { .. }
1336 | ExplainPredicate::TextContains { .. }
1337 | ExplainPredicate::TextContainsCi { .. } => false,
1338 }
1339}
1340
1341fn explain_predicate_contains_text_scan_operator(predicate: &ExplainPredicate) -> bool {
1342 match predicate {
1343 ExplainPredicate::Compare {
1344 op: CompareOp::EndsWith,
1345 ..
1346 }
1347 | ExplainPredicate::TextContains { .. }
1348 | ExplainPredicate::TextContainsCi { .. } => true,
1349 ExplainPredicate::And(children) | ExplainPredicate::Or(children) => children
1350 .iter()
1351 .any(explain_predicate_contains_text_scan_operator),
1352 ExplainPredicate::Not(inner) => explain_predicate_contains_text_scan_operator(inner),
1353 ExplainPredicate::Compare { .. }
1354 | ExplainPredicate::CompareFields { .. }
1355 | ExplainPredicate::None
1356 | ExplainPredicate::True
1357 | ExplainPredicate::False
1358 | ExplainPredicate::IsNull { .. }
1359 | ExplainPredicate::IsNotNull { .. }
1360 | ExplainPredicate::IsMissing { .. }
1361 | ExplainPredicate::IsEmpty { .. }
1362 | ExplainPredicate::IsNotEmpty { .. } => false,
1363 }
1364}
1365
1366impl<E> Query<E>
1367where
1368 E: EntityKind + SingletonEntity,
1369 E::Key: Default,
1370{
1371 pub(crate) fn only(self) -> Self {
1373 let Self { inner, .. } = self;
1374
1375 Self::from_inner(inner.only(E::Key::default().to_key_value()))
1376 }
1377}