qail_core/ast/builders/
aggregates.rs

1//! Aggregate function builders (COUNT, SUM, AVG, etc.)
2
3use crate::ast::{AggregateFunc, Condition, Expr};
4
5/// COUNT(*) aggregate
6pub fn count() -> AggregateBuilder {
7    AggregateBuilder {
8        col: "*".to_string(),
9        func: AggregateFunc::Count,
10        distinct: false,
11        filter: None,
12        alias: None,
13    }
14}
15
16/// COUNT(DISTINCT column) aggregate
17pub fn count_distinct(column: &str) -> AggregateBuilder {
18    AggregateBuilder {
19        col: column.to_string(),
20        func: AggregateFunc::Count,
21        distinct: true,
22        filter: None,
23        alias: None,
24    }
25}
26
27/// COUNT(*) FILTER (WHERE conditions) aggregate
28pub fn count_filter(conditions: Vec<Condition>) -> AggregateBuilder {
29    AggregateBuilder {
30        col: "*".to_string(),
31        func: AggregateFunc::Count,
32        distinct: false,
33        filter: Some(conditions),
34        alias: None,
35    }
36}
37
38/// SUM(column) aggregate
39pub fn sum(column: &str) -> AggregateBuilder {
40    AggregateBuilder {
41        col: column.to_string(),
42        func: AggregateFunc::Sum,
43        distinct: false,
44        filter: None,
45        alias: None,
46    }
47}
48
49/// AVG(column) aggregate
50pub fn avg(column: &str) -> AggregateBuilder {
51    AggregateBuilder {
52        col: column.to_string(),
53        func: AggregateFunc::Avg,
54        distinct: false,
55        filter: None,
56        alias: None,
57    }
58}
59
60/// MIN(column) aggregate
61pub fn min(column: &str) -> AggregateBuilder {
62    AggregateBuilder {
63        col: column.to_string(),
64        func: AggregateFunc::Min,
65        distinct: false,
66        filter: None,
67        alias: None,
68    }
69}
70
71/// MAX(column) aggregate
72pub fn max(column: &str) -> AggregateBuilder {
73    AggregateBuilder {
74        col: column.to_string(),
75        func: AggregateFunc::Max,
76        distinct: false,
77        filter: None,
78        alias: None,
79    }
80}
81
82/// ARRAY_AGG(column) - collect all values into an array
83pub fn array_agg(column: &str) -> AggregateBuilder {
84    AggregateBuilder {
85        col: column.to_string(),
86        func: AggregateFunc::ArrayAgg,
87        distinct: false,
88        filter: None,
89        alias: None,
90    }
91}
92
93/// JSON_AGG(column) - aggregate values as JSON array
94pub fn json_agg(column: &str) -> AggregateBuilder {
95    AggregateBuilder {
96        col: column.to_string(),
97        func: AggregateFunc::JsonAgg,
98        distinct: false,
99        filter: None,
100        alias: None,
101    }
102}
103
104/// JSONB_AGG(column) - aggregate values as JSONB array
105pub fn jsonb_agg(column: &str) -> AggregateBuilder {
106    AggregateBuilder {
107        col: column.to_string(),
108        func: AggregateFunc::JsonbAgg,
109        distinct: false,
110        filter: None,
111        alias: None,
112    }
113}
114
115/// BOOL_AND(column) - returns TRUE if all values are true
116pub fn bool_and(column: &str) -> AggregateBuilder {
117    AggregateBuilder {
118        col: column.to_string(),
119        func: AggregateFunc::BoolAnd,
120        distinct: false,
121        filter: None,
122        alias: None,
123    }
124}
125
126/// BOOL_OR(column) - returns TRUE if any value is true
127pub fn bool_or(column: &str) -> AggregateBuilder {
128    AggregateBuilder {
129        col: column.to_string(),
130        func: AggregateFunc::BoolOr,
131        distinct: false,
132        filter: None,
133        alias: None,
134    }
135}
136
137/// Builder for aggregate expressions
138#[derive(Debug, Clone)]
139pub struct AggregateBuilder {
140    pub(crate) col: String,
141    pub(crate) func: AggregateFunc,
142    pub(crate) distinct: bool,
143    pub(crate) filter: Option<Vec<Condition>>,
144    pub(crate) alias: Option<String>,
145}
146
147impl AggregateBuilder {
148    /// Add DISTINCT modifier
149    pub fn distinct(mut self) -> Self {
150        self.distinct = true;
151        self
152    }
153
154    /// Add FILTER (WHERE ...) clause
155    pub fn filter(mut self, conditions: Vec<Condition>) -> Self {
156        self.filter = Some(conditions);
157        self
158    }
159
160    /// Add alias (AS name)
161    pub fn alias(mut self, name: &str) -> Expr {
162        self.alias = Some(name.to_string());
163        self.build()
164    }
165
166    /// Build the final Expr
167    pub fn build(self) -> Expr {
168        Expr::Aggregate {
169            col: self.col,
170            func: self.func,
171            distinct: self.distinct,
172            filter: self.filter,
173            alias: self.alias,
174        }
175    }
176}
177
178impl From<AggregateBuilder> for Expr {
179    fn from(builder: AggregateBuilder) -> Self {
180        builder.build()
181    }
182}