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 KeyValueCodec,
16 predicate::{CompareOp, MissingRowPolicy},
17 query::{
18 builder::AggregateExpr,
19 explain::ExplainPlan,
20 expr::FilterExpr,
21 expr::OrderTerm as FluentOrderTerm,
22 intent::{AccessRequirements, QueryError, QueryModel, RequiredAccessPath},
23 plan::{
24 AccessPlannedQuery, LoadSpec, PreparedScalarPlanningState, QueryMode,
25 VisibleIndexes,
26 },
27 },
28 schema::{SchemaInfo, SchemaLiteralValidationReason, ValidateError},
29 },
30 entity::{EntityKind, SingletonEntity},
31 value::{InputValue, Value},
32};
33use std::sync::OnceLock;
34
35use core::marker::PhantomData;
36
37#[derive(Clone, Debug)]
46pub(in crate::db) struct StructuralQuery {
47 intent: QueryModel<'static, Value>,
48 access_requirements: AccessRequirements,
49 structural_cache_key: OnceLock<crate::db::query::intent::StructuralQueryCacheKey>,
50}
51
52impl StructuralQuery {
53 #[must_use]
54 pub(in crate::db) const fn new(
55 model: &'static crate::model::entity::EntityModel,
56 consistency: MissingRowPolicy,
57 ) -> Self {
58 Self {
59 intent: QueryModel::new(model, consistency),
60 access_requirements: AccessRequirements::new(),
61 structural_cache_key: OnceLock::new(),
62 }
63 }
64
65 const fn from_intent_and_access_requirements(
69 intent: QueryModel<'static, Value>,
70 access_requirements: AccessRequirements,
71 ) -> Self {
72 Self {
73 intent,
74 access_requirements,
75 structural_cache_key: OnceLock::new(),
76 }
77 }
78
79 fn map_intent(
82 self,
83 map: impl FnOnce(QueryModel<'static, Value>) -> QueryModel<'static, Value>,
84 ) -> Self {
85 let Self {
86 intent,
87 access_requirements,
88 ..
89 } = self;
90
91 Self::from_intent_and_access_requirements(map(intent), access_requirements)
92 }
93
94 fn try_map_intent(
97 self,
98 map: impl FnOnce(QueryModel<'static, Value>) -> Result<QueryModel<'static, Value>, QueryError>,
99 ) -> Result<Self, QueryError> {
100 let Self {
101 intent,
102 access_requirements,
103 ..
104 } = self;
105
106 map(intent)
107 .map(|intent| Self::from_intent_and_access_requirements(intent, access_requirements))
108 }
109
110 #[must_use]
111 const fn mode(&self) -> QueryMode {
112 self.intent.mode()
113 }
114
115 #[must_use]
116 fn has_explicit_order(&self) -> bool {
117 self.intent.has_explicit_order()
118 }
119
120 #[must_use]
121 pub(in crate::db) const fn has_grouping(&self) -> bool {
122 self.intent.has_grouping()
123 }
124
125 #[must_use]
126 pub(in crate::db) const fn has_scalar_filter(&self) -> bool {
127 self.intent.has_scalar_filter()
128 }
129
130 #[must_use]
131 #[cfg(test)]
132 pub(in crate::db) fn scalar_filter_expr_for_test(&self) -> Option<&Expr> {
133 self.intent
134 .scalar_intent_for_cache_key()
135 .filter
136 .as_ref()
137 .and_then(|filter| filter.logical_filter_expr())
138 }
139
140 #[must_use]
141 #[cfg(test)]
142 pub(in crate::db) fn scalar_filter_predicate_for_test(&self) -> Option<&Predicate> {
143 self.intent
144 .scalar_intent_for_cache_key()
145 .filter
146 .as_ref()
147 .and_then(|filter| filter.predicate_subset())
148 }
149
150 #[must_use]
151 #[cfg(feature = "sql")]
152 pub(in crate::db) fn direct_count_cardinality_prefix_candidate(&self) -> bool {
153 matches!(
154 self.intent.direct_count_cardinality_prefix_predicate(),
155 Ok(Some(_))
156 )
157 }
158
159 #[must_use]
160 const fn load_spec(&self) -> Option<LoadSpec> {
161 match self.intent.mode() {
162 QueryMode::Load(spec) => Some(spec),
163 QueryMode::Delete(_) => None,
164 }
165 }
166
167 #[must_use]
169 #[cfg(test)]
170 pub(in crate::db) fn filter_predicate(mut self, predicate: Predicate) -> Self {
171 self.intent = self.intent.filter_predicate(predicate);
172 self
173 }
174
175 #[must_use]
177 #[cfg(any(test, feature = "sql"))]
178 pub(in crate::db) fn filter_normalized_predicate(mut self, predicate: Predicate) -> Self {
179 self.intent = self.intent.filter_normalized_predicate(predicate);
180 self
181 }
182
183 #[must_use]
184 pub(in crate::db) fn filter(mut self, expr: impl Into<FilterExpr>) -> Self {
185 self.intent = self.intent.filter(expr.into());
186 self
187 }
188
189 #[must_use]
190 #[cfg(feature = "sql")]
191 pub(in crate::db) fn filter_expr_with_normalized_predicate(
192 mut self,
193 expr: Expr,
194 predicate: Predicate,
195 ) -> Self {
196 self.intent = self
197 .intent
198 .filter_expr_with_normalized_predicate(expr, predicate);
199 self
200 }
201 pub(in crate::db) fn order_term(mut self, term: FluentOrderTerm) -> Self {
202 self.intent = self.intent.order_term(term);
203 self
204 }
205
206 #[must_use]
210 #[cfg(feature = "sql")]
211 pub(in crate::db) fn filter_expr(mut self, expr: Expr) -> Self {
212 self.intent = self.intent.filter_expr(expr);
213 self
214 }
215
216 #[must_use]
217 #[cfg(any(test, feature = "sql"))]
218 pub(in crate::db) fn order_spec(mut self, order: OrderSpec) -> Self {
219 self.intent = self.intent.order_spec(order);
220 self
221 }
222
223 #[must_use]
224 pub(in crate::db) fn distinct(mut self) -> Self {
225 self.intent = self.intent.distinct();
226 self
227 }
228
229 #[cfg(feature = "sql")]
230 #[must_use]
231 pub(in crate::db) fn select_fields<I, S>(mut self, fields: I) -> Self
232 where
233 I: IntoIterator<Item = S>,
234 S: Into<String>,
235 {
236 self.intent = self.intent.select_fields(fields);
237 self
238 }
239
240 #[cfg(feature = "sql")]
241 #[must_use]
242 pub(in crate::db) fn projection_selection(mut self, selection: ProjectionSelection) -> Self {
243 self.intent = self.intent.projection_selection(selection);
244 self
245 }
246
247 pub(in crate::db) fn group_by(self, field: impl AsRef<str>) -> Result<Self, QueryError> {
248 self.try_map_intent(|intent| intent.push_group_field(field.as_ref()))
249 }
250
251 pub(in crate::db) fn group_by_with_schema(
252 self,
253 field: impl AsRef<str>,
254 schema: &SchemaInfo,
255 ) -> Result<Self, QueryError> {
256 self.try_map_intent(|intent| intent.push_group_field_with_schema(field.as_ref(), schema))
257 }
258
259 #[must_use]
260 pub(in crate::db) fn aggregate(mut self, aggregate: AggregateExpr) -> Self {
261 self.intent = self.intent.push_group_aggregate(aggregate);
262 self
263 }
264
265 #[must_use]
266 fn grouped_limits(mut self, max_groups: u64, max_group_bytes: u64) -> Self {
267 self.intent = self.intent.grouped_limits(max_groups, max_group_bytes);
268 self
269 }
270
271 pub(in crate::db) fn having_group(
272 self,
273 field: impl AsRef<str>,
274 op: CompareOp,
275 value: Value,
276 ) -> Result<Self, QueryError> {
277 let field = field.as_ref().to_owned();
278 self.try_map_intent(|intent| intent.push_having_group_clause(&field, op, value))
279 }
280
281 pub(in crate::db) fn having_group_with_schema(
282 self,
283 field: impl AsRef<str>,
284 schema: &SchemaInfo,
285 op: CompareOp,
286 value: Value,
287 ) -> Result<Self, QueryError> {
288 let field = field.as_ref().to_owned();
289 self.try_map_intent(|intent| {
290 intent.push_having_group_clause_with_schema(&field, schema, op, value)
291 })
292 }
293
294 pub(in crate::db) fn having_aggregate(
295 self,
296 aggregate_index: usize,
297 op: CompareOp,
298 value: Value,
299 ) -> Result<Self, QueryError> {
300 self.try_map_intent(|intent| {
301 intent.push_having_aggregate_clause(aggregate_index, op, value)
302 })
303 }
304
305 #[cfg(test)]
306 pub(in crate::db) fn having_expr(self, expr: Expr) -> Result<Self, QueryError> {
307 self.try_map_intent(|intent| intent.push_having_expr(expr))
308 }
309
310 #[cfg(feature = "sql")]
311 pub(in crate::db) fn having_expr_preserving_shape(
312 self,
313 expr: Expr,
314 ) -> Result<Self, QueryError> {
315 self.try_map_intent(|intent| intent.push_having_expr_preserving_shape(expr))
316 }
317
318 #[must_use]
319 fn by_id(self, id: Value) -> Self {
320 self.map_intent(|intent| intent.by_id(id))
321 }
322
323 #[must_use]
324 fn by_ids<I>(self, ids: I) -> Self
325 where
326 I: IntoIterator<Item = Value>,
327 {
328 self.map_intent(|intent| intent.by_ids(ids))
329 }
330
331 #[must_use]
332 fn only(self, id: Value) -> Self {
333 self.map_intent(|intent| intent.only(id))
334 }
335
336 #[must_use]
337 pub(in crate::db) fn delete(mut self) -> Self {
338 self.intent = self.intent.delete();
339 self
340 }
341
342 #[must_use]
343 pub(in crate::db) fn limit(mut self, limit: u32) -> Self {
344 self.intent = self.intent.limit(limit);
345 self
346 }
347
348 #[must_use]
349 pub(in crate::db) fn offset(mut self, offset: u32) -> Self {
350 self.intent = self.intent.offset(offset);
351 self
352 }
353
354 pub(in crate::db) fn build_plan(&self) -> Result<AccessPlannedQuery, QueryError> {
355 let mut plan = self.intent.build_plan_model()?;
356 self.validate_access_requirements_for_visibility(&mut plan, None)?;
357
358 Ok(plan)
359 }
360
361 pub(in crate::db) fn build_plan_with_visible_indexes(
362 &self,
363 visible_indexes: &VisibleIndexes<'_>,
364 ) -> Result<AccessPlannedQuery, QueryError> {
365 let mut plan = self.intent.build_plan_model_with_indexes(visible_indexes)?;
366 self.validate_access_requirements_for_visibility(&mut plan, Some(visible_indexes))?;
367
368 Ok(plan)
369 }
370
371 pub(in crate::db) fn prepare_scalar_planning_state_with_schema_info(
372 &self,
373 schema_info: SchemaInfo,
374 ) -> Result<PreparedScalarPlanningState<'_>, QueryError> {
375 self.intent
376 .prepare_scalar_planning_state_with_schema_info(schema_info)
377 }
378
379 pub(in crate::db) fn build_plan_with_visible_indexes_from_scalar_planning_state(
380 &self,
381 visible_indexes: &VisibleIndexes<'_>,
382 planning_state: PreparedScalarPlanningState<'_>,
383 ) -> Result<AccessPlannedQuery, QueryError> {
384 let mut plan = self
385 .intent
386 .build_plan_model_with_indexes_from_scalar_planning_state(
387 visible_indexes,
388 planning_state,
389 )?;
390 self.validate_access_requirements_for_visibility(&mut plan, Some(visible_indexes))?;
391
392 Ok(plan)
393 }
394
395 #[cfg(feature = "sql")]
396 pub(in crate::db) fn try_build_count_cardinality_prefix_access_with_schema_info(
397 &self,
398 visible_indexes: &VisibleIndexes<'_>,
399 schema_info: &SchemaInfo,
400 ) -> Result<Option<crate::db::query::plan::CountCardinalityPrefixAccess<'_>>, QueryError> {
401 crate::db::query::plan::try_build_count_cardinality_prefix_access_from_query_model(
402 &self.intent,
403 visible_indexes,
404 schema_info,
405 )
406 }
407
408 pub(in crate::db) fn try_build_trivial_scalar_load_plan_with_schema_info(
409 &self,
410 schema_info: SchemaInfo,
411 ) -> Result<Option<AccessPlannedQuery>, QueryError> {
412 let mut plan = self
413 .intent
414 .try_build_trivial_scalar_load_plan_with_schema_info(schema_info)?;
415 if let Some(plan) = &mut plan {
416 self.validate_access_requirements_for_visibility(plan, None)?;
417 }
418
419 Ok(plan)
420 }
421
422 #[must_use]
423 pub(in crate::db) fn trivial_scalar_load_fast_path_eligible_with_schema(
424 &self,
425 schema_info: &SchemaInfo,
426 ) -> bool {
427 self.intent
428 .trivial_scalar_load_fast_path_eligible_with_schema(schema_info)
429 }
430
431 #[must_use]
432 #[cfg(test)]
433 pub(in crate::db) fn structural_cache_key(
434 &self,
435 ) -> crate::db::query::intent::StructuralQueryCacheKey {
436 crate::db::query::intent::StructuralQueryCacheKey::from_query_model(&self.intent)
437 }
438
439 #[must_use]
440 pub(in crate::db) fn structural_cache_key_with_normalized_predicate_fingerprint(
441 &self,
442 predicate_fingerprint: Option<[u8; 32]>,
443 ) -> crate::db::query::intent::StructuralQueryCacheKey {
444 if predicate_fingerprint.is_none() {
445 return self
446 .structural_cache_key
447 .get_or_init(|| {
448 self.intent
449 .structural_cache_key_with_normalized_predicate_fingerprint(None)
450 })
451 .clone();
452 }
453
454 self.intent
455 .structural_cache_key_with_normalized_predicate_fingerprint(predicate_fingerprint)
456 }
457
458 fn build_plan_for_visibility(
461 &self,
462 visible_indexes: Option<&VisibleIndexes<'_>>,
463 ) -> Result<AccessPlannedQuery, QueryError> {
464 match visible_indexes {
465 Some(visible_indexes) => self.build_plan_with_visible_indexes(visible_indexes),
466 None => self.build_plan(),
467 }
468 }
469
470 fn finalize_access_choice_for_visibility(
471 &self,
472 plan: &mut AccessPlannedQuery,
473 visible_indexes: Option<&VisibleIndexes<'_>>,
474 ) {
475 match visible_indexes {
476 Some(visible_indexes) => {
477 if let Some(schema_info) = visible_indexes.accepted_schema_info() {
478 plan.finalize_access_choice_for_model_with_semantic_indexes_and_schema(
479 self.intent.model(),
480 visible_indexes.accepted_semantic_index_contracts(),
481 schema_info,
482 );
483 } else {
484 plan.finalize_access_choice_for_model_only_with_indexes(
485 self.intent.model(),
486 visible_indexes.generated_model_only_indexes(),
487 );
488 }
489 }
490 None => {
491 plan.finalize_access_choice_for_model_only_with_indexes(
492 self.intent.model(),
493 self.intent.model().indexes(),
494 );
495 }
496 }
497 }
498
499 fn validate_access_requirements_for_visibility(
500 &self,
501 plan: &mut AccessPlannedQuery,
502 visible_indexes: Option<&VisibleIndexes<'_>>,
503 ) -> Result<(), QueryError> {
504 if self.access_requirements.is_empty() {
505 return Ok(());
506 }
507
508 self.finalize_access_choice_for_visibility(plan, visible_indexes);
509 self.access_requirements.validate(plan)
510 }
511
512 const fn require_index(mut self) -> Self {
513 self.access_requirements.require_index();
514 self
515 }
516
517 fn require_index_named(mut self, index_name: impl Into<String>) -> Self {
518 self.access_requirements.require_index_named(index_name);
519 self
520 }
521
522 const fn require_access_path(mut self, path: RequiredAccessPath) -> Self {
523 self.access_requirements.require_access_path(path);
524 self
525 }
526
527 const fn require_no_residual_filter(mut self) -> Self {
528 self.access_requirements.require_no_residual_filter();
529 self
530 }
531
532 #[must_use]
533 pub(in crate::db) const fn model(&self) -> &'static crate::model::entity::EntityModel {
534 self.intent.model()
535 }
536}
537
538#[derive(Clone, Debug)]
547struct QueryPlanHandle {
548 plan: Box<AccessPlannedQuery>,
549}
550
551impl QueryPlanHandle {
552 #[must_use]
553 fn from_plan(plan: AccessPlannedQuery) -> Self {
554 Self {
555 plan: Box::new(plan),
556 }
557 }
558
559 #[must_use]
560 const fn logical_plan(&self) -> &AccessPlannedQuery {
561 &self.plan
562 }
563
564 #[must_use]
565 fn plan_hash_hex(&self) -> String {
566 self.logical_plan().plan_hash_hex()
567 }
568
569 #[must_use]
570 #[cfg(test)]
571 fn into_inner(self) -> AccessPlannedQuery {
572 *self.plan
573 }
574}
575
576#[derive(Debug)]
584pub struct PlannedQuery<E: EntityKind> {
585 plan: QueryPlanHandle,
586 _marker: PhantomData<E>,
587}
588
589impl<E: EntityKind> PlannedQuery<E> {
590 #[must_use]
591 pub(in crate::db) fn from_plan(plan: AccessPlannedQuery) -> Self {
592 Self {
593 plan: QueryPlanHandle::from_plan(plan),
594 _marker: PhantomData,
595 }
596 }
597
598 #[must_use]
599 pub fn explain(&self) -> ExplainPlan {
600 self.plan.logical_plan().explain()
601 }
602
603 #[must_use]
605 pub fn plan_hash_hex(&self) -> String {
606 self.plan.plan_hash_hex()
607 }
608}
609
610#[derive(Clone, Debug)]
620pub struct CompiledQuery<E: EntityKind> {
621 plan: QueryPlanHandle,
622 _marker: PhantomData<E>,
623}
624
625impl<E: EntityKind> CompiledQuery<E> {
626 #[must_use]
627 pub(in crate::db) fn from_plan(plan: AccessPlannedQuery) -> Self {
628 Self {
629 plan: QueryPlanHandle::from_plan(plan),
630 _marker: PhantomData,
631 }
632 }
633
634 #[must_use]
635 pub fn explain(&self) -> ExplainPlan {
636 self.plan.logical_plan().explain()
637 }
638
639 #[must_use]
641 pub fn plan_hash_hex(&self) -> String {
642 self.plan.plan_hash_hex()
643 }
644
645 #[must_use]
646 #[cfg(test)]
647 pub(in crate::db) fn projection_spec(&self) -> crate::db::query::plan::expr::ProjectionSpec {
648 self.plan.logical_plan().projection_spec(E::MODEL)
649 }
650
651 #[cfg(test)]
653 pub(in crate::db) fn into_plan(self) -> AccessPlannedQuery {
654 self.plan.into_inner()
655 }
656
657 #[must_use]
658 #[cfg(test)]
659 pub(in crate::db) fn into_inner(self) -> AccessPlannedQuery {
660 self.plan.into_inner()
661 }
662}
663
664#[derive(Debug)]
676pub struct Query<E: EntityKind> {
677 inner: StructuralQuery,
678 _marker: PhantomData<E>,
679}
680
681impl<E: EntityKind> Query<E> {
682 pub(in crate::db) const fn from_inner(inner: StructuralQuery) -> Self {
684 Self {
685 inner,
686 _marker: PhantomData,
687 }
688 }
689
690 #[must_use]
694 pub const fn new(consistency: MissingRowPolicy) -> Self {
695 Self::from_inner(StructuralQuery::new(E::MODEL, consistency))
696 }
697
698 #[must_use]
700 pub const fn mode(&self) -> QueryMode {
701 self.inner.mode()
702 }
703
704 #[cfg(test)]
705 pub(in crate::db) fn explain_with_visible_indexes(
706 &self,
707 visible_indexes: &VisibleIndexes<'_>,
708 ) -> Result<ExplainPlan, QueryError> {
709 let mut plan = self.build_plan_for_visibility(Some(visible_indexes))?;
710 self.inner
711 .finalize_access_choice_for_visibility(&mut plan, Some(visible_indexes));
712
713 Ok(plan.explain())
714 }
715
716 #[cfg(test)]
717 pub(in crate::db) fn plan_hash_hex_with_visible_indexes(
718 &self,
719 visible_indexes: &VisibleIndexes<'_>,
720 ) -> Result<String, QueryError> {
721 let plan = self.build_plan_for_visibility(Some(visible_indexes))?;
722
723 Ok(plan.plan_hash_hex())
724 }
725
726 fn build_plan_for_visibility(
729 &self,
730 visible_indexes: Option<&VisibleIndexes<'_>>,
731 ) -> Result<AccessPlannedQuery, QueryError> {
732 self.inner.build_plan_for_visibility(visible_indexes)
733 }
734
735 fn map_plan_for_visibility<T>(
739 &self,
740 visible_indexes: Option<&VisibleIndexes<'_>>,
741 map: impl FnOnce(AccessPlannedQuery) -> T,
742 ) -> Result<T, QueryError> {
743 let plan = self.build_plan_for_visibility(visible_indexes)?;
744
745 Ok(map(plan))
746 }
747
748 pub(in crate::db) fn planned_query_from_plan(plan: AccessPlannedQuery) -> PlannedQuery<E> {
750 PlannedQuery::from_plan(plan)
751 }
752
753 pub(in crate::db) fn compiled_query_from_plan(plan: AccessPlannedQuery) -> CompiledQuery<E> {
755 CompiledQuery::from_plan(plan)
756 }
757
758 #[must_use]
759 pub(in crate::db::query) fn has_explicit_order(&self) -> bool {
760 self.inner.has_explicit_order()
761 }
762
763 #[must_use]
764 pub(in crate::db) const fn structural(&self) -> &StructuralQuery {
765 &self.inner
766 }
767
768 #[must_use]
769 pub const fn has_grouping(&self) -> bool {
770 self.inner.has_grouping()
771 }
772
773 #[must_use]
774 pub(in crate::db::query) const fn load_spec(&self) -> Option<LoadSpec> {
775 self.inner.load_spec()
776 }
777
778 #[must_use]
779 pub(in crate::db::query) fn with_load_limit(&self, limit: u32) -> Self {
780 Self::from_inner(self.inner.clone().limit(limit))
781 }
782
783 #[must_use]
785 pub fn filter(mut self, expr: impl Into<FilterExpr>) -> Self {
786 self.inner = self.inner.filter(expr);
787 self
788 }
789
790 #[cfg(all(test, feature = "sql"))]
794 #[must_use]
795 pub(in crate::db) fn filter_expr(mut self, expr: Expr) -> Self {
796 self.inner = self.inner.filter_expr(expr);
797 self
798 }
799
800 #[cfg(test)]
804 #[must_use]
805 pub(in crate::db) fn filter_predicate(mut self, predicate: Predicate) -> Self {
806 self.inner = self.inner.filter_predicate(predicate);
807 self
808 }
809
810 #[must_use]
812 pub fn order_term(mut self, term: FluentOrderTerm) -> Self {
813 self.inner = self.inner.order_term(term);
814 self
815 }
816
817 #[must_use]
819 pub fn order_terms<I>(mut self, terms: I) -> Self
820 where
821 I: IntoIterator<Item = FluentOrderTerm>,
822 {
823 for term in terms {
824 self.inner = self.inner.order_term(term);
825 }
826
827 self
828 }
829
830 #[must_use]
832 pub fn distinct(mut self) -> Self {
833 self.inner = self.inner.distinct();
834 self
835 }
836
837 #[cfg(all(test, feature = "sql"))]
840 #[must_use]
841 pub(in crate::db) fn select_fields<I, S>(mut self, fields: I) -> Self
842 where
843 I: IntoIterator<Item = S>,
844 S: Into<String>,
845 {
846 self.inner = self.inner.select_fields(fields);
847 self
848 }
849
850 pub fn group_by(self, field: impl AsRef<str>) -> Result<Self, QueryError> {
852 let Self { inner, .. } = self;
853 let inner = inner.group_by(field)?;
854
855 Ok(Self::from_inner(inner))
856 }
857
858 pub(in crate::db) fn group_by_with_schema(
859 self,
860 field: impl AsRef<str>,
861 schema: &SchemaInfo,
862 ) -> Result<Self, QueryError> {
863 let Self { inner, .. } = self;
864 let inner = inner.group_by_with_schema(field, schema)?;
865
866 Ok(Self::from_inner(inner))
867 }
868
869 #[must_use]
871 pub fn aggregate(mut self, aggregate: AggregateExpr) -> Self {
872 self.inner = self.inner.aggregate(aggregate);
873 self
874 }
875
876 #[must_use]
878 pub fn grouped_limits(mut self, max_groups: u64, max_group_bytes: u64) -> Self {
879 self.inner = self.inner.grouped_limits(max_groups, max_group_bytes);
880 self
881 }
882
883 pub fn having_group(
885 self,
886 field: impl AsRef<str>,
887 op: CompareOp,
888 value: InputValue,
889 ) -> Result<Self, QueryError> {
890 let field = field.as_ref().to_string();
891 let value = value.try_into_runtime_non_enum().ok_or_else(|| {
892 QueryError::validate(ValidateError::invalid_literal(
893 field.as_str(),
894 SchemaLiteralValidationReason::LiteralTypeMismatch,
895 ))
896 })?;
897 let Self { inner, .. } = self;
898 let inner = inner.having_group(field, op, value)?;
899
900 Ok(Self::from_inner(inner))
901 }
902
903 pub(in crate::db) fn having_group_with_schema(
904 self,
905 field: impl AsRef<str>,
906 schema: &SchemaInfo,
907 op: CompareOp,
908 value: InputValue,
909 ) -> Result<Self, QueryError> {
910 let field = field.as_ref().to_string();
911 let value = value.try_into_runtime_non_enum().ok_or_else(|| {
912 QueryError::validate(ValidateError::invalid_literal(
913 field.as_str(),
914 SchemaLiteralValidationReason::LiteralTypeMismatch,
915 ))
916 })?;
917 let Self { inner, .. } = self;
918 let inner = inner.having_group_with_schema(field, schema, op, value)?;
919
920 Ok(Self::from_inner(inner))
921 }
922
923 pub fn having_aggregate(
925 self,
926 aggregate_index: usize,
927 op: CompareOp,
928 value: InputValue,
929 ) -> Result<Self, QueryError> {
930 let value = value.try_into_runtime_non_enum().ok_or_else(|| {
931 QueryError::validate(ValidateError::invalid_literal(
932 "aggregate",
933 SchemaLiteralValidationReason::LiteralTypeMismatch,
934 ))
935 })?;
936 let Self { inner, .. } = self;
937 let inner = inner.having_aggregate(aggregate_index, op, value)?;
938
939 Ok(Self::from_inner(inner))
940 }
941
942 #[cfg(test)]
946 pub(in crate::db) fn having_expr(self, expr: Expr) -> Result<Self, QueryError> {
947 let Self { inner, .. } = self;
948 let inner = inner.having_expr(expr)?;
949
950 Ok(Self::from_inner(inner))
951 }
952
953 pub(in crate::db) fn by_id(self, id: E::Key) -> Self {
955 let Self { inner, .. } = self;
956
957 Self::from_inner(inner.by_id(id.to_key_value()))
958 }
959
960 pub(in crate::db) fn by_ids<I>(self, ids: I) -> Self
962 where
963 I: IntoIterator<Item = E::Key>,
964 {
965 let Self { inner, .. } = self;
966
967 Self::from_inner(inner.by_ids(ids.into_iter().map(|id| id.to_key_value())))
968 }
969
970 #[must_use]
972 pub fn delete(mut self) -> Self {
973 self.inner = self.inner.delete();
974 self
975 }
976
977 #[must_use]
984 pub fn limit(mut self, limit: u32) -> Self {
985 self.inner = self.inner.limit(limit);
986 self
987 }
988
989 #[must_use]
995 pub fn offset(mut self, offset: u32) -> Self {
996 self.inner = self.inner.offset(offset);
997 self
998 }
999
1000 #[must_use]
1005 pub fn require_index(mut self) -> Self {
1006 self.inner = self.inner.require_index();
1007 self
1008 }
1009
1010 #[must_use]
1015 pub fn require_index_named(mut self, index_name: impl Into<String>) -> Self {
1016 self.inner = self.inner.require_index_named(index_name);
1017 self
1018 }
1019
1020 #[must_use]
1024 pub fn require_access_path(mut self, path: RequiredAccessPath) -> Self {
1025 self.inner = self.inner.require_access_path(path);
1026 self
1027 }
1028
1029 #[must_use]
1034 pub fn require_no_residual_filter(mut self) -> Self {
1035 self.inner = self.inner.require_no_residual_filter();
1036 self
1037 }
1038
1039 pub fn explain(&self) -> Result<ExplainPlan, QueryError> {
1041 let mut plan = self.build_plan_for_visibility(None)?;
1042 self.inner
1043 .finalize_access_choice_for_visibility(&mut plan, None);
1044
1045 Ok(plan.explain())
1046 }
1047
1048 pub fn plan_hash_hex(&self) -> Result<String, QueryError> {
1053 let plan = self.inner.build_plan()?;
1054
1055 Ok(plan.plan_hash_hex())
1056 }
1057
1058 pub fn planned(&self) -> Result<PlannedQuery<E>, QueryError> {
1060 self.map_plan_for_visibility(None, Self::planned_query_from_plan)
1061 }
1062
1063 pub fn plan(&self) -> Result<CompiledQuery<E>, QueryError> {
1067 self.map_plan_for_visibility(None, Self::compiled_query_from_plan)
1068 }
1069
1070 #[cfg(test)]
1071 pub(in crate::db) fn plan_with_visible_indexes(
1072 &self,
1073 visible_indexes: &VisibleIndexes<'_>,
1074 ) -> Result<CompiledQuery<E>, QueryError> {
1075 self.map_plan_for_visibility(Some(visible_indexes), Self::compiled_query_from_plan)
1076 }
1077}
1078
1079impl<E> Query<E>
1080where
1081 E: EntityKind + SingletonEntity,
1082 E::Key: Default,
1083{
1084 pub(in crate::db) fn singleton(self) -> Self {
1086 let Self { inner, .. } = self;
1087
1088 Self::from_inner(inner.only(E::Key::default().to_key_value()))
1089 }
1090}