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_intent_and_access_requirements(
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_intent_and_access_requirements(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)
94 .map(|intent| Self::from_intent_and_access_requirements(intent, access_requirements))
95 }
96
97 #[must_use]
98 const fn mode(&self) -> QueryMode {
99 self.intent.mode()
100 }
101
102 #[must_use]
103 fn has_explicit_order(&self) -> bool {
104 self.intent.has_explicit_order()
105 }
106
107 #[must_use]
108 pub(in crate::db) const fn has_grouping(&self) -> bool {
109 self.intent.has_grouping()
110 }
111
112 #[must_use]
113 const fn load_spec(&self) -> Option<LoadSpec> {
114 match self.intent.mode() {
115 QueryMode::Load(spec) => Some(spec),
116 QueryMode::Delete(_) => None,
117 }
118 }
119
120 #[must_use]
121 pub(in crate::db) fn filter_predicate(mut self, predicate: Predicate) -> Self {
122 self.intent = self.intent.filter_predicate(predicate);
123 self
124 }
125
126 #[must_use]
127 pub(in crate::db) fn filter(mut self, expr: impl Into<FilterExpr>) -> Self {
128 self.intent = self.intent.filter(expr.into());
129 self
130 }
131
132 #[must_use]
133 pub(in crate::db) fn filter_expr_with_normalized_predicate(
134 mut self,
135 expr: Expr,
136 predicate: Predicate,
137 ) -> Self {
138 self.intent = self
139 .intent
140 .filter_expr_with_normalized_predicate(expr, predicate);
141 self
142 }
143 pub(in crate::db) fn order_term(mut self, term: FluentOrderTerm) -> Self {
144 self.intent = self.intent.order_term(term);
145 self
146 }
147
148 #[must_use]
152 pub(in crate::db) fn filter_expr(mut self, expr: Expr) -> Self {
153 self.intent = self.intent.filter_expr(expr);
154 self
155 }
156
157 #[must_use]
158 pub(in crate::db) fn order_spec(mut self, order: OrderSpec) -> Self {
159 self.intent = self.intent.order_spec(order);
160 self
161 }
162
163 #[must_use]
164 pub(in crate::db) fn distinct(mut self) -> Self {
165 self.intent = self.intent.distinct();
166 self
167 }
168
169 #[cfg(feature = "sql")]
170 #[must_use]
171 pub(in crate::db) fn select_fields<I, S>(mut self, fields: I) -> Self
172 where
173 I: IntoIterator<Item = S>,
174 S: Into<String>,
175 {
176 self.intent = self.intent.select_fields(fields);
177 self
178 }
179
180 #[cfg(feature = "sql")]
181 #[must_use]
182 pub(in crate::db) fn projection_selection(mut self, selection: ProjectionSelection) -> Self {
183 self.intent = self.intent.projection_selection(selection);
184 self
185 }
186
187 pub(in crate::db) fn group_by(self, field: impl AsRef<str>) -> Result<Self, QueryError> {
188 self.try_map_intent(|intent| intent.push_group_field(field.as_ref()))
189 }
190
191 pub(in crate::db) fn group_by_with_schema(
192 self,
193 field: impl AsRef<str>,
194 schema: &SchemaInfo,
195 ) -> Result<Self, QueryError> {
196 self.try_map_intent(|intent| intent.push_group_field_with_schema(field.as_ref(), schema))
197 }
198
199 #[must_use]
200 pub(in crate::db) fn aggregate(mut self, aggregate: AggregateExpr) -> Self {
201 self.intent = self.intent.push_group_aggregate(aggregate);
202 self
203 }
204
205 #[must_use]
206 fn grouped_limits(mut self, max_groups: u64, max_group_bytes: u64) -> Self {
207 self.intent = self.intent.grouped_limits(max_groups, max_group_bytes);
208 self
209 }
210
211 pub(in crate::db) fn having_group(
212 self,
213 field: impl AsRef<str>,
214 op: CompareOp,
215 value: Value,
216 ) -> Result<Self, QueryError> {
217 let field = field.as_ref().to_owned();
218 self.try_map_intent(|intent| intent.push_having_group_clause(&field, op, value))
219 }
220
221 pub(in crate::db) fn having_group_with_schema(
222 self,
223 field: impl AsRef<str>,
224 schema: &SchemaInfo,
225 op: CompareOp,
226 value: Value,
227 ) -> Result<Self, QueryError> {
228 let field = field.as_ref().to_owned();
229 self.try_map_intent(|intent| {
230 intent.push_having_group_clause_with_schema(&field, schema, op, value)
231 })
232 }
233
234 pub(in crate::db) fn having_aggregate(
235 self,
236 aggregate_index: usize,
237 op: CompareOp,
238 value: Value,
239 ) -> Result<Self, QueryError> {
240 self.try_map_intent(|intent| {
241 intent.push_having_aggregate_clause(aggregate_index, op, value)
242 })
243 }
244
245 #[cfg(test)]
246 pub(in crate::db) fn having_expr(self, expr: Expr) -> Result<Self, QueryError> {
247 self.try_map_intent(|intent| intent.push_having_expr(expr))
248 }
249
250 pub(in crate::db) fn having_expr_preserving_shape(
251 self,
252 expr: Expr,
253 ) -> Result<Self, QueryError> {
254 self.try_map_intent(|intent| intent.push_having_expr_preserving_shape(expr))
255 }
256
257 #[must_use]
258 fn by_id(self, id: Value) -> Self {
259 self.map_intent(|intent| intent.by_id(id))
260 }
261
262 #[must_use]
263 fn by_ids<I>(self, ids: I) -> Self
264 where
265 I: IntoIterator<Item = Value>,
266 {
267 self.map_intent(|intent| intent.by_ids(ids))
268 }
269
270 #[must_use]
271 fn only(self, id: Value) -> Self {
272 self.map_intent(|intent| intent.only(id))
273 }
274
275 #[must_use]
276 pub(in crate::db) fn delete(mut self) -> Self {
277 self.intent = self.intent.delete();
278 self
279 }
280
281 #[must_use]
282 pub(in crate::db) fn limit(mut self, limit: u32) -> Self {
283 self.intent = self.intent.limit(limit);
284 self
285 }
286
287 #[must_use]
288 pub(in crate::db) fn offset(mut self, offset: u32) -> Self {
289 self.intent = self.intent.offset(offset);
290 self
291 }
292
293 pub(in crate::db) fn build_plan(&self) -> Result<AccessPlannedQuery, QueryError> {
294 let mut plan = self.intent.build_plan_model()?;
295 self.validate_access_requirements_for_visibility(&mut plan, None)?;
296
297 Ok(plan)
298 }
299
300 pub(in crate::db) fn build_plan_with_visible_indexes(
301 &self,
302 visible_indexes: &VisibleIndexes<'_>,
303 ) -> Result<AccessPlannedQuery, QueryError> {
304 let mut plan = self.intent.build_plan_model_with_indexes(visible_indexes)?;
305 self.validate_access_requirements_for_visibility(&mut plan, Some(visible_indexes))?;
306
307 Ok(plan)
308 }
309
310 pub(in crate::db) fn prepare_scalar_planning_state_with_schema_info(
311 &self,
312 schema_info: SchemaInfo,
313 ) -> Result<PreparedScalarPlanningState<'_>, QueryError> {
314 self.intent
315 .prepare_scalar_planning_state_with_schema_info(schema_info)
316 }
317
318 pub(in crate::db) fn build_plan_with_visible_indexes_from_scalar_planning_state(
319 &self,
320 visible_indexes: &VisibleIndexes<'_>,
321 planning_state: PreparedScalarPlanningState<'_>,
322 ) -> Result<AccessPlannedQuery, QueryError> {
323 let mut plan = self
324 .intent
325 .build_plan_model_with_indexes_from_scalar_planning_state(
326 visible_indexes,
327 planning_state,
328 )?;
329 self.validate_access_requirements_for_visibility(&mut plan, Some(visible_indexes))?;
330
331 Ok(plan)
332 }
333
334 pub(in crate::db) fn try_build_trivial_scalar_load_plan_with_schema_info(
335 &self,
336 schema_info: SchemaInfo,
337 ) -> Result<Option<AccessPlannedQuery>, QueryError> {
338 let mut plan = self
339 .intent
340 .try_build_trivial_scalar_load_plan_with_schema_info(schema_info)?;
341 if let Some(plan) = &mut plan {
342 self.validate_access_requirements_for_visibility(plan, None)?;
343 }
344
345 Ok(plan)
346 }
347
348 #[must_use]
349 pub(in crate::db) fn trivial_scalar_load_fast_path_eligible_with_schema(
350 &self,
351 schema_info: &SchemaInfo,
352 ) -> bool {
353 self.intent
354 .trivial_scalar_load_fast_path_eligible_with_schema(schema_info)
355 }
356
357 #[must_use]
358 #[cfg(test)]
359 pub(in crate::db) fn structural_cache_key(
360 &self,
361 ) -> crate::db::query::intent::StructuralQueryCacheKey {
362 crate::db::query::intent::StructuralQueryCacheKey::from_query_model(&self.intent)
363 }
364
365 #[must_use]
366 pub(in crate::db) fn structural_cache_key_with_normalized_predicate_fingerprint(
367 &self,
368 predicate_fingerprint: Option<[u8; 32]>,
369 ) -> crate::db::query::intent::StructuralQueryCacheKey {
370 self.intent
371 .structural_cache_key_with_normalized_predicate_fingerprint(predicate_fingerprint)
372 }
373
374 fn build_plan_for_visibility(
377 &self,
378 visible_indexes: Option<&VisibleIndexes<'_>>,
379 ) -> Result<AccessPlannedQuery, QueryError> {
380 match visible_indexes {
381 Some(visible_indexes) => self.build_plan_with_visible_indexes(visible_indexes),
382 None => self.build_plan(),
383 }
384 }
385
386 fn finalize_access_choice_for_visibility(
387 &self,
388 plan: &mut AccessPlannedQuery,
389 visible_indexes: Option<&VisibleIndexes<'_>>,
390 ) {
391 match visible_indexes {
392 Some(visible_indexes) => {
393 if let Some(schema_info) = visible_indexes.accepted_schema_info() {
394 plan.finalize_access_choice_for_model_with_accepted_indexes_and_schema(
395 self.intent.model(),
396 visible_indexes.accepted_field_path_indexes(),
397 visible_indexes.accepted_expression_indexes(),
398 schema_info,
399 );
400 } else {
401 plan.finalize_access_choice_for_model_only_with_indexes(
402 self.intent.model(),
403 visible_indexes.generated_model_only_indexes(),
404 );
405 }
406 }
407 None => {
408 plan.finalize_access_choice_for_model_only_with_indexes(
409 self.intent.model(),
410 self.intent.model().indexes(),
411 );
412 }
413 }
414 }
415
416 fn validate_access_requirements_for_visibility(
417 &self,
418 plan: &mut AccessPlannedQuery,
419 visible_indexes: Option<&VisibleIndexes<'_>>,
420 ) -> Result<(), QueryError> {
421 if self.access_requirements.is_empty() {
422 return Ok(());
423 }
424
425 self.finalize_access_choice_for_visibility(plan, visible_indexes);
426 self.access_requirements.validate(plan)
427 }
428
429 const fn require_index(mut self) -> Self {
430 self.access_requirements.require_index();
431 self
432 }
433
434 fn require_index_named(mut self, index_name: impl Into<String>) -> Self {
435 self.access_requirements.require_index_named(index_name);
436 self
437 }
438
439 const fn require_access_path(mut self, path: RequiredAccessPath) -> Self {
440 self.access_requirements.require_access_path(path);
441 self
442 }
443
444 const fn require_no_residual_filter(mut self) -> Self {
445 self.access_requirements.require_no_residual_filter();
446 self
447 }
448
449 #[must_use]
450 pub(in crate::db) const fn model(&self) -> &'static crate::model::entity::EntityModel {
451 self.intent.model()
452 }
453}
454
455#[derive(Clone, Debug)]
464struct QueryPlanHandle {
465 plan: Box<AccessPlannedQuery>,
466}
467
468impl QueryPlanHandle {
469 #[must_use]
470 fn from_plan(plan: AccessPlannedQuery) -> Self {
471 Self {
472 plan: Box::new(plan),
473 }
474 }
475
476 #[must_use]
477 const fn logical_plan(&self) -> &AccessPlannedQuery {
478 &self.plan
479 }
480
481 #[must_use]
482 #[cfg(test)]
483 fn into_inner(self) -> AccessPlannedQuery {
484 *self.plan
485 }
486}
487
488#[derive(Debug)]
496pub struct PlannedQuery<E: EntityKind> {
497 plan: QueryPlanHandle,
498 _marker: PhantomData<E>,
499}
500
501impl<E: EntityKind> PlannedQuery<E> {
502 #[must_use]
503 pub(in crate::db) fn from_plan(plan: AccessPlannedQuery) -> Self {
504 Self {
505 plan: QueryPlanHandle::from_plan(plan),
506 _marker: PhantomData,
507 }
508 }
509
510 #[must_use]
511 pub fn explain(&self) -> ExplainPlan {
512 self.plan.logical_plan().explain()
513 }
514
515 #[must_use]
517 pub fn plan_hash_hex(&self) -> String {
518 self.plan.logical_plan().fingerprint().to_string()
519 }
520}
521
522#[derive(Clone, Debug)]
532pub struct CompiledQuery<E: EntityKind> {
533 plan: QueryPlanHandle,
534 _marker: PhantomData<E>,
535}
536
537impl<E: EntityKind> CompiledQuery<E> {
538 #[must_use]
539 pub(in crate::db) fn from_plan(plan: AccessPlannedQuery) -> Self {
540 Self {
541 plan: QueryPlanHandle::from_plan(plan),
542 _marker: PhantomData,
543 }
544 }
545
546 #[must_use]
547 pub fn explain(&self) -> ExplainPlan {
548 self.plan.logical_plan().explain()
549 }
550
551 #[must_use]
553 pub fn plan_hash_hex(&self) -> String {
554 self.plan.logical_plan().fingerprint().to_string()
555 }
556
557 #[must_use]
558 #[cfg(test)]
559 pub(in crate::db) fn projection_spec(&self) -> crate::db::query::plan::expr::ProjectionSpec {
560 self.plan.logical_plan().projection_spec(E::MODEL)
561 }
562
563 #[cfg(test)]
565 pub(in crate::db) fn into_plan(self) -> AccessPlannedQuery {
566 self.plan.into_inner()
567 }
568
569 #[must_use]
570 #[cfg(test)]
571 pub(in crate::db) fn into_inner(self) -> AccessPlannedQuery {
572 self.plan.into_inner()
573 }
574}
575
576#[derive(Debug)]
588pub struct Query<E: EntityKind> {
589 inner: StructuralQuery,
590 _marker: PhantomData<E>,
591}
592
593impl<E: EntityKind> Query<E> {
594 pub(in crate::db) const fn from_inner(inner: StructuralQuery) -> Self {
596 Self {
597 inner,
598 _marker: PhantomData,
599 }
600 }
601
602 #[must_use]
606 pub const fn new(consistency: MissingRowPolicy) -> Self {
607 Self::from_inner(StructuralQuery::new(E::MODEL, consistency))
608 }
609
610 #[must_use]
612 pub const fn mode(&self) -> QueryMode {
613 self.inner.mode()
614 }
615
616 #[cfg(test)]
617 pub(in crate::db) fn explain_with_visible_indexes(
618 &self,
619 visible_indexes: &VisibleIndexes<'_>,
620 ) -> Result<ExplainPlan, QueryError> {
621 let mut plan = self.build_plan_for_visibility(Some(visible_indexes))?;
622 self.inner
623 .finalize_access_choice_for_visibility(&mut plan, Some(visible_indexes));
624
625 Ok(plan.explain())
626 }
627
628 #[cfg(test)]
629 pub(in crate::db) fn plan_hash_hex_with_visible_indexes(
630 &self,
631 visible_indexes: &VisibleIndexes<'_>,
632 ) -> Result<String, QueryError> {
633 let plan = self.build_plan_for_visibility(Some(visible_indexes))?;
634
635 Ok(plan.fingerprint().to_string())
636 }
637
638 fn build_plan_for_visibility(
641 &self,
642 visible_indexes: Option<&VisibleIndexes<'_>>,
643 ) -> Result<AccessPlannedQuery, QueryError> {
644 self.inner.build_plan_for_visibility(visible_indexes)
645 }
646
647 fn map_plan_for_visibility<T>(
651 &self,
652 visible_indexes: Option<&VisibleIndexes<'_>>,
653 map: impl FnOnce(AccessPlannedQuery) -> T,
654 ) -> Result<T, QueryError> {
655 let plan = self.build_plan_for_visibility(visible_indexes)?;
656
657 Ok(map(plan))
658 }
659
660 pub(in crate::db) fn planned_query_from_plan(plan: AccessPlannedQuery) -> PlannedQuery<E> {
662 PlannedQuery::from_plan(plan)
663 }
664
665 pub(in crate::db) fn compiled_query_from_plan(plan: AccessPlannedQuery) -> CompiledQuery<E> {
667 CompiledQuery::from_plan(plan)
668 }
669
670 #[must_use]
671 pub(in crate::db::query) fn has_explicit_order(&self) -> bool {
672 self.inner.has_explicit_order()
673 }
674
675 #[must_use]
676 pub(in crate::db) const fn structural(&self) -> &StructuralQuery {
677 &self.inner
678 }
679
680 #[must_use]
681 pub const fn has_grouping(&self) -> bool {
682 self.inner.has_grouping()
683 }
684
685 #[must_use]
686 pub(in crate::db::query) const fn load_spec(&self) -> Option<LoadSpec> {
687 self.inner.load_spec()
688 }
689
690 #[must_use]
692 pub fn filter(mut self, expr: impl Into<FilterExpr>) -> Self {
693 self.inner = self.inner.filter(expr);
694 self
695 }
696
697 #[cfg(test)]
701 #[must_use]
702 pub(in crate::db) fn filter_expr(mut self, expr: Expr) -> Self {
703 self.inner = self.inner.filter_expr(expr);
704 self
705 }
706
707 #[cfg(test)]
711 #[must_use]
712 pub(in crate::db) fn filter_predicate(mut self, predicate: Predicate) -> Self {
713 self.inner = self.inner.filter_predicate(predicate);
714 self
715 }
716
717 #[must_use]
719 pub fn order_term(mut self, term: FluentOrderTerm) -> Self {
720 self.inner = self.inner.order_term(term);
721 self
722 }
723
724 #[must_use]
726 pub fn order_terms<I>(mut self, terms: I) -> Self
727 where
728 I: IntoIterator<Item = FluentOrderTerm>,
729 {
730 for term in terms {
731 self.inner = self.inner.order_term(term);
732 }
733
734 self
735 }
736
737 #[must_use]
739 pub fn distinct(mut self) -> Self {
740 self.inner = self.inner.distinct();
741 self
742 }
743
744 #[cfg(all(test, feature = "sql"))]
747 #[must_use]
748 pub(in crate::db) fn select_fields<I, S>(mut self, fields: I) -> Self
749 where
750 I: IntoIterator<Item = S>,
751 S: Into<String>,
752 {
753 self.inner = self.inner.select_fields(fields);
754 self
755 }
756
757 pub fn group_by(self, field: impl AsRef<str>) -> Result<Self, QueryError> {
759 let Self { inner, .. } = self;
760 let inner = inner.group_by(field)?;
761
762 Ok(Self::from_inner(inner))
763 }
764
765 pub(in crate::db) fn group_by_with_schema(
766 self,
767 field: impl AsRef<str>,
768 schema: &SchemaInfo,
769 ) -> Result<Self, QueryError> {
770 let Self { inner, .. } = self;
771 let inner = inner.group_by_with_schema(field, schema)?;
772
773 Ok(Self::from_inner(inner))
774 }
775
776 #[must_use]
778 pub fn aggregate(mut self, aggregate: AggregateExpr) -> Self {
779 self.inner = self.inner.aggregate(aggregate);
780 self
781 }
782
783 #[must_use]
785 pub fn grouped_limits(mut self, max_groups: u64, max_group_bytes: u64) -> Self {
786 self.inner = self.inner.grouped_limits(max_groups, max_group_bytes);
787 self
788 }
789
790 pub fn having_group(
792 self,
793 field: impl AsRef<str>,
794 op: CompareOp,
795 value: InputValue,
796 ) -> Result<Self, QueryError> {
797 let Self { inner, .. } = self;
798 let inner = inner.having_group(field, op, value.into())?;
799
800 Ok(Self::from_inner(inner))
801 }
802
803 pub(in crate::db) fn having_group_with_schema(
804 self,
805 field: impl AsRef<str>,
806 schema: &SchemaInfo,
807 op: CompareOp,
808 value: InputValue,
809 ) -> Result<Self, QueryError> {
810 let Self { inner, .. } = self;
811 let inner = inner.having_group_with_schema(field, schema, op, value.into())?;
812
813 Ok(Self::from_inner(inner))
814 }
815
816 pub fn having_aggregate(
818 self,
819 aggregate_index: usize,
820 op: CompareOp,
821 value: InputValue,
822 ) -> Result<Self, QueryError> {
823 let Self { inner, .. } = self;
824 let inner = inner.having_aggregate(aggregate_index, op, value.into())?;
825
826 Ok(Self::from_inner(inner))
827 }
828
829 #[cfg(test)]
833 pub(in crate::db) fn having_expr(self, expr: Expr) -> Result<Self, QueryError> {
834 let Self { inner, .. } = self;
835 let inner = inner.having_expr(expr)?;
836
837 Ok(Self::from_inner(inner))
838 }
839
840 pub(in crate::db) fn by_id(self, id: E::Key) -> Self {
842 let Self { inner, .. } = self;
843
844 Self::from_inner(inner.by_id(id.to_key_value()))
845 }
846
847 pub(in crate::db) fn by_ids<I>(self, ids: I) -> Self
849 where
850 I: IntoIterator<Item = E::Key>,
851 {
852 let Self { inner, .. } = self;
853
854 Self::from_inner(inner.by_ids(ids.into_iter().map(|id| id.to_key_value())))
855 }
856
857 #[must_use]
859 pub fn delete(mut self) -> Self {
860 self.inner = self.inner.delete();
861 self
862 }
863
864 #[must_use]
871 pub fn limit(mut self, limit: u32) -> Self {
872 self.inner = self.inner.limit(limit);
873 self
874 }
875
876 #[must_use]
882 pub fn offset(mut self, offset: u32) -> Self {
883 self.inner = self.inner.offset(offset);
884 self
885 }
886
887 #[must_use]
892 pub fn require_index(mut self) -> Self {
893 self.inner = self.inner.require_index();
894 self
895 }
896
897 #[must_use]
902 pub fn require_index_named(mut self, index_name: impl Into<String>) -> Self {
903 self.inner = self.inner.require_index_named(index_name);
904 self
905 }
906
907 #[must_use]
911 pub fn require_access_path(mut self, path: RequiredAccessPath) -> Self {
912 self.inner = self.inner.require_access_path(path);
913 self
914 }
915
916 #[must_use]
921 pub fn require_no_residual_filter(mut self) -> Self {
922 self.inner = self.inner.require_no_residual_filter();
923 self
924 }
925
926 pub fn explain(&self) -> Result<ExplainPlan, QueryError> {
928 let mut plan = self.build_plan_for_visibility(None)?;
929 self.inner
930 .finalize_access_choice_for_visibility(&mut plan, None);
931
932 Ok(plan.explain())
933 }
934
935 pub fn plan_hash_hex(&self) -> Result<String, QueryError> {
940 let plan = self.inner.build_plan()?;
941
942 Ok(plan.fingerprint().to_string())
943 }
944
945 pub fn planned(&self) -> Result<PlannedQuery<E>, QueryError> {
947 self.map_plan_for_visibility(None, Self::planned_query_from_plan)
948 }
949
950 pub fn plan(&self) -> Result<CompiledQuery<E>, QueryError> {
954 self.map_plan_for_visibility(None, Self::compiled_query_from_plan)
955 }
956
957 #[cfg(test)]
958 pub(in crate::db) fn plan_with_visible_indexes(
959 &self,
960 visible_indexes: &VisibleIndexes<'_>,
961 ) -> Result<CompiledQuery<E>, QueryError> {
962 self.map_plan_for_visibility(Some(visible_indexes), Self::compiled_query_from_plan)
963 }
964}
965
966impl<E> Query<E>
967where
968 E: EntityKind + SingletonEntity,
969 E::Key: Default,
970{
971 pub(in crate::db) fn only(self) -> Self {
973 let Self { inner, .. } = self;
974
975 Self::from_inner(inner.only(E::Key::default().to_key_value()))
976 }
977}