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