rust_query/
value.rs

1pub mod aggregate;
2mod operations;
3pub mod optional;
4pub mod trivial;
5
6use std::{cell::OnceCell, fmt::Debug, marker::PhantomData, ops::Deref, rc::Rc};
7
8use sea_query::{Alias, JoinType, Nullable, SelectStatement};
9
10use crate::{
11    Lazy, Table, Transaction,
12    alias::{Field, MyAlias, Scope},
13    ast::{MySelect, Source},
14    db::{Join, TableRow, TableRowInner},
15    mymap::MyMap,
16    private::Joinable,
17    schema::canonical,
18};
19
20#[derive(Default)]
21pub struct ValueBuilder {
22    pub(crate) from: Rc<MySelect>,
23    // only used for tables
24    pub(super) scope: Scope,
25    // implicit joins
26    pub(super) extra: MyMap<Source, MyAlias>,
27    // calculating these results
28    pub(super) forwarded: MyMap<MyTableRef, (&'static str, DynTypedExpr, MyAlias)>,
29}
30
31impl ValueBuilder {
32    pub(crate) fn get_aggr(
33        &mut self,
34        aggr: Rc<SelectStatement>,
35        conds: Vec<sea_query::Expr>,
36    ) -> MyAlias {
37        let source = Source {
38            kind: crate::ast::SourceKind::Aggregate(aggr),
39            conds: conds
40                .into_iter()
41                .enumerate()
42                .map(|(idx, expr)| (Field::U64(MyAlias::new(idx)), expr))
43                .collect(),
44        };
45        let new_alias = || self.scope.new_alias();
46        *self.extra.get_or_init(source, new_alias)
47    }
48
49    pub(crate) fn get_join<T: Table>(
50        &mut self,
51        expr: sea_query::Expr,
52        possible_null: bool,
53    ) -> MyAlias {
54        let join_type = if possible_null {
55            JoinType::LeftJoin
56        } else {
57            JoinType::Join
58        };
59        let source = Source {
60            kind: crate::ast::SourceKind::Implicit(T::NAME.to_owned(), join_type),
61            conds: vec![(Field::Str(T::ID), expr)],
62        };
63        let new_alias = || self.scope.new_alias();
64        *self.extra.get_or_init(source, new_alias)
65    }
66
67    pub fn get_unique<T: Table>(
68        &mut self,
69        conds: Box<[(&'static str, sea_query::Expr)]>,
70    ) -> sea_query::Expr {
71        let source = Source {
72            kind: crate::ast::SourceKind::Implicit(T::NAME.to_owned(), JoinType::LeftJoin),
73            conds: conds.into_iter().map(|x| (Field::Str(x.0), x.1)).collect(),
74        };
75
76        let new_alias = || self.scope.new_alias();
77        let table = self.extra.get_or_init(source, new_alias);
78        sea_query::Expr::col((*table, Alias::new(T::ID))).into()
79    }
80
81    pub fn get_table<T: Table>(&mut self, table: MyTableRef) -> MyAlias {
82        if Rc::ptr_eq(&self.from.scope_rc, &table.scope_rc) {
83            MyAlias::new(table.idx)
84        } else {
85            let join = Join::<T>::new(table.clone());
86            self.forwarded
87                .get_or_init(table, || {
88                    (
89                        T::NAME,
90                        DynTypedExpr::new(move |b| join.build_expr(b)),
91                        self.scope.new_alias(),
92                    )
93                })
94                .2
95        }
96    }
97}
98
99#[derive(Clone)]
100pub struct MyTableRef {
101    pub(crate) scope_rc: Rc<()>,
102    pub(crate) idx: usize,
103}
104
105impl PartialEq for MyTableRef {
106    fn eq(&self, other: &Self) -> bool {
107        Rc::ptr_eq(&self.scope_rc, &other.scope_rc) && self.idx == other.idx
108    }
109}
110
111pub trait NumTyp: MyTyp + Clone + Copy {
112    const ZERO: Self;
113    fn into_sea_value(self) -> sea_query::Value;
114}
115
116impl NumTyp for i64 {
117    const ZERO: Self = 0;
118    fn into_sea_value(self) -> sea_query::Value {
119        sea_query::Value::BigInt(Some(self))
120    }
121}
122impl NumTyp for f64 {
123    const ZERO: Self = 0.;
124    fn into_sea_value(self) -> sea_query::Value {
125        sea_query::Value::Double(Some(self))
126    }
127}
128
129#[diagnostic::on_unimplemented(
130    message = "Columns with type `{Self}` can not be checked for equality",
131    note = "`EqTyp` is also implemented for all table types"
132)]
133pub trait EqTyp: MyTyp {}
134
135impl EqTyp for String {}
136impl EqTyp for Vec<u8> {}
137impl EqTyp for i64 {}
138impl EqTyp for f64 {}
139impl EqTyp for bool {}
140#[diagnostic::do_not_recommend]
141impl<T: Table> EqTyp for T {}
142
143/// Typ does not depend on scope, so it gets its own trait
144pub trait Typed {
145    type Typ;
146
147    fn build_expr(&self, b: &mut ValueBuilder) -> sea_query::Expr;
148    fn maybe_optional(&self) -> bool {
149        true
150    }
151
152    fn build_table(&self, b: &mut ValueBuilder) -> MyAlias
153    where
154        Self::Typ: Table,
155    {
156        let expr = self.build_expr(b);
157        b.get_join::<Self::Typ>(expr, self.maybe_optional())
158    }
159}
160
161/// Trait for all values that can be used as expressions in queries.
162pub trait IntoExpr<'column, S> {
163    /// The type of the expression.
164    type Typ: MyTyp;
165
166    /// Turn this value into an [Expr].
167    fn into_expr(self) -> Expr<'column, S, Self::Typ>;
168}
169
170impl<X: MyTyp<Sql: Nullable>> Typed for Option<Rc<dyn Typed<Typ = X>>> {
171    type Typ = Option<X>;
172
173    fn build_expr(&self, b: &mut ValueBuilder) -> sea_query::Expr {
174        self.as_ref()
175            .map(|x| x.build_expr(b))
176            .unwrap_or(X::Sql::null().into())
177    }
178}
179
180impl<'column, S, T: IntoExpr<'column, S, Typ = X>, X: MyTyp<Sql: Nullable>> IntoExpr<'column, S>
181    for Option<T>
182{
183    type Typ = Option<X>;
184    fn into_expr(self) -> Expr<'column, S, Self::Typ> {
185        Expr::new(self.map(|x| x.into_expr().inner))
186    }
187}
188
189impl Typed for String {
190    type Typ = String;
191    fn build_expr(&self, _: &mut ValueBuilder) -> sea_query::Expr {
192        sea_query::Expr::from(self)
193    }
194}
195
196impl<'column, S> IntoExpr<'column, S> for String {
197    type Typ = String;
198    fn into_expr(self) -> Expr<'column, S, Self::Typ> {
199        Expr::new(self)
200    }
201}
202
203impl<'column, S> IntoExpr<'column, S> for &str {
204    type Typ = String;
205    fn into_expr(self) -> Expr<'column, S, Self::Typ> {
206        Expr::new(self.to_owned())
207    }
208}
209
210impl Typed for Vec<u8> {
211    type Typ = Vec<u8>;
212    fn build_expr(&self, _: &mut ValueBuilder) -> sea_query::Expr {
213        sea_query::Expr::from(self.to_owned())
214    }
215}
216
217impl<'column, S> IntoExpr<'column, S> for Vec<u8> {
218    type Typ = Vec<u8>;
219    fn into_expr(self) -> Expr<'column, S, Self::Typ> {
220        Expr::new(self)
221    }
222}
223
224impl<'column, S> IntoExpr<'column, S> for &[u8] {
225    type Typ = Vec<u8>;
226    fn into_expr(self) -> Expr<'column, S, Self::Typ> {
227        Expr::new(self.to_owned())
228    }
229}
230
231impl Typed for bool {
232    type Typ = bool;
233    fn build_expr(&self, _: &mut ValueBuilder) -> sea_query::Expr {
234        sea_query::Expr::from(*self)
235    }
236}
237
238impl<'column, S> IntoExpr<'column, S> for bool {
239    type Typ = bool;
240    fn into_expr(self) -> Expr<'column, S, Self::Typ> {
241        Expr::new(self)
242    }
243}
244
245impl Typed for i64 {
246    type Typ = i64;
247    fn build_expr(&self, _: &mut ValueBuilder) -> sea_query::Expr {
248        sea_query::Expr::from(*self)
249    }
250}
251
252impl<'column, S> IntoExpr<'column, S> for i64 {
253    type Typ = i64;
254    fn into_expr(self) -> Expr<'column, S, Self::Typ> {
255        Expr::new(self)
256    }
257}
258
259impl Typed for f64 {
260    type Typ = f64;
261    fn build_expr(&self, _: &mut ValueBuilder) -> sea_query::Expr {
262        sea_query::Expr::from(*self)
263    }
264}
265
266impl<'column, S> IntoExpr<'column, S> for f64 {
267    type Typ = f64;
268    fn into_expr(self) -> Expr<'column, S, Self::Typ> {
269        Expr::new(self)
270    }
271}
272
273impl<T> Typed for &T
274where
275    T: Typed,
276{
277    type Typ = T::Typ;
278    fn build_expr(&self, b: &mut ValueBuilder) -> sea_query::Expr {
279        T::build_expr(self, b)
280    }
281    fn maybe_optional(&self) -> bool {
282        T::maybe_optional(self)
283    }
284    fn build_table(&self, b: &mut ValueBuilder) -> MyAlias
285    where
286        Self::Typ: Table,
287    {
288        T::build_table(self, b)
289    }
290}
291
292impl<'column, S, T> IntoExpr<'column, S> for &T
293where
294    T: IntoExpr<'column, S> + Clone,
295{
296    type Typ = T::Typ;
297    fn into_expr(self) -> Expr<'column, S, Self::Typ> {
298        T::into_expr(self.clone())
299    }
300}
301
302/// Use this a value in a query to get the current datetime as a number of seconds.
303#[derive(Clone, Copy)]
304pub struct UnixEpoch;
305
306impl Typed for UnixEpoch {
307    type Typ = i64;
308    fn build_expr(&self, _: &mut ValueBuilder) -> sea_query::Expr {
309        sea_query::Expr::cust("unixepoch('now')").into()
310    }
311}
312
313impl<'column, S> IntoExpr<'column, S> for UnixEpoch {
314    type Typ = i64;
315    fn into_expr(self) -> Expr<'column, S, Self::Typ> {
316        Expr::new(self)
317    }
318}
319
320pub trait MyTyp: 'static {
321    type Prev: MyTyp;
322    const NULLABLE: bool = false;
323    const TYP: canonical::ColumnType;
324    const FK: Option<(&'static str, &'static str)> = None;
325    type Out: SecretFromSql;
326    type Lazy<'t>;
327    type Ext<'t>;
328    type Sql;
329    fn out_to_lazy<'t>(val: Self::Out) -> Self::Lazy<'t>;
330}
331
332pub(crate) trait SecretFromSql: Sized {
333    fn from_sql(value: rusqlite::types::ValueRef<'_>) -> rusqlite::types::FromSqlResult<Self>;
334}
335
336#[diagnostic::do_not_recommend]
337impl<T: Table> MyTyp for T {
338    type Prev = T::MigrateFrom;
339    const TYP: canonical::ColumnType = canonical::ColumnType::Integer;
340    const FK: Option<(&'static str, &'static str)> = Some((T::NAME, T::ID));
341    type Out = TableRow<T>;
342    type Lazy<'t> = Lazy<'t, T>;
343    type Ext<'t> = T::Ext2<'t>;
344    type Sql = i64;
345    fn out_to_lazy<'t>(val: Self::Out) -> Self::Lazy<'t> {
346        Lazy {
347            id: val,
348            lazy: OnceCell::new(),
349            txn: Transaction::new_ref(),
350        }
351    }
352}
353
354impl<T: Table> SecretFromSql for TableRow<T> {
355    fn from_sql(value: rusqlite::types::ValueRef<'_>) -> rusqlite::types::FromSqlResult<Self> {
356        Ok(TableRow {
357            _local: PhantomData,
358            inner: TableRowInner {
359                _p: PhantomData,
360                idx: value.as_i64()?,
361            },
362        })
363    }
364}
365
366impl MyTyp for i64 {
367    type Prev = Self;
368    const TYP: canonical::ColumnType = canonical::ColumnType::Integer;
369    type Out = Self;
370    type Lazy<'t> = Self;
371    type Ext<'t> = ();
372    type Sql = i64;
373    fn out_to_lazy<'t>(val: Self::Out) -> Self::Lazy<'t> {
374        val
375    }
376}
377
378impl SecretFromSql for i64 {
379    fn from_sql(value: rusqlite::types::ValueRef<'_>) -> rusqlite::types::FromSqlResult<Self> {
380        value.as_i64()
381    }
382}
383
384impl MyTyp for f64 {
385    type Prev = Self;
386    const TYP: canonical::ColumnType = canonical::ColumnType::Real;
387    type Out = Self;
388    type Lazy<'t> = Self;
389    type Ext<'t> = ();
390    type Sql = f64;
391    fn out_to_lazy<'t>(val: Self::Out) -> Self::Lazy<'t> {
392        val
393    }
394}
395
396impl SecretFromSql for f64 {
397    fn from_sql(value: rusqlite::types::ValueRef<'_>) -> rusqlite::types::FromSqlResult<Self> {
398        value.as_f64()
399    }
400}
401
402impl MyTyp for bool {
403    type Prev = Self;
404    const TYP: canonical::ColumnType = canonical::ColumnType::Integer;
405    type Out = Self;
406    type Lazy<'t> = Self;
407    type Ext<'t> = ();
408    type Sql = bool;
409    fn out_to_lazy<'t>(val: Self::Out) -> Self::Lazy<'t> {
410        val
411    }
412}
413
414impl SecretFromSql for bool {
415    fn from_sql(value: rusqlite::types::ValueRef<'_>) -> rusqlite::types::FromSqlResult<Self> {
416        Ok(value.as_i64()? != 0)
417    }
418}
419
420impl MyTyp for String {
421    type Prev = Self;
422    const TYP: canonical::ColumnType = canonical::ColumnType::Text;
423    type Out = Self;
424    type Lazy<'t> = Self;
425    type Ext<'t> = ();
426    type Sql = String;
427    fn out_to_lazy<'t>(val: Self::Out) -> Self::Lazy<'t> {
428        val
429    }
430}
431assert_impl_all!(String: Nullable);
432
433impl SecretFromSql for String {
434    fn from_sql(value: rusqlite::types::ValueRef<'_>) -> rusqlite::types::FromSqlResult<Self> {
435        Ok(value.as_str()?.to_owned())
436    }
437}
438
439impl MyTyp for Vec<u8> {
440    type Prev = Self;
441    const TYP: canonical::ColumnType = canonical::ColumnType::Blob;
442    type Out = Self;
443    type Lazy<'t> = Self;
444    type Ext<'t> = ();
445    type Sql = Vec<u8>;
446    fn out_to_lazy<'t>(val: Self::Out) -> Self::Lazy<'t> {
447        val
448    }
449}
450assert_impl_all!(Vec<u8>: Nullable);
451
452impl SecretFromSql for Vec<u8> {
453    fn from_sql(value: rusqlite::types::ValueRef<'_>) -> rusqlite::types::FromSqlResult<Self> {
454        Ok(value.as_blob()?.to_owned())
455    }
456}
457
458impl<T: MyTyp> MyTyp for Option<T> {
459    type Prev = Option<T::Prev>;
460    const TYP: canonical::ColumnType = T::TYP;
461    const NULLABLE: bool = true;
462    const FK: Option<(&'static str, &'static str)> = T::FK;
463    type Out = Option<T::Out>;
464    type Lazy<'t> = Option<T::Lazy<'t>>;
465    type Ext<'t> = ();
466    type Sql = T::Sql;
467    fn out_to_lazy<'t>(val: Self::Out) -> Self::Lazy<'t> {
468        val.map(T::out_to_lazy)
469    }
470}
471
472impl<T: SecretFromSql> SecretFromSql for Option<T> {
473    fn from_sql(value: rusqlite::types::ValueRef<'_>) -> rusqlite::types::FromSqlResult<Self> {
474        if value.data_type() == rusqlite::types::Type::Null {
475            Ok(None)
476        } else {
477            Ok(Some(T::from_sql(value)?))
478        }
479    }
480}
481
482/// This is an expression that can be used in queries.
483///
484/// - The lifetime parameter `'column` specifies which columns need to be in scope.
485/// - The type parameter `S` specifies the expected schema of the query.
486/// - And finally the type paramter `T` specifies the type of the expression.
487///
488/// [Expr] implements [Deref] to have column fields in case the expression has a table type.
489pub struct Expr<'column, S, T: MyTyp> {
490    pub(crate) _local: PhantomData<*const ()>,
491    pub(crate) inner: Rc<dyn Typed<Typ = T>>,
492    pub(crate) _p: PhantomData<&'column ()>,
493    pub(crate) _p2: PhantomData<S>,
494    pub(crate) ext: OnceCell<Box<T::Ext<'static>>>,
495}
496
497impl<S, T: MyTyp> Debug for Expr<'_, S, T> {
498    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
499        write!(f, "Expr of type {}", std::any::type_name::<T>())
500    }
501}
502
503impl<'column, S, T: MyTyp> Expr<'column, S, T> {
504    /// Extremely easy to use API. Should only be used by the macro to implement migrations.
505    #[doc(hidden)]
506    pub fn _migrate<OldS>(prev: impl IntoExpr<'column, OldS>) -> Self {
507        Self::new(MigratedExpr {
508            prev: DynTypedExpr::erase(prev),
509            _p: PhantomData,
510        })
511    }
512}
513
514pub fn adhoc_expr<S, T: MyTyp>(
515    f: impl 'static + Fn(&mut ValueBuilder) -> sea_query::Expr,
516) -> Expr<'static, S, T> {
517    Expr::adhoc(f)
518}
519
520pub fn new_column<'x, S, C: MyTyp, T: Table>(
521    table: impl IntoExpr<'x, S, Typ = T>,
522    name: &'static str,
523) -> Expr<'x, S, C> {
524    let table = table.into_expr().inner;
525    let possible_null = table.maybe_optional();
526    Expr::adhoc_promise(
527        move |b| sea_query::Expr::col((table.build_table(b), Field::Str(name))).into(),
528        possible_null,
529    )
530}
531
532pub fn unique_from_joinable<'inner, T: Table>(
533    j: impl Joinable<'inner, Typ = T>,
534) -> Expr<'inner, T::Schema, Option<T>> {
535    let list = j.conds();
536    ::rust_query::private::adhoc_expr(move |_b| {
537        let list = list
538            .iter()
539            .map(|(name, col)| (*name, (col.func)(_b)))
540            .collect();
541        _b.get_unique::<T>(list)
542    })
543}
544
545struct AdHoc<F, T> {
546    func: F,
547    maybe_optional: bool,
548    _p: PhantomData<T>,
549}
550impl<F: Fn(&mut ValueBuilder) -> sea_query::Expr, T> Typed for AdHoc<F, T> {
551    type Typ = T;
552
553    fn build_expr(&self, b: &mut ValueBuilder) -> sea_query::Expr {
554        (self.func)(b)
555    }
556    fn maybe_optional(&self) -> bool {
557        self.maybe_optional
558    }
559}
560
561impl<S, T: MyTyp> Expr<'_, S, T> {
562    pub(crate) fn adhoc(f: impl 'static + Fn(&mut ValueBuilder) -> sea_query::Expr) -> Self {
563        Self::new(AdHoc {
564            func: f,
565            maybe_optional: true,
566            _p: PhantomData,
567        })
568    }
569
570    /// Only set `maybe_optional` to `false` if you are absolutely sure that the
571    /// value is not null. The [crate::optional] combinator makes this more difficult.
572    /// There is no reason to use this for values that can not be foreign keys.
573    /// This is used to optimize implicit joins from LEFT JOIN to just JOIN.
574    pub(crate) fn adhoc_promise(
575        f: impl 'static + Fn(&mut ValueBuilder) -> sea_query::Expr,
576        maybe_optional: bool,
577    ) -> Self {
578        Self::new(AdHoc {
579            func: f,
580            maybe_optional,
581            _p: PhantomData,
582        })
583    }
584
585    pub(crate) fn new(val: impl Typed<Typ = T> + 'static) -> Self {
586        Self {
587            _local: PhantomData,
588            inner: Rc::new(val),
589            _p: PhantomData,
590            _p2: PhantomData,
591            ext: OnceCell::new(),
592        }
593    }
594}
595
596impl<S, T: MyTyp> Clone for Expr<'_, S, T> {
597    fn clone(&self) -> Self {
598        Self {
599            _local: PhantomData,
600            inner: self.inner.clone(),
601            _p: self._p,
602            _p2: self._p2,
603            ext: OnceCell::new(),
604        }
605    }
606}
607
608#[derive(Clone)]
609pub struct DynTypedExpr {
610    pub func: Rc<dyn Fn(&mut ValueBuilder) -> sea_query::Expr>,
611}
612
613impl DynTypedExpr {
614    pub fn new(f: impl 'static + Fn(&mut ValueBuilder) -> sea_query::Expr) -> Self {
615        Self { func: Rc::new(f) }
616    }
617    pub fn erase<'x, S>(expr: impl IntoExpr<'x, S>) -> Self {
618        let typed = expr.into_expr().inner;
619        Self::new(move |b| typed.build_expr(b))
620    }
621}
622
623pub struct MigratedExpr<Typ> {
624    prev: DynTypedExpr,
625    _p: PhantomData<Typ>,
626}
627
628impl<Typ> Typed for MigratedExpr<Typ> {
629    type Typ = Typ;
630    fn build_expr(&self, b: &mut ValueBuilder) -> sea_query::Expr {
631        (self.prev.func)(b)
632    }
633}
634
635impl<'column, S, T: MyTyp> IntoExpr<'column, S> for Expr<'column, S, T> {
636    type Typ = T;
637    fn into_expr(self) -> Expr<'column, S, Self::Typ> {
638        self
639    }
640}
641
642impl<'t, T: Table> Deref for Expr<'t, T::Schema, T> {
643    type Target = T::Ext2<'t>;
644
645    fn deref(&self) -> &Self::Target {
646        T::covariant_ext(self.ext.get_or_init(|| {
647            let expr = Expr {
648                _local: PhantomData,
649                inner: self.inner.clone(),
650                _p: PhantomData::<&'static ()>,
651                _p2: PhantomData,
652                ext: OnceCell::new(),
653            };
654            Box::new(T::build_ext2(&expr))
655        }))
656    }
657}