Skip to main content

clicktype_query/
functions.rs

1//! Scalar functions for ClickHouse
2
3use clicktype_core::traits::Numeric;
4use crate::expr::Expression;
5
6// === DATE/TIME FUNCTIONS ===
7
8pub mod date {
9    use super::*;
10
11    /// toDate(expr) - convert to Date
12    pub struct ToDateExpr<E: Expression>(pub E);
13
14    impl<E: Expression> Expression for ToDateExpr<E> {
15        type Output = chrono::NaiveDate;
16
17        fn render(&self) -> String {
18            format!("toDate({})", self.0.render())
19        }
20    }
21
22    pub fn to_date<E: Expression>(expr: E) -> ToDateExpr<E> {
23        ToDateExpr(expr)
24    }
25
26    /// toDateTime(expr) - convert to DateTime
27    pub struct ToDateTimeExpr<E: Expression>(pub E);
28
29    impl<E: Expression> Expression for ToDateTimeExpr<E> {
30        type Output = chrono::NaiveDateTime;
31
32        fn render(&self) -> String {
33            format!("toDateTime({})", self.0.render())
34        }
35    }
36
37    pub fn to_datetime<E: Expression>(expr: E) -> ToDateTimeExpr<E> {
38        ToDateTimeExpr(expr)
39    }
40
41    /// toYYYYMM(date) - convert date to YYYYMM format
42    pub struct ToYYYYMMExpr<E: Expression>(pub E);
43
44    impl<E: Expression> Expression for ToYYYYMMExpr<E> {
45        type Output = u32;
46
47        fn render(&self) -> String {
48            format!("toYYYYMM({})", self.0.render())
49        }
50    }
51
52    pub fn to_yyyymm<E: Expression>(expr: E) -> ToYYYYMMExpr<E> {
53        ToYYYYMMExpr(expr)
54    }
55
56    /// toStartOfDay(datetime) - round to start of day
57    pub struct ToStartOfDayExpr<E: Expression>(pub E);
58
59    impl<E: Expression> Expression for ToStartOfDayExpr<E> {
60        type Output = chrono::NaiveDateTime;
61
62        fn render(&self) -> String {
63            format!("toStartOfDay({})", self.0.render())
64        }
65    }
66
67    pub fn to_start_of_day<E: Expression>(expr: E) -> ToStartOfDayExpr<E> {
68        ToStartOfDayExpr(expr)
69    }
70
71    /// toStartOfHour(datetime) - round to start of hour
72    pub struct ToStartOfHourExpr<E: Expression>(pub E);
73
74    impl<E: Expression> Expression for ToStartOfHourExpr<E> {
75        type Output = chrono::NaiveDateTime;
76
77        fn render(&self) -> String {
78            format!("toStartOfHour({})", self.0.render())
79        }
80    }
81
82    pub fn to_start_of_hour<E: Expression>(expr: E) -> ToStartOfHourExpr<E> {
83        ToStartOfHourExpr(expr)
84    }
85
86    /// now() - current timestamp
87    pub struct NowExpr;
88
89    impl Expression for NowExpr {
90        type Output = chrono::NaiveDateTime;
91
92        fn render(&self) -> String {
93            "now()".to_string()
94        }
95    }
96
97    pub fn now() -> NowExpr {
98        NowExpr
99    }
100
101    /// today() - current date
102    pub struct TodayExpr;
103
104    impl Expression for TodayExpr {
105        type Output = chrono::NaiveDate;
106
107        fn render(&self) -> String {
108            "today()".to_string()
109        }
110    }
111
112    pub fn today() -> TodayExpr {
113        TodayExpr
114    }
115}
116
117// === STRING FUNCTIONS ===
118
119pub mod string {
120    use super::*;
121
122    /// length(s) - string length
123    pub struct LengthExpr<E: Expression<Output = String>>(pub E);
124
125    impl<E: Expression<Output = String>> Expression for LengthExpr<E> {
126        type Output = u64;
127
128        fn render(&self) -> String {
129            format!("length({})", self.0.render())
130        }
131    }
132
133    pub fn length<E: Expression<Output = String>>(expr: E) -> LengthExpr<E> {
134        LengthExpr(expr)
135    }
136
137    /// lower(s) - convert to lowercase
138    pub struct LowerExpr<E: Expression<Output = String>>(pub E);
139
140    impl<E: Expression<Output = String>> Expression for LowerExpr<E> {
141        type Output = String;
142
143        fn render(&self) -> String {
144            format!("lower({})", self.0.render())
145        }
146    }
147
148    pub fn lower<E: Expression<Output = String>>(expr: E) -> LowerExpr<E> {
149        LowerExpr(expr)
150    }
151
152    /// upper(s) - convert to uppercase
153    pub struct UpperExpr<E: Expression<Output = String>>(pub E);
154
155    impl<E: Expression<Output = String>> Expression for UpperExpr<E> {
156        type Output = String;
157
158        fn render(&self) -> String {
159            format!("upper({})", self.0.render())
160        }
161    }
162
163    pub fn upper<E: Expression<Output = String>>(expr: E) -> UpperExpr<E> {
164        UpperExpr(expr)
165    }
166
167    /// concat(a, b, ...) - concatenate strings
168    pub struct ConcatExpr<A: Expression<Output = String>, B: Expression<Output = String>> {
169        a: A,
170        b: B,
171    }
172
173    impl<A: Expression<Output = String>, B: Expression<Output = String>> Expression
174        for ConcatExpr<A, B>
175    {
176        type Output = String;
177
178        fn render(&self) -> String {
179            format!("concat({}, {})", self.a.render(), self.b.render())
180        }
181    }
182
183    pub fn concat<A: Expression<Output = String>, B: Expression<Output = String>>(
184        a: A,
185        b: B,
186    ) -> ConcatExpr<A, B> {
187        ConcatExpr { a, b }
188    }
189
190    /// substring(s, offset, length) - extract substring
191    pub struct SubstringExpr<E: Expression<Output = String>> {
192        inner: E,
193        offset: usize,
194        length: usize,
195    }
196
197    impl<E: Expression<Output = String>> Expression for SubstringExpr<E> {
198        type Output = String;
199
200        fn render(&self) -> String {
201            format!(
202                "substring({}, {}, {})",
203                self.inner.render(),
204                self.offset,
205                self.length
206            )
207        }
208    }
209
210    pub fn substring<E: Expression<Output = String>>(
211        expr: E,
212        offset: usize,
213        length: usize,
214    ) -> SubstringExpr<E> {
215        SubstringExpr {
216            inner: expr,
217            offset,
218            length,
219        }
220    }
221}
222
223// === MATH FUNCTIONS ===
224
225pub mod math {
226    use super::*;
227
228    /// abs(x) - absolute value
229    pub struct AbsExpr<E: Expression>(pub E);
230
231    impl<E: Expression> Expression for AbsExpr<E>
232    where
233        E::Output: Numeric,
234    {
235        type Output = E::Output;
236
237        fn render(&self) -> String {
238            format!("abs({})", self.0.render())
239        }
240    }
241
242    pub fn abs<E: Expression>(expr: E) -> AbsExpr<E>
243    where
244        E::Output: Numeric,
245    {
246        AbsExpr(expr)
247    }
248
249    /// round(x, precision) - round to precision
250    pub struct RoundExpr<E: Expression> {
251        inner: E,
252        precision: u8,
253    }
254
255    impl<E: Expression> Expression for RoundExpr<E>
256    where
257        E::Output: Numeric,
258    {
259        type Output = E::Output;
260
261        fn render(&self) -> String {
262            format!("round({}, {})", self.inner.render(), self.precision)
263        }
264    }
265
266    pub fn round<E: Expression>(expr: E, precision: u8) -> RoundExpr<E>
267    where
268        E::Output: Numeric,
269    {
270        RoundExpr {
271            inner: expr,
272            precision,
273        }
274    }
275
276    /// floor(x) - floor function
277    pub struct FloorExpr<E: Expression>(pub E);
278
279    impl<E: Expression> Expression for FloorExpr<E>
280    where
281        E::Output: Numeric,
282    {
283        type Output = E::Output;
284
285        fn render(&self) -> String {
286            format!("floor({})", self.0.render())
287        }
288    }
289
290    pub fn floor<E: Expression>(expr: E) -> FloorExpr<E>
291    where
292        E::Output: Numeric,
293    {
294        FloorExpr(expr)
295    }
296
297    /// ceil(x) - ceiling function
298    pub struct CeilExpr<E: Expression>(pub E);
299
300    impl<E: Expression> Expression for CeilExpr<E>
301    where
302        E::Output: Numeric,
303    {
304        type Output = E::Output;
305
306        fn render(&self) -> String {
307            format!("ceil({})", self.0.render())
308        }
309    }
310
311    pub fn ceil<E: Expression>(expr: E) -> CeilExpr<E>
312    where
313        E::Output: Numeric,
314    {
315        CeilExpr(expr)
316    }
317
318    /// pow(base, exp) - power function
319    pub struct PowExpr<B: Expression, X: Expression> {
320        base: B,
321        exp: X,
322    }
323
324    impl<B: Expression, X: Expression> Expression for PowExpr<B, X>
325    where
326        B::Output: Numeric,
327        X::Output: Numeric,
328    {
329        type Output = f64;
330
331        fn render(&self) -> String {
332            format!("pow({}, {})", self.base.render(), self.exp.render())
333        }
334    }
335
336    pub fn pow<B: Expression, X: Expression>(base: B, exp: X) -> PowExpr<B, X>
337    where
338        B::Output: Numeric,
339        X::Output: Numeric,
340    {
341        PowExpr { base, exp }
342    }
343}
344
345// === CONDITIONAL FUNCTIONS ===
346
347pub mod conditional {
348    use super::*;
349
350    /// if(condition, then, else) - conditional expression
351    pub struct IfExpr<C, T, E>
352    where
353        C: Expression<Output = bool>,
354        T: Expression,
355        E: Expression,
356    {
357        condition: C,
358        then_expr: T,
359        else_expr: E,
360    }
361
362    impl<C, T, E> Expression for IfExpr<C, T, E>
363    where
364        C: Expression<Output = bool>,
365        T: Expression,
366        E: Expression<Output = T::Output>,
367    {
368        type Output = T::Output;
369
370        fn render(&self) -> String {
371            format!(
372                "if({}, {}, {})",
373                self.condition.render(),
374                self.then_expr.render(),
375                self.else_expr.render()
376            )
377        }
378    }
379
380    pub fn if_<C, T, E>(condition: C, then_expr: T, else_expr: E) -> IfExpr<C, T, E>
381    where
382        C: Expression<Output = bool>,
383        T: Expression,
384        E: Expression<Output = T::Output>,
385    {
386        IfExpr {
387            condition,
388            then_expr,
389            else_expr,
390        }
391    }
392}
393
394// === HASH FUNCTIONS ===
395
396pub mod hash {
397    use super::*;
398
399    /// cityHash64(...) - CityHash64
400    pub struct CityHash64Expr<E: Expression>(pub E);
401
402    impl<E: Expression> Expression for CityHash64Expr<E> {
403        type Output = u64;
404
405        fn render(&self) -> String {
406            format!("cityHash64({})", self.0.render())
407        }
408    }
409
410    pub fn city_hash_64<E: Expression>(expr: E) -> CityHash64Expr<E> {
411        CityHash64Expr(expr)
412    }
413
414    /// xxHash64(...) - xxHash64
415    pub struct XxHash64Expr<E: Expression>(pub E);
416
417    impl<E: Expression> Expression for XxHash64Expr<E> {
418        type Output = u64;
419
420        fn render(&self) -> String {
421            format!("xxHash64({})", self.0.render())
422        }
423    }
424
425    pub fn xx_hash_64<E: Expression>(expr: E) -> XxHash64Expr<E> {
426        XxHash64Expr(expr)
427    }
428}