1#[cfg(feature = "sql")]
7use crate::db::query::plan::expr::ProjectionSelection;
8#[cfg(any(test, feature = "sql"))]
9use crate::db::{
10 predicate::Predicate,
11 query::plan::{OrderSpec, expr::Expr},
12};
13use crate::{
14 db::{
15 predicate::{CompareOp, MissingRowPolicy},
16 query::{
17 builder::AggregateExpr,
18 explain::ExplainPlan,
19 expr::FilterExpr,
20 expr::OrderTerm as FluentOrderTerm,
21 intent::{AccessRequirements, QueryError, QueryModel, RequiredAccessPath},
22 plan::{
23 AccessPlannedQuery, LoadSpec, PreparedScalarPlanningState, QueryMode,
24 VisibleIndexes,
25 },
26 },
27 schema::SchemaInfo,
28 },
29 traits::{EntityKind, KeyValueCodec, SingletonEntity},
30 value::{InputValue, Value},
31};
32use std::sync::OnceLock;
33
34use core::marker::PhantomData;
35
36#[derive(Clone, Debug)]
45pub(in crate::db) struct StructuralQuery {
46 intent: QueryModel<'static, Value>,
47 access_requirements: AccessRequirements,
48 structural_cache_key: OnceLock<crate::db::query::intent::StructuralQueryCacheKey>,
49}
50
51impl StructuralQuery {
52 #[must_use]
53 pub(in crate::db) const fn new(
54 model: &'static crate::model::entity::EntityModel,
55 consistency: MissingRowPolicy,
56 ) -> Self {
57 Self {
58 intent: QueryModel::new(model, consistency),
59 access_requirements: AccessRequirements::new(),
60 structural_cache_key: OnceLock::new(),
61 }
62 }
63
64 const fn from_intent_and_access_requirements(
68 intent: QueryModel<'static, Value>,
69 access_requirements: AccessRequirements,
70 ) -> Self {
71 Self {
72 intent,
73 access_requirements,
74 structural_cache_key: OnceLock::new(),
75 }
76 }
77
78 fn map_intent(
81 self,
82 map: impl FnOnce(QueryModel<'static, Value>) -> QueryModel<'static, Value>,
83 ) -> Self {
84 let Self {
85 intent,
86 access_requirements,
87 ..
88 } = self;
89
90 Self::from_intent_and_access_requirements(map(intent), access_requirements)
91 }
92
93 fn try_map_intent(
96 self,
97 map: impl FnOnce(QueryModel<'static, Value>) -> Result<QueryModel<'static, Value>, QueryError>,
98 ) -> Result<Self, QueryError> {
99 let Self {
100 intent,
101 access_requirements,
102 ..
103 } = self;
104
105 map(intent)
106 .map(|intent| Self::from_intent_and_access_requirements(intent, access_requirements))
107 }
108
109 #[must_use]
110 const fn mode(&self) -> QueryMode {
111 self.intent.mode()
112 }
113
114 #[must_use]
115 fn has_explicit_order(&self) -> bool {
116 self.intent.has_explicit_order()
117 }
118
119 #[must_use]
120 pub(in crate::db) const fn has_grouping(&self) -> bool {
121 self.intent.has_grouping()
122 }
123
124 #[must_use]
125 pub(in crate::db) const fn has_scalar_filter(&self) -> bool {
126 self.intent.has_scalar_filter()
127 }
128
129 #[must_use]
130 const fn load_spec(&self) -> Option<LoadSpec> {
131 match self.intent.mode() {
132 QueryMode::Load(spec) => Some(spec),
133 QueryMode::Delete(_) => None,
134 }
135 }
136
137 #[must_use]
138 #[cfg(any(test, feature = "sql"))]
139 pub(in crate::db) fn filter_predicate(mut self, predicate: Predicate) -> Self {
140 self.intent = self.intent.filter_predicate(predicate);
141 self
142 }
143
144 #[must_use]
145 pub(in crate::db) fn filter(mut self, expr: impl Into<FilterExpr>) -> Self {
146 self.intent = self.intent.filter(expr.into());
147 self
148 }
149
150 #[must_use]
151 #[cfg(feature = "sql")]
152 pub(in crate::db) fn filter_expr_with_normalized_predicate(
153 mut self,
154 expr: Expr,
155 predicate: Predicate,
156 ) -> Self {
157 self.intent = self
158 .intent
159 .filter_expr_with_normalized_predicate(expr, predicate);
160 self
161 }
162 pub(in crate::db) fn order_term(mut self, term: FluentOrderTerm) -> Self {
163 self.intent = self.intent.order_term(term);
164 self
165 }
166
167 #[must_use]
171 #[cfg(feature = "sql")]
172 pub(in crate::db) fn filter_expr(mut self, expr: Expr) -> Self {
173 self.intent = self.intent.filter_expr(expr);
174 self
175 }
176
177 #[must_use]
178 #[cfg(any(test, feature = "sql"))]
179 pub(in crate::db) fn order_spec(mut self, order: OrderSpec) -> Self {
180 self.intent = self.intent.order_spec(order);
181 self
182 }
183
184 #[must_use]
185 pub(in crate::db) fn distinct(mut self) -> Self {
186 self.intent = self.intent.distinct();
187 self
188 }
189
190 #[cfg(feature = "sql")]
191 #[must_use]
192 pub(in crate::db) fn select_fields<I, S>(mut self, fields: I) -> Self
193 where
194 I: IntoIterator<Item = S>,
195 S: Into<String>,
196 {
197 self.intent = self.intent.select_fields(fields);
198 self
199 }
200
201 #[cfg(feature = "sql")]
202 #[must_use]
203 pub(in crate::db) fn projection_selection(mut self, selection: ProjectionSelection) -> Self {
204 self.intent = self.intent.projection_selection(selection);
205 self
206 }
207
208 pub(in crate::db) fn group_by(self, field: impl AsRef<str>) -> Result<Self, QueryError> {
209 self.try_map_intent(|intent| intent.push_group_field(field.as_ref()))
210 }
211
212 pub(in crate::db) fn group_by_with_schema(
213 self,
214 field: impl AsRef<str>,
215 schema: &SchemaInfo,
216 ) -> Result<Self, QueryError> {
217 self.try_map_intent(|intent| intent.push_group_field_with_schema(field.as_ref(), schema))
218 }
219
220 #[must_use]
221 pub(in crate::db) fn aggregate(mut self, aggregate: AggregateExpr) -> Self {
222 self.intent = self.intent.push_group_aggregate(aggregate);
223 self
224 }
225
226 #[must_use]
227 fn grouped_limits(mut self, max_groups: u64, max_group_bytes: u64) -> Self {
228 self.intent = self.intent.grouped_limits(max_groups, max_group_bytes);
229 self
230 }
231
232 pub(in crate::db) fn having_group(
233 self,
234 field: impl AsRef<str>,
235 op: CompareOp,
236 value: Value,
237 ) -> Result<Self, QueryError> {
238 let field = field.as_ref().to_owned();
239 self.try_map_intent(|intent| intent.push_having_group_clause(&field, op, value))
240 }
241
242 pub(in crate::db) fn having_group_with_schema(
243 self,
244 field: impl AsRef<str>,
245 schema: &SchemaInfo,
246 op: CompareOp,
247 value: Value,
248 ) -> Result<Self, QueryError> {
249 let field = field.as_ref().to_owned();
250 self.try_map_intent(|intent| {
251 intent.push_having_group_clause_with_schema(&field, schema, op, value)
252 })
253 }
254
255 pub(in crate::db) fn having_aggregate(
256 self,
257 aggregate_index: usize,
258 op: CompareOp,
259 value: Value,
260 ) -> Result<Self, QueryError> {
261 self.try_map_intent(|intent| {
262 intent.push_having_aggregate_clause(aggregate_index, op, value)
263 })
264 }
265
266 #[cfg(test)]
267 pub(in crate::db) fn having_expr(self, expr: Expr) -> Result<Self, QueryError> {
268 self.try_map_intent(|intent| intent.push_having_expr(expr))
269 }
270
271 #[cfg(feature = "sql")]
272 pub(in crate::db) fn having_expr_preserving_shape(
273 self,
274 expr: Expr,
275 ) -> Result<Self, QueryError> {
276 self.try_map_intent(|intent| intent.push_having_expr_preserving_shape(expr))
277 }
278
279 #[must_use]
280 fn by_id(self, id: Value) -> Self {
281 self.map_intent(|intent| intent.by_id(id))
282 }
283
284 #[must_use]
285 fn by_ids<I>(self, ids: I) -> Self
286 where
287 I: IntoIterator<Item = Value>,
288 {
289 self.map_intent(|intent| intent.by_ids(ids))
290 }
291
292 #[must_use]
293 fn only(self, id: Value) -> Self {
294 self.map_intent(|intent| intent.only(id))
295 }
296
297 #[must_use]
298 pub(in crate::db) fn delete(mut self) -> Self {
299 self.intent = self.intent.delete();
300 self
301 }
302
303 #[must_use]
304 pub(in crate::db) fn limit(mut self, limit: u32) -> Self {
305 self.intent = self.intent.limit(limit);
306 self
307 }
308
309 #[must_use]
310 pub(in crate::db) fn offset(mut self, offset: u32) -> Self {
311 self.intent = self.intent.offset(offset);
312 self
313 }
314
315 pub(in crate::db) fn build_plan(&self) -> Result<AccessPlannedQuery, QueryError> {
316 let mut plan = self.intent.build_plan_model()?;
317 self.validate_access_requirements_for_visibility(&mut plan, None)?;
318
319 Ok(plan)
320 }
321
322 pub(in crate::db) fn build_plan_with_visible_indexes(
323 &self,
324 visible_indexes: &VisibleIndexes<'_>,
325 ) -> Result<AccessPlannedQuery, QueryError> {
326 let mut plan = self.intent.build_plan_model_with_indexes(visible_indexes)?;
327 self.validate_access_requirements_for_visibility(&mut plan, Some(visible_indexes))?;
328
329 Ok(plan)
330 }
331
332 pub(in crate::db) fn prepare_scalar_planning_state_with_schema_info(
333 &self,
334 schema_info: SchemaInfo,
335 ) -> Result<PreparedScalarPlanningState<'_>, QueryError> {
336 self.intent
337 .prepare_scalar_planning_state_with_schema_info(schema_info)
338 }
339
340 pub(in crate::db) fn build_plan_with_visible_indexes_from_scalar_planning_state(
341 &self,
342 visible_indexes: &VisibleIndexes<'_>,
343 planning_state: PreparedScalarPlanningState<'_>,
344 ) -> Result<AccessPlannedQuery, QueryError> {
345 let mut plan = self
346 .intent
347 .build_plan_model_with_indexes_from_scalar_planning_state(
348 visible_indexes,
349 planning_state,
350 )?;
351 self.validate_access_requirements_for_visibility(&mut plan, Some(visible_indexes))?;
352
353 Ok(plan)
354 }
355
356 pub(in crate::db) fn try_build_trivial_scalar_load_plan_with_schema_info(
357 &self,
358 schema_info: SchemaInfo,
359 ) -> Result<Option<AccessPlannedQuery>, QueryError> {
360 let mut plan = self
361 .intent
362 .try_build_trivial_scalar_load_plan_with_schema_info(schema_info)?;
363 if let Some(plan) = &mut plan {
364 self.validate_access_requirements_for_visibility(plan, None)?;
365 }
366
367 Ok(plan)
368 }
369
370 #[must_use]
371 pub(in crate::db) fn trivial_scalar_load_fast_path_eligible_with_schema(
372 &self,
373 schema_info: &SchemaInfo,
374 ) -> bool {
375 self.intent
376 .trivial_scalar_load_fast_path_eligible_with_schema(schema_info)
377 }
378
379 #[must_use]
380 #[cfg(test)]
381 pub(in crate::db) fn structural_cache_key(
382 &self,
383 ) -> crate::db::query::intent::StructuralQueryCacheKey {
384 crate::db::query::intent::StructuralQueryCacheKey::from_query_model(&self.intent)
385 }
386
387 #[must_use]
388 pub(in crate::db) fn structural_cache_key_with_normalized_predicate_fingerprint(
389 &self,
390 predicate_fingerprint: Option<[u8; 32]>,
391 ) -> crate::db::query::intent::StructuralQueryCacheKey {
392 if predicate_fingerprint.is_none() {
393 return self
394 .structural_cache_key
395 .get_or_init(|| {
396 self.intent
397 .structural_cache_key_with_normalized_predicate_fingerprint(None)
398 })
399 .clone();
400 }
401
402 self.intent
403 .structural_cache_key_with_normalized_predicate_fingerprint(predicate_fingerprint)
404 }
405
406 fn build_plan_for_visibility(
409 &self,
410 visible_indexes: Option<&VisibleIndexes<'_>>,
411 ) -> Result<AccessPlannedQuery, QueryError> {
412 match visible_indexes {
413 Some(visible_indexes) => self.build_plan_with_visible_indexes(visible_indexes),
414 None => self.build_plan(),
415 }
416 }
417
418 fn finalize_access_choice_for_visibility(
419 &self,
420 plan: &mut AccessPlannedQuery,
421 visible_indexes: Option<&VisibleIndexes<'_>>,
422 ) {
423 match visible_indexes {
424 Some(visible_indexes) => {
425 if let Some(schema_info) = visible_indexes.accepted_schema_info() {
426 plan.finalize_access_choice_for_model_with_accepted_indexes_and_schema(
427 self.intent.model(),
428 visible_indexes.accepted_field_path_indexes(),
429 visible_indexes.accepted_expression_indexes(),
430 schema_info,
431 );
432 } else {
433 plan.finalize_access_choice_for_model_only_with_indexes(
434 self.intent.model(),
435 visible_indexes.generated_model_only_indexes(),
436 );
437 }
438 }
439 None => {
440 plan.finalize_access_choice_for_model_only_with_indexes(
441 self.intent.model(),
442 self.intent.model().indexes(),
443 );
444 }
445 }
446 }
447
448 fn validate_access_requirements_for_visibility(
449 &self,
450 plan: &mut AccessPlannedQuery,
451 visible_indexes: Option<&VisibleIndexes<'_>>,
452 ) -> Result<(), QueryError> {
453 if self.access_requirements.is_empty() {
454 return Ok(());
455 }
456
457 self.finalize_access_choice_for_visibility(plan, visible_indexes);
458 self.access_requirements.validate(plan)
459 }
460
461 const fn require_index(mut self) -> Self {
462 self.access_requirements.require_index();
463 self
464 }
465
466 fn require_index_named(mut self, index_name: impl Into<String>) -> Self {
467 self.access_requirements.require_index_named(index_name);
468 self
469 }
470
471 const fn require_access_path(mut self, path: RequiredAccessPath) -> Self {
472 self.access_requirements.require_access_path(path);
473 self
474 }
475
476 const fn require_no_residual_filter(mut self) -> Self {
477 self.access_requirements.require_no_residual_filter();
478 self
479 }
480
481 #[must_use]
482 pub(in crate::db) const fn model(&self) -> &'static crate::model::entity::EntityModel {
483 self.intent.model()
484 }
485}
486
487#[derive(Clone, Debug)]
496struct QueryPlanHandle {
497 plan: Box<AccessPlannedQuery>,
498}
499
500impl QueryPlanHandle {
501 #[must_use]
502 fn from_plan(plan: AccessPlannedQuery) -> Self {
503 Self {
504 plan: Box::new(plan),
505 }
506 }
507
508 #[must_use]
509 const fn logical_plan(&self) -> &AccessPlannedQuery {
510 &self.plan
511 }
512
513 #[must_use]
514 #[cfg(test)]
515 fn into_inner(self) -> AccessPlannedQuery {
516 *self.plan
517 }
518}
519
520#[derive(Debug)]
528pub struct PlannedQuery<E: EntityKind> {
529 plan: QueryPlanHandle,
530 _marker: PhantomData<E>,
531}
532
533impl<E: EntityKind> PlannedQuery<E> {
534 #[must_use]
535 pub(in crate::db) fn from_plan(plan: AccessPlannedQuery) -> Self {
536 Self {
537 plan: QueryPlanHandle::from_plan(plan),
538 _marker: PhantomData,
539 }
540 }
541
542 #[must_use]
543 pub fn explain(&self) -> ExplainPlan {
544 self.plan.logical_plan().explain()
545 }
546
547 #[must_use]
549 pub fn plan_hash_hex(&self) -> String {
550 self.plan.logical_plan().fingerprint().to_string()
551 }
552}
553
554#[derive(Clone, Debug)]
564pub struct CompiledQuery<E: EntityKind> {
565 plan: QueryPlanHandle,
566 _marker: PhantomData<E>,
567}
568
569impl<E: EntityKind> CompiledQuery<E> {
570 #[must_use]
571 pub(in crate::db) fn from_plan(plan: AccessPlannedQuery) -> Self {
572 Self {
573 plan: QueryPlanHandle::from_plan(plan),
574 _marker: PhantomData,
575 }
576 }
577
578 #[must_use]
579 pub fn explain(&self) -> ExplainPlan {
580 self.plan.logical_plan().explain()
581 }
582
583 #[must_use]
585 pub fn plan_hash_hex(&self) -> String {
586 self.plan.logical_plan().fingerprint().to_string()
587 }
588
589 #[must_use]
590 #[cfg(test)]
591 pub(in crate::db) fn projection_spec(&self) -> crate::db::query::plan::expr::ProjectionSpec {
592 self.plan.logical_plan().projection_spec(E::MODEL)
593 }
594
595 #[cfg(test)]
597 pub(in crate::db) fn into_plan(self) -> AccessPlannedQuery {
598 self.plan.into_inner()
599 }
600
601 #[must_use]
602 #[cfg(test)]
603 pub(in crate::db) fn into_inner(self) -> AccessPlannedQuery {
604 self.plan.into_inner()
605 }
606}
607
608#[derive(Debug)]
620pub struct Query<E: EntityKind> {
621 inner: StructuralQuery,
622 _marker: PhantomData<E>,
623}
624
625impl<E: EntityKind> Query<E> {
626 pub(in crate::db) const fn from_inner(inner: StructuralQuery) -> Self {
628 Self {
629 inner,
630 _marker: PhantomData,
631 }
632 }
633
634 #[must_use]
638 pub const fn new(consistency: MissingRowPolicy) -> Self {
639 Self::from_inner(StructuralQuery::new(E::MODEL, consistency))
640 }
641
642 #[must_use]
644 pub const fn mode(&self) -> QueryMode {
645 self.inner.mode()
646 }
647
648 #[cfg(test)]
649 pub(in crate::db) fn explain_with_visible_indexes(
650 &self,
651 visible_indexes: &VisibleIndexes<'_>,
652 ) -> Result<ExplainPlan, QueryError> {
653 let mut plan = self.build_plan_for_visibility(Some(visible_indexes))?;
654 self.inner
655 .finalize_access_choice_for_visibility(&mut plan, Some(visible_indexes));
656
657 Ok(plan.explain())
658 }
659
660 #[cfg(test)]
661 pub(in crate::db) fn plan_hash_hex_with_visible_indexes(
662 &self,
663 visible_indexes: &VisibleIndexes<'_>,
664 ) -> Result<String, QueryError> {
665 let plan = self.build_plan_for_visibility(Some(visible_indexes))?;
666
667 Ok(plan.fingerprint().to_string())
668 }
669
670 fn build_plan_for_visibility(
673 &self,
674 visible_indexes: Option<&VisibleIndexes<'_>>,
675 ) -> Result<AccessPlannedQuery, QueryError> {
676 self.inner.build_plan_for_visibility(visible_indexes)
677 }
678
679 fn map_plan_for_visibility<T>(
683 &self,
684 visible_indexes: Option<&VisibleIndexes<'_>>,
685 map: impl FnOnce(AccessPlannedQuery) -> T,
686 ) -> Result<T, QueryError> {
687 let plan = self.build_plan_for_visibility(visible_indexes)?;
688
689 Ok(map(plan))
690 }
691
692 pub(in crate::db) fn planned_query_from_plan(plan: AccessPlannedQuery) -> PlannedQuery<E> {
694 PlannedQuery::from_plan(plan)
695 }
696
697 pub(in crate::db) fn compiled_query_from_plan(plan: AccessPlannedQuery) -> CompiledQuery<E> {
699 CompiledQuery::from_plan(plan)
700 }
701
702 #[must_use]
703 pub(in crate::db::query) fn has_explicit_order(&self) -> bool {
704 self.inner.has_explicit_order()
705 }
706
707 #[must_use]
708 pub(in crate::db) const fn structural(&self) -> &StructuralQuery {
709 &self.inner
710 }
711
712 #[must_use]
713 pub const fn has_grouping(&self) -> bool {
714 self.inner.has_grouping()
715 }
716
717 #[must_use]
718 pub(in crate::db::query) const fn load_spec(&self) -> Option<LoadSpec> {
719 self.inner.load_spec()
720 }
721
722 #[must_use]
724 pub fn filter(mut self, expr: impl Into<FilterExpr>) -> Self {
725 self.inner = self.inner.filter(expr);
726 self
727 }
728
729 #[cfg(test)]
733 #[must_use]
734 pub(in crate::db) fn filter_expr(mut self, expr: Expr) -> Self {
735 self.inner = self.inner.filter_expr(expr);
736 self
737 }
738
739 #[cfg(test)]
743 #[must_use]
744 pub(in crate::db) fn filter_predicate(mut self, predicate: Predicate) -> Self {
745 self.inner = self.inner.filter_predicate(predicate);
746 self
747 }
748
749 #[must_use]
751 pub fn order_term(mut self, term: FluentOrderTerm) -> Self {
752 self.inner = self.inner.order_term(term);
753 self
754 }
755
756 #[must_use]
758 pub fn order_terms<I>(mut self, terms: I) -> Self
759 where
760 I: IntoIterator<Item = FluentOrderTerm>,
761 {
762 for term in terms {
763 self.inner = self.inner.order_term(term);
764 }
765
766 self
767 }
768
769 #[must_use]
771 pub fn distinct(mut self) -> Self {
772 self.inner = self.inner.distinct();
773 self
774 }
775
776 #[cfg(all(test, feature = "sql"))]
779 #[must_use]
780 pub(in crate::db) fn select_fields<I, S>(mut self, fields: I) -> Self
781 where
782 I: IntoIterator<Item = S>,
783 S: Into<String>,
784 {
785 self.inner = self.inner.select_fields(fields);
786 self
787 }
788
789 pub fn group_by(self, field: impl AsRef<str>) -> Result<Self, QueryError> {
791 let Self { inner, .. } = self;
792 let inner = inner.group_by(field)?;
793
794 Ok(Self::from_inner(inner))
795 }
796
797 pub(in crate::db) fn group_by_with_schema(
798 self,
799 field: impl AsRef<str>,
800 schema: &SchemaInfo,
801 ) -> Result<Self, QueryError> {
802 let Self { inner, .. } = self;
803 let inner = inner.group_by_with_schema(field, schema)?;
804
805 Ok(Self::from_inner(inner))
806 }
807
808 #[must_use]
810 pub fn aggregate(mut self, aggregate: AggregateExpr) -> Self {
811 self.inner = self.inner.aggregate(aggregate);
812 self
813 }
814
815 #[must_use]
817 pub fn grouped_limits(mut self, max_groups: u64, max_group_bytes: u64) -> Self {
818 self.inner = self.inner.grouped_limits(max_groups, max_group_bytes);
819 self
820 }
821
822 pub fn having_group(
824 self,
825 field: impl AsRef<str>,
826 op: CompareOp,
827 value: InputValue,
828 ) -> Result<Self, QueryError> {
829 let Self { inner, .. } = self;
830 let inner = inner.having_group(field, op, value.into())?;
831
832 Ok(Self::from_inner(inner))
833 }
834
835 pub(in crate::db) fn having_group_with_schema(
836 self,
837 field: impl AsRef<str>,
838 schema: &SchemaInfo,
839 op: CompareOp,
840 value: InputValue,
841 ) -> Result<Self, QueryError> {
842 let Self { inner, .. } = self;
843 let inner = inner.having_group_with_schema(field, schema, op, value.into())?;
844
845 Ok(Self::from_inner(inner))
846 }
847
848 pub fn having_aggregate(
850 self,
851 aggregate_index: usize,
852 op: CompareOp,
853 value: InputValue,
854 ) -> Result<Self, QueryError> {
855 let Self { inner, .. } = self;
856 let inner = inner.having_aggregate(aggregate_index, op, value.into())?;
857
858 Ok(Self::from_inner(inner))
859 }
860
861 #[cfg(test)]
865 pub(in crate::db) fn having_expr(self, expr: Expr) -> Result<Self, QueryError> {
866 let Self { inner, .. } = self;
867 let inner = inner.having_expr(expr)?;
868
869 Ok(Self::from_inner(inner))
870 }
871
872 pub(in crate::db) fn by_id(self, id: E::Key) -> Self {
874 let Self { inner, .. } = self;
875
876 Self::from_inner(inner.by_id(id.to_key_value()))
877 }
878
879 pub(in crate::db) fn by_ids<I>(self, ids: I) -> Self
881 where
882 I: IntoIterator<Item = E::Key>,
883 {
884 let Self { inner, .. } = self;
885
886 Self::from_inner(inner.by_ids(ids.into_iter().map(|id| id.to_key_value())))
887 }
888
889 #[must_use]
891 pub fn delete(mut self) -> Self {
892 self.inner = self.inner.delete();
893 self
894 }
895
896 #[must_use]
903 pub fn limit(mut self, limit: u32) -> Self {
904 self.inner = self.inner.limit(limit);
905 self
906 }
907
908 #[must_use]
914 pub fn offset(mut self, offset: u32) -> Self {
915 self.inner = self.inner.offset(offset);
916 self
917 }
918
919 #[must_use]
924 pub fn require_index(mut self) -> Self {
925 self.inner = self.inner.require_index();
926 self
927 }
928
929 #[must_use]
934 pub fn require_index_named(mut self, index_name: impl Into<String>) -> Self {
935 self.inner = self.inner.require_index_named(index_name);
936 self
937 }
938
939 #[must_use]
943 pub fn require_access_path(mut self, path: RequiredAccessPath) -> Self {
944 self.inner = self.inner.require_access_path(path);
945 self
946 }
947
948 #[must_use]
953 pub fn require_no_residual_filter(mut self) -> Self {
954 self.inner = self.inner.require_no_residual_filter();
955 self
956 }
957
958 pub fn explain(&self) -> Result<ExplainPlan, QueryError> {
960 let mut plan = self.build_plan_for_visibility(None)?;
961 self.inner
962 .finalize_access_choice_for_visibility(&mut plan, None);
963
964 Ok(plan.explain())
965 }
966
967 pub fn plan_hash_hex(&self) -> Result<String, QueryError> {
972 let plan = self.inner.build_plan()?;
973
974 Ok(plan.fingerprint().to_string())
975 }
976
977 pub fn planned(&self) -> Result<PlannedQuery<E>, QueryError> {
979 self.map_plan_for_visibility(None, Self::planned_query_from_plan)
980 }
981
982 pub fn plan(&self) -> Result<CompiledQuery<E>, QueryError> {
986 self.map_plan_for_visibility(None, Self::compiled_query_from_plan)
987 }
988
989 #[cfg(test)]
990 pub(in crate::db) fn plan_with_visible_indexes(
991 &self,
992 visible_indexes: &VisibleIndexes<'_>,
993 ) -> Result<CompiledQuery<E>, QueryError> {
994 self.map_plan_for_visibility(Some(visible_indexes), Self::compiled_query_from_plan)
995 }
996}
997
998impl<E> Query<E>
999where
1000 E: EntityKind + SingletonEntity,
1001 E::Key: Default,
1002{
1003 pub(in crate::db) fn only(self) -> Self {
1005 let Self { inner, .. } = self;
1006
1007 Self::from_inner(inner.only(E::Key::default().to_key_value()))
1008 }
1009}