Skip to main content

teaql_core/
expr.rs

1use crate::{EntityDescriptor, SelectQuery, Value};
2
3#[derive(Debug, Clone, Copy, PartialEq, Eq)]
4pub enum BinaryOp {
5    Eq,
6    Ne,
7    Gt,
8    Gte,
9    Lt,
10    Lte,
11    Like,
12    NotLike,
13    In,
14    NotIn,
15    InLarge,
16    NotInLarge,
17}
18
19#[derive(Debug, Clone, Copy, PartialEq, Eq)]
20pub enum ExprFunction {
21    Soundex,
22    Gbk,
23    Count,
24    Sum,
25    Avg,
26    Min,
27    Max,
28    Stddev,
29    StddevPop,
30    VarSamp,
31    VarPop,
32    BitAnd,
33    BitOr,
34    BitXor,
35}
36
37#[derive(Debug, Clone, PartialEq)]
38pub enum Expr {
39    Column(String),
40    Value(Value),
41    Function {
42        function: ExprFunction,
43        args: Vec<Expr>,
44    },
45    Binary {
46        left: Box<Expr>,
47        op: BinaryOp,
48        right: Box<Expr>,
49    },
50    SubQuery {
51        left: Box<Expr>,
52        op: BinaryOp,
53        entity: EntityDescriptor,
54        query: Box<SelectQuery>,
55    },
56    Between {
57        expr: Box<Expr>,
58        lower: Box<Expr>,
59        upper: Box<Expr>,
60    },
61    IsNull(Box<Expr>),
62    IsNotNull(Box<Expr>),
63    And(Vec<Expr>),
64    Or(Vec<Expr>),
65    Not(Box<Expr>),
66}
67
68impl Expr {
69    /// Match the long-standing Java runtime policy: collections larger than
70    /// twenty values use the dialect-specific large-set representation.
71    pub const LARGE_IN_THRESHOLD: usize = 20;
72
73    pub fn column(name: impl Into<String>) -> Self {
74        Self::Column(name.into())
75    }
76
77    pub fn value(value: impl Into<Value>) -> Self {
78        Self::Value(value.into())
79    }
80
81    pub fn function(function: ExprFunction, args: impl IntoIterator<Item = Expr>) -> Self {
82        Self::Function {
83            function,
84            args: args.into_iter().collect(),
85        }
86    }
87
88    pub fn soundex(expr: Expr) -> Self {
89        Self::function(ExprFunction::Soundex, [expr])
90    }
91
92    pub fn gbk(expr: Expr) -> Self {
93        Self::function(ExprFunction::Gbk, [expr])
94    }
95
96    pub fn count_all() -> Self {
97        Self::function(ExprFunction::Count, [])
98    }
99
100    pub fn count_expr(expr: Expr) -> Self {
101        Self::function(ExprFunction::Count, [expr])
102    }
103
104    pub fn sum_expr(expr: Expr) -> Self {
105        Self::function(ExprFunction::Sum, [expr])
106    }
107
108    pub fn avg_expr(expr: Expr) -> Self {
109        Self::function(ExprFunction::Avg, [expr])
110    }
111
112    pub fn min_expr(expr: Expr) -> Self {
113        Self::function(ExprFunction::Min, [expr])
114    }
115
116    pub fn max_expr(expr: Expr) -> Self {
117        Self::function(ExprFunction::Max, [expr])
118    }
119
120    pub fn stddev_expr(expr: Expr) -> Self {
121        Self::function(ExprFunction::Stddev, [expr])
122    }
123
124    pub fn stddev_pop_expr(expr: Expr) -> Self {
125        Self::function(ExprFunction::StddevPop, [expr])
126    }
127
128    pub fn var_samp_expr(expr: Expr) -> Self {
129        Self::function(ExprFunction::VarSamp, [expr])
130    }
131
132    pub fn var_pop_expr(expr: Expr) -> Self {
133        Self::function(ExprFunction::VarPop, [expr])
134    }
135
136    pub fn bit_and_expr(expr: Expr) -> Self {
137        Self::function(ExprFunction::BitAnd, [expr])
138    }
139
140    pub fn bit_or_expr(expr: Expr) -> Self {
141        Self::function(ExprFunction::BitOr, [expr])
142    }
143
144    pub fn bit_xor_expr(expr: Expr) -> Self {
145        Self::function(ExprFunction::BitXor, [expr])
146    }
147
148    pub fn sound_like(column: impl Into<String>, value: impl Into<Value>) -> Self {
149        Self::binary(
150            Self::soundex(Self::column(column)),
151            BinaryOp::Eq,
152            Self::soundex(Self::value(value)),
153        )
154    }
155
156    pub fn eq(column: impl Into<String>, value: impl Into<Value>) -> Self {
157        Self::binary(Self::column(column), BinaryOp::Eq, Self::value(value))
158    }
159
160    pub fn ne(column: impl Into<String>, value: impl Into<Value>) -> Self {
161        Self::binary(Self::column(column), BinaryOp::Ne, Self::value(value))
162    }
163
164    pub fn gt(column: impl Into<String>, value: impl Into<Value>) -> Self {
165        Self::binary(Self::column(column), BinaryOp::Gt, Self::value(value))
166    }
167
168    pub fn gte(column: impl Into<String>, value: impl Into<Value>) -> Self {
169        Self::binary(Self::column(column), BinaryOp::Gte, Self::value(value))
170    }
171
172    pub fn lt(column: impl Into<String>, value: impl Into<Value>) -> Self {
173        Self::binary(Self::column(column), BinaryOp::Lt, Self::value(value))
174    }
175
176    pub fn lte(column: impl Into<String>, value: impl Into<Value>) -> Self {
177        Self::binary(Self::column(column), BinaryOp::Lte, Self::value(value))
178    }
179
180    pub fn like(column: impl Into<String>, pattern: impl Into<String>) -> Self {
181        Self::binary(
182            Self::column(column),
183            BinaryOp::Like,
184            Self::value(pattern.into()),
185        )
186    }
187
188    pub fn not_like(column: impl Into<String>, pattern: impl Into<String>) -> Self {
189        Self::binary(
190            Self::column(column),
191            BinaryOp::NotLike,
192            Self::value(pattern.into()),
193        )
194    }
195
196    pub fn contain(column: impl Into<String>, value: impl Into<String>) -> Self {
197        Self::like(column, format!("%{}%", value.into()))
198    }
199
200    pub fn not_contain(column: impl Into<String>, value: impl Into<String>) -> Self {
201        Self::not_like(column, format!("%{}%", value.into()))
202    }
203
204    pub fn begin_with(column: impl Into<String>, value: impl Into<String>) -> Self {
205        Self::like(column, format!("{}%", value.into()))
206    }
207
208    pub fn not_begin_with(column: impl Into<String>, value: impl Into<String>) -> Self {
209        Self::not_like(column, format!("{}%", value.into()))
210    }
211
212    pub fn end_with(column: impl Into<String>, value: impl Into<String>) -> Self {
213        Self::like(column, format!("%{}", value.into()))
214    }
215
216    pub fn not_end_with(column: impl Into<String>, value: impl Into<String>) -> Self {
217        Self::not_like(column, format!("%{}", value.into()))
218    }
219
220    pub fn binary(left: Expr, op: BinaryOp, right: Expr) -> Self {
221        Self::Binary {
222            left: Box::new(left),
223            op,
224            right: Box::new(right),
225        }
226    }
227
228    pub fn compare_columns(
229        left_column: impl Into<String>,
230        op: BinaryOp,
231        right_column: impl Into<String>,
232    ) -> Self {
233        Self::binary(Self::column(left_column), op, Self::column(right_column))
234    }
235
236    pub fn in_list(column: impl Into<String>, values: impl IntoIterator<Item = Value>) -> Self {
237        let values = values.into_iter().collect::<Vec<_>>();
238        Self::binary(
239            Self::column(column),
240            if values.len() > Self::LARGE_IN_THRESHOLD {
241                BinaryOp::InLarge
242            } else {
243                BinaryOp::In
244            },
245            Self::Value(Value::List(values)),
246        )
247    }
248
249    pub fn not_in_list(column: impl Into<String>, values: impl IntoIterator<Item = Value>) -> Self {
250        let values = values.into_iter().collect::<Vec<_>>();
251        Self::binary(
252            Self::column(column),
253            if values.len() > Self::LARGE_IN_THRESHOLD {
254                BinaryOp::NotInLarge
255            } else {
256                BinaryOp::NotIn
257            },
258            Self::Value(Value::List(values)),
259        )
260    }
261
262    pub fn in_large(column: impl Into<String>, values: impl IntoIterator<Item = Value>) -> Self {
263        Self::binary(
264            Self::column(column),
265            BinaryOp::InLarge,
266            Self::Value(Value::List(values.into_iter().collect())),
267        )
268    }
269
270    pub fn not_in_large(
271        column: impl Into<String>,
272        values: impl IntoIterator<Item = Value>,
273    ) -> Self {
274        Self::binary(
275            Self::column(column),
276            BinaryOp::NotInLarge,
277            Self::Value(Value::List(values.into_iter().collect())),
278        )
279    }
280
281    pub fn in_subquery(
282        column: impl Into<String>,
283        entity: EntityDescriptor,
284        query: SelectQuery,
285        field: impl Into<String>,
286    ) -> Self {
287        Self::subquery(Self::column(column), BinaryOp::In, entity, query, field)
288    }
289
290    pub fn not_in_subquery(
291        column: impl Into<String>,
292        entity: EntityDescriptor,
293        query: SelectQuery,
294        field: impl Into<String>,
295    ) -> Self {
296        Self::subquery(Self::column(column), BinaryOp::NotIn, entity, query, field)
297    }
298
299    pub fn subquery(
300        left: Expr,
301        op: BinaryOp,
302        entity: EntityDescriptor,
303        mut query: SelectQuery,
304        field: impl Into<String>,
305    ) -> Self {
306        query.projection = vec![field.into()];
307        Self::SubQuery {
308            left: Box::new(left),
309            op,
310            entity,
311            query: Box::new(query),
312        }
313    }
314
315    pub fn between(
316        column: impl Into<String>,
317        lower: impl Into<Value>,
318        upper: impl Into<Value>,
319    ) -> Self {
320        Self::Between {
321            expr: Box::new(Self::column(column)),
322            lower: Box::new(Self::value(lower)),
323            upper: Box::new(Self::value(upper)),
324        }
325    }
326
327    pub fn is_null(column: impl Into<String>) -> Self {
328        Self::IsNull(Box::new(Self::column(column)))
329    }
330
331    pub fn is_not_null(column: impl Into<String>) -> Self {
332        Self::IsNotNull(Box::new(Self::column(column)))
333    }
334
335    pub fn and(parts: impl IntoIterator<Item = Expr>) -> Self {
336        let mut unique = Vec::new();
337        for part in parts {
338            if !unique.contains(&part) {
339                unique.push(part);
340            }
341        }
342        Self::And(unique)
343    }
344
345    pub fn or(parts: impl IntoIterator<Item = Expr>) -> Self {
346        let mut unique = Vec::new();
347        for part in parts {
348            if !unique.contains(&part) {
349                unique.push(part);
350            }
351        }
352        Self::Or(unique)
353    }
354
355    pub fn negate(expr: Expr) -> Self {
356        Self::Not(Box::new(expr))
357    }
358
359    pub fn and_expr(self, other: Expr) -> Self {
360        if self == other {
361            return self;
362        }
363        match self {
364            Self::And(mut parts) => {
365                if !parts.contains(&other) {
366                    parts.push(other);
367                }
368                Self::And(parts)
369            }
370            expr => Self::And(vec![expr, other]),
371        }
372    }
373
374    pub fn or_expr(self, other: Expr) -> Self {
375        if self == other {
376            return self;
377        }
378        match self {
379            Self::Or(mut parts) => {
380                if !parts.contains(&other) {
381                    parts.push(other);
382                }
383                Self::Or(parts)
384            }
385            expr => Self::Or(vec![expr, other]),
386        }
387    }
388}