1use std::marker::PhantomData;
4use clicktype_core::traits::{ClickHouseType, TypedColumn, Numeric};
5
6pub trait Expression: Sized {
8 type Output: ClickHouseType;
10
11 fn render(&self) -> String;
13
14 fn is_aggregate(&self) -> bool {
16 false
17 }
18}
19
20#[derive(Debug, Clone, Copy)]
22pub struct ColumnExpr<C: TypedColumn> {
23 _col: PhantomData<C>,
24}
25
26impl<C: TypedColumn> ColumnExpr<C> {
27 pub fn new() -> Self {
28 Self { _col: PhantomData }
29 }
30}
31
32impl<C: TypedColumn> Expression for ColumnExpr<C> {
33 type Output = C::Type;
34
35 fn render(&self) -> String {
36 C::name().to_string()
37 }
38}
39
40#[derive(Debug, Clone)]
42pub struct Literal<T: ClickHouseType> {
43 value: String,
44 _phantom: PhantomData<T>,
45}
46
47impl<T: ClickHouseType> Literal<T> {
48 pub fn new(value: String) -> Self {
49 Self {
50 value,
51 _phantom: PhantomData,
52 }
53 }
54}
55
56impl<T: ClickHouseType> Expression for Literal<T> {
57 type Output = T;
58
59 fn render(&self) -> String {
60 self.value.clone()
61 }
62}
63
64pub struct Eq;
67pub struct Ne;
68pub struct Lt;
69pub struct Le;
70pub struct Gt;
71pub struct Ge;
72
73pub trait ComparisonOp {
74 fn symbol() -> &'static str;
75}
76
77impl ComparisonOp for Eq {
78 fn symbol() -> &'static str {
79 "="
80 }
81}
82
83impl ComparisonOp for Ne {
84 fn symbol() -> &'static str {
85 "!="
86 }
87}
88
89impl ComparisonOp for Lt {
90 fn symbol() -> &'static str {
91 "<"
92 }
93}
94
95impl ComparisonOp for Le {
96 fn symbol() -> &'static str {
97 "<="
98 }
99}
100
101impl ComparisonOp for Gt {
102 fn symbol() -> &'static str {
103 ">"
104 }
105}
106
107impl ComparisonOp for Ge {
108 fn symbol() -> &'static str {
109 ">="
110 }
111}
112
113pub struct CompareExpr<L: Expression, R: Expression, Op: ComparisonOp> {
115 left: L,
116 right: R,
117 _op: PhantomData<Op>,
118}
119
120impl<L: Expression, R: Expression, Op: ComparisonOp> CompareExpr<L, R, Op> {
121 pub fn new(left: L, right: R) -> Self {
122 Self {
123 left,
124 right,
125 _op: PhantomData,
126 }
127 }
128}
129
130impl<L: Expression, R: Expression, Op: ComparisonOp> Expression for CompareExpr<L, R, Op> {
131 type Output = bool;
132
133 fn render(&self) -> String {
134 format!("{} {} {}", self.left.render(), Op::symbol(), self.right.render())
135 }
136}
137
138pub trait Comparable: Expression {
140 fn eq<R>(self, rhs: R) -> CompareExpr<Self, Literal<Self::Output>, Eq>
141 where
142 R: Into<Literal<Self::Output>>,
143 {
144 CompareExpr::new(self, rhs.into())
145 }
146
147 fn ne<R>(self, rhs: R) -> CompareExpr<Self, Literal<Self::Output>, Ne>
148 where
149 R: Into<Literal<Self::Output>>,
150 {
151 CompareExpr::new(self, rhs.into())
152 }
153
154 fn lt<R>(self, rhs: R) -> CompareExpr<Self, Literal<Self::Output>, Lt>
155 where
156 R: Into<Literal<Self::Output>>,
157 {
158 CompareExpr::new(self, rhs.into())
159 }
160
161 fn le<R>(self, rhs: R) -> CompareExpr<Self, Literal<Self::Output>, Le>
162 where
163 R: Into<Literal<Self::Output>>,
164 {
165 CompareExpr::new(self, rhs.into())
166 }
167
168 fn gt<R>(self, rhs: R) -> CompareExpr<Self, Literal<Self::Output>, Gt>
169 where
170 R: Into<Literal<Self::Output>>,
171 {
172 CompareExpr::new(self, rhs.into())
173 }
174
175 fn ge<R>(self, rhs: R) -> CompareExpr<Self, Literal<Self::Output>, Ge>
176 where
177 R: Into<Literal<Self::Output>>,
178 {
179 CompareExpr::new(self, rhs.into())
180 }
181}
182
183impl<E: Expression> Comparable for E {}
184
185pub struct And;
188pub struct Or;
189pub struct Not;
190
191pub struct AndExpr<L: Expression<Output = bool>, R: Expression<Output = bool>> {
193 left: L,
194 right: R,
195}
196
197impl<L: Expression<Output = bool>, R: Expression<Output = bool>> Expression for AndExpr<L, R> {
198 type Output = bool;
199
200 fn render(&self) -> String {
201 format!("({} AND {})", self.left.render(), self.right.render())
202 }
203}
204
205pub struct OrExpr<L: Expression<Output = bool>, R: Expression<Output = bool>> {
207 left: L,
208 right: R,
209}
210
211impl<L: Expression<Output = bool>, R: Expression<Output = bool>> Expression for OrExpr<L, R> {
212 type Output = bool;
213
214 fn render(&self) -> String {
215 format!("({} OR {})", self.left.render(), self.right.render())
216 }
217}
218
219pub struct NotExpr<E: Expression<Output = bool>> {
221 inner: E,
222}
223
224impl<E: Expression<Output = bool>> Expression for NotExpr<E> {
225 type Output = bool;
226
227 fn render(&self) -> String {
228 format!("NOT ({})", self.inner.render())
229 }
230}
231
232pub trait Logical: Expression<Output = bool> {
234 fn and<R: Expression<Output = bool>>(self, rhs: R) -> AndExpr<Self, R> {
235 AndExpr { left: self, right: rhs }
236 }
237
238 fn or<R: Expression<Output = bool>>(self, rhs: R) -> OrExpr<Self, R> {
239 OrExpr { left: self, right: rhs }
240 }
241
242 fn not(self) -> NotExpr<Self> {
243 NotExpr { inner: self }
244 }
245}
246
247impl<E: Expression<Output = bool>> Logical for E {}
248
249pub struct Add;
252pub struct Sub;
253pub struct Mul;
254pub struct Div;
255pub struct Mod;
256
257pub trait ArithmeticOp {
258 fn symbol() -> &'static str;
259}
260
261impl ArithmeticOp for Add {
262 fn symbol() -> &'static str {
263 "+"
264 }
265}
266
267impl ArithmeticOp for Sub {
268 fn symbol() -> &'static str {
269 "-"
270 }
271}
272
273impl ArithmeticOp for Mul {
274 fn symbol() -> &'static str {
275 "*"
276 }
277}
278
279impl ArithmeticOp for Div {
280 fn symbol() -> &'static str {
281 "/"
282 }
283}
284
285impl ArithmeticOp for Mod {
286 fn symbol() -> &'static str {
287 "%"
288 }
289}
290
291pub struct ArithExpr<L: Expression, R: Expression, Op: ArithmeticOp> {
293 left: L,
294 right: R,
295 _op: PhantomData<Op>,
296}
297
298impl<L, R, Op> Expression for ArithExpr<L, R, Op>
299where
300 L: Expression,
301 R: Expression,
302 Op: ArithmeticOp,
303 L::Output: Numeric,
304 R::Output: Numeric,
305{
306 type Output = L::Output;
307
308 fn render(&self) -> String {
309 format!("({} {} {})", self.left.render(), Op::symbol(), self.right.render())
310 }
311}
312
313pub trait Arithmetic: Expression
315where
316 Self::Output: Numeric,
317{
318 fn add<R>(self, rhs: R) -> ArithExpr<Self, R, Add>
319 where
320 R: Expression,
321 R::Output: Numeric,
322 {
323 ArithExpr {
324 left: self,
325 right: rhs,
326 _op: PhantomData,
327 }
328 }
329
330 fn sub<R>(self, rhs: R) -> ArithExpr<Self, R, Sub>
331 where
332 R: Expression,
333 R::Output: Numeric,
334 {
335 ArithExpr {
336 left: self,
337 right: rhs,
338 _op: PhantomData,
339 }
340 }
341
342 fn mul<R>(self, rhs: R) -> ArithExpr<Self, R, Mul>
343 where
344 R: Expression,
345 R::Output: Numeric,
346 {
347 ArithExpr {
348 left: self,
349 right: rhs,
350 _op: PhantomData,
351 }
352 }
353
354 fn div<R>(self, rhs: R) -> ArithExpr<Self, R, Div>
355 where
356 R: Expression,
357 R::Output: Numeric,
358 {
359 ArithExpr {
360 left: self,
361 right: rhs,
362 _op: PhantomData,
363 }
364 }
365
366 fn modulo<R>(self, rhs: R) -> ArithExpr<Self, R, Mod>
367 where
368 R: Expression,
369 R::Output: Numeric,
370 {
371 ArithExpr {
372 left: self,
373 right: rhs,
374 _op: PhantomData,
375 }
376 }
377}
378
379impl<E: Expression> Arithmetic for E where E::Output: Numeric {}
380
381pub struct LikeExpr<E: Expression<Output = String>> {
385 inner: E,
386 pattern: String,
387}
388
389impl<E: Expression<Output = String>> Expression for LikeExpr<E> {
390 type Output = bool;
391
392 fn render(&self) -> String {
393 format!("{} LIKE '{}'", self.inner.render(), self.pattern)
394 }
395}
396
397pub struct ILikeExpr<E: Expression<Output = String>> {
399 inner: E,
400 pattern: String,
401}
402
403impl<E: Expression<Output = String>> Expression for ILikeExpr<E> {
404 type Output = bool;
405
406 fn render(&self) -> String {
407 format!("{} ILIKE '{}'", self.inner.render(), self.pattern)
408 }
409}
410
411pub trait StringOps: Expression<Output = String> {
413 fn like(self, pattern: &str) -> LikeExpr<Self> {
414 LikeExpr {
415 inner: self,
416 pattern: pattern.to_string(),
417 }
418 }
419
420 fn ilike(self, pattern: &str) -> ILikeExpr<Self> {
421 ILikeExpr {
422 inner: self,
423 pattern: pattern.to_string(),
424 }
425 }
426}
427
428impl<E: Expression<Output = String>> StringOps for E {}
429
430pub struct IsNullExpr<E: Expression> {
434 inner: E,
435}
436
437impl<E: Expression> Expression for IsNullExpr<E> {
438 type Output = bool;
439
440 fn render(&self) -> String {
441 format!("{} IS NULL", self.inner.render())
442 }
443}
444
445pub struct IsNotNullExpr<E: Expression> {
447 inner: E,
448}
449
450impl<E: Expression> Expression for IsNotNullExpr<E> {
451 type Output = bool;
452
453 fn render(&self) -> String {
454 format!("{} IS NOT NULL", self.inner.render())
455 }
456}
457
458pub trait NullOps: Expression {
460 fn is_null(self) -> IsNullExpr<Self> {
461 IsNullExpr { inner: self }
462 }
463
464 fn is_not_null(self) -> IsNotNullExpr<Self> {
465 IsNotNullExpr { inner: self }
466 }
467}
468
469impl<E: Expression> NullOps for E {}
470
471impl<C: TypedColumn> Expression for C {
473 type Output = C::Type;
474
475 fn render(&self) -> String {
476 C::name().to_string()
477 }
478}
479
480impl From<i8> for Literal<i8> {
482 fn from(value: i8) -> Self {
483 Literal::new(value.to_string())
484 }
485}
486
487impl From<i16> for Literal<i16> {
488 fn from(value: i16) -> Self {
489 Literal::new(value.to_string())
490 }
491}
492
493impl From<i32> for Literal<i32> {
494 fn from(value: i32) -> Self {
495 Literal::new(value.to_string())
496 }
497}
498
499impl From<i64> for Literal<i64> {
500 fn from(value: i64) -> Self {
501 Literal::new(value.to_string())
502 }
503}
504
505impl From<u8> for Literal<u8> {
506 fn from(value: u8) -> Self {
507 Literal::new(value.to_string())
508 }
509}
510
511impl From<u16> for Literal<u16> {
512 fn from(value: u16) -> Self {
513 Literal::new(value.to_string())
514 }
515}
516
517impl From<u32> for Literal<u32> {
518 fn from(value: u32) -> Self {
519 Literal::new(value.to_string())
520 }
521}
522
523impl From<u64> for Literal<u64> {
524 fn from(value: u64) -> Self {
525 Literal::new(value.to_string())
526 }
527}
528
529impl From<f32> for Literal<f32> {
530 fn from(value: f32) -> Self {
531 Literal::new(value.to_string())
532 }
533}
534
535impl From<f64> for Literal<f64> {
536 fn from(value: f64) -> Self {
537 Literal::new(value.to_string())
538 }
539}
540
541impl From<&str> for Literal<String> {
542 fn from(value: &str) -> Self {
543 Literal::new(format!("'{}'", value))
544 }
545}
546
547impl From<String> for Literal<String> {
548 fn from(value: String) -> Self {
549 Literal::new(format!("'{}'", value))
550 }
551}