Skip to main content

clicktype_query/
aggregate.rs

1//! Aggregate functions for ClickHouse
2
3use std::marker::PhantomData;
4use clicktype_core::traits::{ClickHouseType, Numeric};
5use crate::expr::Expression;
6
7/// Trait for aggregate functions
8pub trait AggregateFn {
9    /// Input type
10    type Input: ClickHouseType;
11    /// Output type
12    type Output: ClickHouseType;
13    /// Function name in SQL
14    fn name() -> &'static str;
15}
16
17/// Aggregate expression wrapper
18pub struct AggregateExpr<F: AggregateFn, E: Expression> {
19    inner: E,
20    _fn: PhantomData<F>,
21}
22
23impl<F: AggregateFn, E: Expression> AggregateExpr<F, E> {
24    pub fn new(inner: E) -> Self {
25        Self {
26            inner,
27            _fn: PhantomData,
28        }
29    }
30}
31
32impl<F: AggregateFn, E: Expression> Expression for AggregateExpr<F, E> {
33    type Output = F::Output;
34
35    fn render(&self) -> String {
36        format!("{}({})", F::name(), self.inner.render())
37    }
38
39    fn is_aggregate(&self) -> bool {
40        true
41    }
42}
43
44// === STANDARD AGGREGATE FUNCTIONS ===
45
46/// COUNT function
47pub struct Count;
48
49impl AggregateFn for Count {
50    type Input = u64;
51    type Output = u64;
52
53    fn name() -> &'static str {
54        "count"
55    }
56}
57
58/// SUM function
59pub struct Sum<T: Numeric>(PhantomData<T>);
60
61impl<T: Numeric> AggregateFn for Sum<T> {
62    type Input = T;
63    type Output = T;
64
65    fn name() -> &'static str {
66        "sum"
67    }
68}
69
70/// AVG function
71pub struct Avg<T: Numeric>(PhantomData<T>);
72
73impl<T: Numeric> AggregateFn for Avg<T> {
74    type Input = T;
75    type Output = f64;
76
77    fn name() -> &'static str {
78        "avg"
79    }
80}
81
82/// MIN function
83pub struct Min<T: ClickHouseType>(PhantomData<T>);
84
85impl<T: ClickHouseType> AggregateFn for Min<T> {
86    type Input = T;
87    type Output = T;
88
89    fn name() -> &'static str {
90        "min"
91    }
92}
93
94/// MAX function
95pub struct Max<T: ClickHouseType>(PhantomData<T>);
96
97impl<T: ClickHouseType> AggregateFn for Max<T> {
98    type Input = T;
99    type Output = T;
100
101    fn name() -> &'static str {
102        "max"
103    }
104}
105
106/// ANY function
107pub struct Any<T: ClickHouseType>(PhantomData<T>);
108
109impl<T: ClickHouseType> AggregateFn for Any<T> {
110    type Input = T;
111    type Output = T;
112
113    fn name() -> &'static str {
114        "any"
115    }
116}
117
118/// ANY_LAST function
119pub struct AnyLast<T: ClickHouseType>(PhantomData<T>);
120
121impl<T: ClickHouseType> AggregateFn for AnyLast<T> {
122    type Input = T;
123    type Output = T;
124
125    fn name() -> &'static str {
126        "anyLast"
127    }
128}
129
130// === ADVANCED CLICKHOUSE FUNCTIONS ===
131
132/// UNIQ function (HyperLogLog approximate)
133pub struct Uniq<T: ClickHouseType>(PhantomData<T>);
134
135impl<T: ClickHouseType> AggregateFn for Uniq<T> {
136    type Input = T;
137    type Output = u64;
138
139    fn name() -> &'static str {
140        "uniq"
141    }
142}
143
144/// UNIQ_EXACT function (exact unique count)
145pub struct UniqExact<T: ClickHouseType>(PhantomData<T>);
146
147impl<T: ClickHouseType> AggregateFn for UniqExact<T> {
148    type Input = T;
149    type Output = u64;
150
151    fn name() -> &'static str {
152        "uniqExact"
153    }
154}
155
156/// GROUP_ARRAY function
157pub struct GroupArray<T: ClickHouseType>(PhantomData<T>);
158
159impl<T: ClickHouseType> AggregateFn for GroupArray<T> {
160    type Input = T;
161    type Output = Vec<T>;
162
163    fn name() -> &'static str {
164        "groupArray"
165    }
166}
167
168// === ERGONOMIC API ===
169
170/// Star expression for COUNT(*)
171pub struct Star;
172
173impl Expression for Star {
174    type Output = u64;
175
176    fn render(&self) -> String {
177        "*".to_string()
178    }
179}
180
181/// count(*) - count all rows
182pub fn count_all() -> AggregateExpr<Count, Star> {
183    AggregateExpr::new(Star)
184}
185
186/// count(expr) - count non-null values
187pub fn count<E: Expression>(expr: E) -> AggregateExpr<Count, E> {
188    AggregateExpr::new(expr)
189}
190
191/// sum(expr) - sum of values
192pub fn sum<E: Expression>(expr: E) -> AggregateExpr<Sum<E::Output>, E>
193where
194    E::Output: Numeric,
195{
196    AggregateExpr::new(expr)
197}
198
199/// avg(expr) - average of values
200pub fn avg<E: Expression>(expr: E) -> AggregateExpr<Avg<E::Output>, E>
201where
202    E::Output: Numeric,
203{
204    AggregateExpr::new(expr)
205}
206
207/// min(expr) - minimum value
208pub fn min<E: Expression>(expr: E) -> AggregateExpr<Min<E::Output>, E> {
209    AggregateExpr::new(expr)
210}
211
212/// max(expr) - maximum value
213pub fn max<E: Expression>(expr: E) -> AggregateExpr<Max<E::Output>, E> {
214    AggregateExpr::new(expr)
215}
216
217/// any(expr) - any value (non-deterministic)
218pub fn any<E: Expression>(expr: E) -> AggregateExpr<Any<E::Output>, E> {
219    AggregateExpr::new(expr)
220}
221
222/// anyLast(expr) - last value seen
223pub fn any_last<E: Expression>(expr: E) -> AggregateExpr<AnyLast<E::Output>, E> {
224    AggregateExpr::new(expr)
225}
226
227/// uniq(expr) - approximate unique count (HyperLogLog)
228pub fn uniq<E: Expression>(expr: E) -> AggregateExpr<Uniq<E::Output>, E> {
229    AggregateExpr::new(expr)
230}
231
232/// uniqExact(expr) - exact unique count
233pub fn uniq_exact<E: Expression>(expr: E) -> AggregateExpr<UniqExact<E::Output>, E> {
234    AggregateExpr::new(expr)
235}
236
237/// groupArray(expr) - collect values into array
238pub fn group_array<E: Expression>(expr: E) -> AggregateExpr<GroupArray<E::Output>, E> {
239    AggregateExpr::new(expr)
240}
241
242// === PARAMETRIC AGGREGATE FUNCTIONS ===
243
244/// Quantile expression
245pub struct QuantileExpr<E: Expression> {
246    level: f64,
247    inner: E,
248}
249
250impl<E: Expression> Expression for QuantileExpr<E>
251where
252    E::Output: Numeric,
253{
254    type Output = f64;
255
256    fn render(&self) -> String {
257        format!("quantile({})({})", self.level, self.inner.render())
258    }
259
260    fn is_aggregate(&self) -> bool {
261        true
262    }
263}
264
265/// quantile(level)(expr) - quantile at given level
266pub fn quantile<E: Expression>(level: f64, expr: E) -> QuantileExpr<E>
267where
268    E::Output: Numeric,
269{
270    QuantileExpr { level, inner: expr }
271}
272
273/// ArgMax expression
274pub struct ArgMaxExpr<A: Expression, V: Expression> {
275    arg: A,
276    val: V,
277}
278
279impl<A: Expression, V: Expression> Expression for ArgMaxExpr<A, V> {
280    type Output = A::Output;
281
282    fn render(&self) -> String {
283        format!("argMax({}, {})", self.arg.render(), self.val.render())
284    }
285
286    fn is_aggregate(&self) -> bool {
287        true
288    }
289}
290
291/// argMax(arg, val) - value of arg where val is maximum
292pub fn arg_max<A: Expression, V: Expression>(arg: A, val: V) -> ArgMaxExpr<A, V> {
293    ArgMaxExpr { arg, val }
294}
295
296/// ArgMin expression
297pub struct ArgMinExpr<A: Expression, V: Expression> {
298    arg: A,
299    val: V,
300}
301
302impl<A: Expression, V: Expression> Expression for ArgMinExpr<A, V> {
303    type Output = A::Output;
304
305    fn render(&self) -> String {
306        format!("argMin({}, {})", self.arg.render(), self.val.render())
307    }
308
309    fn is_aggregate(&self) -> bool {
310        true
311    }
312}
313
314/// argMin(arg, val) - value of arg where val is minimum
315pub fn arg_min<A: Expression, V: Expression>(arg: A, val: V) -> ArgMinExpr<A, V> {
316    ArgMinExpr { arg, val }
317}
318
319/// TopK expression
320pub struct TopKExpr<const N: usize, E: Expression> {
321    inner: E,
322}
323
324impl<const N: usize, E: Expression> Expression for TopKExpr<N, E> {
325    type Output = Vec<E::Output>;
326
327    fn render(&self) -> String {
328        format!("topK({})({})", N, self.inner.render())
329    }
330
331    fn is_aggregate(&self) -> bool {
332        true
333    }
334}
335
336/// topK(N)(expr) - top N most frequent values
337pub fn top_k<const N: usize, E: Expression>(expr: E) -> TopKExpr<N, E> {
338    TopKExpr { inner: expr }
339}
340
341/// GroupArrayIf expression
342pub struct GroupArrayIfExpr<E: Expression, C: Expression<Output = bool>> {
343    inner: E,
344    condition: C,
345}
346
347impl<E: Expression, C: Expression<Output = bool>> Expression for GroupArrayIfExpr<E, C> {
348    type Output = Vec<E::Output>;
349
350    fn render(&self) -> String {
351        format!(
352            "groupArrayIf({}, {})",
353            self.inner.render(),
354            self.condition.render()
355        )
356    }
357
358    fn is_aggregate(&self) -> bool {
359        true
360    }
361}
362
363/// groupArrayIf(expr, condition) - collect values where condition is true
364pub fn group_array_if<E: Expression, C: Expression<Output = bool>>(
365    expr: E,
366    condition: C,
367) -> GroupArrayIfExpr<E, C> {
368    GroupArrayIfExpr {
369        inner: expr,
370        condition,
371    }
372}