icydb_core/db/query/builder/
aggregate.rs1use crate::db::query::plan::AggregateKind;
7
8#[derive(Clone, Debug, Eq, PartialEq)]
17pub struct AggregateExpr {
18 kind: AggregateKind,
19 target_field: Option<String>,
20 distinct: bool,
21}
22
23impl AggregateExpr {
24 const fn new(kind: AggregateKind, target_field: Option<String>) -> Self {
26 Self {
27 kind,
28 target_field,
29 distinct: false,
30 }
31 }
32
33 #[must_use]
35 pub const fn distinct(mut self) -> Self {
36 self.distinct = true;
37 self
38 }
39
40 #[must_use]
42 pub(crate) const fn kind(&self) -> AggregateKind {
43 self.kind
44 }
45
46 #[must_use]
48 pub(crate) fn target_field(&self) -> Option<&str> {
49 self.target_field.as_deref()
50 }
51
52 #[must_use]
54 pub(crate) const fn is_distinct(&self) -> bool {
55 self.distinct
56 }
57
58 pub(in crate::db::query) const fn from_semantic_parts(
60 kind: AggregateKind,
61 target_field: Option<String>,
62 distinct: bool,
63 ) -> Self {
64 Self {
65 kind,
66 target_field,
67 distinct,
68 }
69 }
70
71 #[must_use]
73 pub(in crate::db) fn terminal_for_kind(kind: AggregateKind) -> Self {
74 match kind {
75 AggregateKind::Count => count(),
76 AggregateKind::Exists => exists(),
77 AggregateKind::Min => min(),
78 AggregateKind::Max => max(),
79 AggregateKind::First => first(),
80 AggregateKind::Last => last(),
81 AggregateKind::Sum | AggregateKind::Avg => unreachable!(
82 "AggregateExpr::terminal_for_kind does not support SUM/AVG field-target kinds"
83 ),
84 }
85 }
86
87 #[must_use]
89 pub(in crate::db) fn field_target_extrema_for_kind(
90 kind: AggregateKind,
91 field: impl AsRef<str>,
92 ) -> Self {
93 match kind {
94 AggregateKind::Min => min_by(field),
95 AggregateKind::Max => max_by(field),
96 _ => unreachable!("AggregateExpr::field_target_extrema_for_kind requires MIN/MAX kind"),
97 }
98 }
99}
100
101#[must_use]
103pub const fn count() -> AggregateExpr {
104 AggregateExpr::new(AggregateKind::Count, None)
105}
106
107#[must_use]
109pub fn count_by(field: impl AsRef<str>) -> AggregateExpr {
110 AggregateExpr::new(AggregateKind::Count, Some(field.as_ref().to_string()))
111}
112
113#[must_use]
115pub fn sum(field: impl AsRef<str>) -> AggregateExpr {
116 AggregateExpr::new(AggregateKind::Sum, Some(field.as_ref().to_string()))
117}
118
119#[must_use]
121pub fn avg(field: impl AsRef<str>) -> AggregateExpr {
122 AggregateExpr::new(AggregateKind::Avg, Some(field.as_ref().to_string()))
123}
124
125#[must_use]
127pub const fn exists() -> AggregateExpr {
128 AggregateExpr::new(AggregateKind::Exists, None)
129}
130
131#[must_use]
133pub const fn first() -> AggregateExpr {
134 AggregateExpr::new(AggregateKind::First, None)
135}
136
137#[must_use]
139pub const fn last() -> AggregateExpr {
140 AggregateExpr::new(AggregateKind::Last, None)
141}
142
143#[must_use]
145pub const fn min() -> AggregateExpr {
146 AggregateExpr::new(AggregateKind::Min, None)
147}
148
149#[must_use]
151pub fn min_by(field: impl AsRef<str>) -> AggregateExpr {
152 AggregateExpr::new(AggregateKind::Min, Some(field.as_ref().to_string()))
153}
154
155#[must_use]
157pub const fn max() -> AggregateExpr {
158 AggregateExpr::new(AggregateKind::Max, None)
159}
160
161#[must_use]
163pub fn max_by(field: impl AsRef<str>) -> AggregateExpr {
164 AggregateExpr::new(AggregateKind::Max, Some(field.as_ref().to_string()))
165}