Skip to main content

rust_query/value/
into_expr.rs

1use sea_query::Nullable;
2
3use crate::{
4    Expr, Lazy, Table, TableRow,
5    value::{DbTyp, EqTyp},
6};
7
8/// Trait for all values that can be used as expressions in queries.
9///
10/// There is a hierarchy of types that can be used to build queries.
11/// - [TableRow], [i64], [f64], [bool], `&[u8]`, `&str`:
12///   These are the base types for building expressions. They all
13///   implement [IntoExpr] and are [Copy]. Note that [TableRow] is special
14///   because it refers to a table row that is guaranteed to exist.
15/// - [Expr] is the type that all [IntoExpr] values can be converted into.
16///   It has a lot of methods to combine expressions into more complicated expressions.
17///   Next to those, it implements [std::ops::Deref], if the expression is a table expression.
18///   This can be used to get access to the columns of the table, which can themselves be table expressions.
19///   Note that combinators like [crate::optional] and [crate::aggregate] also have [Expr] as return type.
20///
21/// Note that while [Expr] implements [IntoExpr], you may want to use `&Expr` instead.
22/// Using a reference lets you reuse [Expr] without calling [Clone] explicitly.
23pub trait IntoExpr<'column, S> {
24    /// The type of the expression.
25    type Typ: DbTyp;
26
27    /// Turn this value into an [Expr].
28    fn into_expr(self) -> Expr<'column, S, Self::Typ>;
29}
30
31impl<'column, S, T: IntoExpr<'column, S, Typ = X>, X: EqTyp> IntoExpr<'column, S> for Option<T> {
32    type Typ = Option<X>;
33    fn into_expr(self) -> Expr<'column, S, Self::Typ> {
34        let this = self.map(|x| x.into_expr().inner);
35        Expr::adhoc(move |b| {
36            this.as_ref()
37                .map(|x| (x.func)(b))
38                .unwrap_or(<X::Sql as Nullable>::null().into())
39        })
40    }
41}
42
43impl<'column, S> IntoExpr<'column, S> for String {
44    type Typ = String;
45    fn into_expr(self) -> Expr<'column, S, Self::Typ> {
46        Expr::adhoc(move |_| sea_query::Expr::from(self.clone()))
47    }
48}
49
50impl<'column, S> IntoExpr<'column, S> for &str {
51    type Typ = String;
52    fn into_expr(self) -> Expr<'column, S, Self::Typ> {
53        self.to_owned().into_expr()
54    }
55}
56
57impl<'column, S> IntoExpr<'column, S> for Vec<u8> {
58    type Typ = Vec<u8>;
59    fn into_expr(self) -> Expr<'column, S, Self::Typ> {
60        Expr::adhoc(move |_| sea_query::Expr::from(self.clone()))
61    }
62}
63
64impl<'column, S> IntoExpr<'column, S> for &[u8] {
65    type Typ = Vec<u8>;
66    fn into_expr(self) -> Expr<'column, S, Self::Typ> {
67        self.to_owned().into_expr()
68    }
69}
70
71impl<'column, S> IntoExpr<'column, S> for bool {
72    type Typ = bool;
73    fn into_expr(self) -> Expr<'column, S, Self::Typ> {
74        Expr::adhoc(move |_| sea_query::Expr::from(self))
75    }
76}
77
78impl<'column, S> IntoExpr<'column, S> for i64 {
79    type Typ = i64;
80    fn into_expr(self) -> Expr<'column, S, Self::Typ> {
81        Expr::adhoc(move |_| sea_query::Expr::from(self))
82    }
83}
84impl<'column, S> IntoExpr<'column, S> for f64 {
85    type Typ = f64;
86    fn into_expr(self) -> Expr<'column, S, Self::Typ> {
87        Expr::adhoc(move |_| sea_query::Expr::from(self))
88    }
89}
90
91#[cfg(feature = "jiff-02")]
92/// Note that timestamps before `0000-01-01 00:00:00` can not be used in an expression.
93/// The reason is that datetimes are represented in sqlite as strings and for negative
94/// years the sorting order is wrong.
95///
96/// The conversion is lossless, everything up to nanoseconds is preserved.
97impl<'column, S> IntoExpr<'column, S> for jiff::Timestamp {
98    type Typ = Self;
99    fn into_expr(self) -> Expr<'column, S, Self::Typ> {
100        Expr::adhoc(move |_| sea_query::Expr::from(self.out_to_value()))
101    }
102}
103
104#[cfg(feature = "jiff-02")]
105/// Note that dates before `0000-01-01` can not be used in an expression.
106/// The reason is that dates are represented in sqlite as strings and for negative
107/// years the sorting order is wrong.
108impl<'column, S> IntoExpr<'column, S> for jiff::civil::Date {
109    type Typ = Self;
110
111    fn into_expr(self) -> Expr<'column, S, Self::Typ> {
112        Expr::adhoc(move |_| sea_query::Expr::from(self.out_to_value()))
113    }
114}
115
116impl<'column, S, T> IntoExpr<'column, S> for &T
117where
118    T: IntoExpr<'column, S> + Clone,
119{
120    type Typ = T::Typ;
121    fn into_expr(self) -> Expr<'column, S, Self::Typ> {
122        T::into_expr(self.clone())
123    }
124}
125
126impl<'column, T: Table> IntoExpr<'column, T::Schema> for TableRow<T> {
127    type Typ = Self;
128    fn into_expr(self) -> Expr<'static, T::Schema, Self::Typ> {
129        let idx = self.inner.idx;
130
131        Expr::adhoc_promise(
132            move |_| sea_query::Expr::val(idx),
133            false, // table row is proof of existence
134        )
135    }
136}
137
138impl<'column, T: Table> IntoExpr<'column, T::Schema> for Lazy<'_, T> {
139    type Typ = TableRow<T>;
140
141    fn into_expr(self) -> crate::Expr<'column, T::Schema, Self::Typ> {
142        self.id.into_expr()
143    }
144}
145
146impl<'column, S, T: DbTyp> IntoExpr<'column, S> for Expr<'column, S, T> {
147    type Typ = T;
148    fn into_expr(self) -> Expr<'column, S, Self::Typ> {
149        self
150    }
151}