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