1#[cfg(feature = "sql")]
7use crate::db::query::plan::expr::ProjectionSelection;
8use crate::{
9 db::{
10 predicate::{CompareOp, MissingRowPolicy, Predicate},
11 query::{
12 builder::AggregateExpr,
13 explain::ExplainPlan,
14 expr::FilterExpr,
15 expr::OrderTerm as FluentOrderTerm,
16 intent::{AccessRequirements, QueryError, QueryModel, RequiredAccessPath},
17 plan::{
18 AccessPlannedQuery, LoadSpec, OrderSpec, PreparedScalarPlanningState, QueryMode,
19 VisibleIndexes, expr::Expr,
20 },
21 },
22 schema::SchemaInfo,
23 },
24 traits::{EntityKind, KeyValueCodec, SingletonEntity},
25 value::{InputValue, Value},
26};
27use core::marker::PhantomData;
28
29#[derive(Clone, Debug)]
38pub(in crate::db) struct StructuralQuery {
39 intent: QueryModel<'static, Value>,
40 access_requirements: AccessRequirements,
41}
42
43impl StructuralQuery {
44 #[must_use]
45 pub(in crate::db) const fn new(
46 model: &'static crate::model::entity::EntityModel,
47 consistency: MissingRowPolicy,
48 ) -> Self {
49 Self {
50 intent: QueryModel::new(model, consistency),
51 access_requirements: AccessRequirements::new(),
52 }
53 }
54
55 const fn from_parts(
59 intent: QueryModel<'static, Value>,
60 access_requirements: AccessRequirements,
61 ) -> Self {
62 Self {
63 intent,
64 access_requirements,
65 }
66 }
67
68 fn map_intent(
71 self,
72 map: impl FnOnce(QueryModel<'static, Value>) -> QueryModel<'static, Value>,
73 ) -> Self {
74 let Self {
75 intent,
76 access_requirements,
77 } = self;
78
79 Self::from_parts(map(intent), access_requirements)
80 }
81
82 fn try_map_intent(
85 self,
86 map: impl FnOnce(QueryModel<'static, Value>) -> Result<QueryModel<'static, Value>, QueryError>,
87 ) -> Result<Self, QueryError> {
88 let Self {
89 intent,
90 access_requirements,
91 } = self;
92
93 map(intent).map(|intent| Self::from_parts(intent, access_requirements))
94 }
95
96 #[must_use]
97 const fn mode(&self) -> QueryMode {
98 self.intent.mode()
99 }
100
101 #[must_use]
102 fn has_explicit_order(&self) -> bool {
103 self.intent.has_explicit_order()
104 }
105
106 #[must_use]
107 pub(in crate::db) const fn has_grouping(&self) -> bool {
108 self.intent.has_grouping()
109 }
110
111 #[must_use]
112 const fn load_spec(&self) -> Option<LoadSpec> {
113 match self.intent.mode() {
114 QueryMode::Load(spec) => Some(spec),
115 QueryMode::Delete(_) => None,
116 }
117 }
118
119 #[must_use]
120 pub(in crate::db) fn filter_predicate(mut self, predicate: Predicate) -> Self {
121 self.intent = self.intent.filter_predicate(predicate);
122 self
123 }
124
125 #[must_use]
126 pub(in crate::db) fn filter(mut self, expr: impl Into<FilterExpr>) -> Self {
127 self.intent = self.intent.filter(expr.into());
128 self
129 }
130
131 #[must_use]
132 pub(in crate::db) fn filter_expr_with_normalized_predicate(
133 mut self,
134 expr: Expr,
135 predicate: Predicate,
136 ) -> Self {
137 self.intent = self
138 .intent
139 .filter_expr_with_normalized_predicate(expr, predicate);
140 self
141 }
142 pub(in crate::db) fn order_term(mut self, term: FluentOrderTerm) -> Self {
143 self.intent = self.intent.order_term(term);
144 self
145 }
146
147 #[must_use]
151 pub(in crate::db) fn filter_expr(mut self, expr: Expr) -> Self {
152 self.intent = self.intent.filter_expr(expr);
153 self
154 }
155
156 #[must_use]
157 pub(in crate::db) fn order_spec(mut self, order: OrderSpec) -> Self {
158 self.intent = self.intent.order_spec(order);
159 self
160 }
161
162 #[must_use]
163 pub(in crate::db) fn distinct(mut self) -> Self {
164 self.intent = self.intent.distinct();
165 self
166 }
167
168 #[cfg(all(test, feature = "sql"))]
169 #[must_use]
170 pub(in crate::db) fn select_fields<I, S>(mut self, fields: I) -> Self
171 where
172 I: IntoIterator<Item = S>,
173 S: Into<String>,
174 {
175 self.intent = self.intent.select_fields(fields);
176 self
177 }
178
179 #[cfg(feature = "sql")]
180 #[must_use]
181 pub(in crate::db) fn projection_selection(mut self, selection: ProjectionSelection) -> Self {
182 self.intent = self.intent.projection_selection(selection);
183 self
184 }
185
186 #[cfg(feature = "sql")]
191 #[must_use]
192 pub(in crate::db) fn select_field_id(mut self, field: impl Into<String>) -> Self {
193 self.intent = self.intent.select_field_id(field);
194 self
195 }
196
197 pub(in crate::db) fn group_by(self, field: impl AsRef<str>) -> Result<Self, QueryError> {
198 self.try_map_intent(|intent| intent.push_group_field(field.as_ref()))
199 }
200
201 pub(in crate::db) fn group_by_with_schema(
202 self,
203 field: impl AsRef<str>,
204 schema: &SchemaInfo,
205 ) -> Result<Self, QueryError> {
206 self.try_map_intent(|intent| intent.push_group_field_with_schema(field.as_ref(), schema))
207 }
208
209 #[must_use]
210 pub(in crate::db) fn aggregate(mut self, aggregate: AggregateExpr) -> Self {
211 self.intent = self.intent.push_group_aggregate(aggregate);
212 self
213 }
214
215 #[must_use]
216 fn grouped_limits(mut self, max_groups: u64, max_group_bytes: u64) -> Self {
217 self.intent = self.intent.grouped_limits(max_groups, max_group_bytes);
218 self
219 }
220
221 pub(in crate::db) fn having_group(
222 self,
223 field: impl AsRef<str>,
224 op: CompareOp,
225 value: Value,
226 ) -> Result<Self, QueryError> {
227 let field = field.as_ref().to_owned();
228 self.try_map_intent(|intent| intent.push_having_group_clause(&field, op, value))
229 }
230
231 pub(in crate::db) fn having_group_with_schema(
232 self,
233 field: impl AsRef<str>,
234 schema: &SchemaInfo,
235 op: CompareOp,
236 value: Value,
237 ) -> Result<Self, QueryError> {
238 let field = field.as_ref().to_owned();
239 self.try_map_intent(|intent| {
240 intent.push_having_group_clause_with_schema(&field, schema, op, value)
241 })
242 }
243
244 pub(in crate::db) fn having_aggregate(
245 self,
246 aggregate_index: usize,
247 op: CompareOp,
248 value: Value,
249 ) -> Result<Self, QueryError> {
250 self.try_map_intent(|intent| {
251 intent.push_having_aggregate_clause(aggregate_index, op, value)
252 })
253 }
254
255 #[cfg(test)]
256 pub(in crate::db) fn having_expr(self, expr: Expr) -> Result<Self, QueryError> {
257 self.try_map_intent(|intent| intent.push_having_expr(expr))
258 }
259
260 pub(in crate::db) fn having_expr_preserving_shape(
261 self,
262 expr: Expr,
263 ) -> Result<Self, QueryError> {
264 self.try_map_intent(|intent| intent.push_having_expr_preserving_shape(expr))
265 }
266
267 #[must_use]
268 fn by_id(self, id: Value) -> Self {
269 self.map_intent(|intent| intent.by_id(id))
270 }
271
272 #[must_use]
273 fn by_ids<I>(self, ids: I) -> Self
274 where
275 I: IntoIterator<Item = Value>,
276 {
277 self.map_intent(|intent| intent.by_ids(ids))
278 }
279
280 #[must_use]
281 fn only(self, id: Value) -> Self {
282 self.map_intent(|intent| intent.only(id))
283 }
284
285 #[must_use]
286 pub(in crate::db) fn delete(mut self) -> Self {
287 self.intent = self.intent.delete();
288 self
289 }
290
291 #[must_use]
292 pub(in crate::db) fn limit(mut self, limit: u32) -> Self {
293 self.intent = self.intent.limit(limit);
294 self
295 }
296
297 #[must_use]
298 pub(in crate::db) fn offset(mut self, offset: u32) -> Self {
299 self.intent = self.intent.offset(offset);
300 self
301 }
302
303 pub(in crate::db) fn build_plan(&self) -> Result<AccessPlannedQuery, QueryError> {
304 let mut plan = self.intent.build_plan_model()?;
305 self.validate_access_requirements_for_visibility(&mut plan, None)?;
306
307 Ok(plan)
308 }
309
310 pub(in crate::db) fn build_plan_with_visible_indexes(
311 &self,
312 visible_indexes: &VisibleIndexes<'_>,
313 ) -> Result<AccessPlannedQuery, QueryError> {
314 let mut plan = self.intent.build_plan_model_with_indexes(visible_indexes)?;
315 self.validate_access_requirements_for_visibility(&mut plan, Some(visible_indexes))?;
316
317 Ok(plan)
318 }
319
320 pub(in crate::db) fn prepare_scalar_planning_state_with_schema_info(
321 &self,
322 schema_info: SchemaInfo,
323 ) -> Result<PreparedScalarPlanningState<'_>, QueryError> {
324 self.intent
325 .prepare_scalar_planning_state_with_schema_info(schema_info)
326 }
327
328 pub(in crate::db) fn build_plan_with_visible_indexes_from_scalar_planning_state(
329 &self,
330 visible_indexes: &VisibleIndexes<'_>,
331 planning_state: PreparedScalarPlanningState<'_>,
332 ) -> Result<AccessPlannedQuery, QueryError> {
333 let mut plan = self
334 .intent
335 .build_plan_model_with_indexes_from_scalar_planning_state(
336 visible_indexes,
337 planning_state,
338 )?;
339 self.validate_access_requirements_for_visibility(&mut plan, Some(visible_indexes))?;
340
341 Ok(plan)
342 }
343
344 pub(in crate::db) fn try_build_trivial_scalar_load_plan_with_schema_info(
345 &self,
346 schema_info: SchemaInfo,
347 ) -> Result<Option<AccessPlannedQuery>, QueryError> {
348 let mut plan = self
349 .intent
350 .try_build_trivial_scalar_load_plan_with_schema_info(schema_info)?;
351 if let Some(plan) = &mut plan {
352 self.validate_access_requirements_for_visibility(plan, None)?;
353 }
354
355 Ok(plan)
356 }
357
358 #[must_use]
359 pub(in crate::db) fn trivial_scalar_load_fast_path_eligible(&self) -> bool {
360 self.intent.trivial_scalar_load_fast_path_eligible()
361 }
362
363 #[must_use]
364 #[cfg(test)]
365 pub(in crate::db) fn structural_cache_key(
366 &self,
367 ) -> crate::db::query::intent::StructuralQueryCacheKey {
368 crate::db::query::intent::StructuralQueryCacheKey::from_query_model(&self.intent)
369 }
370
371 #[must_use]
372 pub(in crate::db) fn structural_cache_key_with_normalized_predicate_fingerprint(
373 &self,
374 predicate_fingerprint: Option<[u8; 32]>,
375 ) -> crate::db::query::intent::StructuralQueryCacheKey {
376 self.intent
377 .structural_cache_key_with_normalized_predicate_fingerprint(predicate_fingerprint)
378 }
379
380 fn build_plan_for_visibility(
383 &self,
384 visible_indexes: Option<&VisibleIndexes<'_>>,
385 ) -> Result<AccessPlannedQuery, QueryError> {
386 match visible_indexes {
387 Some(visible_indexes) => self.build_plan_with_visible_indexes(visible_indexes),
388 None => self.build_plan(),
389 }
390 }
391
392 fn finalize_access_choice_for_visibility(
393 &self,
394 plan: &mut AccessPlannedQuery,
395 visible_indexes: Option<&VisibleIndexes<'_>>,
396 ) {
397 match visible_indexes {
398 Some(visible_indexes) => {
399 if let Some(schema_info) = visible_indexes.accepted_schema_info() {
400 plan.finalize_access_choice_for_model_with_accepted_indexes_and_schema(
401 self.intent.model(),
402 visible_indexes.accepted_field_path_indexes(),
403 visible_indexes.accepted_expression_indexes(),
404 schema_info,
405 );
406 } else {
407 plan.finalize_access_choice_for_model_only_with_indexes(
408 self.intent.model(),
409 visible_indexes.generated_model_only_indexes(),
410 );
411 }
412 }
413 None => {
414 plan.finalize_access_choice_for_model_only_with_indexes(
415 self.intent.model(),
416 self.intent.model().indexes(),
417 );
418 }
419 }
420 }
421
422 fn validate_access_requirements_for_visibility(
423 &self,
424 plan: &mut AccessPlannedQuery,
425 visible_indexes: Option<&VisibleIndexes<'_>>,
426 ) -> Result<(), QueryError> {
427 if self.access_requirements.is_empty() {
428 return Ok(());
429 }
430
431 self.finalize_access_choice_for_visibility(plan, visible_indexes);
432 self.access_requirements.validate(plan)
433 }
434
435 const fn require_index(mut self) -> Self {
436 self.access_requirements.require_index();
437 self
438 }
439
440 fn require_index_named(mut self, index_name: impl Into<String>) -> Self {
441 self.access_requirements.require_index_named(index_name);
442 self
443 }
444
445 const fn require_access_path(mut self, path: RequiredAccessPath) -> Self {
446 self.access_requirements.require_access_path(path);
447 self
448 }
449
450 const fn require_no_residual_filter(mut self) -> Self {
451 self.access_requirements.require_no_residual_filter();
452 self
453 }
454
455 #[must_use]
456 pub(in crate::db) const fn model(&self) -> &'static crate::model::entity::EntityModel {
457 self.intent.model()
458 }
459}
460
461#[derive(Clone, Debug)]
470struct QueryPlanHandle {
471 plan: Box<AccessPlannedQuery>,
472}
473
474impl QueryPlanHandle {
475 #[must_use]
476 fn from_plan(plan: AccessPlannedQuery) -> Self {
477 Self {
478 plan: Box::new(plan),
479 }
480 }
481
482 #[must_use]
483 const fn logical_plan(&self) -> &AccessPlannedQuery {
484 &self.plan
485 }
486
487 #[must_use]
488 #[cfg(test)]
489 fn into_inner(self) -> AccessPlannedQuery {
490 *self.plan
491 }
492}
493
494#[derive(Debug)]
502pub struct PlannedQuery<E: EntityKind> {
503 plan: QueryPlanHandle,
504 _marker: PhantomData<E>,
505}
506
507impl<E: EntityKind> PlannedQuery<E> {
508 #[must_use]
509 pub(in crate::db) fn from_plan(plan: AccessPlannedQuery) -> Self {
510 Self {
511 plan: QueryPlanHandle::from_plan(plan),
512 _marker: PhantomData,
513 }
514 }
515
516 #[must_use]
517 pub fn explain(&self) -> ExplainPlan {
518 self.plan.logical_plan().explain()
519 }
520
521 #[must_use]
523 pub fn plan_hash_hex(&self) -> String {
524 self.plan.logical_plan().fingerprint().to_string()
525 }
526}
527
528#[derive(Clone, Debug)]
538pub struct CompiledQuery<E: EntityKind> {
539 plan: QueryPlanHandle,
540 _marker: PhantomData<E>,
541}
542
543impl<E: EntityKind> CompiledQuery<E> {
544 #[must_use]
545 pub(in crate::db) fn from_plan(plan: AccessPlannedQuery) -> Self {
546 Self {
547 plan: QueryPlanHandle::from_plan(plan),
548 _marker: PhantomData,
549 }
550 }
551
552 #[must_use]
553 pub fn explain(&self) -> ExplainPlan {
554 self.plan.logical_plan().explain()
555 }
556
557 #[must_use]
559 pub fn plan_hash_hex(&self) -> String {
560 self.plan.logical_plan().fingerprint().to_string()
561 }
562
563 #[must_use]
564 #[cfg(test)]
565 pub(in crate::db) fn projection_spec(&self) -> crate::db::query::plan::expr::ProjectionSpec {
566 self.plan.logical_plan().projection_spec(E::MODEL)
567 }
568
569 #[cfg(test)]
571 pub(in crate::db) fn into_plan(self) -> AccessPlannedQuery {
572 self.plan.into_inner()
573 }
574
575 #[must_use]
576 #[cfg(test)]
577 pub(in crate::db) fn into_inner(self) -> AccessPlannedQuery {
578 self.plan.into_inner()
579 }
580}
581
582#[derive(Debug)]
594pub struct Query<E: EntityKind> {
595 inner: StructuralQuery,
596 _marker: PhantomData<E>,
597}
598
599impl<E: EntityKind> Query<E> {
600 pub(in crate::db) const fn from_inner(inner: StructuralQuery) -> Self {
602 Self {
603 inner,
604 _marker: PhantomData,
605 }
606 }
607
608 #[must_use]
612 pub const fn new(consistency: MissingRowPolicy) -> Self {
613 Self::from_inner(StructuralQuery::new(E::MODEL, consistency))
614 }
615
616 #[must_use]
618 pub const fn mode(&self) -> QueryMode {
619 self.inner.mode()
620 }
621
622 #[cfg(test)]
623 pub(in crate::db) fn explain_with_visible_indexes(
624 &self,
625 visible_indexes: &VisibleIndexes<'_>,
626 ) -> Result<ExplainPlan, QueryError> {
627 let mut plan = self.build_plan_for_visibility(Some(visible_indexes))?;
628 self.inner
629 .finalize_access_choice_for_visibility(&mut plan, Some(visible_indexes));
630
631 Ok(plan.explain())
632 }
633
634 #[cfg(test)]
635 pub(in crate::db) fn plan_hash_hex_with_visible_indexes(
636 &self,
637 visible_indexes: &VisibleIndexes<'_>,
638 ) -> Result<String, QueryError> {
639 let plan = self.build_plan_for_visibility(Some(visible_indexes))?;
640
641 Ok(plan.fingerprint().to_string())
642 }
643
644 fn build_plan_for_visibility(
647 &self,
648 visible_indexes: Option<&VisibleIndexes<'_>>,
649 ) -> Result<AccessPlannedQuery, QueryError> {
650 self.inner.build_plan_for_visibility(visible_indexes)
651 }
652
653 fn map_plan_for_visibility<T>(
657 &self,
658 visible_indexes: Option<&VisibleIndexes<'_>>,
659 map: impl FnOnce(AccessPlannedQuery) -> T,
660 ) -> Result<T, QueryError> {
661 let plan = self.build_plan_for_visibility(visible_indexes)?;
662
663 Ok(map(plan))
664 }
665
666 pub(in crate::db) fn planned_query_from_plan(plan: AccessPlannedQuery) -> PlannedQuery<E> {
668 PlannedQuery::from_plan(plan)
669 }
670
671 pub(in crate::db) fn compiled_query_from_plan(plan: AccessPlannedQuery) -> CompiledQuery<E> {
673 CompiledQuery::from_plan(plan)
674 }
675
676 #[must_use]
677 pub(in crate::db::query) fn has_explicit_order(&self) -> bool {
678 self.inner.has_explicit_order()
679 }
680
681 #[must_use]
682 pub(in crate::db) const fn structural(&self) -> &StructuralQuery {
683 &self.inner
684 }
685
686 #[must_use]
687 pub const fn has_grouping(&self) -> bool {
688 self.inner.has_grouping()
689 }
690
691 #[must_use]
692 pub(in crate::db::query) const fn load_spec(&self) -> Option<LoadSpec> {
693 self.inner.load_spec()
694 }
695
696 #[must_use]
698 pub fn filter(mut self, expr: impl Into<FilterExpr>) -> Self {
699 self.inner = self.inner.filter(expr);
700 self
701 }
702
703 #[cfg(test)]
707 #[must_use]
708 pub(in crate::db) fn filter_expr(mut self, expr: Expr) -> Self {
709 self.inner = self.inner.filter_expr(expr);
710 self
711 }
712
713 #[cfg(test)]
717 #[must_use]
718 pub(in crate::db) fn filter_predicate(mut self, predicate: Predicate) -> Self {
719 self.inner = self.inner.filter_predicate(predicate);
720 self
721 }
722
723 #[must_use]
725 pub fn order_term(mut self, term: FluentOrderTerm) -> Self {
726 self.inner = self.inner.order_term(term);
727 self
728 }
729
730 #[must_use]
732 pub fn order_terms<I>(mut self, terms: I) -> Self
733 where
734 I: IntoIterator<Item = FluentOrderTerm>,
735 {
736 for term in terms {
737 self.inner = self.inner.order_term(term);
738 }
739
740 self
741 }
742
743 #[must_use]
745 pub fn distinct(mut self) -> Self {
746 self.inner = self.inner.distinct();
747 self
748 }
749
750 #[cfg(all(test, feature = "sql"))]
753 #[must_use]
754 pub(in crate::db) fn select_fields<I, S>(mut self, fields: I) -> Self
755 where
756 I: IntoIterator<Item = S>,
757 S: Into<String>,
758 {
759 self.inner = self.inner.select_fields(fields);
760 self
761 }
762
763 pub fn group_by(self, field: impl AsRef<str>) -> Result<Self, QueryError> {
765 let Self { inner, .. } = self;
766 let inner = inner.group_by(field)?;
767
768 Ok(Self::from_inner(inner))
769 }
770
771 pub(in crate::db) fn group_by_with_schema(
772 self,
773 field: impl AsRef<str>,
774 schema: &SchemaInfo,
775 ) -> Result<Self, QueryError> {
776 let Self { inner, .. } = self;
777 let inner = inner.group_by_with_schema(field, schema)?;
778
779 Ok(Self::from_inner(inner))
780 }
781
782 #[must_use]
784 pub fn aggregate(mut self, aggregate: AggregateExpr) -> Self {
785 self.inner = self.inner.aggregate(aggregate);
786 self
787 }
788
789 #[must_use]
791 pub fn grouped_limits(mut self, max_groups: u64, max_group_bytes: u64) -> Self {
792 self.inner = self.inner.grouped_limits(max_groups, max_group_bytes);
793 self
794 }
795
796 pub fn having_group(
798 self,
799 field: impl AsRef<str>,
800 op: CompareOp,
801 value: InputValue,
802 ) -> Result<Self, QueryError> {
803 let Self { inner, .. } = self;
804 let inner = inner.having_group(field, op, value.into())?;
805
806 Ok(Self::from_inner(inner))
807 }
808
809 pub(in crate::db) fn having_group_with_schema(
810 self,
811 field: impl AsRef<str>,
812 schema: &SchemaInfo,
813 op: CompareOp,
814 value: InputValue,
815 ) -> Result<Self, QueryError> {
816 let Self { inner, .. } = self;
817 let inner = inner.having_group_with_schema(field, schema, op, value.into())?;
818
819 Ok(Self::from_inner(inner))
820 }
821
822 pub fn having_aggregate(
824 self,
825 aggregate_index: usize,
826 op: CompareOp,
827 value: InputValue,
828 ) -> Result<Self, QueryError> {
829 let Self { inner, .. } = self;
830 let inner = inner.having_aggregate(aggregate_index, op, value.into())?;
831
832 Ok(Self::from_inner(inner))
833 }
834
835 #[cfg(test)]
839 pub(in crate::db) fn having_expr(self, expr: Expr) -> Result<Self, QueryError> {
840 let Self { inner, .. } = self;
841 let inner = inner.having_expr(expr)?;
842
843 Ok(Self::from_inner(inner))
844 }
845
846 pub(in crate::db) fn by_id(self, id: E::Key) -> Self {
848 let Self { inner, .. } = self;
849
850 Self::from_inner(inner.by_id(id.to_key_value()))
851 }
852
853 pub(in crate::db) fn by_ids<I>(self, ids: I) -> Self
855 where
856 I: IntoIterator<Item = E::Key>,
857 {
858 let Self { inner, .. } = self;
859
860 Self::from_inner(inner.by_ids(ids.into_iter().map(|id| id.to_key_value())))
861 }
862
863 #[must_use]
865 pub fn delete(mut self) -> Self {
866 self.inner = self.inner.delete();
867 self
868 }
869
870 #[must_use]
877 pub fn limit(mut self, limit: u32) -> Self {
878 self.inner = self.inner.limit(limit);
879 self
880 }
881
882 #[must_use]
888 pub fn offset(mut self, offset: u32) -> Self {
889 self.inner = self.inner.offset(offset);
890 self
891 }
892
893 #[must_use]
898 pub fn require_index(mut self) -> Self {
899 self.inner = self.inner.require_index();
900 self
901 }
902
903 #[must_use]
908 pub fn require_index_named(mut self, index_name: impl Into<String>) -> Self {
909 self.inner = self.inner.require_index_named(index_name);
910 self
911 }
912
913 #[must_use]
917 pub fn require_access_path(mut self, path: RequiredAccessPath) -> Self {
918 self.inner = self.inner.require_access_path(path);
919 self
920 }
921
922 #[must_use]
927 pub fn require_no_residual_filter(mut self) -> Self {
928 self.inner = self.inner.require_no_residual_filter();
929 self
930 }
931
932 pub fn explain(&self) -> Result<ExplainPlan, QueryError> {
934 let mut plan = self.build_plan_for_visibility(None)?;
935 self.inner
936 .finalize_access_choice_for_visibility(&mut plan, None);
937
938 Ok(plan.explain())
939 }
940
941 pub fn plan_hash_hex(&self) -> Result<String, QueryError> {
946 let plan = self.inner.build_plan()?;
947
948 Ok(plan.fingerprint().to_string())
949 }
950
951 pub fn planned(&self) -> Result<PlannedQuery<E>, QueryError> {
953 self.map_plan_for_visibility(None, Self::planned_query_from_plan)
954 }
955
956 pub fn plan(&self) -> Result<CompiledQuery<E>, QueryError> {
960 self.map_plan_for_visibility(None, Self::compiled_query_from_plan)
961 }
962
963 #[cfg(test)]
964 pub(in crate::db) fn plan_with_visible_indexes(
965 &self,
966 visible_indexes: &VisibleIndexes<'_>,
967 ) -> Result<CompiledQuery<E>, QueryError> {
968 self.map_plan_for_visibility(Some(visible_indexes), Self::compiled_query_from_plan)
969 }
970}
971
972impl<E> Query<E>
973where
974 E: EntityKind + SingletonEntity,
975 E::Key: Default,
976{
977 pub(in crate::db) fn only(self) -> Self {
979 let Self { inner, .. } = self;
980
981 Self::from_inner(inner.only(E::Key::default().to_key_value()))
982 }
983}