1use std::num::NonZeroU32;
16
17#[cfg(feature = "diagnostics")]
18use crate::db::FluentTerminalExecutionAttribution;
19#[cfg(feature = "diagnostics")]
20use crate::db::query::read_intent::ReadIntentKind;
21use crate::{
22 db::{
23 DbSession, PersistedRow, Query,
24 query::{
25 admission::QueryAdmissionPolicy,
26 api::ResponseCardinalityExt,
27 builder::{
28 AvgBySlotTerminal, AvgDistinctBySlotTerminal, CountDistinctBySlotTerminal,
29 CountRowsTerminal, DistinctValuesBySlotTerminal, ExistsRowsTerminal,
30 FirstIdTerminal, FirstValueBySlotTerminal, LastIdTerminal, LastValueBySlotTerminal,
31 MaxIdBySlotTerminal, MaxIdTerminal, MedianIdBySlotTerminal, MinIdBySlotTerminal,
32 MinIdTerminal, MinMaxIdBySlotTerminal, NthIdBySlotTerminal, SumBySlotTerminal,
33 SumDistinctBySlotTerminal, ValueProjectionExpr, ValuesBySlotTerminal,
34 ValuesBySlotWithIdsTerminal,
35 },
36 explain::{ExplainAggregateTerminalPlan, ExplainExecutionNodeDescriptor},
37 fluent::load::{FluentLoadQuery, LoadQueryResult},
38 intent::{IntentError, QueryError},
39 plan::AggregateKind,
40 read_intent::{
41 COMPLETE_SMALL_EXECUTION_LIMIT, COMPLETE_SMALL_MAX_ROWS,
42 PUBLIC_PAGE_MAX_RESPONSE_BYTES,
43 },
44 },
45 response::EntityResponse,
46 },
47 traits::EntityValue,
48 types::{Decimal, Id},
49 value::{OutputValue, Value},
50};
51
52type MinMaxByIds<E> = Option<(Id<E>, Id<E>)>;
53
54trait TerminalStrategyDriver<E: PersistedRow + EntityValue> {
64 type Output;
65 type ExplainOutput;
66
67 fn execute(
68 self,
69 session: &DbSession<E::Canister>,
70 query: &Query<E>,
71 ) -> Result<Self::Output, QueryError>;
72
73 fn explain(
74 &self,
75 session: &DbSession<E::Canister>,
76 query: &Query<E>,
77 ) -> Result<Self::ExplainOutput, QueryError>;
78}
79
80macro_rules! impl_aggregate_terminal_driver {
84 ($terminal:ty, $output:ty, $execute:ident) => {
85 impl<E> TerminalStrategyDriver<E> for $terminal
86 where
87 E: PersistedRow + EntityValue,
88 {
89 type Output = $output;
90 type ExplainOutput = ExplainAggregateTerminalPlan;
91
92 fn execute(
93 self,
94 session: &DbSession<E::Canister>,
95 query: &Query<E>,
96 ) -> Result<Self::Output, QueryError> {
97 session.$execute(query, self)
98 }
99
100 fn explain(
101 &self,
102 session: &DbSession<E::Canister>,
103 query: &Query<E>,
104 ) -> Result<Self::ExplainOutput, QueryError> {
105 session.explain_query_prepared_aggregate_terminal_with_visible_indexes(query, self)
106 }
107 }
108 };
109}
110
111macro_rules! impl_projection_terminal_driver {
115 ($terminal:ty, $output:ty, $execute:ident) => {
116 impl<E> TerminalStrategyDriver<E> for $terminal
117 where
118 E: PersistedRow + EntityValue,
119 {
120 type Output = $output;
121 type ExplainOutput = ExplainExecutionNodeDescriptor;
122
123 fn execute(
124 self,
125 session: &DbSession<E::Canister>,
126 query: &Query<E>,
127 ) -> Result<Self::Output, QueryError> {
128 session.$execute(query, self)
129 }
130
131 fn explain(
132 &self,
133 session: &DbSession<E::Canister>,
134 query: &Query<E>,
135 ) -> Result<Self::ExplainOutput, QueryError> {
136 session.explain_query_prepared_projection_terminal_with_visible_indexes(query, self)
137 }
138 }
139 };
140}
141
142impl_aggregate_terminal_driver!(CountRowsTerminal, u32, execute_fluent_count_rows_terminal);
143impl_aggregate_terminal_driver!(
144 ExistsRowsTerminal,
145 bool,
146 execute_fluent_exists_rows_terminal
147);
148impl_aggregate_terminal_driver!(MinIdTerminal, Option<Id<E>>, execute_fluent_min_id_terminal);
149impl_aggregate_terminal_driver!(MaxIdTerminal, Option<Id<E>>, execute_fluent_max_id_terminal);
150impl_aggregate_terminal_driver!(
151 MinIdBySlotTerminal,
152 Option<Id<E>>,
153 execute_fluent_min_id_by_slot
154);
155impl_aggregate_terminal_driver!(
156 MaxIdBySlotTerminal,
157 Option<Id<E>>,
158 execute_fluent_max_id_by_slot
159);
160impl_aggregate_terminal_driver!(
161 SumBySlotTerminal,
162 Option<Decimal>,
163 execute_fluent_sum_by_slot
164);
165impl_aggregate_terminal_driver!(
166 SumDistinctBySlotTerminal,
167 Option<Decimal>,
168 execute_fluent_sum_distinct_by_slot
169);
170impl_aggregate_terminal_driver!(
171 AvgBySlotTerminal,
172 Option<Decimal>,
173 execute_fluent_avg_by_slot
174);
175impl_aggregate_terminal_driver!(
176 AvgDistinctBySlotTerminal,
177 Option<Decimal>,
178 execute_fluent_avg_distinct_by_slot
179);
180impl_aggregate_terminal_driver!(
181 FirstIdTerminal,
182 Option<Id<E>>,
183 execute_fluent_first_id_terminal
184);
185impl_aggregate_terminal_driver!(
186 LastIdTerminal,
187 Option<Id<E>>,
188 execute_fluent_last_id_terminal
189);
190impl_aggregate_terminal_driver!(
191 NthIdBySlotTerminal,
192 Option<Id<E>>,
193 execute_fluent_nth_id_by_slot
194);
195impl_aggregate_terminal_driver!(
196 MedianIdBySlotTerminal,
197 Option<Id<E>>,
198 execute_fluent_median_id_by_slot
199);
200impl_aggregate_terminal_driver!(
201 MinMaxIdBySlotTerminal,
202 MinMaxByIds<E>,
203 execute_fluent_min_max_id_by_slot
204);
205
206impl_projection_terminal_driver!(
207 ValuesBySlotTerminal,
208 Vec<Value>,
209 execute_fluent_values_by_slot
210);
211impl_projection_terminal_driver!(
212 DistinctValuesBySlotTerminal,
213 Vec<Value>,
214 execute_fluent_distinct_values_by_slot
215);
216impl_projection_terminal_driver!(
217 CountDistinctBySlotTerminal,
218 u32,
219 execute_fluent_count_distinct_by_slot
220);
221impl_projection_terminal_driver!(
222 ValuesBySlotWithIdsTerminal,
223 Vec<(Id<E>, Value)>,
224 execute_fluent_values_by_with_ids_slot
225);
226impl_projection_terminal_driver!(
227 FirstValueBySlotTerminal,
228 Option<Value>,
229 execute_fluent_first_value_by_slot
230);
231impl_projection_terminal_driver!(
232 LastValueBySlotTerminal,
233 Option<Value>,
234 execute_fluent_last_value_by_slot
235);
236
237fn output(value: Value) -> OutputValue {
239 OutputValue::from(value)
240}
241
242fn output_values(values: Vec<Value>) -> Vec<OutputValue> {
244 values.into_iter().map(output).collect()
245}
246
247fn output_values_with_ids<E: PersistedRow>(
249 values: Vec<(Id<E>, Value)>,
250) -> Vec<(Id<E>, OutputValue)> {
251 values
252 .into_iter()
253 .map(|(id, value)| (id, output(value)))
254 .collect()
255}
256
257fn non_zero_u32(value: u32) -> Result<NonZeroU32, QueryError> {
258 NonZeroU32::new(value).ok_or_else(QueryError::invariant)
259}
260
261impl<E> FluentLoadQuery<'_, E>
262where
263 E: PersistedRow,
264{
265 pub fn execute(&self) -> Result<LoadQueryResult<E>, QueryError>
271 where
272 E: EntityValue,
273 {
274 self.with_admitted_non_paged(DbSession::execute_query_result)
275 }
276
277 pub fn execute_trusted(&self) -> Result<LoadQueryResult<E>, QueryError>
283 where
284 E: EntityValue,
285 {
286 self.with_non_paged(DbSession::execute_query_result)
287 }
288
289 pub fn execute_rows(&self) -> Result<EntityResponse<E>, QueryError>
291 where
292 E: EntityValue,
293 {
294 self.with_admitted_non_paged(DbSession::execute_scalar_query_rows)
295 }
296
297 pub fn execute_rows_trusted(&self) -> Result<EntityResponse<E>, QueryError>
303 where
304 E: EntityValue,
305 {
306 self.with_non_paged(DbSession::execute_scalar_query_rows)
307 }
308
309 fn with_admitted_non_paged<T>(
310 &self,
311 map: impl FnOnce(&DbSession<E::Canister>, &Query<E>) -> Result<T, QueryError>,
312 ) -> Result<T, QueryError>
313 where
314 E: EntityValue,
315 {
316 self.ensure_non_paged_mode_ready()?;
317 self.ensure_default_read_admission()?;
318 map(self.session, self.query())
319 }
320
321 fn with_non_paged<T>(
324 &self,
325 map: impl FnOnce(&DbSession<E::Canister>, &Query<E>) -> Result<T, QueryError>,
326 ) -> Result<T, QueryError>
327 where
328 E: EntityValue,
329 {
330 self.ensure_non_paged_mode_ready()?;
331 map(self.session, self.query())
332 }
333
334 fn explain_execution_descriptor(&self) -> Result<ExplainExecutionNodeDescriptor, QueryError>
337 where
338 E: EntityValue,
339 {
340 self.with_non_paged(DbSession::explain_query_execution_with_visible_indexes)
341 }
342
343 fn render_execution_descriptor(
346 &self,
347 render: impl FnOnce(ExplainExecutionNodeDescriptor) -> String,
348 ) -> Result<String, QueryError>
349 where
350 E: EntityValue,
351 {
352 let descriptor = self.explain_execution_descriptor()?;
353
354 Ok(render(descriptor))
355 }
356
357 fn execute_terminal<S>(&self, strategy: S) -> Result<S::Output, QueryError>
360 where
361 E: EntityValue,
362 S: TerminalStrategyDriver<E>,
363 {
364 self.with_admitted_non_paged(|session, query| strategy.execute(session, query))
365 }
366
367 fn explain_terminal<S>(&self, strategy: &S) -> Result<S::ExplainOutput, QueryError>
370 where
371 E: EntityValue,
372 S: TerminalStrategyDriver<E>,
373 {
374 self.with_non_paged(|session, query| strategy.explain(session, query))
375 }
376
377 fn ensure_exists_intent_owns_limit(&self) -> Result<(), QueryError> {
378 self.ensure_semantic_terminal_owns_limit(IntentError::raw_limit_before_exists_terminal())
379 }
380
381 fn ensure_count_exact_intent_owns_limit(&self) -> Result<(), QueryError> {
382 self.ensure_semantic_terminal_owns_limit(
383 IntentError::raw_limit_before_count_exact_terminal(),
384 )
385 }
386
387 fn ensure_sum_exact_intent_owns_limit(&self) -> Result<(), QueryError> {
388 self.ensure_semantic_terminal_owns_limit(IntentError::raw_limit_before_sum_exact_terminal())
389 }
390
391 fn ensure_collect_complete_intent_owns_limit(&self) -> Result<(), QueryError> {
392 self.ensure_semantic_terminal_owns_limit(
393 IntentError::raw_limit_before_collect_complete_terminal(),
394 )
395 }
396
397 pub fn is_empty(&self) -> Result<bool, QueryError>
403 where
404 E: EntityValue,
405 {
406 self.not_exists()
407 }
408
409 pub fn not_exists(&self) -> Result<bool, QueryError>
411 where
412 E: EntityValue,
413 {
414 Ok(!self.exists()?)
415 }
416
417 pub fn exists(&self) -> Result<bool, QueryError>
419 where
420 E: EntityValue,
421 {
422 self.ensure_exists_intent_owns_limit()?;
423
424 self.execute_terminal(ExistsRowsTerminal::new())
425 }
426
427 #[cfg(feature = "diagnostics")]
430 #[doc(hidden)]
431 pub fn exists_with_attribution(
432 &self,
433 ) -> Result<(bool, FluentTerminalExecutionAttribution), QueryError>
434 where
435 E: EntityValue,
436 {
437 self.ensure_exists_intent_owns_limit()?;
438
439 let (exists, attribution) = self.with_admitted_non_paged(|session, query| {
440 session.execute_fluent_exists_rows_terminal_with_attribution(
441 query,
442 ExistsRowsTerminal::new(),
443 )
444 })?;
445
446 Ok((
447 exists,
448 attribution.with_read_intent(ReadIntentKind::ExistenceCheck),
449 ))
450 }
451
452 pub fn explain_exists(&self) -> Result<ExplainAggregateTerminalPlan, QueryError>
454 where
455 E: EntityValue,
456 {
457 self.ensure_exists_intent_owns_limit()?;
458
459 self.explain_terminal(&ExistsRowsTerminal::new())
460 }
461
462 pub fn collect_complete(&self) -> Result<Vec<E>, QueryError>
469 where
470 E: EntityValue,
471 {
472 self.ensure_collect_complete_intent_owns_limit()?;
473 self.ensure_non_paged_mode_ready()?;
474
475 let query = self.query().with_load_limit(COMPLETE_SMALL_EXECUTION_LIMIT);
476 let policy = QueryAdmissionPolicy::public_read(
477 non_zero_u32(COMPLETE_SMALL_EXECUTION_LIMIT)?,
478 non_zero_u32(PUBLIC_PAGE_MAX_RESPONSE_BYTES)?,
479 );
480
481 self.session
482 .ensure_query_read_admission_policy(&query, &policy)?;
483
484 let response = self.session.execute_scalar_query_rows(&query)?;
485 if response.count() > COMPLETE_SMALL_MAX_ROWS {
486 return Err(QueryError::intent(
487 IntentError::complete_read_too_many_rows(),
488 ));
489 }
490
491 Ok(response.entities())
492 }
493
494 pub fn explain_not_exists(&self) -> Result<ExplainAggregateTerminalPlan, QueryError>
498 where
499 E: EntityValue,
500 {
501 self.explain_exists()
502 }
503
504 pub fn explain_execution(&self) -> Result<ExplainExecutionNodeDescriptor, QueryError>
506 where
507 E: EntityValue,
508 {
509 self.explain_execution_descriptor()
510 }
511
512 pub fn explain_execution_text(&self) -> Result<String, QueryError>
514 where
515 E: EntityValue,
516 {
517 self.render_execution_descriptor(|descriptor| descriptor.render_text_tree())
518 }
519
520 pub fn explain_execution_json(&self) -> Result<String, QueryError>
522 where
523 E: EntityValue,
524 {
525 self.with_non_paged(DbSession::explain_query_execution_json_with_visible_indexes)
526 }
527
528 pub fn explain_execution_verbose(&self) -> Result<String, QueryError>
530 where
531 E: EntityValue,
532 {
533 self.with_non_paged(DbSession::explain_query_execution_verbose_with_visible_indexes)
534 }
535
536 pub fn count(&self) -> Result<u32, QueryError>
538 where
539 E: EntityValue,
540 {
541 self.execute_terminal(CountRowsTerminal::new())
542 }
543
544 pub fn count_exact(&self) -> Result<u32, QueryError>
550 where
551 E: EntityValue,
552 {
553 self.ensure_count_exact_intent_owns_limit()?;
554
555 self.execute_terminal(CountRowsTerminal::new())
556 }
557
558 #[cfg(feature = "diagnostics")]
560 #[doc(hidden)]
561 pub fn count_with_attribution(
562 &self,
563 ) -> Result<(u32, FluentTerminalExecutionAttribution), QueryError>
564 where
565 E: EntityValue,
566 {
567 let (count, attribution) = self.with_admitted_non_paged(|session, query| {
568 session.execute_fluent_count_rows_terminal_with_attribution(
569 query,
570 CountRowsTerminal::new(),
571 )
572 })?;
573
574 Ok((
575 count,
576 attribution.with_read_intent(ReadIntentKind::BoundedRowWindow),
577 ))
578 }
579
580 #[cfg(feature = "diagnostics")]
582 #[doc(hidden)]
583 pub fn count_exact_with_attribution(
584 &self,
585 ) -> Result<(u32, FluentTerminalExecutionAttribution), QueryError>
586 where
587 E: EntityValue,
588 {
589 self.ensure_count_exact_intent_owns_limit()?;
590
591 let (count, attribution) = self.with_admitted_non_paged(|session, query| {
592 session.execute_fluent_count_rows_terminal_with_attribution(
593 query,
594 CountRowsTerminal::new(),
595 )
596 })?;
597
598 Ok((
599 count,
600 attribution.with_read_intent(ReadIntentKind::ExactAggregate),
601 ))
602 }
603
604 pub fn bytes(&self) -> Result<u64, QueryError>
607 where
608 E: EntityValue,
609 {
610 self.with_admitted_non_paged(DbSession::execute_fluent_bytes)
611 }
612
613 pub fn bytes_by(&self, field: impl AsRef<str>) -> Result<u64, QueryError>
616 where
617 E: EntityValue,
618 {
619 let target_slot = self.resolve_non_paged_slot(field)?;
620
621 self.with_admitted_non_paged(|session, query| {
622 session.execute_fluent_bytes_by_slot(query, target_slot)
623 })
624 }
625
626 pub fn explain_bytes_by(
628 &self,
629 field: impl AsRef<str>,
630 ) -> Result<ExplainExecutionNodeDescriptor, QueryError>
631 where
632 E: EntityValue,
633 {
634 let target_slot = self.resolve_non_paged_slot(field)?;
635
636 self.with_non_paged(|session, query| {
637 session.explain_query_bytes_by_with_visible_indexes(query, target_slot.field())
638 })
639 }
640
641 pub fn min(&self) -> Result<Option<Id<E>>, QueryError>
643 where
644 E: EntityValue,
645 {
646 self.execute_terminal(MinIdTerminal::new())
647 }
648
649 pub fn explain_min(&self) -> Result<ExplainAggregateTerminalPlan, QueryError>
651 where
652 E: EntityValue,
653 {
654 self.explain_terminal(&MinIdTerminal::new())
655 }
656
657 pub fn min_by(&self, field: impl AsRef<str>) -> Result<Option<Id<E>>, QueryError>
661 where
662 E: EntityValue,
663 {
664 let target_slot = self.resolve_non_paged_slot(field)?;
665
666 self.execute_terminal(MinIdBySlotTerminal::new(target_slot))
667 }
668
669 pub fn max(&self) -> Result<Option<Id<E>>, QueryError>
671 where
672 E: EntityValue,
673 {
674 self.execute_terminal(MaxIdTerminal::new())
675 }
676
677 pub fn explain_max(&self) -> Result<ExplainAggregateTerminalPlan, QueryError>
679 where
680 E: EntityValue,
681 {
682 self.explain_terminal(&MaxIdTerminal::new())
683 }
684
685 pub fn max_by(&self, field: impl AsRef<str>) -> Result<Option<Id<E>>, QueryError>
689 where
690 E: EntityValue,
691 {
692 let target_slot = self.resolve_non_paged_slot(field)?;
693
694 self.execute_terminal(MaxIdBySlotTerminal::new(target_slot))
695 }
696
697 pub fn nth_by(&self, field: impl AsRef<str>, nth: usize) -> Result<Option<Id<E>>, QueryError>
700 where
701 E: EntityValue,
702 {
703 let target_slot = self.resolve_non_paged_slot(field)?;
704
705 self.execute_terminal(NthIdBySlotTerminal::new(target_slot, nth))
706 }
707
708 pub fn sum_by(&self, field: impl AsRef<str>) -> Result<Option<Decimal>, QueryError>
710 where
711 E: EntityValue,
712 {
713 let target_slot = self.resolve_non_paged_slot(field)?;
714
715 self.execute_terminal(SumBySlotTerminal::new(target_slot))
716 }
717
718 pub fn sum_exact(&self, field: impl AsRef<str>) -> Result<Option<Decimal>, QueryError>
724 where
725 E: EntityValue,
726 {
727 self.ensure_sum_exact_intent_owns_limit()?;
728
729 let target_slot = self.resolve_non_paged_slot(field)?;
730
731 self.execute_terminal(SumBySlotTerminal::new(target_slot))
732 }
733
734 pub fn explain_sum_by(
736 &self,
737 field: impl AsRef<str>,
738 ) -> Result<ExplainAggregateTerminalPlan, QueryError>
739 where
740 E: EntityValue,
741 {
742 let target_slot = self.resolve_non_paged_slot(field)?;
743
744 self.explain_terminal(&SumBySlotTerminal::new(target_slot))
745 }
746
747 pub fn sum_distinct_by(&self, field: impl AsRef<str>) -> Result<Option<Decimal>, QueryError>
749 where
750 E: EntityValue,
751 {
752 let target_slot = self.resolve_non_paged_slot(field)?;
753
754 self.execute_terminal(SumDistinctBySlotTerminal::new(target_slot))
755 }
756
757 pub fn explain_sum_distinct_by(
759 &self,
760 field: impl AsRef<str>,
761 ) -> Result<ExplainAggregateTerminalPlan, QueryError>
762 where
763 E: EntityValue,
764 {
765 let target_slot = self.resolve_non_paged_slot(field)?;
766
767 self.explain_terminal(&SumDistinctBySlotTerminal::new(target_slot))
768 }
769
770 pub fn avg_by(&self, field: impl AsRef<str>) -> Result<Option<Decimal>, QueryError>
772 where
773 E: EntityValue,
774 {
775 let target_slot = self.resolve_non_paged_slot(field)?;
776
777 self.execute_terminal(AvgBySlotTerminal::new(target_slot))
778 }
779
780 pub fn explain_avg_by(
782 &self,
783 field: impl AsRef<str>,
784 ) -> Result<ExplainAggregateTerminalPlan, QueryError>
785 where
786 E: EntityValue,
787 {
788 let target_slot = self.resolve_non_paged_slot(field)?;
789
790 self.explain_terminal(&AvgBySlotTerminal::new(target_slot))
791 }
792
793 pub fn avg_distinct_by(&self, field: impl AsRef<str>) -> Result<Option<Decimal>, QueryError>
795 where
796 E: EntityValue,
797 {
798 let target_slot = self.resolve_non_paged_slot(field)?;
799
800 self.execute_terminal(AvgDistinctBySlotTerminal::new(target_slot))
801 }
802
803 pub fn explain_avg_distinct_by(
805 &self,
806 field: impl AsRef<str>,
807 ) -> Result<ExplainAggregateTerminalPlan, QueryError>
808 where
809 E: EntityValue,
810 {
811 let target_slot = self.resolve_non_paged_slot(field)?;
812
813 self.explain_terminal(&AvgDistinctBySlotTerminal::new(target_slot))
814 }
815
816 pub fn median_by(&self, field: impl AsRef<str>) -> Result<Option<Id<E>>, QueryError>
821 where
822 E: EntityValue,
823 {
824 let target_slot = self.resolve_non_paged_slot(field)?;
825
826 self.execute_terminal(MedianIdBySlotTerminal::new(target_slot))
827 }
828
829 pub fn count_distinct_by(&self, field: impl AsRef<str>) -> Result<u32, QueryError>
832 where
833 E: EntityValue,
834 {
835 let target_slot = self.resolve_non_paged_slot(field)?;
836
837 self.execute_terminal(CountDistinctBySlotTerminal::new(target_slot))
838 }
839
840 pub fn explain_count_distinct_by(
842 &self,
843 field: impl AsRef<str>,
844 ) -> Result<ExplainExecutionNodeDescriptor, QueryError>
845 where
846 E: EntityValue,
847 {
848 let target_slot = self.resolve_non_paged_slot(field)?;
849
850 self.explain_terminal(&CountDistinctBySlotTerminal::new(target_slot))
851 }
852
853 pub fn min_max_by(&self, field: impl AsRef<str>) -> Result<MinMaxByIds<E>, QueryError>
857 where
858 E: EntityValue,
859 {
860 let target_slot = self.resolve_non_paged_slot(field)?;
861
862 self.execute_terminal(MinMaxIdBySlotTerminal::new(target_slot))
863 }
864
865 pub fn values_by(&self, field: impl AsRef<str>) -> Result<Vec<OutputValue>, QueryError>
867 where
868 E: EntityValue,
869 {
870 let target_slot = self.resolve_non_paged_slot(field)?;
871
872 self.execute_terminal(ValuesBySlotTerminal::new(target_slot))
873 .map(output_values)
874 }
875
876 pub fn project_values<P>(&self, projection: &P) -> Result<Vec<OutputValue>, QueryError>
879 where
880 E: EntityValue,
881 P: ValueProjectionExpr,
882 {
883 let target_slot = self.resolve_non_paged_slot(projection.field())?;
884
885 self.with_admitted_non_paged(|session, query| {
886 session.execute_fluent_project_values_by_slot(
887 query,
888 target_slot,
889 projection.projection_plan().into_expr(),
890 )
891 })
892 .map(output_values)
893 }
894
895 pub fn explain_project_values<P>(
897 &self,
898 projection: &P,
899 ) -> Result<ExplainExecutionNodeDescriptor, QueryError>
900 where
901 E: EntityValue,
902 P: ValueProjectionExpr,
903 {
904 let target_slot = self.resolve_non_paged_slot(projection.field())?;
905
906 self.explain_terminal(&ValuesBySlotTerminal::new(target_slot))
907 }
908
909 pub fn explain_values_by(
911 &self,
912 field: impl AsRef<str>,
913 ) -> Result<ExplainExecutionNodeDescriptor, QueryError>
914 where
915 E: EntityValue,
916 {
917 let target_slot = self.resolve_non_paged_slot(field)?;
918
919 self.explain_terminal(&ValuesBySlotTerminal::new(target_slot))
920 }
921
922 pub fn take(&self, take_count: u32) -> Result<EntityResponse<E>, QueryError>
924 where
925 E: EntityValue,
926 {
927 self.with_admitted_non_paged(|session, query| {
928 session.execute_fluent_take(query, take_count)
929 })
930 }
931
932 pub fn top_k_by(
940 &self,
941 field: impl AsRef<str>,
942 take_count: u32,
943 ) -> Result<EntityResponse<E>, QueryError>
944 where
945 E: EntityValue,
946 {
947 let target_slot = self.resolve_non_paged_slot(field)?;
948
949 self.with_admitted_non_paged(|session, query| {
950 session.execute_fluent_top_k_rows_by_slot(query, target_slot, take_count)
951 })
952 }
953
954 pub fn bottom_k_by(
962 &self,
963 field: impl AsRef<str>,
964 take_count: u32,
965 ) -> Result<EntityResponse<E>, QueryError>
966 where
967 E: EntityValue,
968 {
969 let target_slot = self.resolve_non_paged_slot(field)?;
970
971 self.with_admitted_non_paged(|session, query| {
972 session.execute_fluent_bottom_k_rows_by_slot(query, target_slot, take_count)
973 })
974 }
975
976 pub fn top_k_by_values(
984 &self,
985 field: impl AsRef<str>,
986 take_count: u32,
987 ) -> Result<Vec<OutputValue>, QueryError>
988 where
989 E: EntityValue,
990 {
991 let target_slot = self.resolve_non_paged_slot(field)?;
992
993 self.with_admitted_non_paged(|session, query| {
994 session
995 .execute_fluent_top_k_values_by_slot(query, target_slot, take_count)
996 .map(output_values)
997 })
998 }
999
1000 pub fn bottom_k_by_values(
1008 &self,
1009 field: impl AsRef<str>,
1010 take_count: u32,
1011 ) -> Result<Vec<OutputValue>, QueryError>
1012 where
1013 E: EntityValue,
1014 {
1015 let target_slot = self.resolve_non_paged_slot(field)?;
1016
1017 self.with_admitted_non_paged(|session, query| {
1018 session
1019 .execute_fluent_bottom_k_values_by_slot(query, target_slot, take_count)
1020 .map(output_values)
1021 })
1022 }
1023
1024 pub fn top_k_by_with_ids(
1032 &self,
1033 field: impl AsRef<str>,
1034 take_count: u32,
1035 ) -> Result<Vec<(Id<E>, OutputValue)>, QueryError>
1036 where
1037 E: EntityValue,
1038 {
1039 let target_slot = self.resolve_non_paged_slot(field)?;
1040
1041 self.with_admitted_non_paged(|session, query| {
1042 session
1043 .execute_fluent_top_k_values_with_ids_by_slot(query, target_slot, take_count)
1044 .map(output_values_with_ids)
1045 })
1046 }
1047
1048 pub fn bottom_k_by_with_ids(
1056 &self,
1057 field: impl AsRef<str>,
1058 take_count: u32,
1059 ) -> Result<Vec<(Id<E>, OutputValue)>, QueryError>
1060 where
1061 E: EntityValue,
1062 {
1063 let target_slot = self.resolve_non_paged_slot(field)?;
1064
1065 self.with_admitted_non_paged(|session, query| {
1066 session
1067 .execute_fluent_bottom_k_values_with_ids_by_slot(query, target_slot, take_count)
1068 .map(output_values_with_ids)
1069 })
1070 }
1071
1072 pub fn distinct_values_by(&self, field: impl AsRef<str>) -> Result<Vec<OutputValue>, QueryError>
1075 where
1076 E: EntityValue,
1077 {
1078 let target_slot = self.resolve_non_paged_slot(field)?;
1079
1080 self.execute_terminal(DistinctValuesBySlotTerminal::new(target_slot))
1081 .map(output_values)
1082 }
1083
1084 pub fn explain_distinct_values_by(
1086 &self,
1087 field: impl AsRef<str>,
1088 ) -> Result<ExplainExecutionNodeDescriptor, QueryError>
1089 where
1090 E: EntityValue,
1091 {
1092 let target_slot = self.resolve_non_paged_slot(field)?;
1093
1094 self.explain_terminal(&DistinctValuesBySlotTerminal::new(target_slot))
1095 }
1096
1097 pub fn values_by_with_ids(
1100 &self,
1101 field: impl AsRef<str>,
1102 ) -> Result<Vec<(Id<E>, OutputValue)>, QueryError>
1103 where
1104 E: EntityValue,
1105 {
1106 let target_slot = self.resolve_non_paged_slot(field)?;
1107
1108 self.execute_terminal(ValuesBySlotWithIdsTerminal::new(target_slot))
1109 .map(output_values_with_ids)
1110 }
1111
1112 pub fn project_values_with_ids<P>(
1115 &self,
1116 projection: &P,
1117 ) -> Result<Vec<(Id<E>, OutputValue)>, QueryError>
1118 where
1119 E: EntityValue,
1120 P: ValueProjectionExpr,
1121 {
1122 let target_slot = self.resolve_non_paged_slot(projection.field())?;
1123
1124 self.with_admitted_non_paged(|session, query| {
1125 session.execute_fluent_project_values_with_ids_by_slot(
1126 query,
1127 target_slot,
1128 projection.projection_plan().into_expr(),
1129 )
1130 })
1131 .map(output_values_with_ids)
1132 }
1133
1134 pub fn explain_values_by_with_ids(
1136 &self,
1137 field: impl AsRef<str>,
1138 ) -> Result<ExplainExecutionNodeDescriptor, QueryError>
1139 where
1140 E: EntityValue,
1141 {
1142 let target_slot = self.resolve_non_paged_slot(field)?;
1143
1144 self.explain_terminal(&ValuesBySlotWithIdsTerminal::new(target_slot))
1145 }
1146
1147 pub fn first_value_by(&self, field: impl AsRef<str>) -> Result<Option<OutputValue>, QueryError>
1150 where
1151 E: EntityValue,
1152 {
1153 let target_slot = self.resolve_non_paged_slot(field)?;
1154
1155 self.execute_terminal(FirstValueBySlotTerminal::new(target_slot))
1156 .map(|value| value.map(output))
1157 }
1158
1159 pub fn project_first_value<P>(&self, projection: &P) -> Result<Option<OutputValue>, QueryError>
1162 where
1163 E: EntityValue,
1164 P: ValueProjectionExpr,
1165 {
1166 let target_slot = self.resolve_non_paged_slot(projection.field())?;
1167
1168 self.with_admitted_non_paged(|session, query| {
1169 session.execute_fluent_project_terminal_value_by_slot(
1170 query,
1171 target_slot,
1172 AggregateKind::First,
1173 projection.projection_plan().into_expr(),
1174 )
1175 })
1176 .map(|value| value.map(output))
1177 }
1178
1179 pub fn explain_first_value_by(
1181 &self,
1182 field: impl AsRef<str>,
1183 ) -> Result<ExplainExecutionNodeDescriptor, QueryError>
1184 where
1185 E: EntityValue,
1186 {
1187 let target_slot = self.resolve_non_paged_slot(field)?;
1188
1189 self.explain_terminal(&FirstValueBySlotTerminal::new(target_slot))
1190 }
1191
1192 pub fn last_value_by(&self, field: impl AsRef<str>) -> Result<Option<OutputValue>, QueryError>
1195 where
1196 E: EntityValue,
1197 {
1198 let target_slot = self.resolve_non_paged_slot(field)?;
1199
1200 self.execute_terminal(LastValueBySlotTerminal::new(target_slot))
1201 .map(|value| value.map(output))
1202 }
1203
1204 pub fn project_last_value<P>(&self, projection: &P) -> Result<Option<OutputValue>, QueryError>
1207 where
1208 E: EntityValue,
1209 P: ValueProjectionExpr,
1210 {
1211 let target_slot = self.resolve_non_paged_slot(projection.field())?;
1212
1213 self.with_admitted_non_paged(|session, query| {
1214 session.execute_fluent_project_terminal_value_by_slot(
1215 query,
1216 target_slot,
1217 AggregateKind::Last,
1218 projection.projection_plan().into_expr(),
1219 )
1220 })
1221 .map(|value| value.map(output))
1222 }
1223
1224 pub fn explain_last_value_by(
1226 &self,
1227 field: impl AsRef<str>,
1228 ) -> Result<ExplainExecutionNodeDescriptor, QueryError>
1229 where
1230 E: EntityValue,
1231 {
1232 let target_slot = self.resolve_non_paged_slot(field)?;
1233
1234 self.explain_terminal(&LastValueBySlotTerminal::new(target_slot))
1235 }
1236
1237 pub fn first(&self) -> Result<Option<Id<E>>, QueryError>
1239 where
1240 E: EntityValue,
1241 {
1242 self.execute_terminal(FirstIdTerminal::new())
1243 }
1244
1245 pub fn explain_first(&self) -> Result<ExplainAggregateTerminalPlan, QueryError>
1247 where
1248 E: EntityValue,
1249 {
1250 self.explain_terminal(&FirstIdTerminal::new())
1251 }
1252
1253 pub fn last(&self) -> Result<Option<Id<E>>, QueryError>
1255 where
1256 E: EntityValue,
1257 {
1258 self.execute_terminal(LastIdTerminal::new())
1259 }
1260
1261 pub fn explain_last(&self) -> Result<ExplainAggregateTerminalPlan, QueryError>
1263 where
1264 E: EntityValue,
1265 {
1266 self.explain_terminal(&LastIdTerminal::new())
1267 }
1268
1269 pub fn require_one(&self) -> Result<(), QueryError>
1271 where
1272 E: EntityValue,
1273 {
1274 self.execute_rows()?.require_one()?;
1275 Ok(())
1276 }
1277
1278 pub fn require_some(&self) -> Result<(), QueryError>
1280 where
1281 E: EntityValue,
1282 {
1283 self.execute_rows()?.require_some()?;
1284 Ok(())
1285 }
1286}