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