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 descriptor.contains_type(ExplainExecutionNodeType::TopNSeek)
364 ));
365 logical_diagnostics.push(format!(
366 "diag.d.has_index_range_limit_pushdown={}",
367 descriptor.contains_type(ExplainExecutionNodeType::IndexRangeLimitPushdown)
368 ));
369 logical_diagnostics.push(format!(
370 "diag.d.has_index_predicate_prefilter={}",
371 descriptor.contains_type(ExplainExecutionNodeType::IndexPredicatePrefilter)
372 ));
373 logical_diagnostics.push(format!(
374 "diag.d.has_residual_filter={}",
375 descriptor.contains_type(ExplainExecutionNodeType::ResidualFilter)
376 ));
377
378 logical_diagnostics.push(format!("diag.p.mode={:?}", explain.mode()));
380 logical_diagnostics.push(format!(
381 "diag.p.order_pushdown={}",
382 plan_order_pushdown_label(explain.order_pushdown())
383 ));
384 logical_diagnostics.push(format!(
385 "diag.p.predicate_pushdown={}",
386 plan_predicate_pushdown_label(explain.predicate(), explain.access())
387 ));
388 logical_diagnostics.push(format!("diag.p.distinct={}", explain.distinct()));
389 logical_diagnostics.push(format!("diag.p.page={:?}", explain.page()));
390 logical_diagnostics.push(format!("diag.p.consistency={:?}", explain.consistency()));
391
392 Ok(FinalizedQueryDiagnostics::new(
393 descriptor,
394 route_diagnostics,
395 logical_diagnostics,
396 reuse,
397 ))
398 }
399
400 pub(in crate::db) fn finalized_execution_diagnostics_from_plan_with_descriptor_mutator(
403 &self,
404 plan: &AccessPlannedQuery,
405 reuse: Option<TraceReuseEvent>,
406 mutate_descriptor: impl FnOnce(&mut ExplainExecutionNodeDescriptor),
407 ) -> Result<FinalizedQueryDiagnostics, QueryError> {
408 let mut diagnostics = self.finalized_execution_diagnostics_from_plan(plan, reuse)?;
409 mutate_descriptor(&mut diagnostics.execution);
410
411 Ok(diagnostics)
412 }
413
414 fn explain_execution_verbose_from_plan(
417 &self,
418 plan: &AccessPlannedQuery,
419 ) -> Result<String, QueryError> {
420 self.finalized_execution_diagnostics_from_plan(plan, None)
421 .map(|diagnostics| diagnostics.render_text_verbose())
422 }
423
424 fn finalize_explain_access_choice_for_visibility(
427 &self,
428 plan: &mut AccessPlannedQuery,
429 visible_indexes: Option<&VisibleIndexes<'_>>,
430 ) {
431 let visible_indexes = match visible_indexes {
432 Some(visible_indexes) => visible_indexes.as_slice(),
433 None => self.intent.model().indexes(),
434 };
435
436 plan.finalize_access_choice_for_model_with_indexes(self.intent.model(), visible_indexes);
437 }
438
439 fn explain_execution_descriptor_for_visibility(
442 &self,
443 visible_indexes: Option<&VisibleIndexes<'_>>,
444 ) -> Result<ExplainExecutionNodeDescriptor, QueryError> {
445 let mut plan = self.build_plan_for_visibility(visible_indexes)?;
446 self.finalize_explain_access_choice_for_visibility(&mut plan, visible_indexes);
447
448 self.explain_execution_descriptor_from_plan(&plan)
449 }
450
451 fn explain_execution_verbose_for_visibility(
454 &self,
455 visible_indexes: Option<&VisibleIndexes<'_>>,
456 ) -> Result<String, QueryError> {
457 let mut plan = self.build_plan_for_visibility(visible_indexes)?;
458 self.finalize_explain_access_choice_for_visibility(&mut plan, visible_indexes);
459
460 self.explain_execution_verbose_from_plan(&plan)
461 }
462
463 #[cfg(feature = "sql")]
464 #[must_use]
465 pub(in crate::db) const fn model(&self) -> &'static crate::model::entity::EntityModel {
466 self.intent.model()
467 }
468
469 #[inline(never)]
470 pub(in crate::db) fn explain_execution_with_visible_indexes(
471 &self,
472 visible_indexes: &VisibleIndexes<'_>,
473 ) -> Result<ExplainExecutionNodeDescriptor, QueryError> {
474 self.explain_execution_descriptor_for_visibility(Some(visible_indexes))
475 }
476
477 #[inline(never)]
479 pub(in crate::db) fn explain_execution(
480 &self,
481 ) -> Result<ExplainExecutionNodeDescriptor, QueryError> {
482 self.explain_execution_descriptor_for_visibility(None)
483 }
484
485 #[inline(never)]
488 pub(in crate::db) fn explain_execution_verbose(&self) -> Result<String, QueryError> {
489 self.explain_execution_verbose_for_visibility(None)
490 }
491
492 #[inline(never)]
493 pub(in crate::db) fn explain_execution_verbose_with_visible_indexes(
494 &self,
495 visible_indexes: &VisibleIndexes<'_>,
496 ) -> Result<String, QueryError> {
497 self.explain_execution_verbose_for_visibility(Some(visible_indexes))
498 }
499
500 #[inline(never)]
501 pub(in crate::db) fn explain_aggregate_terminal_with_visible_indexes(
502 &self,
503 visible_indexes: &VisibleIndexes<'_>,
504 aggregate: AggregateRouteShape<'_>,
505 ) -> Result<ExplainAggregateTerminalPlan, QueryError> {
506 let plan = self.build_plan_with_visible_indexes(visible_indexes)?;
507 let query_explain = plan.explain();
508 let terminal = aggregate.kind();
509 let execution = assemble_aggregate_terminal_execution_descriptor(&plan, aggregate);
510
511 Ok(ExplainAggregateTerminalPlan::new(
512 query_explain,
513 terminal,
514 execution,
515 ))
516 }
517
518 #[inline(never)]
519 pub(in crate::db) fn explain_prepared_aggregate_terminal_with_visible_indexes<S>(
520 &self,
521 visible_indexes: &VisibleIndexes<'_>,
522 strategy: &S,
523 ) -> Result<ExplainAggregateTerminalPlan, QueryError>
524 where
525 S: PreparedFluentAggregateExplainStrategy,
526 {
527 let Some(kind) = strategy.explain_aggregate_kind() else {
528 return Err(QueryError::invariant(
529 "prepared fluent aggregate explain requires an explain-visible aggregate kind",
530 ));
531 };
532 let aggregate = AggregateRouteShape::new_from_fields(
533 kind,
534 strategy.explain_projected_field(),
535 self.intent.model().fields(),
536 self.intent.model().primary_key().name(),
537 );
538
539 self.explain_aggregate_terminal_with_visible_indexes(visible_indexes, aggregate)
540 }
541}
542
543#[derive(Clone, Debug)]
553enum QueryPlanHandle {
554 Plan(Box<AccessPlannedQuery>),
555 Prepared(SharedPreparedExecutionPlan),
556}
557
558impl QueryPlanHandle {
559 #[must_use]
560 fn from_plan(plan: AccessPlannedQuery) -> Self {
561 Self::Plan(Box::new(plan))
562 }
563
564 #[must_use]
565 const fn from_prepared(prepared_plan: SharedPreparedExecutionPlan) -> Self {
566 Self::Prepared(prepared_plan)
567 }
568
569 #[must_use]
570 fn logical_plan(&self) -> &AccessPlannedQuery {
571 match self {
572 Self::Plan(plan) => plan,
573 Self::Prepared(prepared_plan) => prepared_plan.logical_plan(),
574 }
575 }
576
577 fn into_prepared_execution_plan<E: EntityKind>(self) -> PreparedExecutionPlan<E> {
578 match self {
579 Self::Plan(plan) => PreparedExecutionPlan::new(*plan),
580 Self::Prepared(prepared_plan) => prepared_plan.typed_clone::<E>(),
581 }
582 }
583
584 #[must_use]
585 #[cfg(test)]
586 fn into_inner(self) -> AccessPlannedQuery {
587 match self {
588 Self::Plan(plan) => *plan,
589 Self::Prepared(prepared_plan) => prepared_plan.logical_plan().clone(),
590 }
591 }
592}
593
594#[derive(Debug)]
602pub struct PlannedQuery<E: EntityKind> {
603 plan: QueryPlanHandle,
604 _marker: PhantomData<E>,
605}
606
607impl<E: EntityKind> PlannedQuery<E> {
608 #[must_use]
609 fn from_plan(plan: AccessPlannedQuery) -> Self {
610 Self {
611 plan: QueryPlanHandle::from_plan(plan),
612 _marker: PhantomData,
613 }
614 }
615
616 #[must_use]
617 pub(in crate::db) const fn from_prepared_plan(
618 prepared_plan: SharedPreparedExecutionPlan,
619 ) -> Self {
620 Self {
621 plan: QueryPlanHandle::from_prepared(prepared_plan),
622 _marker: PhantomData,
623 }
624 }
625
626 #[must_use]
627 pub fn explain(&self) -> ExplainPlan {
628 self.plan.logical_plan().explain()
629 }
630
631 #[must_use]
633 pub fn plan_hash_hex(&self) -> String {
634 self.plan.logical_plan().fingerprint().to_string()
635 }
636}
637
638#[derive(Clone, Debug)]
648pub struct CompiledQuery<E: EntityKind> {
649 plan: QueryPlanHandle,
650 _marker: PhantomData<E>,
651}
652
653impl<E: EntityKind> CompiledQuery<E> {
654 #[must_use]
655 fn from_plan(plan: AccessPlannedQuery) -> Self {
656 Self {
657 plan: QueryPlanHandle::from_plan(plan),
658 _marker: PhantomData,
659 }
660 }
661
662 #[must_use]
663 pub(in crate::db) const fn from_prepared_plan(
664 prepared_plan: SharedPreparedExecutionPlan,
665 ) -> Self {
666 Self {
667 plan: QueryPlanHandle::from_prepared(prepared_plan),
668 _marker: PhantomData,
669 }
670 }
671
672 #[must_use]
673 pub fn explain(&self) -> ExplainPlan {
674 self.plan.logical_plan().explain()
675 }
676
677 #[must_use]
679 pub fn plan_hash_hex(&self) -> String {
680 self.plan.logical_plan().fingerprint().to_string()
681 }
682
683 #[must_use]
684 #[cfg(test)]
685 pub(in crate::db) fn projection_spec(&self) -> crate::db::query::plan::expr::ProjectionSpec {
686 self.plan.logical_plan().projection_spec(E::MODEL)
687 }
688
689 pub(in crate::db) fn into_prepared_execution_plan(
691 self,
692 ) -> crate::db::executor::PreparedExecutionPlan<E> {
693 self.plan.into_prepared_execution_plan::<E>()
694 }
695
696 #[must_use]
697 #[cfg(test)]
698 pub(in crate::db) fn into_inner(self) -> AccessPlannedQuery {
699 self.plan.into_inner()
700 }
701}
702
703#[derive(Debug)]
715pub struct Query<E: EntityKind> {
716 inner: StructuralQuery,
717 _marker: PhantomData<E>,
718}
719
720impl<E: EntityKind> Query<E> {
721 pub(in crate::db) const fn from_inner(inner: StructuralQuery) -> Self {
723 Self {
724 inner,
725 _marker: PhantomData,
726 }
727 }
728
729 #[must_use]
733 pub const fn new(consistency: MissingRowPolicy) -> Self {
734 Self::from_inner(StructuralQuery::new(E::MODEL, consistency))
735 }
736
737 #[must_use]
739 pub const fn mode(&self) -> QueryMode {
740 self.inner.mode()
741 }
742
743 pub(in crate::db) fn explain_with_visible_indexes(
744 &self,
745 visible_indexes: &VisibleIndexes<'_>,
746 ) -> Result<ExplainPlan, QueryError> {
747 let plan = self.build_plan_for_visibility(Some(visible_indexes))?;
748
749 Ok(plan.explain())
750 }
751
752 pub(in crate::db) fn plan_hash_hex_with_visible_indexes(
753 &self,
754 visible_indexes: &VisibleIndexes<'_>,
755 ) -> Result<String, QueryError> {
756 let plan = self.build_plan_for_visibility(Some(visible_indexes))?;
757
758 Ok(plan.fingerprint().to_string())
759 }
760
761 fn build_plan_for_visibility(
764 &self,
765 visible_indexes: Option<&VisibleIndexes<'_>>,
766 ) -> Result<AccessPlannedQuery, QueryError> {
767 self.inner.build_plan_for_visibility(visible_indexes)
768 }
769
770 fn map_plan_for_visibility<T>(
774 &self,
775 visible_indexes: Option<&VisibleIndexes<'_>>,
776 map: impl FnOnce(AccessPlannedQuery) -> T,
777 ) -> Result<T, QueryError> {
778 let plan = self.build_plan_for_visibility(visible_indexes)?;
779
780 Ok(map(plan))
781 }
782
783 fn prepared_execution_plan_for_visibility(
787 &self,
788 visible_indexes: Option<&VisibleIndexes<'_>>,
789 ) -> Result<PreparedExecutionPlan<E>, QueryError> {
790 self.map_plan_for_visibility(visible_indexes, PreparedExecutionPlan::<E>::new)
791 }
792
793 pub(in crate::db) fn planned_query_from_plan(plan: AccessPlannedQuery) -> PlannedQuery<E> {
795 PlannedQuery::from_plan(plan)
796 }
797
798 pub(in crate::db) fn compiled_query_from_plan(plan: AccessPlannedQuery) -> CompiledQuery<E> {
800 CompiledQuery::from_plan(plan)
801 }
802
803 #[must_use]
804 pub(crate) fn has_explicit_order(&self) -> bool {
805 self.inner.has_explicit_order()
806 }
807
808 #[must_use]
809 pub(in crate::db) const fn structural(&self) -> &StructuralQuery {
810 &self.inner
811 }
812
813 #[must_use]
814 pub const fn has_grouping(&self) -> bool {
815 self.inner.has_grouping()
816 }
817
818 #[must_use]
819 pub(crate) const fn load_spec(&self) -> Option<LoadSpec> {
820 self.inner.load_spec()
821 }
822
823 #[must_use]
825 pub fn filter(mut self, expr: impl Into<FilterExpr>) -> Self {
826 self.inner = self.inner.filter(expr);
827 self
828 }
829
830 #[cfg(test)]
834 #[must_use]
835 pub(in crate::db) fn filter_expr(mut self, expr: Expr) -> Self {
836 self.inner = self.inner.filter_expr(expr);
837 self
838 }
839
840 #[must_use]
841 pub(in crate::db) fn filter_predicate(mut self, predicate: Predicate) -> Self {
842 self.inner = self.inner.filter_predicate(predicate);
843 self
844 }
845
846 #[must_use]
848 pub fn order_term(mut self, term: FluentOrderTerm) -> Self {
849 self.inner = self.inner.order_term(term);
850 self
851 }
852
853 #[must_use]
855 pub fn order_terms<I>(mut self, terms: I) -> Self
856 where
857 I: IntoIterator<Item = FluentOrderTerm>,
858 {
859 for term in terms {
860 self.inner = self.inner.order_term(term);
861 }
862
863 self
864 }
865
866 #[must_use]
868 pub fn distinct(mut self) -> Self {
869 self.inner = self.inner.distinct();
870 self
871 }
872
873 #[cfg(all(test, feature = "sql"))]
876 #[must_use]
877 pub(in crate::db) fn select_fields<I, S>(mut self, fields: I) -> Self
878 where
879 I: IntoIterator<Item = S>,
880 S: Into<String>,
881 {
882 self.inner = self.inner.select_fields(fields);
883 self
884 }
885
886 pub fn group_by(self, field: impl AsRef<str>) -> Result<Self, QueryError> {
888 let Self { inner, .. } = self;
889 let inner = inner.group_by(field)?;
890
891 Ok(Self::from_inner(inner))
892 }
893
894 #[must_use]
896 pub fn aggregate(mut self, aggregate: AggregateExpr) -> Self {
897 self.inner = self.inner.aggregate(aggregate);
898 self
899 }
900
901 #[must_use]
903 pub fn grouped_limits(mut self, max_groups: u64, max_group_bytes: u64) -> Self {
904 self.inner = self.inner.grouped_limits(max_groups, max_group_bytes);
905 self
906 }
907
908 pub fn having_group(
910 self,
911 field: impl AsRef<str>,
912 op: CompareOp,
913 value: Value,
914 ) -> Result<Self, QueryError> {
915 let Self { inner, .. } = self;
916 let inner = inner.having_group(field, op, value)?;
917
918 Ok(Self::from_inner(inner))
919 }
920
921 pub fn having_aggregate(
923 self,
924 aggregate_index: usize,
925 op: CompareOp,
926 value: Value,
927 ) -> Result<Self, QueryError> {
928 let Self { inner, .. } = self;
929 let inner = inner.having_aggregate(aggregate_index, op, value)?;
930
931 Ok(Self::from_inner(inner))
932 }
933
934 #[cfg(test)]
938 pub(in crate::db) fn having_expr(self, expr: Expr) -> Result<Self, QueryError> {
939 let Self { inner, .. } = self;
940 let inner = inner.having_expr(expr)?;
941
942 Ok(Self::from_inner(inner))
943 }
944
945 pub(crate) fn by_id(self, id: E::Key) -> Self {
947 let Self { inner, .. } = self;
948
949 Self::from_inner(inner.by_id(id.to_value()))
950 }
951
952 pub(crate) fn by_ids<I>(self, ids: I) -> Self
954 where
955 I: IntoIterator<Item = E::Key>,
956 {
957 let Self { inner, .. } = self;
958
959 Self::from_inner(inner.by_ids(ids.into_iter().map(|id| id.to_value())))
960 }
961
962 #[must_use]
964 pub fn delete(mut self) -> Self {
965 self.inner = self.inner.delete();
966 self
967 }
968
969 #[must_use]
976 pub fn limit(mut self, limit: u32) -> Self {
977 self.inner = self.inner.limit(limit);
978 self
979 }
980
981 #[must_use]
987 pub fn offset(mut self, offset: u32) -> Self {
988 self.inner = self.inner.offset(offset);
989 self
990 }
991
992 pub fn explain(&self) -> Result<ExplainPlan, QueryError> {
994 let plan = self.planned()?;
995
996 Ok(plan.explain())
997 }
998
999 pub fn plan_hash_hex(&self) -> Result<String, QueryError> {
1004 let plan = self.inner.build_plan()?;
1005
1006 Ok(plan.fingerprint().to_string())
1007 }
1008
1009 fn explain_execution_descriptor_for_visibility(
1012 &self,
1013 visible_indexes: Option<&VisibleIndexes<'_>>,
1014 ) -> Result<ExplainExecutionNodeDescriptor, QueryError>
1015 where
1016 E: EntityValue,
1017 {
1018 match visible_indexes {
1019 Some(visible_indexes) => self
1020 .inner
1021 .explain_execution_with_visible_indexes(visible_indexes),
1022 None => self.inner.explain_execution(),
1023 }
1024 }
1025
1026 fn render_execution_descriptor_for_visibility(
1029 &self,
1030 visible_indexes: Option<&VisibleIndexes<'_>>,
1031 render: impl FnOnce(ExplainExecutionNodeDescriptor) -> String,
1032 ) -> Result<String, QueryError>
1033 where
1034 E: EntityValue,
1035 {
1036 let descriptor = self.explain_execution_descriptor_for_visibility(visible_indexes)?;
1037
1038 Ok(render(descriptor))
1039 }
1040
1041 fn explain_execution_verbose_for_visibility(
1044 &self,
1045 visible_indexes: Option<&VisibleIndexes<'_>>,
1046 ) -> Result<String, QueryError>
1047 where
1048 E: EntityValue,
1049 {
1050 match visible_indexes {
1051 Some(visible_indexes) => self
1052 .inner
1053 .explain_execution_verbose_with_visible_indexes(visible_indexes),
1054 None => self.inner.explain_execution_verbose(),
1055 }
1056 }
1057
1058 pub fn explain_execution(&self) -> Result<ExplainExecutionNodeDescriptor, QueryError>
1060 where
1061 E: EntityValue,
1062 {
1063 self.explain_execution_descriptor_for_visibility(None)
1064 }
1065
1066 pub(in crate::db) fn explain_execution_with_visible_indexes(
1067 &self,
1068 visible_indexes: &VisibleIndexes<'_>,
1069 ) -> Result<ExplainExecutionNodeDescriptor, QueryError>
1070 where
1071 E: EntityValue,
1072 {
1073 self.explain_execution_descriptor_for_visibility(Some(visible_indexes))
1074 }
1075
1076 pub fn explain_execution_text(&self) -> Result<String, QueryError>
1078 where
1079 E: EntityValue,
1080 {
1081 self.render_execution_descriptor_for_visibility(None, |descriptor| {
1082 descriptor.render_text_tree()
1083 })
1084 }
1085
1086 pub fn explain_execution_json(&self) -> Result<String, QueryError>
1088 where
1089 E: EntityValue,
1090 {
1091 self.render_execution_descriptor_for_visibility(None, |descriptor| {
1092 descriptor.render_json_canonical()
1093 })
1094 }
1095
1096 #[inline(never)]
1098 pub fn explain_execution_verbose(&self) -> Result<String, QueryError>
1099 where
1100 E: EntityValue,
1101 {
1102 self.explain_execution_verbose_for_visibility(None)
1103 }
1104
1105 #[cfg(test)]
1107 #[inline(never)]
1108 pub(in crate::db) fn explain_aggregate_terminal(
1109 &self,
1110 aggregate: AggregateExpr,
1111 ) -> Result<ExplainAggregateTerminalPlan, QueryError>
1112 where
1113 E: EntityValue,
1114 {
1115 self.inner.explain_aggregate_terminal_with_visible_indexes(
1116 &VisibleIndexes::schema_owned(E::MODEL.indexes()),
1117 AggregateRouteShape::new_from_fields(
1118 aggregate.kind(),
1119 aggregate.target_field(),
1120 E::MODEL.fields(),
1121 E::MODEL.primary_key().name(),
1122 ),
1123 )
1124 }
1125
1126 pub(in crate::db) fn explain_prepared_aggregate_terminal_with_visible_indexes<S>(
1127 &self,
1128 visible_indexes: &VisibleIndexes<'_>,
1129 strategy: &S,
1130 ) -> Result<ExplainAggregateTerminalPlan, QueryError>
1131 where
1132 E: EntityValue,
1133 S: PreparedFluentAggregateExplainStrategy,
1134 {
1135 self.inner
1136 .explain_prepared_aggregate_terminal_with_visible_indexes(visible_indexes, strategy)
1137 }
1138
1139 pub(in crate::db) fn explain_bytes_by_with_visible_indexes(
1140 &self,
1141 visible_indexes: &VisibleIndexes<'_>,
1142 target_field: &str,
1143 ) -> Result<ExplainExecutionNodeDescriptor, QueryError>
1144 where
1145 E: EntityValue,
1146 {
1147 let executable = self.prepared_execution_plan_for_visibility(Some(visible_indexes))?;
1148 let mut descriptor = executable
1149 .explain_load_execution_node_descriptor()
1150 .map_err(QueryError::execute)?;
1151 let projection_mode = executable.bytes_by_projection_mode(target_field);
1152 let projection_mode_label =
1153 PreparedExecutionPlan::<E>::bytes_by_projection_mode_label(projection_mode);
1154
1155 descriptor
1156 .node_properties
1157 .insert("terminal", Value::from("bytes_by"));
1158 descriptor
1159 .node_properties
1160 .insert("terminal_field", Value::from(target_field.to_string()));
1161 descriptor.node_properties.insert(
1162 "terminal_projection_mode",
1163 Value::from(projection_mode_label),
1164 );
1165 descriptor.node_properties.insert(
1166 "terminal_index_only",
1167 Value::from(matches!(
1168 projection_mode,
1169 BytesByProjectionMode::CoveringIndex | BytesByProjectionMode::CoveringConstant
1170 )),
1171 );
1172
1173 Ok(descriptor)
1174 }
1175
1176 pub(in crate::db) fn explain_prepared_projection_terminal_with_visible_indexes(
1177 &self,
1178 visible_indexes: &VisibleIndexes<'_>,
1179 strategy: &PreparedFluentProjectionStrategy,
1180 ) -> Result<ExplainExecutionNodeDescriptor, QueryError>
1181 where
1182 E: EntityValue,
1183 {
1184 let executable = self.prepared_execution_plan_for_visibility(Some(visible_indexes))?;
1185 let mut descriptor = executable
1186 .explain_load_execution_node_descriptor()
1187 .map_err(QueryError::execute)?;
1188 let projection_descriptor = strategy.explain_descriptor();
1189
1190 descriptor.node_properties.insert(
1191 "terminal",
1192 Value::from(projection_descriptor.terminal_label()),
1193 );
1194 descriptor.node_properties.insert(
1195 "terminal_field",
1196 Value::from(projection_descriptor.field_label().to_string()),
1197 );
1198 descriptor.node_properties.insert(
1199 "terminal_output",
1200 Value::from(projection_descriptor.output_label()),
1201 );
1202
1203 Ok(descriptor)
1204 }
1205
1206 pub fn planned(&self) -> Result<PlannedQuery<E>, QueryError> {
1208 self.map_plan_for_visibility(None, Self::planned_query_from_plan)
1209 }
1210
1211 pub fn plan(&self) -> Result<CompiledQuery<E>, QueryError> {
1215 self.map_plan_for_visibility(None, Self::compiled_query_from_plan)
1216 }
1217
1218 #[cfg(test)]
1219 pub(in crate::db) fn plan_with_visible_indexes(
1220 &self,
1221 visible_indexes: &VisibleIndexes<'_>,
1222 ) -> Result<CompiledQuery<E>, QueryError> {
1223 self.map_plan_for_visibility(Some(visible_indexes), Self::compiled_query_from_plan)
1224 }
1225}
1226
1227fn plan_order_pushdown_label(order_pushdown: &ExplainOrderPushdown) -> String {
1228 match order_pushdown {
1229 ExplainOrderPushdown::MissingModelContext => "missing_model_context".to_string(),
1230 ExplainOrderPushdown::EligibleSecondaryIndex { index, prefix_len } => {
1231 format!("eligible(index={index},prefix_len={prefix_len})")
1232 }
1233 ExplainOrderPushdown::Rejected(reason) => format!("rejected({reason:?})"),
1234 }
1235}
1236
1237fn plan_predicate_pushdown_label(
1238 predicate: &ExplainPredicate,
1239 access: &ExplainAccessPath,
1240) -> String {
1241 let access_label = explain_access_kind_label(access);
1242 if matches!(predicate, ExplainPredicate::None) {
1243 return "none".to_string();
1244 }
1245 if access_label == "full_scan" {
1246 if explain_predicate_contains_non_strict_compare(predicate) {
1247 return "fallback(non_strict_compare_coercion)".to_string();
1248 }
1249 if explain_predicate_contains_empty_prefix_starts_with(predicate) {
1250 return "fallback(starts_with_empty_prefix)".to_string();
1251 }
1252 if explain_predicate_contains_is_null(predicate) {
1253 return "fallback(is_null_full_scan)".to_string();
1254 }
1255 if explain_predicate_contains_text_scan_operator(predicate) {
1256 return "fallback(text_operator_full_scan)".to_string();
1257 }
1258
1259 return format!("fallback({access_label})");
1260 }
1261
1262 format!("applied({access_label})")
1263}
1264
1265fn explain_predicate_contains_non_strict_compare(predicate: &ExplainPredicate) -> bool {
1266 match predicate {
1267 ExplainPredicate::Compare { coercion, .. }
1268 | ExplainPredicate::CompareFields { coercion, .. } => coercion.id != CoercionId::Strict,
1269 ExplainPredicate::And(children) | ExplainPredicate::Or(children) => children
1270 .iter()
1271 .any(explain_predicate_contains_non_strict_compare),
1272 ExplainPredicate::Not(inner) => explain_predicate_contains_non_strict_compare(inner),
1273 ExplainPredicate::None
1274 | ExplainPredicate::True
1275 | ExplainPredicate::False
1276 | ExplainPredicate::IsNull { .. }
1277 | ExplainPredicate::IsNotNull { .. }
1278 | ExplainPredicate::IsMissing { .. }
1279 | ExplainPredicate::IsEmpty { .. }
1280 | ExplainPredicate::IsNotEmpty { .. }
1281 | ExplainPredicate::TextContains { .. }
1282 | ExplainPredicate::TextContainsCi { .. } => false,
1283 }
1284}
1285
1286fn explain_predicate_contains_is_null(predicate: &ExplainPredicate) -> bool {
1287 match predicate {
1288 ExplainPredicate::IsNull { .. } => true,
1289 ExplainPredicate::And(children) | ExplainPredicate::Or(children) => {
1290 children.iter().any(explain_predicate_contains_is_null)
1291 }
1292 ExplainPredicate::Not(inner) => explain_predicate_contains_is_null(inner),
1293 ExplainPredicate::None
1294 | ExplainPredicate::True
1295 | ExplainPredicate::False
1296 | ExplainPredicate::Compare { .. }
1297 | ExplainPredicate::CompareFields { .. }
1298 | ExplainPredicate::IsNotNull { .. }
1299 | ExplainPredicate::IsMissing { .. }
1300 | ExplainPredicate::IsEmpty { .. }
1301 | ExplainPredicate::IsNotEmpty { .. }
1302 | ExplainPredicate::TextContains { .. }
1303 | ExplainPredicate::TextContainsCi { .. } => false,
1304 }
1305}
1306
1307fn explain_predicate_contains_empty_prefix_starts_with(predicate: &ExplainPredicate) -> bool {
1308 match predicate {
1309 ExplainPredicate::Compare {
1310 op: CompareOp::StartsWith,
1311 value: Value::Text(prefix),
1312 ..
1313 } => prefix.is_empty(),
1314 ExplainPredicate::And(children) | ExplainPredicate::Or(children) => children
1315 .iter()
1316 .any(explain_predicate_contains_empty_prefix_starts_with),
1317 ExplainPredicate::Not(inner) => explain_predicate_contains_empty_prefix_starts_with(inner),
1318 ExplainPredicate::None
1319 | ExplainPredicate::True
1320 | ExplainPredicate::False
1321 | ExplainPredicate::Compare { .. }
1322 | ExplainPredicate::CompareFields { .. }
1323 | ExplainPredicate::IsNull { .. }
1324 | ExplainPredicate::IsNotNull { .. }
1325 | ExplainPredicate::IsMissing { .. }
1326 | ExplainPredicate::IsEmpty { .. }
1327 | ExplainPredicate::IsNotEmpty { .. }
1328 | ExplainPredicate::TextContains { .. }
1329 | ExplainPredicate::TextContainsCi { .. } => false,
1330 }
1331}
1332
1333fn explain_predicate_contains_text_scan_operator(predicate: &ExplainPredicate) -> bool {
1334 match predicate {
1335 ExplainPredicate::Compare {
1336 op: CompareOp::EndsWith,
1337 ..
1338 }
1339 | ExplainPredicate::TextContains { .. }
1340 | ExplainPredicate::TextContainsCi { .. } => true,
1341 ExplainPredicate::And(children) | ExplainPredicate::Or(children) => children
1342 .iter()
1343 .any(explain_predicate_contains_text_scan_operator),
1344 ExplainPredicate::Not(inner) => explain_predicate_contains_text_scan_operator(inner),
1345 ExplainPredicate::Compare { .. }
1346 | ExplainPredicate::CompareFields { .. }
1347 | ExplainPredicate::None
1348 | ExplainPredicate::True
1349 | ExplainPredicate::False
1350 | ExplainPredicate::IsNull { .. }
1351 | ExplainPredicate::IsNotNull { .. }
1352 | ExplainPredicate::IsMissing { .. }
1353 | ExplainPredicate::IsEmpty { .. }
1354 | ExplainPredicate::IsNotEmpty { .. } => false,
1355 }
1356}
1357
1358impl<E> Query<E>
1359where
1360 E: EntityKind + SingletonEntity,
1361 E::Key: Default,
1362{
1363 pub(crate) fn only(self) -> Self {
1365 let Self { inner, .. } = self;
1366
1367 Self::from_inner(inner.only(E::Key::default().to_value()))
1368 }
1369}