Skip to main content

a3s_orm/
expression.rs

1use std::marker::PhantomData;
2
3use crate::value::{IntoSqlValue, Value};
4
5mod comparison {
6    pub trait Sealed<Rhs> {}
7
8    impl<T> Sealed<T> for T {}
9    impl<T> Sealed<Option<T>> for T {}
10    impl<T> Sealed<T> for Option<T> {}
11}
12
13mod numeric {
14    pub trait Sealed {}
15
16    macro_rules! numeric_types {
17        ($($value:ty),+ $(,)?) => {
18            $(impl Sealed for $value {})+
19        };
20    }
21
22    numeric_types!(i8, i16, i32, i64, isize, u8, u16, u32, u64, usize, f32, f64);
23
24    #[cfg(feature = "decimal")]
25    impl Sealed for rust_decimal::Decimal {}
26
27    impl<T: Sealed> Sealed for Option<T> {}
28}
29
30/// Marks SQL value types that can be compared without discarding their base
31/// type, including nullable/non-nullable forms of the same type.
32pub trait SqlComparable<Rhs>: comparison::Sealed<Rhs> {}
33
34impl<T> SqlComparable<T> for T {}
35impl<T> SqlComparable<Option<T>> for T {}
36impl<T> SqlComparable<T> for Option<T> {}
37
38/// Marks numeric SQL value types that support same-type arithmetic.
39pub trait SqlNumeric: numeric::Sealed {}
40
41macro_rules! numeric_types {
42    ($($value:ty),+ $(,)?) => {
43        $(impl SqlNumeric for $value {})+
44    };
45}
46
47numeric_types!(i8, i16, i32, i64, isize, u8, u16, u32, u64, usize, f32, f64);
48
49#[cfg(feature = "decimal")]
50impl SqlNumeric for rust_decimal::Decimal {}
51
52impl<T: SqlNumeric> SqlNumeric for Option<T> {}
53
54#[derive(Clone, Debug)]
55pub struct SelectSubquery(pub(crate) Box<crate::ast::SelectNode>);
56
57#[derive(Clone, Debug)]
58pub enum Expression {
59    Column {
60        table: &'static str,
61        name: &'static str,
62    },
63    Value(Value),
64    Subquery(SelectSubquery),
65    Function {
66        name: &'static str,
67        arguments: Vec<Expression>,
68    },
69    Coalesce(Vec<Expression>),
70    Least(Vec<Expression>),
71    Cast {
72        expression: Box<Expression>,
73        sql_type: &'static str,
74    },
75    Alias {
76        expression: Box<Expression>,
77        alias: &'static str,
78    },
79    Wildcard,
80    Window {
81        expression: Box<Expression>,
82        partition_by: Vec<Expression>,
83        order_by: Vec<(Expression, OrderDirection)>,
84        frame: Option<WindowFrame>,
85    },
86    Binary {
87        left: Box<Expression>,
88        operator: BinaryOperator,
89        right: Box<Expression>,
90    },
91    Unary {
92        operator: UnaryOperator,
93        expression: Box<Expression>,
94    },
95    And(Vec<Expression>),
96    Or(Vec<Expression>),
97}
98
99impl Expression {
100    pub fn and(self, other: Expression) -> Self {
101        match self {
102            Self::And(mut expressions) => {
103                expressions.push(other);
104                Self::And(expressions)
105            }
106            expression => Self::And(vec![expression, other]),
107        }
108    }
109
110    pub fn or(self, other: Expression) -> Self {
111        match self {
112            Self::Or(mut expressions) => {
113                expressions.push(other);
114                Self::Or(expressions)
115            }
116            expression => Self::Or(vec![expression, other]),
117        }
118    }
119}
120
121/// Negate a predicate while retaining its AST and bound parameters.
122pub fn not(expression: Expression) -> Expression {
123    Expression::Unary {
124        operator: UnaryOperator::Not,
125        expression: Box::new(expression),
126    }
127}
128
129#[derive(Clone, Copy, Debug)]
130pub enum BinaryOperator {
131    Eq,
132    NotEq,
133    GreaterThan,
134    GreaterThanOrEq,
135    LessThan,
136    LessThanOrEq,
137    Like,
138    In,
139    Is,
140    IsNot,
141    Add,
142}
143
144#[derive(Clone, Copy, Debug)]
145pub enum UnaryOperator {
146    IsNull,
147    IsNotNull,
148    Not,
149    Exists,
150}
151
152#[derive(Clone, Copy, Debug, PartialEq, Eq)]
153pub enum OrderDirection {
154    Asc,
155    Desc,
156}
157
158#[derive(Clone, Copy, Debug, PartialEq, Eq)]
159pub enum WindowFrameUnits {
160    Rows,
161    Range,
162    Groups,
163}
164
165#[derive(Clone, Copy, Debug, PartialEq, Eq)]
166pub enum WindowBoundary {
167    UnboundedPreceding,
168    Preceding(u64),
169    CurrentRow,
170    Following(u64),
171    UnboundedFollowing,
172}
173
174#[derive(Clone, Copy, Debug, PartialEq, Eq)]
175pub struct WindowFrame {
176    pub units: WindowFrameUnits,
177    pub start: WindowBoundary,
178    pub end: WindowBoundary,
179}
180
181#[derive(Debug)]
182pub struct Column<T, V> {
183    table: &'static str,
184    name: &'static str,
185    marker: PhantomData<fn() -> (T, V)>,
186}
187
188impl<T, V> Clone for Column<T, V> {
189    fn clone(&self) -> Self {
190        *self
191    }
192}
193
194impl<T, V> Copy for Column<T, V> {}
195
196impl<T, V> Column<T, V> {
197    pub const fn new(table: &'static str, name: &'static str) -> Self {
198        Self {
199            table,
200            name,
201            marker: PhantomData,
202        }
203    }
204
205    pub const fn table_name(self) -> &'static str {
206        self.table
207    }
208
209    pub const fn name(self) -> &'static str {
210        self.name
211    }
212
213    pub fn expression(self) -> Expression {
214        Expression::Column {
215            table: self.table,
216            name: self.name,
217        }
218    }
219
220    pub fn eq(self, value: impl IntoSqlValue<V>) -> Expression {
221        self.compare(
222            BinaryOperator::Eq,
223            Expression::Value(value.into_sql_value()),
224        )
225    }
226
227    pub fn ne(self, value: impl IntoSqlValue<V>) -> Expression {
228        self.compare(
229            BinaryOperator::NotEq,
230            Expression::Value(value.into_sql_value()),
231        )
232    }
233
234    pub fn gt(self, value: impl IntoSqlValue<V>) -> Expression {
235        self.compare(
236            BinaryOperator::GreaterThan,
237            Expression::Value(value.into_sql_value()),
238        )
239    }
240
241    pub fn gte(self, value: impl IntoSqlValue<V>) -> Expression {
242        self.compare(
243            BinaryOperator::GreaterThanOrEq,
244            Expression::Value(value.into_sql_value()),
245        )
246    }
247
248    pub fn lt(self, value: impl IntoSqlValue<V>) -> Expression {
249        self.compare(
250            BinaryOperator::LessThan,
251            Expression::Value(value.into_sql_value()),
252        )
253    }
254
255    pub fn lte(self, value: impl IntoSqlValue<V>) -> Expression {
256        self.compare(
257            BinaryOperator::LessThanOrEq,
258            Expression::Value(value.into_sql_value()),
259        )
260    }
261
262    pub fn like(self, value: impl IntoSqlValue<V>) -> Expression {
263        self.compare(
264            BinaryOperator::Like,
265            Expression::Value(value.into_sql_value()),
266        )
267    }
268
269    pub fn eq_column<OtherTable, OtherValue>(
270        self,
271        other: Column<OtherTable, OtherValue>,
272    ) -> Expression
273    where
274        V: SqlComparable<OtherValue>,
275    {
276        self.compare(BinaryOperator::Eq, other.expression())
277    }
278
279    pub fn ne_column<OtherTable, OtherValue>(
280        self,
281        other: Column<OtherTable, OtherValue>,
282    ) -> Expression
283    where
284        V: SqlComparable<OtherValue>,
285    {
286        self.compare(BinaryOperator::NotEq, other.expression())
287    }
288
289    pub fn gt_column<OtherTable, OtherValue>(
290        self,
291        other: Column<OtherTable, OtherValue>,
292    ) -> Expression
293    where
294        V: SqlComparable<OtherValue>,
295    {
296        self.compare(BinaryOperator::GreaterThan, other.expression())
297    }
298
299    pub fn gte_column<OtherTable, OtherValue>(
300        self,
301        other: Column<OtherTable, OtherValue>,
302    ) -> Expression
303    where
304        V: SqlComparable<OtherValue>,
305    {
306        self.compare(BinaryOperator::GreaterThanOrEq, other.expression())
307    }
308
309    pub fn lt_column<OtherTable, OtherValue>(
310        self,
311        other: Column<OtherTable, OtherValue>,
312    ) -> Expression
313    where
314        V: SqlComparable<OtherValue>,
315    {
316        self.compare(BinaryOperator::LessThan, other.expression())
317    }
318
319    pub fn lte_column<OtherTable, OtherValue>(
320        self,
321        other: Column<OtherTable, OtherValue>,
322    ) -> Expression
323    where
324        V: SqlComparable<OtherValue>,
325    {
326        self.compare(BinaryOperator::LessThanOrEq, other.expression())
327    }
328
329    pub fn eq_subquery<Source: crate::Table>(
330        self,
331        query: crate::query::SelectQuery<Source, V>,
332    ) -> Expression {
333        self.compare(
334            BinaryOperator::Eq,
335            Expression::Subquery(SelectSubquery(Box::new(query.into_node()))),
336        )
337    }
338
339    pub fn in_subquery<Source: crate::Table>(
340        self,
341        query: crate::query::SelectQuery<Source, V>,
342    ) -> Expression {
343        self.compare(
344            BinaryOperator::In,
345            Expression::Subquery(SelectSubquery(Box::new(query.into_node()))),
346        )
347    }
348
349    pub fn is_null(self) -> Expression {
350        Expression::Unary {
351            operator: UnaryOperator::IsNull,
352            expression: Box::new(self.expression()),
353        }
354    }
355
356    pub fn is_not_null(self) -> Expression {
357        Expression::Unary {
358            operator: UnaryOperator::IsNotNull,
359            expression: Box::new(self.expression()),
360        }
361    }
362
363    fn compare(self, operator: BinaryOperator, right: Expression) -> Expression {
364        Expression::Binary {
365            left: Box::new(self.expression()),
366            operator,
367            right: Box::new(right),
368        }
369    }
370}
371
372impl<T, V, Rhs> std::ops::Add<Rhs> for Column<T, V>
373where
374    V: SqlNumeric,
375    Rhs: IntoSqlValue<V>,
376{
377    type Output = crate::TypedExpression<V>;
378
379    fn add(self, value: Rhs) -> Self::Output {
380        crate::TypedExpression::new(Expression::Binary {
381            left: Box::new(self.expression()),
382            operator: BinaryOperator::Add,
383            right: Box::new(Expression::Value(value.into_sql_value())),
384        })
385    }
386}
387
388pub fn exists<Source: crate::Table, Output>(
389    query: crate::query::SelectQuery<Source, Output>,
390) -> Expression {
391    Expression::Unary {
392        operator: UnaryOperator::Exists,
393        expression: Box::new(Expression::Subquery(SelectSubquery(Box::new(
394            query.into_node(),
395        )))),
396    }
397}
398
399pub trait Selection {
400    type Output;
401    fn expressions(self) -> Vec<Expression>;
402}
403
404pub struct AliasedSelection<S> {
405    selection: S,
406    alias: &'static str,
407}
408
409pub trait SelectionExt: Selection + Sized {
410    fn alias(self, alias: &'static str) -> AliasedSelection<Self> {
411        AliasedSelection {
412            selection: self,
413            alias,
414        }
415    }
416}
417
418impl<T, V> SelectionExt for Column<T, V> {}
419
420impl<S: Selection> Selection for AliasedSelection<S> {
421    type Output = S::Output;
422
423    fn expressions(self) -> Vec<Expression> {
424        self.selection
425            .expressions()
426            .into_iter()
427            .map(|expression| Expression::Alias {
428                expression: Box::new(expression),
429                alias: self.alias,
430            })
431            .collect()
432    }
433}
434
435impl<T, V> Selection for Column<T, V> {
436    type Output = V;
437
438    fn expressions(self) -> Vec<Expression> {
439        vec![self.expression()]
440    }
441}
442
443macro_rules! tuple_selection {
444    ($($name:ident),+ $(,)?) => {
445        impl<$($name),+> Selection for ($($name,)+)
446        where
447            $($name: Selection,)+
448        {
449            type Output = ($($name::Output,)+);
450
451            #[allow(non_snake_case)]
452            fn expressions(self) -> Vec<Expression> {
453                let ($($name,)+) = self;
454                let mut expressions = Vec::new();
455                $(expressions.extend($name.expressions());)+
456                expressions
457            }
458        }
459    };
460}
461
462tuple_selection!(A, B);
463tuple_selection!(A, B, C);
464tuple_selection!(A, B, C, D);
465tuple_selection!(A, B, C, D, E);
466tuple_selection!(A, B, C, D, E, F);
467tuple_selection!(A, B, C, D, E, F, G);
468tuple_selection!(A, B, C, D, E, F, G, H);