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