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