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