rust_query/
rows.rs

1use std::{marker::PhantomData, rc::Rc};
2
3use sea_query::{ExprTrait, IntoIden};
4
5use crate::{
6    Expr, Table,
7    alias::{Field, JoinableTable, TmpTable},
8    ast::MySelect,
9    db::Join,
10    joinable::Joinable,
11    value::{DynTypedExpr, IntoExpr, MyTableRef, MyTyp},
12};
13
14/// [Rows] keeps track of all rows in the current query.
15///
16/// This is the base type for other query types like [crate::args::Aggregate] and [crate::args::Query].
17/// It contains basic query functionality like joining tables and filters.
18///
19/// [Rows] mutability is only about which rows are included.
20/// Adding new columns does not require mutating [Rows].
21pub struct Rows<'inner, S> {
22    // we might store 'inner
23    pub(crate) phantom: PhantomData<fn(&'inner ()) -> &'inner ()>,
24    pub(crate) _p: PhantomData<S>,
25    pub(crate) ast: Rc<MySelect>,
26}
27
28impl<'inner, S> Rows<'inner, S> {
29    /// Join a table, this is like a super simple [Iterator::flat_map] but for queries.
30    ///
31    /// After this operation [Rows] has rows for the combinations of each original row with each row of the table.
32    /// (Also called the "Carthesian product")
33    ///
34    /// The expression that is returned refers to the joined table.
35    pub fn join<T: Table<Schema = S>>(
36        &mut self,
37        j: impl Joinable<'inner, Typ = T>,
38    ) -> Expr<'inner, S, T> {
39        let out = self.join_private::<T>();
40        for (name, val) in j.conds() {
41            let out = out.inner.clone();
42            self.filter(Expr::adhoc(move |b| {
43                sea_query::Expr::col((out.build_table(b), Field::Str(name))).eq((val.func)(b))
44            }));
45        }
46        out
47    }
48
49    #[doc(hidden)]
50    pub fn join_private<T: Table<Schema = S>>(&mut self) -> Expr<'inner, S, T> {
51        self.join_inner(JoinableTable::Normal(T::NAME.into()))
52    }
53
54    pub(crate) fn join_custom<T: Table<Schema = S>>(&mut self, t: T) -> Expr<'inner, S, T> {
55        self.join_inner(t.name())
56    }
57
58    pub(crate) fn join_tmp<T: Table<Schema = S>>(&mut self, tmp: TmpTable) -> Expr<'inner, S, T> {
59        let tmp_string = tmp.into_iden();
60        self.join_inner(JoinableTable::Normal(tmp_string))
61    }
62
63    fn join_inner<T: Table<Schema = S>>(&mut self, name: JoinableTable) -> Expr<'inner, S, T> {
64        let table_idx = self.ast.tables.len();
65        Rc::make_mut(&mut self.ast).tables.push(name);
66        Expr::new(Join::new(MyTableRef {
67            scope_rc: self.ast.scope_rc.clone(),
68            idx: table_idx,
69        }))
70    }
71
72    // Join a vector of values.
73    // pub fn vec<V: IntoExpr<'inner>>(&mut self, vec: Vec<V>) -> Join<'inner, V::Typ> {
74    //     todo!()
75    // }
76
77    /// Filter rows based on an expression.
78    pub fn filter(&mut self, prop: impl IntoExpr<'inner, S, Typ = bool>) {
79        let prop = DynTypedExpr::erase(prop);
80        Rc::make_mut(&mut self.ast).filters.push(prop);
81    }
82
83    /// Filter out rows where this expression is [None].
84    ///
85    /// Returns a new expression with the unwrapped type.
86    pub fn filter_some<Typ: MyTyp>(
87        &mut self,
88        val: impl IntoExpr<'inner, S, Typ = Option<Typ>>,
89    ) -> Expr<'inner, S, Typ> {
90        let val = val.into_expr();
91        Rc::make_mut(&mut self.ast)
92            .filters
93            .push(DynTypedExpr::erase(val.is_some()));
94
95        // we already removed all rows with null, so this is ok.
96        Expr::adhoc_promise(move |b| val.inner.build_expr(b), false)
97    }
98}