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 #[cfg(test)]
131 pub(in crate::db) fn scalar_filter_expr_for_test(&self) -> Option<&Expr> {
132 self.intent
133 .scalar_intent_for_cache_key()
134 .filter
135 .as_ref()
136 .and_then(|filter| filter.logical_filter_expr())
137 }
138
139 #[must_use]
140 #[cfg(test)]
141 pub(in crate::db) fn scalar_filter_predicate_for_test(&self) -> Option<&Predicate> {
142 self.intent
143 .scalar_intent_for_cache_key()
144 .filter
145 .as_ref()
146 .and_then(|filter| filter.predicate_subset())
147 }
148
149 #[must_use]
150 #[cfg(feature = "sql")]
151 pub(in crate::db) fn direct_count_cardinality_prefix_candidate(&self) -> bool {
152 if self.intent.validate_policy_shape().is_err() {
153 return false;
154 }
155
156 let access_inputs = self.intent.planning_access_inputs();
157 let logical_inputs = self.intent.planning_logical_inputs();
158 if access_inputs.order().is_some()
159 || access_inputs.has_key_access_override()
160 || logical_inputs.distinct()
161 || logical_inputs.has_group()
162 || logical_inputs.has_having_expr()
163 || (logical_inputs.has_filter_expr() && !logical_inputs.filter_predicate_covers_expr())
164 {
165 return false;
166 }
167
168 let QueryMode::Load(load_spec) = self.intent.mode() else {
169 return false;
170 };
171 load_spec.limit().is_none()
172 && load_spec.offset() == 0
173 && access_inputs.predicate().is_some()
174 }
175
176 #[must_use]
177 const fn load_spec(&self) -> Option<LoadSpec> {
178 match self.intent.mode() {
179 QueryMode::Load(spec) => Some(spec),
180 QueryMode::Delete(_) => None,
181 }
182 }
183
184 #[must_use]
186 #[cfg(test)]
187 pub(in crate::db) fn filter_predicate(mut self, predicate: Predicate) -> Self {
188 self.intent = self.intent.filter_predicate(predicate);
189 self
190 }
191
192 #[must_use]
194 #[cfg(any(test, feature = "sql"))]
195 pub(in crate::db) fn filter_normalized_predicate(mut self, predicate: Predicate) -> Self {
196 self.intent = self.intent.filter_normalized_predicate(predicate);
197 self
198 }
199
200 #[must_use]
201 pub(in crate::db) fn filter(mut self, expr: impl Into<FilterExpr>) -> Self {
202 self.intent = self.intent.filter(expr.into());
203 self
204 }
205
206 #[must_use]
207 #[cfg(feature = "sql")]
208 pub(in crate::db) fn filter_expr_with_normalized_predicate(
209 mut self,
210 expr: Expr,
211 predicate: Predicate,
212 ) -> Self {
213 self.intent = self
214 .intent
215 .filter_expr_with_normalized_predicate(expr, predicate);
216 self
217 }
218 pub(in crate::db) fn order_term(mut self, term: FluentOrderTerm) -> Self {
219 self.intent = self.intent.order_term(term);
220 self
221 }
222
223 #[must_use]
227 #[cfg(feature = "sql")]
228 pub(in crate::db) fn filter_expr(mut self, expr: Expr) -> Self {
229 self.intent = self.intent.filter_expr(expr);
230 self
231 }
232
233 #[must_use]
234 #[cfg(any(test, feature = "sql"))]
235 pub(in crate::db) fn order_spec(mut self, order: OrderSpec) -> Self {
236 self.intent = self.intent.order_spec(order);
237 self
238 }
239
240 #[must_use]
241 pub(in crate::db) fn distinct(mut self) -> Self {
242 self.intent = self.intent.distinct();
243 self
244 }
245
246 #[cfg(feature = "sql")]
247 #[must_use]
248 pub(in crate::db) fn select_fields<I, S>(mut self, fields: I) -> Self
249 where
250 I: IntoIterator<Item = S>,
251 S: Into<String>,
252 {
253 self.intent = self.intent.select_fields(fields);
254 self
255 }
256
257 #[cfg(feature = "sql")]
258 #[must_use]
259 pub(in crate::db) fn projection_selection(mut self, selection: ProjectionSelection) -> Self {
260 self.intent = self.intent.projection_selection(selection);
261 self
262 }
263
264 pub(in crate::db) fn group_by(self, field: impl AsRef<str>) -> Result<Self, QueryError> {
265 self.try_map_intent(|intent| intent.push_group_field(field.as_ref()))
266 }
267
268 pub(in crate::db) fn group_by_with_schema(
269 self,
270 field: impl AsRef<str>,
271 schema: &SchemaInfo,
272 ) -> Result<Self, QueryError> {
273 self.try_map_intent(|intent| intent.push_group_field_with_schema(field.as_ref(), schema))
274 }
275
276 #[must_use]
277 pub(in crate::db) fn aggregate(mut self, aggregate: AggregateExpr) -> Self {
278 self.intent = self.intent.push_group_aggregate(aggregate);
279 self
280 }
281
282 #[must_use]
283 fn grouped_limits(mut self, max_groups: u64, max_group_bytes: u64) -> Self {
284 self.intent = self.intent.grouped_limits(max_groups, max_group_bytes);
285 self
286 }
287
288 pub(in crate::db) fn having_group(
289 self,
290 field: impl AsRef<str>,
291 op: CompareOp,
292 value: Value,
293 ) -> Result<Self, QueryError> {
294 let field = field.as_ref().to_owned();
295 self.try_map_intent(|intent| intent.push_having_group_clause(&field, op, value))
296 }
297
298 pub(in crate::db) fn having_group_with_schema(
299 self,
300 field: impl AsRef<str>,
301 schema: &SchemaInfo,
302 op: CompareOp,
303 value: Value,
304 ) -> Result<Self, QueryError> {
305 let field = field.as_ref().to_owned();
306 self.try_map_intent(|intent| {
307 intent.push_having_group_clause_with_schema(&field, schema, op, value)
308 })
309 }
310
311 pub(in crate::db) fn having_aggregate(
312 self,
313 aggregate_index: usize,
314 op: CompareOp,
315 value: Value,
316 ) -> Result<Self, QueryError> {
317 self.try_map_intent(|intent| {
318 intent.push_having_aggregate_clause(aggregate_index, op, value)
319 })
320 }
321
322 #[cfg(test)]
323 pub(in crate::db) fn having_expr(self, expr: Expr) -> Result<Self, QueryError> {
324 self.try_map_intent(|intent| intent.push_having_expr(expr))
325 }
326
327 #[cfg(feature = "sql")]
328 pub(in crate::db) fn having_expr_preserving_shape(
329 self,
330 expr: Expr,
331 ) -> Result<Self, QueryError> {
332 self.try_map_intent(|intent| intent.push_having_expr_preserving_shape(expr))
333 }
334
335 #[must_use]
336 fn by_id(self, id: Value) -> Self {
337 self.map_intent(|intent| intent.by_id(id))
338 }
339
340 #[must_use]
341 fn by_ids<I>(self, ids: I) -> Self
342 where
343 I: IntoIterator<Item = Value>,
344 {
345 self.map_intent(|intent| intent.by_ids(ids))
346 }
347
348 #[must_use]
349 fn only(self, id: Value) -> Self {
350 self.map_intent(|intent| intent.only(id))
351 }
352
353 #[must_use]
354 pub(in crate::db) fn delete(mut self) -> Self {
355 self.intent = self.intent.delete();
356 self
357 }
358
359 #[must_use]
360 pub(in crate::db) fn limit(mut self, limit: u32) -> Self {
361 self.intent = self.intent.limit(limit);
362 self
363 }
364
365 #[must_use]
366 pub(in crate::db) fn offset(mut self, offset: u32) -> Self {
367 self.intent = self.intent.offset(offset);
368 self
369 }
370
371 pub(in crate::db) fn build_plan(&self) -> Result<AccessPlannedQuery, QueryError> {
372 let mut plan = self.intent.build_plan_model()?;
373 self.validate_access_requirements_for_visibility(&mut plan, None)?;
374
375 Ok(plan)
376 }
377
378 pub(in crate::db) fn build_plan_with_visible_indexes(
379 &self,
380 visible_indexes: &VisibleIndexes<'_>,
381 ) -> Result<AccessPlannedQuery, QueryError> {
382 let mut plan = self.intent.build_plan_model_with_indexes(visible_indexes)?;
383 self.validate_access_requirements_for_visibility(&mut plan, Some(visible_indexes))?;
384
385 Ok(plan)
386 }
387
388 pub(in crate::db) fn prepare_scalar_planning_state_with_schema_info(
389 &self,
390 schema_info: SchemaInfo,
391 ) -> Result<PreparedScalarPlanningState<'_>, QueryError> {
392 self.intent
393 .prepare_scalar_planning_state_with_schema_info(schema_info)
394 }
395
396 pub(in crate::db) fn build_plan_with_visible_indexes_from_scalar_planning_state(
397 &self,
398 visible_indexes: &VisibleIndexes<'_>,
399 planning_state: PreparedScalarPlanningState<'_>,
400 ) -> Result<AccessPlannedQuery, QueryError> {
401 let mut plan = self
402 .intent
403 .build_plan_model_with_indexes_from_scalar_planning_state(
404 visible_indexes,
405 planning_state,
406 )?;
407 self.validate_access_requirements_for_visibility(&mut plan, Some(visible_indexes))?;
408
409 Ok(plan)
410 }
411
412 #[cfg(feature = "sql")]
413 pub(in crate::db) fn try_build_count_cardinality_prefix_access_with_schema_info(
414 &self,
415 visible_indexes: &VisibleIndexes<'_>,
416 schema_info: &SchemaInfo,
417 ) -> Result<Option<crate::db::query::plan::CountCardinalityPrefixAccess<'_>>, QueryError> {
418 crate::db::query::plan::try_build_count_cardinality_prefix_access_from_query_model(
419 &self.intent,
420 visible_indexes,
421 schema_info,
422 )
423 }
424
425 pub(in crate::db) fn try_build_trivial_scalar_load_plan_with_schema_info(
426 &self,
427 schema_info: SchemaInfo,
428 ) -> Result<Option<AccessPlannedQuery>, QueryError> {
429 let mut plan = self
430 .intent
431 .try_build_trivial_scalar_load_plan_with_schema_info(schema_info)?;
432 if let Some(plan) = &mut plan {
433 self.validate_access_requirements_for_visibility(plan, None)?;
434 }
435
436 Ok(plan)
437 }
438
439 #[must_use]
440 pub(in crate::db) fn trivial_scalar_load_fast_path_eligible_with_schema(
441 &self,
442 schema_info: &SchemaInfo,
443 ) -> bool {
444 self.intent
445 .trivial_scalar_load_fast_path_eligible_with_schema(schema_info)
446 }
447
448 #[must_use]
449 #[cfg(test)]
450 pub(in crate::db) fn structural_cache_key(
451 &self,
452 ) -> crate::db::query::intent::StructuralQueryCacheKey {
453 crate::db::query::intent::StructuralQueryCacheKey::from_query_model(&self.intent)
454 }
455
456 #[must_use]
457 pub(in crate::db) fn structural_cache_key_with_normalized_predicate_fingerprint(
458 &self,
459 predicate_fingerprint: Option<[u8; 32]>,
460 ) -> crate::db::query::intent::StructuralQueryCacheKey {
461 if predicate_fingerprint.is_none() {
462 return self
463 .structural_cache_key
464 .get_or_init(|| {
465 self.intent
466 .structural_cache_key_with_normalized_predicate_fingerprint(None)
467 })
468 .clone();
469 }
470
471 self.intent
472 .structural_cache_key_with_normalized_predicate_fingerprint(predicate_fingerprint)
473 }
474
475 fn build_plan_for_visibility(
478 &self,
479 visible_indexes: Option<&VisibleIndexes<'_>>,
480 ) -> Result<AccessPlannedQuery, QueryError> {
481 match visible_indexes {
482 Some(visible_indexes) => self.build_plan_with_visible_indexes(visible_indexes),
483 None => self.build_plan(),
484 }
485 }
486
487 fn finalize_access_choice_for_visibility(
488 &self,
489 plan: &mut AccessPlannedQuery,
490 visible_indexes: Option<&VisibleIndexes<'_>>,
491 ) {
492 match visible_indexes {
493 Some(visible_indexes) => {
494 if let Some(schema_info) = visible_indexes.accepted_schema_info() {
495 plan.finalize_access_choice_for_model_with_semantic_indexes_and_schema(
496 self.intent.model(),
497 visible_indexes.accepted_semantic_index_contracts(),
498 schema_info,
499 );
500 } else {
501 plan.finalize_access_choice_for_model_only_with_indexes(
502 self.intent.model(),
503 visible_indexes.generated_model_only_indexes(),
504 );
505 }
506 }
507 None => {
508 plan.finalize_access_choice_for_model_only_with_indexes(
509 self.intent.model(),
510 self.intent.model().indexes(),
511 );
512 }
513 }
514 }
515
516 fn validate_access_requirements_for_visibility(
517 &self,
518 plan: &mut AccessPlannedQuery,
519 visible_indexes: Option<&VisibleIndexes<'_>>,
520 ) -> Result<(), QueryError> {
521 if self.access_requirements.is_empty() {
522 return Ok(());
523 }
524
525 self.finalize_access_choice_for_visibility(plan, visible_indexes);
526 self.access_requirements.validate(plan)
527 }
528
529 const fn require_index(mut self) -> Self {
530 self.access_requirements.require_index();
531 self
532 }
533
534 fn require_index_named(mut self, index_name: impl Into<String>) -> Self {
535 self.access_requirements.require_index_named(index_name);
536 self
537 }
538
539 const fn require_access_path(mut self, path: RequiredAccessPath) -> Self {
540 self.access_requirements.require_access_path(path);
541 self
542 }
543
544 const fn require_no_residual_filter(mut self) -> Self {
545 self.access_requirements.require_no_residual_filter();
546 self
547 }
548
549 #[must_use]
550 pub(in crate::db) const fn model(&self) -> &'static crate::model::entity::EntityModel {
551 self.intent.model()
552 }
553}
554
555#[derive(Clone, Debug)]
564struct QueryPlanHandle {
565 plan: Box<AccessPlannedQuery>,
566}
567
568impl QueryPlanHandle {
569 #[must_use]
570 fn from_plan(plan: AccessPlannedQuery) -> Self {
571 Self {
572 plan: Box::new(plan),
573 }
574 }
575
576 #[must_use]
577 const fn logical_plan(&self) -> &AccessPlannedQuery {
578 &self.plan
579 }
580
581 #[must_use]
582 fn plan_hash_hex(&self) -> String {
583 self.logical_plan().plan_hash_hex()
584 }
585
586 #[must_use]
587 #[cfg(test)]
588 fn into_inner(self) -> AccessPlannedQuery {
589 *self.plan
590 }
591}
592
593#[derive(Debug)]
601pub struct PlannedQuery<E: EntityKind> {
602 plan: QueryPlanHandle,
603 _marker: PhantomData<E>,
604}
605
606impl<E: EntityKind> PlannedQuery<E> {
607 #[must_use]
608 pub(in crate::db) fn from_plan(plan: AccessPlannedQuery) -> Self {
609 Self {
610 plan: QueryPlanHandle::from_plan(plan),
611 _marker: PhantomData,
612 }
613 }
614
615 #[must_use]
616 pub fn explain(&self) -> ExplainPlan {
617 self.plan.logical_plan().explain()
618 }
619
620 #[must_use]
622 pub fn plan_hash_hex(&self) -> String {
623 self.plan.plan_hash_hex()
624 }
625}
626
627#[derive(Clone, Debug)]
637pub struct CompiledQuery<E: EntityKind> {
638 plan: QueryPlanHandle,
639 _marker: PhantomData<E>,
640}
641
642impl<E: EntityKind> CompiledQuery<E> {
643 #[must_use]
644 pub(in crate::db) fn from_plan(plan: AccessPlannedQuery) -> Self {
645 Self {
646 plan: QueryPlanHandle::from_plan(plan),
647 _marker: PhantomData,
648 }
649 }
650
651 #[must_use]
652 pub fn explain(&self) -> ExplainPlan {
653 self.plan.logical_plan().explain()
654 }
655
656 #[must_use]
658 pub fn plan_hash_hex(&self) -> String {
659 self.plan.plan_hash_hex()
660 }
661
662 #[must_use]
663 #[cfg(test)]
664 pub(in crate::db) fn projection_spec(&self) -> crate::db::query::plan::expr::ProjectionSpec {
665 self.plan.logical_plan().projection_spec(E::MODEL)
666 }
667
668 #[cfg(test)]
670 pub(in crate::db) fn into_plan(self) -> AccessPlannedQuery {
671 self.plan.into_inner()
672 }
673
674 #[must_use]
675 #[cfg(test)]
676 pub(in crate::db) fn into_inner(self) -> AccessPlannedQuery {
677 self.plan.into_inner()
678 }
679}
680
681#[derive(Debug)]
693pub struct Query<E: EntityKind> {
694 inner: StructuralQuery,
695 _marker: PhantomData<E>,
696}
697
698impl<E: EntityKind> Query<E> {
699 pub(in crate::db) const fn from_inner(inner: StructuralQuery) -> Self {
701 Self {
702 inner,
703 _marker: PhantomData,
704 }
705 }
706
707 #[must_use]
711 pub const fn new(consistency: MissingRowPolicy) -> Self {
712 Self::from_inner(StructuralQuery::new(E::MODEL, consistency))
713 }
714
715 #[must_use]
717 pub const fn mode(&self) -> QueryMode {
718 self.inner.mode()
719 }
720
721 #[cfg(test)]
722 pub(in crate::db) fn explain_with_visible_indexes(
723 &self,
724 visible_indexes: &VisibleIndexes<'_>,
725 ) -> Result<ExplainPlan, QueryError> {
726 let mut plan = self.build_plan_for_visibility(Some(visible_indexes))?;
727 self.inner
728 .finalize_access_choice_for_visibility(&mut plan, Some(visible_indexes));
729
730 Ok(plan.explain())
731 }
732
733 #[cfg(test)]
734 pub(in crate::db) fn plan_hash_hex_with_visible_indexes(
735 &self,
736 visible_indexes: &VisibleIndexes<'_>,
737 ) -> Result<String, QueryError> {
738 let plan = self.build_plan_for_visibility(Some(visible_indexes))?;
739
740 Ok(plan.plan_hash_hex())
741 }
742
743 fn build_plan_for_visibility(
746 &self,
747 visible_indexes: Option<&VisibleIndexes<'_>>,
748 ) -> Result<AccessPlannedQuery, QueryError> {
749 self.inner.build_plan_for_visibility(visible_indexes)
750 }
751
752 fn map_plan_for_visibility<T>(
756 &self,
757 visible_indexes: Option<&VisibleIndexes<'_>>,
758 map: impl FnOnce(AccessPlannedQuery) -> T,
759 ) -> Result<T, QueryError> {
760 let plan = self.build_plan_for_visibility(visible_indexes)?;
761
762 Ok(map(plan))
763 }
764
765 pub(in crate::db) fn planned_query_from_plan(plan: AccessPlannedQuery) -> PlannedQuery<E> {
767 PlannedQuery::from_plan(plan)
768 }
769
770 pub(in crate::db) fn compiled_query_from_plan(plan: AccessPlannedQuery) -> CompiledQuery<E> {
772 CompiledQuery::from_plan(plan)
773 }
774
775 #[must_use]
776 pub(in crate::db::query) fn has_explicit_order(&self) -> bool {
777 self.inner.has_explicit_order()
778 }
779
780 #[must_use]
781 pub(in crate::db) const fn structural(&self) -> &StructuralQuery {
782 &self.inner
783 }
784
785 #[must_use]
786 pub const fn has_grouping(&self) -> bool {
787 self.inner.has_grouping()
788 }
789
790 #[must_use]
791 pub(in crate::db::query) const fn load_spec(&self) -> Option<LoadSpec> {
792 self.inner.load_spec()
793 }
794
795 #[must_use]
797 pub fn filter(mut self, expr: impl Into<FilterExpr>) -> Self {
798 self.inner = self.inner.filter(expr);
799 self
800 }
801
802 #[cfg(test)]
806 #[must_use]
807 pub(in crate::db) fn filter_expr(mut self, expr: Expr) -> Self {
808 self.inner = self.inner.filter_expr(expr);
809 self
810 }
811
812 #[cfg(test)]
816 #[must_use]
817 pub(in crate::db) fn filter_predicate(mut self, predicate: Predicate) -> Self {
818 self.inner = self.inner.filter_predicate(predicate);
819 self
820 }
821
822 #[must_use]
824 pub fn order_term(mut self, term: FluentOrderTerm) -> Self {
825 self.inner = self.inner.order_term(term);
826 self
827 }
828
829 #[must_use]
831 pub fn order_terms<I>(mut self, terms: I) -> Self
832 where
833 I: IntoIterator<Item = FluentOrderTerm>,
834 {
835 for term in terms {
836 self.inner = self.inner.order_term(term);
837 }
838
839 self
840 }
841
842 #[must_use]
844 pub fn distinct(mut self) -> Self {
845 self.inner = self.inner.distinct();
846 self
847 }
848
849 #[cfg(all(test, feature = "sql"))]
852 #[must_use]
853 pub(in crate::db) fn select_fields<I, S>(mut self, fields: I) -> Self
854 where
855 I: IntoIterator<Item = S>,
856 S: Into<String>,
857 {
858 self.inner = self.inner.select_fields(fields);
859 self
860 }
861
862 pub fn group_by(self, field: impl AsRef<str>) -> Result<Self, QueryError> {
864 let Self { inner, .. } = self;
865 let inner = inner.group_by(field)?;
866
867 Ok(Self::from_inner(inner))
868 }
869
870 pub(in crate::db) fn group_by_with_schema(
871 self,
872 field: impl AsRef<str>,
873 schema: &SchemaInfo,
874 ) -> Result<Self, QueryError> {
875 let Self { inner, .. } = self;
876 let inner = inner.group_by_with_schema(field, schema)?;
877
878 Ok(Self::from_inner(inner))
879 }
880
881 #[must_use]
883 pub fn aggregate(mut self, aggregate: AggregateExpr) -> Self {
884 self.inner = self.inner.aggregate(aggregate);
885 self
886 }
887
888 #[must_use]
890 pub fn grouped_limits(mut self, max_groups: u64, max_group_bytes: u64) -> Self {
891 self.inner = self.inner.grouped_limits(max_groups, max_group_bytes);
892 self
893 }
894
895 pub fn having_group(
897 self,
898 field: impl AsRef<str>,
899 op: CompareOp,
900 value: InputValue,
901 ) -> Result<Self, QueryError> {
902 let Self { inner, .. } = self;
903 let inner = inner.having_group(field, op, value.into())?;
904
905 Ok(Self::from_inner(inner))
906 }
907
908 pub(in crate::db) fn having_group_with_schema(
909 self,
910 field: impl AsRef<str>,
911 schema: &SchemaInfo,
912 op: CompareOp,
913 value: InputValue,
914 ) -> Result<Self, QueryError> {
915 let Self { inner, .. } = self;
916 let inner = inner.having_group_with_schema(field, schema, op, value.into())?;
917
918 Ok(Self::from_inner(inner))
919 }
920
921 pub fn having_aggregate(
923 self,
924 aggregate_index: usize,
925 op: CompareOp,
926 value: InputValue,
927 ) -> Result<Self, QueryError> {
928 let Self { inner, .. } = self;
929 let inner = inner.having_aggregate(aggregate_index, op, value.into())?;
930
931 Ok(Self::from_inner(inner))
932 }
933
934 #[cfg(test)]
938 pub(in crate::db) fn having_expr(self, expr: Expr) -> Result<Self, QueryError> {
939 let Self { inner, .. } = self;
940 let inner = inner.having_expr(expr)?;
941
942 Ok(Self::from_inner(inner))
943 }
944
945 pub(in crate::db) fn by_id(self, id: E::Key) -> Self {
947 let Self { inner, .. } = self;
948
949 Self::from_inner(inner.by_id(id.to_key_value()))
950 }
951
952 pub(in crate::db) fn by_ids<I>(self, ids: I) -> Self
954 where
955 I: IntoIterator<Item = E::Key>,
956 {
957 let Self { inner, .. } = self;
958
959 Self::from_inner(inner.by_ids(ids.into_iter().map(|id| id.to_key_value())))
960 }
961
962 #[must_use]
964 pub fn delete(mut self) -> Self {
965 self.inner = self.inner.delete();
966 self
967 }
968
969 #[must_use]
976 pub fn limit(mut self, limit: u32) -> Self {
977 self.inner = self.inner.limit(limit);
978 self
979 }
980
981 #[must_use]
987 pub fn offset(mut self, offset: u32) -> Self {
988 self.inner = self.inner.offset(offset);
989 self
990 }
991
992 #[must_use]
997 pub fn require_index(mut self) -> Self {
998 self.inner = self.inner.require_index();
999 self
1000 }
1001
1002 #[must_use]
1007 pub fn require_index_named(mut self, index_name: impl Into<String>) -> Self {
1008 self.inner = self.inner.require_index_named(index_name);
1009 self
1010 }
1011
1012 #[must_use]
1016 pub fn require_access_path(mut self, path: RequiredAccessPath) -> Self {
1017 self.inner = self.inner.require_access_path(path);
1018 self
1019 }
1020
1021 #[must_use]
1026 pub fn require_no_residual_filter(mut self) -> Self {
1027 self.inner = self.inner.require_no_residual_filter();
1028 self
1029 }
1030
1031 pub fn explain(&self) -> Result<ExplainPlan, QueryError> {
1033 let mut plan = self.build_plan_for_visibility(None)?;
1034 self.inner
1035 .finalize_access_choice_for_visibility(&mut plan, None);
1036
1037 Ok(plan.explain())
1038 }
1039
1040 pub fn plan_hash_hex(&self) -> Result<String, QueryError> {
1045 let plan = self.inner.build_plan()?;
1046
1047 Ok(plan.plan_hash_hex())
1048 }
1049
1050 pub fn planned(&self) -> Result<PlannedQuery<E>, QueryError> {
1052 self.map_plan_for_visibility(None, Self::planned_query_from_plan)
1053 }
1054
1055 pub fn plan(&self) -> Result<CompiledQuery<E>, QueryError> {
1059 self.map_plan_for_visibility(None, Self::compiled_query_from_plan)
1060 }
1061
1062 #[cfg(test)]
1063 pub(in crate::db) fn plan_with_visible_indexes(
1064 &self,
1065 visible_indexes: &VisibleIndexes<'_>,
1066 ) -> Result<CompiledQuery<E>, QueryError> {
1067 self.map_plan_for_visibility(Some(visible_indexes), Self::compiled_query_from_plan)
1068 }
1069}
1070
1071impl<E> Query<E>
1072where
1073 E: EntityKind + SingletonEntity,
1074 E::Key: Default,
1075{
1076 pub(in crate::db) fn only(self) -> Self {
1078 let Self { inner, .. } = self;
1079
1080 Self::from_inner(inner.only(E::Key::default().to_key_value()))
1081 }
1082}