1use std::num::NonZeroU32;
16
17#[cfg(feature = "diagnostics")]
18use crate::db::FluentTerminalExecutionAttribution;
19#[cfg(feature = "diagnostics")]
20use crate::db::QueryExecutionAttribution;
21use crate::db::query::read_intent::ReadIntentKind;
22use crate::{
23 db::{
24 DbSession, PersistedRow, Query,
25 query::{
26 admission::QueryAdmissionPolicy,
27 api::ResponseCardinalityExt,
28 builder::{
29 AvgBySlotTerminal, AvgDistinctBySlotTerminal, CountDistinctBySlotTerminal,
30 CountRowsTerminal, DistinctValuesBySlotTerminal, ExistsRowsTerminal,
31 FirstIdTerminal, FirstValueBySlotTerminal, LastIdTerminal, LastValueBySlotTerminal,
32 MaxIdBySlotTerminal, MaxIdTerminal, MedianIdBySlotTerminal, MinIdBySlotTerminal,
33 MinIdTerminal, MinMaxIdBySlotTerminal, NthIdBySlotTerminal, SumBySlotTerminal,
34 SumDistinctBySlotTerminal, ValueProjectionExpr, ValuesBySlotTerminal,
35 ValuesBySlotWithIdsTerminal,
36 },
37 explain::{ExplainAggregateTerminalPlan, ExplainExecutionNodeDescriptor},
38 fluent::load::{FluentLoadQuery, LoadQueryResult},
39 intent::{IntentError, QueryError},
40 plan::AggregateKind,
41 read_intent::{
42 COMPLETE_SMALL_EXECUTION_LIMIT, COMPLETE_SMALL_MAX_ROWS,
43 PUBLIC_PAGE_MAX_RESPONSE_BYTES,
44 },
45 },
46 response::EntityResponse,
47 },
48 traits::EntityValue,
49 types::{Decimal, Id},
50 value::{OutputValue, Value},
51};
52
53type MinMaxByIds<E> = Option<(Id<E>, Id<E>)>;
54
55trait TerminalStrategyDriver<E: PersistedRow + EntityValue> {
65 type Output;
66 type ExplainOutput;
67
68 fn execute(
69 self,
70 session: &DbSession<E::Canister>,
71 query: &Query<E>,
72 ) -> Result<Self::Output, QueryError>;
73
74 fn explain(
75 &self,
76 session: &DbSession<E::Canister>,
77 query: &Query<E>,
78 ) -> Result<Self::ExplainOutput, QueryError>;
79}
80
81macro_rules! impl_aggregate_terminal_driver {
85 ($terminal:ty, $output:ty, $execute:ident) => {
86 impl<E> TerminalStrategyDriver<E> for $terminal
87 where
88 E: PersistedRow + EntityValue,
89 {
90 type Output = $output;
91 type ExplainOutput = ExplainAggregateTerminalPlan;
92
93 fn execute(
94 self,
95 session: &DbSession<E::Canister>,
96 query: &Query<E>,
97 ) -> Result<Self::Output, QueryError> {
98 session.$execute(query, self)
99 }
100
101 fn explain(
102 &self,
103 session: &DbSession<E::Canister>,
104 query: &Query<E>,
105 ) -> Result<Self::ExplainOutput, QueryError> {
106 session.explain_query_prepared_aggregate_terminal_with_visible_indexes(query, self)
107 }
108 }
109 };
110}
111
112macro_rules! impl_projection_terminal_driver {
116 ($terminal:ty, $output:ty, $execute:ident) => {
117 impl<E> TerminalStrategyDriver<E> for $terminal
118 where
119 E: PersistedRow + EntityValue,
120 {
121 type Output = $output;
122 type ExplainOutput = ExplainExecutionNodeDescriptor;
123
124 fn execute(
125 self,
126 session: &DbSession<E::Canister>,
127 query: &Query<E>,
128 ) -> Result<Self::Output, QueryError> {
129 session.$execute(query, self)
130 }
131
132 fn explain(
133 &self,
134 session: &DbSession<E::Canister>,
135 query: &Query<E>,
136 ) -> Result<Self::ExplainOutput, QueryError> {
137 session.explain_query_prepared_projection_terminal_with_visible_indexes(query, self)
138 }
139 }
140 };
141}
142
143impl_aggregate_terminal_driver!(CountRowsTerminal, u32, execute_fluent_count_rows_terminal);
144impl_aggregate_terminal_driver!(
145 ExistsRowsTerminal,
146 bool,
147 execute_fluent_exists_rows_terminal
148);
149impl_aggregate_terminal_driver!(MinIdTerminal, Option<Id<E>>, execute_fluent_min_id_terminal);
150impl_aggregate_terminal_driver!(MaxIdTerminal, Option<Id<E>>, execute_fluent_max_id_terminal);
151impl_aggregate_terminal_driver!(
152 MinIdBySlotTerminal,
153 Option<Id<E>>,
154 execute_fluent_min_id_by_slot
155);
156impl_aggregate_terminal_driver!(
157 MaxIdBySlotTerminal,
158 Option<Id<E>>,
159 execute_fluent_max_id_by_slot
160);
161impl_aggregate_terminal_driver!(
162 SumBySlotTerminal,
163 Option<Decimal>,
164 execute_fluent_sum_by_slot
165);
166impl_aggregate_terminal_driver!(
167 SumDistinctBySlotTerminal,
168 Option<Decimal>,
169 execute_fluent_sum_distinct_by_slot
170);
171impl_aggregate_terminal_driver!(
172 AvgBySlotTerminal,
173 Option<Decimal>,
174 execute_fluent_avg_by_slot
175);
176impl_aggregate_terminal_driver!(
177 AvgDistinctBySlotTerminal,
178 Option<Decimal>,
179 execute_fluent_avg_distinct_by_slot
180);
181impl_aggregate_terminal_driver!(
182 FirstIdTerminal,
183 Option<Id<E>>,
184 execute_fluent_first_id_terminal
185);
186impl_aggregate_terminal_driver!(
187 LastIdTerminal,
188 Option<Id<E>>,
189 execute_fluent_last_id_terminal
190);
191impl_aggregate_terminal_driver!(
192 NthIdBySlotTerminal,
193 Option<Id<E>>,
194 execute_fluent_nth_id_by_slot
195);
196impl_aggregate_terminal_driver!(
197 MedianIdBySlotTerminal,
198 Option<Id<E>>,
199 execute_fluent_median_id_by_slot
200);
201impl_aggregate_terminal_driver!(
202 MinMaxIdBySlotTerminal,
203 MinMaxByIds<E>,
204 execute_fluent_min_max_id_by_slot
205);
206
207impl_projection_terminal_driver!(
208 ValuesBySlotTerminal,
209 Vec<Value>,
210 execute_fluent_values_by_slot
211);
212impl_projection_terminal_driver!(
213 DistinctValuesBySlotTerminal,
214 Vec<Value>,
215 execute_fluent_distinct_values_by_slot
216);
217impl_projection_terminal_driver!(
218 CountDistinctBySlotTerminal,
219 u32,
220 execute_fluent_count_distinct_by_slot
221);
222impl_projection_terminal_driver!(
223 ValuesBySlotWithIdsTerminal,
224 Vec<(Id<E>, Value)>,
225 execute_fluent_values_by_with_ids_slot
226);
227impl_projection_terminal_driver!(
228 FirstValueBySlotTerminal,
229 Option<Value>,
230 execute_fluent_first_value_by_slot
231);
232impl_projection_terminal_driver!(
233 LastValueBySlotTerminal,
234 Option<Value>,
235 execute_fluent_last_value_by_slot
236);
237
238fn output(value: Value) -> OutputValue {
240 OutputValue::from(value)
241}
242
243fn output_values(values: Vec<Value>) -> Vec<OutputValue> {
245 values.into_iter().map(output).collect()
246}
247
248fn output_values_with_ids<E: PersistedRow>(
250 values: Vec<(Id<E>, Value)>,
251) -> Vec<(Id<E>, OutputValue)> {
252 values
253 .into_iter()
254 .map(|(id, value)| (id, output(value)))
255 .collect()
256}
257
258fn non_zero_u32(value: u32) -> Result<NonZeroU32, QueryError> {
259 NonZeroU32::new(value).ok_or_else(QueryError::invariant)
260}
261
262fn collect_complete_entities<E>(response: EntityResponse<E>) -> Result<Vec<E>, QueryError>
263where
264 E: PersistedRow,
265{
266 if response.count() > COMPLETE_SMALL_MAX_ROWS {
267 return Err(QueryError::intent(
268 IntentError::complete_read_too_many_rows(),
269 ));
270 }
271
272 Ok(response.entities())
273}
274
275impl<E> FluentLoadQuery<'_, E>
276where
277 E: PersistedRow,
278{
279 pub fn execute(&self) -> Result<LoadQueryResult<E>, QueryError>
285 where
286 E: EntityValue,
287 {
288 self.with_admitted_non_paged(DbSession::execute_query_result)
289 }
290
291 pub fn execute_rows(&self) -> Result<EntityResponse<E>, QueryError>
293 where
294 E: EntityValue,
295 {
296 self.with_admitted_non_paged(DbSession::execute_scalar_query_rows)
297 }
298
299 fn with_admitted_non_paged<T>(
300 &self,
301 map: impl FnOnce(&DbSession<E::Canister>, &Query<E>) -> Result<T, QueryError>,
302 ) -> Result<T, QueryError>
303 where
304 E: EntityValue,
305 {
306 self.ensure_non_paged_mode_ready()?;
307 self.ensure_default_read_admission()?;
308 map(self.session, self.query())
309 }
310
311 fn with_non_paged<T>(
314 &self,
315 map: impl FnOnce(&DbSession<E::Canister>, &Query<E>) -> Result<T, QueryError>,
316 ) -> Result<T, QueryError>
317 where
318 E: EntityValue,
319 {
320 self.ensure_non_paged_mode_ready()?;
321 map(self.session, self.query())
322 }
323
324 fn explain_execution_descriptor(&self) -> Result<ExplainExecutionNodeDescriptor, QueryError>
327 where
328 E: EntityValue,
329 {
330 self.with_non_paged(DbSession::explain_query_execution_with_visible_indexes)
331 }
332
333 fn render_execution_descriptor(
336 &self,
337 render: impl FnOnce(ExplainExecutionNodeDescriptor) -> String,
338 ) -> Result<String, QueryError>
339 where
340 E: EntityValue,
341 {
342 let descriptor = self.explain_execution_descriptor()?;
343
344 Ok(render(descriptor))
345 }
346
347 fn execute_terminal<S>(&self, strategy: S) -> Result<S::Output, QueryError>
350 where
351 E: EntityValue,
352 S: TerminalStrategyDriver<E>,
353 {
354 self.with_admitted_non_paged(|session, query| strategy.execute(session, query))
355 }
356
357 fn explain_terminal<S>(&self, strategy: &S) -> Result<S::ExplainOutput, QueryError>
360 where
361 E: EntityValue,
362 S: TerminalStrategyDriver<E>,
363 {
364 self.with_non_paged(|session, query| strategy.explain(session, query))
365 }
366
367 fn explain_exact_aggregate_terminal<S>(
368 &self,
369 strategy: &S,
370 ) -> Result<ExplainAggregateTerminalPlan, QueryError>
371 where
372 E: EntityValue,
373 S: TerminalStrategyDriver<E, ExplainOutput = ExplainAggregateTerminalPlan>,
374 {
375 self.explain_terminal(strategy)
376 .map(|plan| plan.with_read_intent(ReadIntentKind::ExactAggregate))
377 }
378
379 fn ensure_exists_intent_owns_limit(&self) -> Result<(), QueryError> {
380 self.ensure_semantic_terminal_owns_limit(IntentError::raw_limit_before_exists_terminal())
381 }
382
383 fn ensure_count_exact_intent_owns_limit(&self) -> Result<(), QueryError> {
384 self.ensure_exact_aggregate_intent_owns_limit(
385 IntentError::raw_limit_before_count_exact_terminal(),
386 )
387 }
388
389 fn ensure_sum_exact_intent_owns_limit(&self) -> Result<(), QueryError> {
390 self.ensure_exact_aggregate_intent_owns_limit(
391 IntentError::raw_limit_before_sum_exact_terminal(),
392 )
393 }
394
395 fn ensure_min_exact_intent_owns_limit(&self) -> Result<(), QueryError> {
396 self.ensure_exact_aggregate_intent_owns_limit(
397 IntentError::raw_limit_before_min_exact_terminal(),
398 )
399 }
400
401 fn ensure_max_exact_intent_owns_limit(&self) -> Result<(), QueryError> {
402 self.ensure_exact_aggregate_intent_owns_limit(
403 IntentError::raw_limit_before_max_exact_terminal(),
404 )
405 }
406
407 fn ensure_avg_exact_intent_owns_limit(&self) -> Result<(), QueryError> {
408 self.ensure_exact_aggregate_intent_owns_limit(
409 IntentError::raw_limit_before_avg_exact_terminal(),
410 )
411 }
412
413 fn ensure_exact_aggregate_intent_owns_limit(&self, err: IntentError) -> Result<(), QueryError> {
414 self.ensure_semantic_terminal_owns_limit(err)
415 }
416
417 fn ensure_collect_complete_intent_owns_limit(&self) -> Result<(), QueryError> {
418 self.ensure_semantic_terminal_owns_limit(
419 IntentError::raw_limit_before_collect_complete_terminal(),
420 )
421 }
422
423 pub fn is_empty(&self) -> Result<bool, QueryError>
429 where
430 E: EntityValue,
431 {
432 self.not_exists()
433 }
434
435 pub fn not_exists(&self) -> Result<bool, QueryError>
437 where
438 E: EntityValue,
439 {
440 Ok(!self.exists()?)
441 }
442
443 pub fn exists(&self) -> Result<bool, QueryError>
445 where
446 E: EntityValue,
447 {
448 self.ensure_exists_intent_owns_limit()?;
449
450 self.execute_terminal(ExistsRowsTerminal::new())
451 }
452
453 #[cfg(feature = "diagnostics")]
456 #[doc(hidden)]
457 pub fn exists_with_attribution(
458 &self,
459 ) -> Result<(bool, FluentTerminalExecutionAttribution), QueryError>
460 where
461 E: EntityValue,
462 {
463 self.ensure_exists_intent_owns_limit()?;
464
465 let (exists, attribution) = self.with_admitted_non_paged(|session, query| {
466 session.execute_fluent_exists_rows_terminal_with_attribution(
467 query,
468 ExistsRowsTerminal::new(),
469 )
470 })?;
471
472 Ok((
473 exists,
474 attribution.with_read_intent(ReadIntentKind::ExistenceCheck),
475 ))
476 }
477
478 pub fn explain_exists(&self) -> Result<ExplainAggregateTerminalPlan, QueryError>
480 where
481 E: EntityValue,
482 {
483 self.ensure_exists_intent_owns_limit()?;
484
485 self.explain_terminal(&ExistsRowsTerminal::new())
486 .map(|plan| plan.with_read_intent(ReadIntentKind::ExistenceCheck))
487 }
488
489 pub fn collect_complete(&self) -> Result<Vec<E>, QueryError>
496 where
497 E: EntityValue,
498 {
499 self.ensure_collect_complete_intent_owns_limit()?;
500 self.ensure_non_paged_mode_ready()?;
501
502 let query = self.query().with_load_limit(COMPLETE_SMALL_EXECUTION_LIMIT);
503 let policy = QueryAdmissionPolicy::public_read(
504 non_zero_u32(COMPLETE_SMALL_EXECUTION_LIMIT)?,
505 non_zero_u32(PUBLIC_PAGE_MAX_RESPONSE_BYTES)?,
506 );
507
508 self.session
509 .ensure_query_read_admission_policy(&query, &policy)?;
510
511 let response = self.session.execute_scalar_query_rows(&query)?;
512
513 collect_complete_entities(response)
514 }
515
516 #[cfg(feature = "diagnostics")]
519 #[doc(hidden)]
520 pub fn collect_complete_with_attribution(
521 &self,
522 ) -> Result<(Vec<E>, QueryExecutionAttribution), QueryError>
523 where
524 E: EntityValue,
525 {
526 self.ensure_collect_complete_intent_owns_limit()?;
527 self.ensure_non_paged_mode_ready()?;
528
529 let query = self.query().with_load_limit(COMPLETE_SMALL_EXECUTION_LIMIT);
530 let policy = QueryAdmissionPolicy::public_read(
531 non_zero_u32(COMPLETE_SMALL_EXECUTION_LIMIT)?,
532 non_zero_u32(PUBLIC_PAGE_MAX_RESPONSE_BYTES)?,
533 );
534
535 self.session
536 .ensure_query_read_admission_policy(&query, &policy)?;
537
538 let (result, attribution) = self.session.execute_query_result_with_attribution(&query)?;
539 let response = result.into_rows()?;
540 let entities = collect_complete_entities(response)?;
541
542 Ok((
543 entities,
544 attribution.with_read_intent(ReadIntentKind::CompleteSmallSet),
545 ))
546 }
547
548 pub fn explain_not_exists(&self) -> Result<ExplainAggregateTerminalPlan, QueryError>
552 where
553 E: EntityValue,
554 {
555 self.explain_exists()
556 }
557
558 pub fn explain_execution(&self) -> Result<ExplainExecutionNodeDescriptor, QueryError>
560 where
561 E: EntityValue,
562 {
563 self.explain_execution_descriptor()
564 }
565
566 pub fn explain_execution_text(&self) -> Result<String, QueryError>
568 where
569 E: EntityValue,
570 {
571 self.render_execution_descriptor(|descriptor| descriptor.render_text_tree())
572 }
573
574 pub fn explain_execution_json(&self) -> Result<String, QueryError>
576 where
577 E: EntityValue,
578 {
579 self.with_non_paged(DbSession::explain_query_execution_json_with_visible_indexes)
580 }
581
582 pub fn explain_execution_verbose(&self) -> Result<String, QueryError>
584 where
585 E: EntityValue,
586 {
587 self.with_non_paged(DbSession::explain_query_execution_verbose_with_visible_indexes)
588 }
589
590 pub fn count(&self) -> Result<u32, QueryError>
592 where
593 E: EntityValue,
594 {
595 self.execute_terminal(CountRowsTerminal::new())
596 }
597
598 pub fn count_exact(&self) -> Result<u32, QueryError>
604 where
605 E: EntityValue,
606 {
607 self.ensure_count_exact_intent_owns_limit()?;
608
609 self.execute_terminal(CountRowsTerminal::new())
610 }
611
612 pub fn explain_count_exact(&self) -> Result<ExplainAggregateTerminalPlan, QueryError>
614 where
615 E: EntityValue,
616 {
617 self.ensure_count_exact_intent_owns_limit()?;
618
619 self.explain_exact_aggregate_terminal(&CountRowsTerminal::new())
620 }
621
622 #[cfg(feature = "diagnostics")]
624 #[doc(hidden)]
625 pub fn count_with_attribution(
626 &self,
627 ) -> Result<(u32, FluentTerminalExecutionAttribution), QueryError>
628 where
629 E: EntityValue,
630 {
631 let (count, attribution) = self.with_admitted_non_paged(|session, query| {
632 session.execute_fluent_count_rows_terminal_with_attribution(
633 query,
634 CountRowsTerminal::new(),
635 )
636 })?;
637
638 Ok((
639 count,
640 attribution.with_read_intent(ReadIntentKind::BoundedRowWindow),
641 ))
642 }
643
644 #[cfg(feature = "diagnostics")]
646 #[doc(hidden)]
647 pub fn count_exact_with_attribution(
648 &self,
649 ) -> Result<(u32, FluentTerminalExecutionAttribution), QueryError>
650 where
651 E: EntityValue,
652 {
653 self.ensure_count_exact_intent_owns_limit()?;
654
655 let (count, attribution) = self.with_admitted_non_paged(|session, query| {
656 session.execute_fluent_count_rows_terminal_with_attribution(
657 query,
658 CountRowsTerminal::new(),
659 )
660 })?;
661
662 Ok((
663 count,
664 attribution.with_read_intent(ReadIntentKind::ExactAggregate),
665 ))
666 }
667
668 pub fn bytes(&self) -> Result<u64, QueryError>
671 where
672 E: EntityValue,
673 {
674 self.with_admitted_non_paged(DbSession::execute_fluent_bytes)
675 }
676
677 pub fn bytes_by(&self, field: impl AsRef<str>) -> Result<u64, QueryError>
680 where
681 E: EntityValue,
682 {
683 let target_slot = self.resolve_non_paged_slot(field)?;
684
685 self.with_admitted_non_paged(|session, query| {
686 session.execute_fluent_bytes_by_slot(query, target_slot)
687 })
688 }
689
690 pub fn explain_bytes_by(
692 &self,
693 field: impl AsRef<str>,
694 ) -> Result<ExplainExecutionNodeDescriptor, QueryError>
695 where
696 E: EntityValue,
697 {
698 let target_slot = self.resolve_non_paged_slot(field)?;
699
700 self.with_non_paged(|session, query| {
701 session.explain_query_bytes_by_with_visible_indexes(query, target_slot.field())
702 })
703 }
704
705 pub fn min(&self) -> Result<Option<Id<E>>, QueryError>
707 where
708 E: EntityValue,
709 {
710 self.execute_terminal(MinIdTerminal::new())
711 }
712
713 pub fn min_id_exact(&self) -> Result<Option<Id<E>>, QueryError>
719 where
720 E: EntityValue,
721 {
722 self.ensure_min_exact_intent_owns_limit()?;
723
724 self.execute_terminal(MinIdTerminal::new())
725 }
726
727 pub fn explain_min(&self) -> Result<ExplainAggregateTerminalPlan, QueryError>
729 where
730 E: EntityValue,
731 {
732 self.explain_terminal(&MinIdTerminal::new())
733 }
734
735 pub fn explain_min_id_exact(&self) -> Result<ExplainAggregateTerminalPlan, QueryError>
737 where
738 E: EntityValue,
739 {
740 self.ensure_min_exact_intent_owns_limit()?;
741
742 self.explain_exact_aggregate_terminal(&MinIdTerminal::new())
743 }
744
745 pub fn min_by(&self, field: impl AsRef<str>) -> Result<Option<Id<E>>, QueryError>
749 where
750 E: EntityValue,
751 {
752 let target_slot = self.resolve_non_paged_slot(field)?;
753
754 self.execute_terminal(MinIdBySlotTerminal::new(target_slot))
755 }
756
757 pub fn min_exact_by(&self, field: impl AsRef<str>) -> Result<Option<Id<E>>, QueryError>
763 where
764 E: EntityValue,
765 {
766 self.ensure_min_exact_intent_owns_limit()?;
767
768 let target_slot = self.resolve_non_paged_slot(field)?;
769
770 self.execute_terminal(MinIdBySlotTerminal::new(target_slot))
771 }
772
773 pub fn explain_min_exact_by(
775 &self,
776 field: impl AsRef<str>,
777 ) -> Result<ExplainAggregateTerminalPlan, QueryError>
778 where
779 E: EntityValue,
780 {
781 self.ensure_min_exact_intent_owns_limit()?;
782
783 let target_slot = self.resolve_non_paged_slot(field)?;
784
785 self.explain_exact_aggregate_terminal(&MinIdBySlotTerminal::new(target_slot))
786 }
787
788 pub fn max(&self) -> Result<Option<Id<E>>, QueryError>
790 where
791 E: EntityValue,
792 {
793 self.execute_terminal(MaxIdTerminal::new())
794 }
795
796 pub fn max_id_exact(&self) -> Result<Option<Id<E>>, QueryError>
802 where
803 E: EntityValue,
804 {
805 self.ensure_max_exact_intent_owns_limit()?;
806
807 self.execute_terminal(MaxIdTerminal::new())
808 }
809
810 pub fn explain_max(&self) -> Result<ExplainAggregateTerminalPlan, QueryError>
812 where
813 E: EntityValue,
814 {
815 self.explain_terminal(&MaxIdTerminal::new())
816 }
817
818 pub fn explain_max_id_exact(&self) -> Result<ExplainAggregateTerminalPlan, QueryError>
820 where
821 E: EntityValue,
822 {
823 self.ensure_max_exact_intent_owns_limit()?;
824
825 self.explain_exact_aggregate_terminal(&MaxIdTerminal::new())
826 }
827
828 pub fn max_by(&self, field: impl AsRef<str>) -> Result<Option<Id<E>>, QueryError>
832 where
833 E: EntityValue,
834 {
835 let target_slot = self.resolve_non_paged_slot(field)?;
836
837 self.execute_terminal(MaxIdBySlotTerminal::new(target_slot))
838 }
839
840 pub fn max_exact_by(&self, field: impl AsRef<str>) -> Result<Option<Id<E>>, QueryError>
846 where
847 E: EntityValue,
848 {
849 self.ensure_max_exact_intent_owns_limit()?;
850
851 let target_slot = self.resolve_non_paged_slot(field)?;
852
853 self.execute_terminal(MaxIdBySlotTerminal::new(target_slot))
854 }
855
856 pub fn explain_max_exact_by(
858 &self,
859 field: impl AsRef<str>,
860 ) -> Result<ExplainAggregateTerminalPlan, QueryError>
861 where
862 E: EntityValue,
863 {
864 self.ensure_max_exact_intent_owns_limit()?;
865
866 let target_slot = self.resolve_non_paged_slot(field)?;
867
868 self.explain_exact_aggregate_terminal(&MaxIdBySlotTerminal::new(target_slot))
869 }
870
871 pub fn nth_by(&self, field: impl AsRef<str>, nth: usize) -> Result<Option<Id<E>>, QueryError>
874 where
875 E: EntityValue,
876 {
877 let target_slot = self.resolve_non_paged_slot(field)?;
878
879 self.execute_terminal(NthIdBySlotTerminal::new(target_slot, nth))
880 }
881
882 pub fn sum_by(&self, field: impl AsRef<str>) -> Result<Option<Decimal>, QueryError>
884 where
885 E: EntityValue,
886 {
887 let target_slot = self.resolve_non_paged_slot(field)?;
888
889 self.execute_terminal(SumBySlotTerminal::new(target_slot))
890 }
891
892 pub fn sum_exact(&self, field: impl AsRef<str>) -> Result<Option<Decimal>, QueryError>
898 where
899 E: EntityValue,
900 {
901 self.ensure_sum_exact_intent_owns_limit()?;
902
903 let target_slot = self.resolve_non_paged_slot(field)?;
904
905 self.execute_terminal(SumBySlotTerminal::new(target_slot))
906 }
907
908 pub fn explain_sum_exact(
910 &self,
911 field: impl AsRef<str>,
912 ) -> Result<ExplainAggregateTerminalPlan, QueryError>
913 where
914 E: EntityValue,
915 {
916 self.ensure_sum_exact_intent_owns_limit()?;
917
918 let target_slot = self.resolve_non_paged_slot(field)?;
919
920 self.explain_exact_aggregate_terminal(&SumBySlotTerminal::new(target_slot))
921 }
922
923 pub fn explain_sum_by(
925 &self,
926 field: impl AsRef<str>,
927 ) -> Result<ExplainAggregateTerminalPlan, QueryError>
928 where
929 E: EntityValue,
930 {
931 let target_slot = self.resolve_non_paged_slot(field)?;
932
933 self.explain_terminal(&SumBySlotTerminal::new(target_slot))
934 }
935
936 pub fn sum_distinct_by(&self, field: impl AsRef<str>) -> Result<Option<Decimal>, QueryError>
938 where
939 E: EntityValue,
940 {
941 let target_slot = self.resolve_non_paged_slot(field)?;
942
943 self.execute_terminal(SumDistinctBySlotTerminal::new(target_slot))
944 }
945
946 pub fn explain_sum_distinct_by(
948 &self,
949 field: impl AsRef<str>,
950 ) -> Result<ExplainAggregateTerminalPlan, QueryError>
951 where
952 E: EntityValue,
953 {
954 let target_slot = self.resolve_non_paged_slot(field)?;
955
956 self.explain_terminal(&SumDistinctBySlotTerminal::new(target_slot))
957 }
958
959 pub fn avg_by(&self, field: impl AsRef<str>) -> Result<Option<Decimal>, QueryError>
961 where
962 E: EntityValue,
963 {
964 let target_slot = self.resolve_non_paged_slot(field)?;
965
966 self.execute_terminal(AvgBySlotTerminal::new(target_slot))
967 }
968
969 pub fn avg_exact(&self, field: impl AsRef<str>) -> Result<Option<Decimal>, QueryError>
975 where
976 E: EntityValue,
977 {
978 self.ensure_avg_exact_intent_owns_limit()?;
979
980 let target_slot = self.resolve_non_paged_slot(field)?;
981
982 self.execute_terminal(AvgBySlotTerminal::new(target_slot))
983 }
984
985 pub fn explain_avg_by(
987 &self,
988 field: impl AsRef<str>,
989 ) -> Result<ExplainAggregateTerminalPlan, QueryError>
990 where
991 E: EntityValue,
992 {
993 let target_slot = self.resolve_non_paged_slot(field)?;
994
995 self.explain_terminal(&AvgBySlotTerminal::new(target_slot))
996 }
997
998 pub fn explain_avg_exact(
1000 &self,
1001 field: impl AsRef<str>,
1002 ) -> Result<ExplainAggregateTerminalPlan, QueryError>
1003 where
1004 E: EntityValue,
1005 {
1006 self.ensure_avg_exact_intent_owns_limit()?;
1007
1008 let target_slot = self.resolve_non_paged_slot(field)?;
1009
1010 self.explain_exact_aggregate_terminal(&AvgBySlotTerminal::new(target_slot))
1011 }
1012
1013 pub fn avg_distinct_by(&self, field: impl AsRef<str>) -> Result<Option<Decimal>, QueryError>
1015 where
1016 E: EntityValue,
1017 {
1018 let target_slot = self.resolve_non_paged_slot(field)?;
1019
1020 self.execute_terminal(AvgDistinctBySlotTerminal::new(target_slot))
1021 }
1022
1023 pub fn explain_avg_distinct_by(
1025 &self,
1026 field: impl AsRef<str>,
1027 ) -> Result<ExplainAggregateTerminalPlan, QueryError>
1028 where
1029 E: EntityValue,
1030 {
1031 let target_slot = self.resolve_non_paged_slot(field)?;
1032
1033 self.explain_terminal(&AvgDistinctBySlotTerminal::new(target_slot))
1034 }
1035
1036 pub fn median_by(&self, field: impl AsRef<str>) -> Result<Option<Id<E>>, QueryError>
1041 where
1042 E: EntityValue,
1043 {
1044 let target_slot = self.resolve_non_paged_slot(field)?;
1045
1046 self.execute_terminal(MedianIdBySlotTerminal::new(target_slot))
1047 }
1048
1049 pub fn count_distinct_by(&self, field: impl AsRef<str>) -> Result<u32, QueryError>
1052 where
1053 E: EntityValue,
1054 {
1055 let target_slot = self.resolve_non_paged_slot(field)?;
1056
1057 self.execute_terminal(CountDistinctBySlotTerminal::new(target_slot))
1058 }
1059
1060 pub fn explain_count_distinct_by(
1062 &self,
1063 field: impl AsRef<str>,
1064 ) -> Result<ExplainExecutionNodeDescriptor, QueryError>
1065 where
1066 E: EntityValue,
1067 {
1068 let target_slot = self.resolve_non_paged_slot(field)?;
1069
1070 self.explain_terminal(&CountDistinctBySlotTerminal::new(target_slot))
1071 }
1072
1073 pub fn min_max_by(&self, field: impl AsRef<str>) -> Result<MinMaxByIds<E>, QueryError>
1077 where
1078 E: EntityValue,
1079 {
1080 let target_slot = self.resolve_non_paged_slot(field)?;
1081
1082 self.execute_terminal(MinMaxIdBySlotTerminal::new(target_slot))
1083 }
1084
1085 pub fn values_by(&self, field: impl AsRef<str>) -> Result<Vec<OutputValue>, QueryError>
1087 where
1088 E: EntityValue,
1089 {
1090 let target_slot = self.resolve_non_paged_slot(field)?;
1091
1092 self.execute_terminal(ValuesBySlotTerminal::new(target_slot))
1093 .map(output_values)
1094 }
1095
1096 pub fn project_values<P>(&self, projection: &P) -> Result<Vec<OutputValue>, QueryError>
1099 where
1100 E: EntityValue,
1101 P: ValueProjectionExpr,
1102 {
1103 let target_slot = self.resolve_non_paged_slot(projection.field())?;
1104
1105 self.with_admitted_non_paged(|session, query| {
1106 session.execute_fluent_project_values_by_slot(
1107 query,
1108 target_slot,
1109 projection.projection_plan().into_expr(),
1110 )
1111 })
1112 .map(output_values)
1113 }
1114
1115 pub fn explain_project_values<P>(
1117 &self,
1118 projection: &P,
1119 ) -> Result<ExplainExecutionNodeDescriptor, QueryError>
1120 where
1121 E: EntityValue,
1122 P: ValueProjectionExpr,
1123 {
1124 let target_slot = self.resolve_non_paged_slot(projection.field())?;
1125
1126 self.explain_terminal(&ValuesBySlotTerminal::new(target_slot))
1127 }
1128
1129 pub fn explain_values_by(
1131 &self,
1132 field: impl AsRef<str>,
1133 ) -> Result<ExplainExecutionNodeDescriptor, QueryError>
1134 where
1135 E: EntityValue,
1136 {
1137 let target_slot = self.resolve_non_paged_slot(field)?;
1138
1139 self.explain_terminal(&ValuesBySlotTerminal::new(target_slot))
1140 }
1141
1142 pub fn take(&self, take_count: u32) -> Result<EntityResponse<E>, QueryError>
1144 where
1145 E: EntityValue,
1146 {
1147 self.with_admitted_non_paged(|session, query| {
1148 session.execute_fluent_take(query, take_count)
1149 })
1150 }
1151
1152 pub fn top_k_by(
1160 &self,
1161 field: impl AsRef<str>,
1162 take_count: u32,
1163 ) -> Result<EntityResponse<E>, QueryError>
1164 where
1165 E: EntityValue,
1166 {
1167 let target_slot = self.resolve_non_paged_slot(field)?;
1168
1169 self.with_admitted_non_paged(|session, query| {
1170 session.execute_fluent_top_k_rows_by_slot(query, target_slot, take_count)
1171 })
1172 }
1173
1174 pub fn bottom_k_by(
1182 &self,
1183 field: impl AsRef<str>,
1184 take_count: u32,
1185 ) -> Result<EntityResponse<E>, QueryError>
1186 where
1187 E: EntityValue,
1188 {
1189 let target_slot = self.resolve_non_paged_slot(field)?;
1190
1191 self.with_admitted_non_paged(|session, query| {
1192 session.execute_fluent_bottom_k_rows_by_slot(query, target_slot, take_count)
1193 })
1194 }
1195
1196 pub fn top_k_by_values(
1204 &self,
1205 field: impl AsRef<str>,
1206 take_count: u32,
1207 ) -> Result<Vec<OutputValue>, QueryError>
1208 where
1209 E: EntityValue,
1210 {
1211 let target_slot = self.resolve_non_paged_slot(field)?;
1212
1213 self.with_admitted_non_paged(|session, query| {
1214 session
1215 .execute_fluent_top_k_values_by_slot(query, target_slot, take_count)
1216 .map(output_values)
1217 })
1218 }
1219
1220 pub fn bottom_k_by_values(
1228 &self,
1229 field: impl AsRef<str>,
1230 take_count: u32,
1231 ) -> Result<Vec<OutputValue>, QueryError>
1232 where
1233 E: EntityValue,
1234 {
1235 let target_slot = self.resolve_non_paged_slot(field)?;
1236
1237 self.with_admitted_non_paged(|session, query| {
1238 session
1239 .execute_fluent_bottom_k_values_by_slot(query, target_slot, take_count)
1240 .map(output_values)
1241 })
1242 }
1243
1244 pub fn top_k_by_with_ids(
1252 &self,
1253 field: impl AsRef<str>,
1254 take_count: u32,
1255 ) -> Result<Vec<(Id<E>, OutputValue)>, QueryError>
1256 where
1257 E: EntityValue,
1258 {
1259 let target_slot = self.resolve_non_paged_slot(field)?;
1260
1261 self.with_admitted_non_paged(|session, query| {
1262 session
1263 .execute_fluent_top_k_values_with_ids_by_slot(query, target_slot, take_count)
1264 .map(output_values_with_ids)
1265 })
1266 }
1267
1268 pub fn bottom_k_by_with_ids(
1276 &self,
1277 field: impl AsRef<str>,
1278 take_count: u32,
1279 ) -> Result<Vec<(Id<E>, OutputValue)>, QueryError>
1280 where
1281 E: EntityValue,
1282 {
1283 let target_slot = self.resolve_non_paged_slot(field)?;
1284
1285 self.with_admitted_non_paged(|session, query| {
1286 session
1287 .execute_fluent_bottom_k_values_with_ids_by_slot(query, target_slot, take_count)
1288 .map(output_values_with_ids)
1289 })
1290 }
1291
1292 pub fn distinct_values_by(&self, field: impl AsRef<str>) -> Result<Vec<OutputValue>, QueryError>
1295 where
1296 E: EntityValue,
1297 {
1298 let target_slot = self.resolve_non_paged_slot(field)?;
1299
1300 self.execute_terminal(DistinctValuesBySlotTerminal::new(target_slot))
1301 .map(output_values)
1302 }
1303
1304 pub fn explain_distinct_values_by(
1306 &self,
1307 field: impl AsRef<str>,
1308 ) -> Result<ExplainExecutionNodeDescriptor, QueryError>
1309 where
1310 E: EntityValue,
1311 {
1312 let target_slot = self.resolve_non_paged_slot(field)?;
1313
1314 self.explain_terminal(&DistinctValuesBySlotTerminal::new(target_slot))
1315 }
1316
1317 pub fn values_by_with_ids(
1320 &self,
1321 field: impl AsRef<str>,
1322 ) -> Result<Vec<(Id<E>, OutputValue)>, QueryError>
1323 where
1324 E: EntityValue,
1325 {
1326 let target_slot = self.resolve_non_paged_slot(field)?;
1327
1328 self.execute_terminal(ValuesBySlotWithIdsTerminal::new(target_slot))
1329 .map(output_values_with_ids)
1330 }
1331
1332 pub fn project_values_with_ids<P>(
1335 &self,
1336 projection: &P,
1337 ) -> Result<Vec<(Id<E>, OutputValue)>, QueryError>
1338 where
1339 E: EntityValue,
1340 P: ValueProjectionExpr,
1341 {
1342 let target_slot = self.resolve_non_paged_slot(projection.field())?;
1343
1344 self.with_admitted_non_paged(|session, query| {
1345 session.execute_fluent_project_values_with_ids_by_slot(
1346 query,
1347 target_slot,
1348 projection.projection_plan().into_expr(),
1349 )
1350 })
1351 .map(output_values_with_ids)
1352 }
1353
1354 pub fn explain_values_by_with_ids(
1356 &self,
1357 field: impl AsRef<str>,
1358 ) -> Result<ExplainExecutionNodeDescriptor, QueryError>
1359 where
1360 E: EntityValue,
1361 {
1362 let target_slot = self.resolve_non_paged_slot(field)?;
1363
1364 self.explain_terminal(&ValuesBySlotWithIdsTerminal::new(target_slot))
1365 }
1366
1367 pub fn first_value_by(&self, field: impl AsRef<str>) -> Result<Option<OutputValue>, QueryError>
1370 where
1371 E: EntityValue,
1372 {
1373 let target_slot = self.resolve_non_paged_slot(field)?;
1374
1375 self.execute_terminal(FirstValueBySlotTerminal::new(target_slot))
1376 .map(|value| value.map(output))
1377 }
1378
1379 pub fn project_first_value<P>(&self, projection: &P) -> Result<Option<OutputValue>, QueryError>
1382 where
1383 E: EntityValue,
1384 P: ValueProjectionExpr,
1385 {
1386 let target_slot = self.resolve_non_paged_slot(projection.field())?;
1387
1388 self.with_admitted_non_paged(|session, query| {
1389 session.execute_fluent_project_terminal_value_by_slot(
1390 query,
1391 target_slot,
1392 AggregateKind::First,
1393 projection.projection_plan().into_expr(),
1394 )
1395 })
1396 .map(|value| value.map(output))
1397 }
1398
1399 pub fn explain_first_value_by(
1401 &self,
1402 field: impl AsRef<str>,
1403 ) -> Result<ExplainExecutionNodeDescriptor, QueryError>
1404 where
1405 E: EntityValue,
1406 {
1407 let target_slot = self.resolve_non_paged_slot(field)?;
1408
1409 self.explain_terminal(&FirstValueBySlotTerminal::new(target_slot))
1410 }
1411
1412 pub fn last_value_by(&self, field: impl AsRef<str>) -> Result<Option<OutputValue>, QueryError>
1415 where
1416 E: EntityValue,
1417 {
1418 let target_slot = self.resolve_non_paged_slot(field)?;
1419
1420 self.execute_terminal(LastValueBySlotTerminal::new(target_slot))
1421 .map(|value| value.map(output))
1422 }
1423
1424 pub fn project_last_value<P>(&self, projection: &P) -> Result<Option<OutputValue>, QueryError>
1427 where
1428 E: EntityValue,
1429 P: ValueProjectionExpr,
1430 {
1431 let target_slot = self.resolve_non_paged_slot(projection.field())?;
1432
1433 self.with_admitted_non_paged(|session, query| {
1434 session.execute_fluent_project_terminal_value_by_slot(
1435 query,
1436 target_slot,
1437 AggregateKind::Last,
1438 projection.projection_plan().into_expr(),
1439 )
1440 })
1441 .map(|value| value.map(output))
1442 }
1443
1444 pub fn explain_last_value_by(
1446 &self,
1447 field: impl AsRef<str>,
1448 ) -> Result<ExplainExecutionNodeDescriptor, QueryError>
1449 where
1450 E: EntityValue,
1451 {
1452 let target_slot = self.resolve_non_paged_slot(field)?;
1453
1454 self.explain_terminal(&LastValueBySlotTerminal::new(target_slot))
1455 }
1456
1457 pub fn first(&self) -> Result<Option<Id<E>>, QueryError>
1459 where
1460 E: EntityValue,
1461 {
1462 self.execute_terminal(FirstIdTerminal::new())
1463 }
1464
1465 pub fn explain_first(&self) -> Result<ExplainAggregateTerminalPlan, QueryError>
1467 where
1468 E: EntityValue,
1469 {
1470 self.explain_terminal(&FirstIdTerminal::new())
1471 }
1472
1473 pub fn last(&self) -> Result<Option<Id<E>>, QueryError>
1475 where
1476 E: EntityValue,
1477 {
1478 self.execute_terminal(LastIdTerminal::new())
1479 }
1480
1481 pub fn explain_last(&self) -> Result<ExplainAggregateTerminalPlan, QueryError>
1483 where
1484 E: EntityValue,
1485 {
1486 self.explain_terminal(&LastIdTerminal::new())
1487 }
1488
1489 pub fn require_one(&self) -> Result<(), QueryError>
1491 where
1492 E: EntityValue,
1493 {
1494 self.execute_rows()?.require_one()?;
1495 Ok(())
1496 }
1497
1498 pub fn require_some(&self) -> Result<(), QueryError>
1500 where
1501 E: EntityValue,
1502 {
1503 self.execute_rows()?.require_some()?;
1504 Ok(())
1505 }
1506}