rust_query/
value.rs

1pub mod aggregate;
2mod operations;
3pub mod optional;
4pub mod trivial;
5
6use std::{fmt::Debug, marker::PhantomData, ops::Deref, rc::Rc};
7
8use ref_cast::RefCast;
9use sea_query::{Alias, Nullable, SelectStatement, SimpleExpr};
10
11use crate::{
12    IntoSelect, Select, Table,
13    alias::{Field, MyAlias, RawAlias},
14    ast::{MySelect, Source},
15    db::{TableRow, TableRowInner},
16    hash,
17};
18
19#[derive(Clone, Copy)]
20pub struct ValueBuilder<'x> {
21    pub(crate) inner: &'x MySelect,
22}
23
24impl<'x> ValueBuilder<'x> {
25    pub(crate) fn get_aggr(
26        self,
27        aggr: SelectStatement,
28        conds: Vec<(Field, SimpleExpr)>,
29    ) -> MyAlias {
30        let source = Source {
31            kind: crate::ast::SourceKind::Aggregate(aggr),
32            conds,
33        };
34        let new_alias = || self.inner.scope.new_alias();
35        *self.inner.extra.get_or_init(source, new_alias)
36    }
37
38    pub(crate) fn get_join<T: Table>(self, expr: SimpleExpr) -> MyAlias {
39        let source = Source {
40            kind: crate::ast::SourceKind::Implicit(T::NAME.to_owned()),
41            conds: vec![(Field::Str(T::ID), expr)],
42        };
43        let new_alias = || self.inner.scope.new_alias();
44        *self.inner.extra.get_or_init(source, new_alias)
45    }
46
47    pub fn get_unique<T: Table>(self, conds: Vec<(&'static str, SimpleExpr)>) -> SimpleExpr {
48        let source = Source {
49            kind: crate::ast::SourceKind::Implicit(T::NAME.to_owned()),
50            conds: conds.into_iter().map(|x| (Field::Str(x.0), x.1)).collect(),
51        };
52
53        let new_alias = || self.inner.scope.new_alias();
54        let table = self.inner.extra.get_or_init(source, new_alias);
55        sea_query::Expr::col((*table, Alias::new(T::ID))).into()
56    }
57}
58
59pub trait NumTyp: MyTyp + Clone + Copy {
60    const ZERO: Self;
61    fn into_sea_value(self) -> sea_query::Value;
62}
63
64impl NumTyp for i64 {
65    const ZERO: Self = 0;
66    fn into_sea_value(self) -> sea_query::Value {
67        sea_query::Value::BigInt(Some(self))
68    }
69}
70impl NumTyp for f64 {
71    const ZERO: Self = 0.;
72    fn into_sea_value(self) -> sea_query::Value {
73        sea_query::Value::Double(Some(self))
74    }
75}
76
77#[diagnostic::on_unimplemented(
78    message = "Columns with type `{Self}` can not be checked for equality",
79    note = "`EqTyp` is also implemented for all table types"
80)]
81pub trait EqTyp {}
82
83impl EqTyp for String {}
84impl EqTyp for Vec<u8> {}
85impl EqTyp for i64 {}
86impl EqTyp for f64 {}
87impl EqTyp for bool {}
88#[diagnostic::do_not_recommend]
89impl<T: Table> EqTyp for T {}
90
91/// Typ does not depend on scope, so it gets its own trait
92pub trait Typed {
93    type Typ;
94
95    #[doc(hidden)]
96    fn build_expr(&self, b: ValueBuilder) -> SimpleExpr;
97    #[doc(hidden)]
98    fn build_table(&self, b: ValueBuilder) -> MyAlias
99    where
100        Self::Typ: Table,
101    {
102        b.get_join::<Self::Typ>(self.build_expr(b))
103    }
104}
105
106/// Trait for all values that can be used as expressions in queries.
107pub trait IntoExpr<'column, S>: Clone {
108    /// The type of the expression.
109    type Typ: MyTyp;
110
111    /// Turn this value into an [Expr].
112    fn into_expr(self) -> Expr<'column, S, Self::Typ>;
113}
114
115impl<T: Typed<Typ = X>, X: MyTyp<Sql: Nullable>> Typed for Option<T> {
116    type Typ = Option<T::Typ>;
117
118    fn build_expr(&self, b: ValueBuilder) -> SimpleExpr {
119        self.as_ref()
120            .map(|x| T::build_expr(x, b))
121            .unwrap_or(X::Sql::null().into())
122    }
123}
124
125impl<'column, S, T: IntoExpr<'column, S, Typ = X>, X: MyTyp<Sql: Nullable>> IntoExpr<'column, S>
126    for Option<T>
127{
128    type Typ = Option<X>;
129    fn into_expr(self) -> Expr<'column, S, Self::Typ> {
130        Expr::new(self.map(|x| x.into_expr().inner))
131    }
132}
133
134impl Typed for String {
135    type Typ = String;
136    fn build_expr(&self, _: ValueBuilder) -> SimpleExpr {
137        SimpleExpr::from(self)
138    }
139}
140
141impl<'column, S> IntoExpr<'column, S> for String {
142    type Typ = String;
143    fn into_expr(self) -> Expr<'column, S, Self::Typ> {
144        Expr::new(self)
145    }
146}
147
148impl<'column, S> IntoExpr<'column, S> for &str {
149    type Typ = String;
150    fn into_expr(self) -> Expr<'column, S, Self::Typ> {
151        Expr::new(self.to_owned())
152    }
153}
154
155impl Typed for Vec<u8> {
156    type Typ = Vec<u8>;
157    fn build_expr(&self, _: ValueBuilder) -> SimpleExpr {
158        SimpleExpr::from(self.to_owned())
159    }
160}
161
162impl<'column, S> IntoExpr<'column, S> for Vec<u8> {
163    type Typ = Vec<u8>;
164    fn into_expr(self) -> Expr<'column, S, Self::Typ> {
165        Expr::new(self)
166    }
167}
168
169impl<'column, S> IntoExpr<'column, S> for &[u8] {
170    type Typ = Vec<u8>;
171    fn into_expr(self) -> Expr<'column, S, Self::Typ> {
172        Expr::new(self.to_owned())
173    }
174}
175
176impl Typed for bool {
177    type Typ = bool;
178    fn build_expr(&self, _: ValueBuilder) -> SimpleExpr {
179        SimpleExpr::from(*self)
180    }
181}
182
183impl<'column, S> IntoExpr<'column, S> for bool {
184    type Typ = bool;
185    fn into_expr(self) -> Expr<'column, S, Self::Typ> {
186        Expr::new(self)
187    }
188}
189
190impl Typed for i64 {
191    type Typ = i64;
192    fn build_expr(&self, _: ValueBuilder) -> SimpleExpr {
193        SimpleExpr::from(*self)
194    }
195}
196
197impl<'column, S> IntoExpr<'column, S> for i64 {
198    type Typ = i64;
199    fn into_expr(self) -> Expr<'column, S, Self::Typ> {
200        Expr::new(self)
201    }
202}
203
204impl Typed for f64 {
205    type Typ = f64;
206    fn build_expr(&self, _: ValueBuilder) -> SimpleExpr {
207        SimpleExpr::from(*self)
208    }
209}
210
211impl<'column, S> IntoExpr<'column, S> for f64 {
212    type Typ = f64;
213    fn into_expr(self) -> Expr<'column, S, Self::Typ> {
214        Expr::new(self)
215    }
216}
217
218impl<T> Typed for &T
219where
220    T: Typed,
221{
222    type Typ = T::Typ;
223    fn build_expr(&self, b: ValueBuilder) -> SimpleExpr {
224        T::build_expr(self, b)
225    }
226    fn build_table(&self, b: crate::value::ValueBuilder) -> MyAlias
227    where
228        Self::Typ: Table,
229    {
230        T::build_table(self, b)
231    }
232}
233
234impl<'column, S, T> IntoExpr<'column, S> for &T
235where
236    T: IntoExpr<'column, S>,
237{
238    type Typ = T::Typ;
239    fn into_expr(self) -> Expr<'column, S, Self::Typ> {
240        T::into_expr(self.clone())
241    }
242}
243
244/// Use this a value in a query to get the current datetime as a number.
245#[derive(Clone, Copy)]
246pub struct UnixEpoch;
247
248impl Typed for UnixEpoch {
249    type Typ = i64;
250    fn build_expr(&self, _: ValueBuilder) -> SimpleExpr {
251        sea_query::Expr::col(RawAlias("unixepoch('now')".to_owned())).into()
252    }
253}
254
255impl<'column, S> IntoExpr<'column, S> for UnixEpoch {
256    type Typ = i64;
257    fn into_expr(self) -> Expr<'column, S, Self::Typ> {
258        Expr::new(self)
259    }
260}
261
262pub trait MyTyp: 'static {
263    type Prev: MyTyp;
264    const NULLABLE: bool = false;
265    const TYP: hash::ColumnType;
266    const FK: Option<(&'static str, &'static str)> = None;
267    type Out<'t>: SecretFromSql<'t>;
268    type Sql;
269}
270
271pub(crate) trait SecretFromSql<'t>: Sized {
272    fn from_sql(value: rusqlite::types::ValueRef<'_>) -> rusqlite::types::FromSqlResult<Self>;
273}
274
275#[diagnostic::do_not_recommend]
276impl<T: Table> MyTyp for T {
277    type Prev = T::MigrateFrom;
278    const TYP: hash::ColumnType = hash::ColumnType::Integer;
279    const FK: Option<(&'static str, &'static str)> = Some((T::NAME, T::ID));
280    type Out<'t> = TableRow<'t, Self>;
281    type Sql = i64;
282}
283
284impl<'t, T> SecretFromSql<'t> for TableRow<'t, T> {
285    fn from_sql(value: rusqlite::types::ValueRef<'_>) -> rusqlite::types::FromSqlResult<Self> {
286        Ok(TableRow {
287            _p: PhantomData,
288            _local: PhantomData,
289            inner: TableRowInner {
290                _p: PhantomData,
291                idx: value.as_i64()?,
292            },
293        })
294    }
295}
296
297impl MyTyp for i64 {
298    type Prev = Self;
299    const TYP: hash::ColumnType = hash::ColumnType::Integer;
300    type Out<'t> = Self;
301    type Sql = i64;
302}
303
304impl SecretFromSql<'_> for i64 {
305    fn from_sql(value: rusqlite::types::ValueRef<'_>) -> rusqlite::types::FromSqlResult<Self> {
306        value.as_i64()
307    }
308}
309
310impl MyTyp for f64 {
311    type Prev = Self;
312    const TYP: hash::ColumnType = hash::ColumnType::Float;
313    type Out<'t> = Self;
314    type Sql = f64;
315}
316
317impl SecretFromSql<'_> for f64 {
318    fn from_sql(value: rusqlite::types::ValueRef<'_>) -> rusqlite::types::FromSqlResult<Self> {
319        value.as_f64()
320    }
321}
322
323impl MyTyp for bool {
324    type Prev = Self;
325    const TYP: hash::ColumnType = hash::ColumnType::Integer;
326    type Out<'t> = Self;
327    type Sql = bool;
328}
329
330impl SecretFromSql<'_> for bool {
331    fn from_sql(value: rusqlite::types::ValueRef<'_>) -> rusqlite::types::FromSqlResult<Self> {
332        Ok(value.as_i64()? != 0)
333    }
334}
335
336impl MyTyp for String {
337    type Prev = Self;
338    const TYP: hash::ColumnType = hash::ColumnType::String;
339    type Out<'t> = Self;
340    type Sql = String;
341}
342assert_impl_all!(String: Nullable);
343
344impl SecretFromSql<'_> for String {
345    fn from_sql(value: rusqlite::types::ValueRef<'_>) -> rusqlite::types::FromSqlResult<Self> {
346        Ok(value.as_str()?.to_owned())
347    }
348}
349
350impl MyTyp for Vec<u8> {
351    type Prev = Self;
352    const TYP: hash::ColumnType = hash::ColumnType::Blob;
353    type Out<'t> = Self;
354    type Sql = Vec<u8>;
355}
356assert_impl_all!(Vec<u8>: Nullable);
357
358impl SecretFromSql<'_> for Vec<u8> {
359    fn from_sql(value: rusqlite::types::ValueRef<'_>) -> rusqlite::types::FromSqlResult<Self> {
360        Ok(value.as_blob()?.to_owned())
361    }
362}
363
364impl<T: MyTyp> MyTyp for Option<T> {
365    type Prev = Option<T::Prev>;
366    const TYP: hash::ColumnType = T::TYP;
367    const NULLABLE: bool = true;
368    const FK: Option<(&'static str, &'static str)> = T::FK;
369    type Out<'t> = Option<T::Out<'t>>;
370    type Sql = T::Sql;
371}
372
373impl<'t, T: SecretFromSql<'t>> SecretFromSql<'t> for Option<T> {
374    fn from_sql(value: rusqlite::types::ValueRef<'_>) -> rusqlite::types::FromSqlResult<Self> {
375        if value.data_type() == rusqlite::types::Type::Null {
376            Ok(None)
377        } else {
378            Ok(Some(T::from_sql(value)?))
379        }
380    }
381}
382
383/// This is an expression that can be used in queries.
384///
385/// - The lifetime parameter `'column` specifies which columns need to be in scope.
386/// - The type parameter `S` specifies the expected schema of the query.
387/// - And finally the type paramter `T` specifies the type of the expression.
388///
389/// [Expr] implements [Deref] to have table extension methods in case the type is a table type.
390pub struct Expr<'column, S, T> {
391    pub(crate) inner: DynTyped<T>,
392    pub(crate) _p: PhantomData<&'column ()>,
393    pub(crate) _p2: PhantomData<S>,
394}
395
396impl<'column, S, T> Debug for Expr<'column, S, T> {
397    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
398        write!(f, "Expr of type {}", std::any::type_name::<T>())
399    }
400}
401
402impl<'column, S, T: 'static> Expr<'column, S, T> {
403    /// Extremely easy to use API. Should only be used by the macro to implement migrations.
404    #[doc(hidden)]
405    pub fn _migrate<OldS>(prev: impl IntoExpr<'column, OldS>) -> Self {
406        Self::new(MigratedExpr {
407            prev: prev.into_expr().inner.erase(),
408            _p: PhantomData,
409        })
410    }
411}
412
413pub fn adhoc_expr<S, T: 'static>(
414    f: impl 'static + Fn(ValueBuilder) -> SimpleExpr,
415) -> Expr<'static, S, T> {
416    Expr::adhoc(f)
417}
418
419pub fn new_column<'x, S, T: 'static>(val: impl Typed<Typ = T> + 'static) -> Expr<'x, S, T> {
420    Expr::new(val)
421}
422
423pub fn assume_expr<S, T: 'static>(e: Expr<S, Option<T>>) -> Expr<S, T> {
424    let inner = e.inner;
425    Expr::adhoc(move |b| inner.build_expr(b))
426}
427
428pub fn new_dummy<'x, S, T: MyTyp>(
429    val: impl Typed<Typ = T> + 'static,
430) -> Select<'x, 'x, S, T::Out<'x>> {
431    IntoSelect::into_select(Expr::new(val))
432}
433
434pub fn into_owned<'x, S, T>(val: impl IntoExpr<'x, S, Typ = T>) -> DynTyped<T> {
435    val.into_expr().inner
436}
437
438struct AdHoc<F, T>(F, PhantomData<T>);
439impl<F: Fn(ValueBuilder) -> SimpleExpr, T> Typed for AdHoc<F, T> {
440    type Typ = T;
441
442    fn build_expr(&self, b: ValueBuilder) -> SimpleExpr {
443        (self.0)(b)
444    }
445}
446
447impl<S, T: 'static> Expr<'_, S, T> {
448    pub(crate) fn adhoc(f: impl 'static + Fn(ValueBuilder) -> SimpleExpr) -> Self {
449        Self::new(AdHoc(f, PhantomData))
450    }
451
452    pub(crate) fn new(val: impl Typed<Typ = T> + 'static) -> Self {
453        Self {
454            inner: DynTyped(Rc::new(val)),
455            _p: PhantomData,
456            _p2: PhantomData,
457        }
458    }
459}
460
461impl<'column, S, T> Clone for Expr<'column, S, T> {
462    fn clone(&self) -> Self {
463        Self {
464            inner: self.inner.clone(),
465            _p: self._p.clone(),
466            _p2: self._p2.clone(),
467        }
468    }
469}
470
471// TODO: remove this and replace with `Private`
472impl<'column, S, T: 'static> Typed for Expr<'column, S, T> {
473    type Typ = T;
474
475    fn build_expr(&self, b: ValueBuilder) -> SimpleExpr {
476        self.inner.0.as_ref().build_expr(b)
477    }
478
479    fn build_table(&self, b: crate::value::ValueBuilder) -> MyAlias
480    where
481        Self::Typ: Table,
482    {
483        self.inner.0.as_ref().build_table(b)
484    }
485}
486
487pub struct DynTypedExpr(pub(crate) Box<dyn Fn(ValueBuilder) -> SimpleExpr>);
488
489impl<Typ: 'static> DynTyped<Typ> {
490    pub fn erase(self) -> DynTypedExpr {
491        DynTypedExpr(Box::new(move |b| self.build_expr(b)))
492    }
493}
494
495pub struct MigratedExpr<Typ> {
496    prev: DynTypedExpr,
497    _p: PhantomData<Typ>,
498}
499
500impl<Typ> Typed for MigratedExpr<Typ> {
501    type Typ = Typ;
502    fn build_expr(&self, b: ValueBuilder) -> SimpleExpr {
503        self.prev.0(b)
504    }
505}
506
507pub struct DynTyped<Typ>(pub(crate) Rc<dyn Typed<Typ = Typ>>);
508
509impl<T> Clone for DynTyped<T> {
510    fn clone(&self) -> Self {
511        Self(self.0.clone())
512    }
513}
514
515impl<Typ: 'static> Typed for DynTyped<Typ> {
516    type Typ = Typ;
517
518    fn build_expr(&self, b: ValueBuilder) -> SimpleExpr {
519        self.0.build_expr(b)
520    }
521
522    fn build_table(&self, b: crate::value::ValueBuilder) -> MyAlias
523    where
524        Self::Typ: Table,
525    {
526        self.0.build_table(b)
527    }
528}
529
530impl<'column, S, T: MyTyp> IntoExpr<'column, S> for Expr<'column, S, T> {
531    type Typ = T;
532    fn into_expr(self) -> Expr<'column, S, Self::Typ> {
533        self
534    }
535}
536
537impl<'column, S, T: Table> Deref for Expr<'column, S, T> {
538    type Target = T::Ext<Self>;
539
540    fn deref(&self) -> &Self::Target {
541        RefCast::ref_cast(self)
542    }
543}