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