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