1use crate::{
16 db::{
17 DbSession, PersistedRow, Query,
18 query::{
19 api::ResponseCardinalityExt,
20 builder::{
21 AvgBySlotTerminal, AvgDistinctBySlotTerminal, CountDistinctBySlotTerminal,
22 CountRowsTerminal, DistinctValuesBySlotTerminal, ExistsRowsTerminal,
23 FirstIdTerminal, FirstValueBySlotTerminal, LastIdTerminal, LastValueBySlotTerminal,
24 MaxIdBySlotTerminal, MaxIdTerminal, MedianIdBySlotTerminal, MinIdBySlotTerminal,
25 MinIdTerminal, MinMaxIdBySlotTerminal, NthIdBySlotTerminal, SumBySlotTerminal,
26 SumDistinctBySlotTerminal, ValueProjectionExpr, ValuesBySlotTerminal,
27 ValuesBySlotWithIdsTerminal,
28 },
29 explain::{ExplainAggregateTerminalPlan, ExplainExecutionNodeDescriptor},
30 fluent::load::{FluentLoadQuery, LoadQueryResult},
31 intent::QueryError,
32 plan::AggregateKind,
33 },
34 response::EntityResponse,
35 },
36 traits::EntityValue,
37 types::{Decimal, Id},
38 value::{OutputValue, Value},
39};
40
41type MinMaxByIds<E> = Option<(Id<E>, Id<E>)>;
42
43trait TerminalStrategyDriver<E: PersistedRow + EntityValue> {
53 type Output;
54 type ExplainOutput;
55
56 fn execute(
57 self,
58 session: &DbSession<E::Canister>,
59 query: &Query<E>,
60 ) -> Result<Self::Output, QueryError>;
61
62 fn explain(
63 &self,
64 session: &DbSession<E::Canister>,
65 query: &Query<E>,
66 ) -> Result<Self::ExplainOutput, QueryError>;
67}
68
69macro_rules! impl_aggregate_terminal_driver {
73 ($terminal:ty, $output:ty, $execute:ident) => {
74 impl<E> TerminalStrategyDriver<E> for $terminal
75 where
76 E: PersistedRow + EntityValue,
77 {
78 type Output = $output;
79 type ExplainOutput = ExplainAggregateTerminalPlan;
80
81 fn execute(
82 self,
83 session: &DbSession<E::Canister>,
84 query: &Query<E>,
85 ) -> Result<Self::Output, QueryError> {
86 session.$execute(query, self)
87 }
88
89 fn explain(
90 &self,
91 session: &DbSession<E::Canister>,
92 query: &Query<E>,
93 ) -> Result<Self::ExplainOutput, QueryError> {
94 session.explain_query_prepared_aggregate_terminal_with_visible_indexes(query, self)
95 }
96 }
97 };
98}
99
100macro_rules! impl_projection_terminal_driver {
104 ($terminal:ty, $output:ty, $execute:ident) => {
105 impl<E> TerminalStrategyDriver<E> for $terminal
106 where
107 E: PersistedRow + EntityValue,
108 {
109 type Output = $output;
110 type ExplainOutput = ExplainExecutionNodeDescriptor;
111
112 fn execute(
113 self,
114 session: &DbSession<E::Canister>,
115 query: &Query<E>,
116 ) -> Result<Self::Output, QueryError> {
117 session.$execute(query, self)
118 }
119
120 fn explain(
121 &self,
122 session: &DbSession<E::Canister>,
123 query: &Query<E>,
124 ) -> Result<Self::ExplainOutput, QueryError> {
125 session.explain_query_prepared_projection_terminal_with_visible_indexes(query, self)
126 }
127 }
128 };
129}
130
131impl_aggregate_terminal_driver!(CountRowsTerminal, u32, execute_fluent_count_rows_terminal);
132impl_aggregate_terminal_driver!(
133 ExistsRowsTerminal,
134 bool,
135 execute_fluent_exists_rows_terminal
136);
137impl_aggregate_terminal_driver!(MinIdTerminal, Option<Id<E>>, execute_fluent_min_id_terminal);
138impl_aggregate_terminal_driver!(MaxIdTerminal, Option<Id<E>>, execute_fluent_max_id_terminal);
139impl_aggregate_terminal_driver!(
140 MinIdBySlotTerminal,
141 Option<Id<E>>,
142 execute_fluent_min_id_by_slot
143);
144impl_aggregate_terminal_driver!(
145 MaxIdBySlotTerminal,
146 Option<Id<E>>,
147 execute_fluent_max_id_by_slot
148);
149impl_aggregate_terminal_driver!(
150 SumBySlotTerminal,
151 Option<Decimal>,
152 execute_fluent_sum_by_slot
153);
154impl_aggregate_terminal_driver!(
155 SumDistinctBySlotTerminal,
156 Option<Decimal>,
157 execute_fluent_sum_distinct_by_slot
158);
159impl_aggregate_terminal_driver!(
160 AvgBySlotTerminal,
161 Option<Decimal>,
162 execute_fluent_avg_by_slot
163);
164impl_aggregate_terminal_driver!(
165 AvgDistinctBySlotTerminal,
166 Option<Decimal>,
167 execute_fluent_avg_distinct_by_slot
168);
169impl_aggregate_terminal_driver!(
170 FirstIdTerminal,
171 Option<Id<E>>,
172 execute_fluent_first_id_terminal
173);
174impl_aggregate_terminal_driver!(
175 LastIdTerminal,
176 Option<Id<E>>,
177 execute_fluent_last_id_terminal
178);
179impl_aggregate_terminal_driver!(
180 NthIdBySlotTerminal,
181 Option<Id<E>>,
182 execute_fluent_nth_id_by_slot
183);
184impl_aggregate_terminal_driver!(
185 MedianIdBySlotTerminal,
186 Option<Id<E>>,
187 execute_fluent_median_id_by_slot
188);
189impl_aggregate_terminal_driver!(
190 MinMaxIdBySlotTerminal,
191 MinMaxByIds<E>,
192 execute_fluent_min_max_id_by_slot
193);
194
195impl_projection_terminal_driver!(
196 ValuesBySlotTerminal,
197 Vec<Value>,
198 execute_fluent_values_by_slot
199);
200impl_projection_terminal_driver!(
201 DistinctValuesBySlotTerminal,
202 Vec<Value>,
203 execute_fluent_distinct_values_by_slot
204);
205impl_projection_terminal_driver!(
206 CountDistinctBySlotTerminal,
207 u32,
208 execute_fluent_count_distinct_by_slot
209);
210impl_projection_terminal_driver!(
211 ValuesBySlotWithIdsTerminal,
212 Vec<(Id<E>, Value)>,
213 execute_fluent_values_by_with_ids_slot
214);
215impl_projection_terminal_driver!(
216 FirstValueBySlotTerminal,
217 Option<Value>,
218 execute_fluent_first_value_by_slot
219);
220impl_projection_terminal_driver!(
221 LastValueBySlotTerminal,
222 Option<Value>,
223 execute_fluent_last_value_by_slot
224);
225
226fn output(value: Value) -> OutputValue {
228 OutputValue::from(value)
229}
230
231fn output_values(values: Vec<Value>) -> Vec<OutputValue> {
233 values.into_iter().map(output).collect()
234}
235
236fn output_values_with_ids<E: PersistedRow>(
238 values: Vec<(Id<E>, Value)>,
239) -> Vec<(Id<E>, OutputValue)> {
240 values
241 .into_iter()
242 .map(|(id, value)| (id, output(value)))
243 .collect()
244}
245
246impl<E> FluentLoadQuery<'_, E>
247where
248 E: PersistedRow,
249{
250 pub fn execute(&self) -> Result<LoadQueryResult<E>, QueryError>
256 where
257 E: EntityValue,
258 {
259 self.with_non_paged(DbSession::execute_query_result)
260 }
261
262 fn with_non_paged<T>(
265 &self,
266 map: impl FnOnce(&DbSession<E::Canister>, &Query<E>) -> Result<T, QueryError>,
267 ) -> Result<T, QueryError>
268 where
269 E: EntityValue,
270 {
271 self.ensure_non_paged_mode_ready()?;
272 map(self.session, self.query())
273 }
274
275 fn explain_execution_descriptor(&self) -> Result<ExplainExecutionNodeDescriptor, QueryError>
278 where
279 E: EntityValue,
280 {
281 self.with_non_paged(DbSession::explain_query_execution_with_visible_indexes)
282 }
283
284 fn render_execution_descriptor(
287 &self,
288 render: impl FnOnce(ExplainExecutionNodeDescriptor) -> String,
289 ) -> Result<String, QueryError>
290 where
291 E: EntityValue,
292 {
293 let descriptor = self.explain_execution_descriptor()?;
294
295 Ok(render(descriptor))
296 }
297
298 fn execute_terminal<S>(&self, strategy: S) -> Result<S::Output, QueryError>
301 where
302 E: EntityValue,
303 S: TerminalStrategyDriver<E>,
304 {
305 self.with_non_paged(|session, query| strategy.execute(session, query))
306 }
307
308 fn explain_terminal<S>(&self, strategy: &S) -> Result<S::ExplainOutput, QueryError>
311 where
312 E: EntityValue,
313 S: TerminalStrategyDriver<E>,
314 {
315 self.with_non_paged(|session, query| strategy.explain(session, query))
316 }
317
318 pub fn is_empty(&self) -> Result<bool, QueryError>
324 where
325 E: EntityValue,
326 {
327 self.not_exists()
328 }
329
330 pub fn not_exists(&self) -> Result<bool, QueryError>
332 where
333 E: EntityValue,
334 {
335 Ok(!self.exists()?)
336 }
337
338 pub fn exists(&self) -> Result<bool, QueryError>
340 where
341 E: EntityValue,
342 {
343 self.execute_terminal(ExistsRowsTerminal::new())
344 }
345
346 pub fn explain_exists(&self) -> Result<ExplainAggregateTerminalPlan, QueryError>
348 where
349 E: EntityValue,
350 {
351 self.explain_terminal(&ExistsRowsTerminal::new())
352 }
353
354 pub fn explain_not_exists(&self) -> Result<ExplainAggregateTerminalPlan, QueryError>
358 where
359 E: EntityValue,
360 {
361 self.explain_exists()
362 }
363
364 pub fn explain_execution(&self) -> Result<ExplainExecutionNodeDescriptor, QueryError>
366 where
367 E: EntityValue,
368 {
369 self.explain_execution_descriptor()
370 }
371
372 pub fn explain_execution_text(&self) -> Result<String, QueryError>
374 where
375 E: EntityValue,
376 {
377 self.render_execution_descriptor(|descriptor| descriptor.render_text_tree())
378 }
379
380 pub fn explain_execution_json(&self) -> Result<String, QueryError>
382 where
383 E: EntityValue,
384 {
385 self.render_execution_descriptor(|descriptor| descriptor.render_json_canonical())
386 }
387
388 pub fn explain_execution_verbose(&self) -> Result<String, QueryError>
390 where
391 E: EntityValue,
392 {
393 self.with_non_paged(DbSession::explain_query_execution_verbose_with_visible_indexes)
394 }
395
396 pub fn count(&self) -> Result<u32, QueryError>
398 where
399 E: EntityValue,
400 {
401 self.execute_terminal(CountRowsTerminal::new())
402 }
403
404 pub fn bytes(&self) -> Result<u64, QueryError>
407 where
408 E: EntityValue,
409 {
410 self.with_non_paged(DbSession::execute_fluent_bytes)
411 }
412
413 pub fn bytes_by(&self, field: impl AsRef<str>) -> Result<u64, QueryError>
416 where
417 E: EntityValue,
418 {
419 let target_slot = self.resolve_non_paged_slot(field)?;
420
421 self.with_non_paged(|session, query| {
422 session.execute_fluent_bytes_by_slot(query, target_slot)
423 })
424 }
425
426 pub fn explain_bytes_by(
428 &self,
429 field: impl AsRef<str>,
430 ) -> Result<ExplainExecutionNodeDescriptor, QueryError>
431 where
432 E: EntityValue,
433 {
434 let target_slot = self.resolve_non_paged_slot(field)?;
435
436 self.with_non_paged(|session, query| {
437 session.explain_query_bytes_by_with_visible_indexes(query, target_slot.field())
438 })
439 }
440
441 pub fn min(&self) -> Result<Option<Id<E>>, QueryError>
443 where
444 E: EntityValue,
445 {
446 self.execute_terminal(MinIdTerminal::new())
447 }
448
449 pub fn explain_min(&self) -> Result<ExplainAggregateTerminalPlan, QueryError>
451 where
452 E: EntityValue,
453 {
454 self.explain_terminal(&MinIdTerminal::new())
455 }
456
457 pub fn min_by(&self, field: impl AsRef<str>) -> Result<Option<Id<E>>, QueryError>
461 where
462 E: EntityValue,
463 {
464 let target_slot = self.resolve_non_paged_slot(field)?;
465
466 self.execute_terminal(MinIdBySlotTerminal::new(target_slot))
467 }
468
469 pub fn max(&self) -> Result<Option<Id<E>>, QueryError>
471 where
472 E: EntityValue,
473 {
474 self.execute_terminal(MaxIdTerminal::new())
475 }
476
477 pub fn explain_max(&self) -> Result<ExplainAggregateTerminalPlan, QueryError>
479 where
480 E: EntityValue,
481 {
482 self.explain_terminal(&MaxIdTerminal::new())
483 }
484
485 pub fn max_by(&self, field: impl AsRef<str>) -> Result<Option<Id<E>>, QueryError>
489 where
490 E: EntityValue,
491 {
492 let target_slot = self.resolve_non_paged_slot(field)?;
493
494 self.execute_terminal(MaxIdBySlotTerminal::new(target_slot))
495 }
496
497 pub fn nth_by(&self, field: impl AsRef<str>, nth: usize) -> Result<Option<Id<E>>, QueryError>
500 where
501 E: EntityValue,
502 {
503 let target_slot = self.resolve_non_paged_slot(field)?;
504
505 self.execute_terminal(NthIdBySlotTerminal::new(target_slot, nth))
506 }
507
508 pub fn sum_by(&self, field: impl AsRef<str>) -> Result<Option<Decimal>, QueryError>
510 where
511 E: EntityValue,
512 {
513 let target_slot = self.resolve_non_paged_slot(field)?;
514
515 self.execute_terminal(SumBySlotTerminal::new(target_slot))
516 }
517
518 pub fn explain_sum_by(
520 &self,
521 field: impl AsRef<str>,
522 ) -> Result<ExplainAggregateTerminalPlan, QueryError>
523 where
524 E: EntityValue,
525 {
526 let target_slot = self.resolve_non_paged_slot(field)?;
527
528 self.explain_terminal(&SumBySlotTerminal::new(target_slot))
529 }
530
531 pub fn sum_distinct_by(&self, field: impl AsRef<str>) -> Result<Option<Decimal>, QueryError>
533 where
534 E: EntityValue,
535 {
536 let target_slot = self.resolve_non_paged_slot(field)?;
537
538 self.execute_terminal(SumDistinctBySlotTerminal::new(target_slot))
539 }
540
541 pub fn explain_sum_distinct_by(
543 &self,
544 field: impl AsRef<str>,
545 ) -> Result<ExplainAggregateTerminalPlan, QueryError>
546 where
547 E: EntityValue,
548 {
549 let target_slot = self.resolve_non_paged_slot(field)?;
550
551 self.explain_terminal(&SumDistinctBySlotTerminal::new(target_slot))
552 }
553
554 pub fn avg_by(&self, field: impl AsRef<str>) -> Result<Option<Decimal>, QueryError>
556 where
557 E: EntityValue,
558 {
559 let target_slot = self.resolve_non_paged_slot(field)?;
560
561 self.execute_terminal(AvgBySlotTerminal::new(target_slot))
562 }
563
564 pub fn explain_avg_by(
566 &self,
567 field: impl AsRef<str>,
568 ) -> Result<ExplainAggregateTerminalPlan, QueryError>
569 where
570 E: EntityValue,
571 {
572 let target_slot = self.resolve_non_paged_slot(field)?;
573
574 self.explain_terminal(&AvgBySlotTerminal::new(target_slot))
575 }
576
577 pub fn avg_distinct_by(&self, field: impl AsRef<str>) -> Result<Option<Decimal>, QueryError>
579 where
580 E: EntityValue,
581 {
582 let target_slot = self.resolve_non_paged_slot(field)?;
583
584 self.execute_terminal(AvgDistinctBySlotTerminal::new(target_slot))
585 }
586
587 pub fn explain_avg_distinct_by(
589 &self,
590 field: impl AsRef<str>,
591 ) -> Result<ExplainAggregateTerminalPlan, QueryError>
592 where
593 E: EntityValue,
594 {
595 let target_slot = self.resolve_non_paged_slot(field)?;
596
597 self.explain_terminal(&AvgDistinctBySlotTerminal::new(target_slot))
598 }
599
600 pub fn median_by(&self, field: impl AsRef<str>) -> Result<Option<Id<E>>, QueryError>
605 where
606 E: EntityValue,
607 {
608 let target_slot = self.resolve_non_paged_slot(field)?;
609
610 self.execute_terminal(MedianIdBySlotTerminal::new(target_slot))
611 }
612
613 pub fn count_distinct_by(&self, field: impl AsRef<str>) -> Result<u32, QueryError>
616 where
617 E: EntityValue,
618 {
619 let target_slot = self.resolve_non_paged_slot(field)?;
620
621 self.execute_terminal(CountDistinctBySlotTerminal::new(target_slot))
622 }
623
624 pub fn explain_count_distinct_by(
626 &self,
627 field: impl AsRef<str>,
628 ) -> Result<ExplainExecutionNodeDescriptor, QueryError>
629 where
630 E: EntityValue,
631 {
632 let target_slot = self.resolve_non_paged_slot(field)?;
633
634 self.explain_terminal(&CountDistinctBySlotTerminal::new(target_slot))
635 }
636
637 pub fn min_max_by(&self, field: impl AsRef<str>) -> Result<MinMaxByIds<E>, QueryError>
641 where
642 E: EntityValue,
643 {
644 let target_slot = self.resolve_non_paged_slot(field)?;
645
646 self.execute_terminal(MinMaxIdBySlotTerminal::new(target_slot))
647 }
648
649 pub fn values_by(&self, field: impl AsRef<str>) -> Result<Vec<OutputValue>, QueryError>
651 where
652 E: EntityValue,
653 {
654 let target_slot = self.resolve_non_paged_slot(field)?;
655
656 self.execute_terminal(ValuesBySlotTerminal::new(target_slot))
657 .map(output_values)
658 }
659
660 pub fn project_values<P>(&self, projection: &P) -> Result<Vec<OutputValue>, QueryError>
663 where
664 E: EntityValue,
665 P: ValueProjectionExpr,
666 {
667 let target_slot = self.resolve_non_paged_slot(projection.field())?;
668
669 self.with_non_paged(|session, query| {
670 session.execute_fluent_project_values_by_slot(
671 query,
672 target_slot,
673 projection.projection_plan().into_expr(),
674 )
675 })
676 .map(output_values)
677 }
678
679 pub fn explain_project_values<P>(
681 &self,
682 projection: &P,
683 ) -> Result<ExplainExecutionNodeDescriptor, QueryError>
684 where
685 E: EntityValue,
686 P: ValueProjectionExpr,
687 {
688 let target_slot = self.resolve_non_paged_slot(projection.field())?;
689
690 self.explain_terminal(&ValuesBySlotTerminal::new(target_slot))
691 }
692
693 pub fn explain_values_by(
695 &self,
696 field: impl AsRef<str>,
697 ) -> Result<ExplainExecutionNodeDescriptor, QueryError>
698 where
699 E: EntityValue,
700 {
701 let target_slot = self.resolve_non_paged_slot(field)?;
702
703 self.explain_terminal(&ValuesBySlotTerminal::new(target_slot))
704 }
705
706 pub fn take(&self, take_count: u32) -> Result<EntityResponse<E>, QueryError>
708 where
709 E: EntityValue,
710 {
711 self.with_non_paged(|session, query| session.execute_fluent_take(query, take_count))
712 }
713
714 pub fn top_k_by(
722 &self,
723 field: impl AsRef<str>,
724 take_count: u32,
725 ) -> Result<EntityResponse<E>, QueryError>
726 where
727 E: EntityValue,
728 {
729 let target_slot = self.resolve_non_paged_slot(field)?;
730
731 self.with_non_paged(|session, query| {
732 session.execute_fluent_top_k_rows_by_slot(query, target_slot, take_count)
733 })
734 }
735
736 pub fn bottom_k_by(
744 &self,
745 field: impl AsRef<str>,
746 take_count: u32,
747 ) -> Result<EntityResponse<E>, QueryError>
748 where
749 E: EntityValue,
750 {
751 let target_slot = self.resolve_non_paged_slot(field)?;
752
753 self.with_non_paged(|session, query| {
754 session.execute_fluent_bottom_k_rows_by_slot(query, target_slot, take_count)
755 })
756 }
757
758 pub fn top_k_by_values(
766 &self,
767 field: impl AsRef<str>,
768 take_count: u32,
769 ) -> Result<Vec<OutputValue>, QueryError>
770 where
771 E: EntityValue,
772 {
773 let target_slot = self.resolve_non_paged_slot(field)?;
774
775 self.with_non_paged(|session, query| {
776 session
777 .execute_fluent_top_k_values_by_slot(query, target_slot, take_count)
778 .map(output_values)
779 })
780 }
781
782 pub fn bottom_k_by_values(
790 &self,
791 field: impl AsRef<str>,
792 take_count: u32,
793 ) -> Result<Vec<OutputValue>, QueryError>
794 where
795 E: EntityValue,
796 {
797 let target_slot = self.resolve_non_paged_slot(field)?;
798
799 self.with_non_paged(|session, query| {
800 session
801 .execute_fluent_bottom_k_values_by_slot(query, target_slot, take_count)
802 .map(output_values)
803 })
804 }
805
806 pub fn top_k_by_with_ids(
814 &self,
815 field: impl AsRef<str>,
816 take_count: u32,
817 ) -> Result<Vec<(Id<E>, OutputValue)>, QueryError>
818 where
819 E: EntityValue,
820 {
821 let target_slot = self.resolve_non_paged_slot(field)?;
822
823 self.with_non_paged(|session, query| {
824 session
825 .execute_fluent_top_k_values_with_ids_by_slot(query, target_slot, take_count)
826 .map(output_values_with_ids)
827 })
828 }
829
830 pub fn bottom_k_by_with_ids(
838 &self,
839 field: impl AsRef<str>,
840 take_count: u32,
841 ) -> Result<Vec<(Id<E>, OutputValue)>, QueryError>
842 where
843 E: EntityValue,
844 {
845 let target_slot = self.resolve_non_paged_slot(field)?;
846
847 self.with_non_paged(|session, query| {
848 session
849 .execute_fluent_bottom_k_values_with_ids_by_slot(query, target_slot, take_count)
850 .map(output_values_with_ids)
851 })
852 }
853
854 pub fn distinct_values_by(&self, field: impl AsRef<str>) -> Result<Vec<OutputValue>, QueryError>
857 where
858 E: EntityValue,
859 {
860 let target_slot = self.resolve_non_paged_slot(field)?;
861
862 self.execute_terminal(DistinctValuesBySlotTerminal::new(target_slot))
863 .map(output_values)
864 }
865
866 pub fn explain_distinct_values_by(
868 &self,
869 field: impl AsRef<str>,
870 ) -> Result<ExplainExecutionNodeDescriptor, QueryError>
871 where
872 E: EntityValue,
873 {
874 let target_slot = self.resolve_non_paged_slot(field)?;
875
876 self.explain_terminal(&DistinctValuesBySlotTerminal::new(target_slot))
877 }
878
879 pub fn values_by_with_ids(
882 &self,
883 field: impl AsRef<str>,
884 ) -> Result<Vec<(Id<E>, OutputValue)>, QueryError>
885 where
886 E: EntityValue,
887 {
888 let target_slot = self.resolve_non_paged_slot(field)?;
889
890 self.execute_terminal(ValuesBySlotWithIdsTerminal::new(target_slot))
891 .map(output_values_with_ids)
892 }
893
894 pub fn project_values_with_ids<P>(
897 &self,
898 projection: &P,
899 ) -> Result<Vec<(Id<E>, OutputValue)>, QueryError>
900 where
901 E: EntityValue,
902 P: ValueProjectionExpr,
903 {
904 let target_slot = self.resolve_non_paged_slot(projection.field())?;
905
906 self.with_non_paged(|session, query| {
907 session.execute_fluent_project_values_with_ids_by_slot(
908 query,
909 target_slot,
910 projection.projection_plan().into_expr(),
911 )
912 })
913 .map(output_values_with_ids)
914 }
915
916 pub fn explain_values_by_with_ids(
918 &self,
919 field: impl AsRef<str>,
920 ) -> Result<ExplainExecutionNodeDescriptor, QueryError>
921 where
922 E: EntityValue,
923 {
924 let target_slot = self.resolve_non_paged_slot(field)?;
925
926 self.explain_terminal(&ValuesBySlotWithIdsTerminal::new(target_slot))
927 }
928
929 pub fn first_value_by(&self, field: impl AsRef<str>) -> Result<Option<OutputValue>, QueryError>
932 where
933 E: EntityValue,
934 {
935 let target_slot = self.resolve_non_paged_slot(field)?;
936
937 self.execute_terminal(FirstValueBySlotTerminal::new(target_slot))
938 .map(|value| value.map(output))
939 }
940
941 pub fn project_first_value<P>(&self, projection: &P) -> Result<Option<OutputValue>, QueryError>
944 where
945 E: EntityValue,
946 P: ValueProjectionExpr,
947 {
948 let target_slot = self.resolve_non_paged_slot(projection.field())?;
949
950 self.with_non_paged(|session, query| {
951 session.execute_fluent_project_terminal_value_by_slot(
952 query,
953 target_slot,
954 AggregateKind::First,
955 projection.projection_plan().into_expr(),
956 )
957 })
958 .map(|value| value.map(output))
959 }
960
961 pub fn explain_first_value_by(
963 &self,
964 field: impl AsRef<str>,
965 ) -> Result<ExplainExecutionNodeDescriptor, QueryError>
966 where
967 E: EntityValue,
968 {
969 let target_slot = self.resolve_non_paged_slot(field)?;
970
971 self.explain_terminal(&FirstValueBySlotTerminal::new(target_slot))
972 }
973
974 pub fn last_value_by(&self, field: impl AsRef<str>) -> Result<Option<OutputValue>, QueryError>
977 where
978 E: EntityValue,
979 {
980 let target_slot = self.resolve_non_paged_slot(field)?;
981
982 self.execute_terminal(LastValueBySlotTerminal::new(target_slot))
983 .map(|value| value.map(output))
984 }
985
986 pub fn project_last_value<P>(&self, projection: &P) -> Result<Option<OutputValue>, QueryError>
989 where
990 E: EntityValue,
991 P: ValueProjectionExpr,
992 {
993 let target_slot = self.resolve_non_paged_slot(projection.field())?;
994
995 self.with_non_paged(|session, query| {
996 session.execute_fluent_project_terminal_value_by_slot(
997 query,
998 target_slot,
999 AggregateKind::Last,
1000 projection.projection_plan().into_expr(),
1001 )
1002 })
1003 .map(|value| value.map(output))
1004 }
1005
1006 pub fn explain_last_value_by(
1008 &self,
1009 field: impl AsRef<str>,
1010 ) -> Result<ExplainExecutionNodeDescriptor, QueryError>
1011 where
1012 E: EntityValue,
1013 {
1014 let target_slot = self.resolve_non_paged_slot(field)?;
1015
1016 self.explain_terminal(&LastValueBySlotTerminal::new(target_slot))
1017 }
1018
1019 pub fn first(&self) -> Result<Option<Id<E>>, QueryError>
1021 where
1022 E: EntityValue,
1023 {
1024 self.execute_terminal(FirstIdTerminal::new())
1025 }
1026
1027 pub fn explain_first(&self) -> Result<ExplainAggregateTerminalPlan, QueryError>
1029 where
1030 E: EntityValue,
1031 {
1032 self.explain_terminal(&FirstIdTerminal::new())
1033 }
1034
1035 pub fn last(&self) -> Result<Option<Id<E>>, QueryError>
1037 where
1038 E: EntityValue,
1039 {
1040 self.execute_terminal(LastIdTerminal::new())
1041 }
1042
1043 pub fn explain_last(&self) -> Result<ExplainAggregateTerminalPlan, QueryError>
1045 where
1046 E: EntityValue,
1047 {
1048 self.explain_terminal(&LastIdTerminal::new())
1049 }
1050
1051 pub fn require_one(&self) -> Result<(), QueryError>
1053 where
1054 E: EntityValue,
1055 {
1056 self.execute()?.into_rows()?.require_one()?;
1057 Ok(())
1058 }
1059
1060 pub fn require_some(&self) -> Result<(), QueryError>
1062 where
1063 E: EntityValue,
1064 {
1065 self.execute()?.into_rows()?.require_some()?;
1066 Ok(())
1067 }
1068}