rust_query/
rows.rs

1use std::{marker::PhantomData, rc::Rc};
2
3use sea_query::Iden;
4
5use crate::{
6    Expr, Table,
7    alias::TmpTable,
8    ast::MySelect,
9    db::Join,
10    value::{IntoExpr, MyTableRef, Typed},
11};
12
13/// [Rows] keeps track of all rows in the current query.
14///
15/// This is the base type for other query types like [crate::args::Aggregate] and [crate::args::Query].
16/// It contains basic query functionality like joining tables and filters.
17///
18/// [Rows] mutability is only about which rows are included.
19/// Adding new columns does not require mutating [Rows].
20pub struct Rows<'inner, S> {
21    // we might store 'inner
22    pub(crate) phantom: PhantomData<fn(&'inner ()) -> &'inner ()>,
23    pub(crate) _p: PhantomData<S>,
24    pub(crate) ast: Rc<MySelect>,
25}
26
27impl<'inner, S> Rows<'inner, S> {
28    /// Join a table, this is like a super simple [Iterator::flat_map] but for queries.
29    ///
30    /// After this operation [Rows] has rows for the combinations of each original row with each row of the table.
31    /// (Also called the "Carthesian product")
32    pub fn join<T: Table<Schema = S>>(&mut self, _: T) -> Expr<'inner, S, T> {
33        self.join_string(T::NAME.to_owned())
34    }
35
36    pub(crate) fn join_custom<T: Table<Schema = S>>(&mut self, t: T) -> Expr<'inner, S, T> {
37        self.join_string(t.name())
38    }
39
40    pub(crate) fn join_tmp<T: Table<Schema = S>>(&mut self, tmp: TmpTable) -> Expr<'inner, S, T> {
41        let mut tmp_string = String::new();
42        tmp.unquoted(&mut tmp_string);
43        self.join_string(tmp_string)
44    }
45
46    fn join_string<T: Table<Schema = S>>(&mut self, name: String) -> Expr<'inner, S, T> {
47        let table_idx = self.ast.tables.len();
48        Rc::make_mut(&mut self.ast).tables.push(name);
49        Expr::new(Join::new(MyTableRef {
50            scope_rc: self.ast.scope_rc.clone(),
51            idx: table_idx,
52        }))
53    }
54
55    // Join a vector of values.
56    // pub fn vec<V: IntoExpr<'inner>>(&mut self, vec: Vec<V>) -> Join<'inner, V::Typ> {
57    //     todo!()
58    // }
59
60    /// Filter rows based on a column.
61    pub fn filter(&mut self, prop: impl IntoExpr<'inner, S, Typ = bool>) {
62        let prop = prop.into_expr();
63        Rc::make_mut(&mut self.ast).filters.push(prop.inner);
64    }
65
66    /// Filter out rows where this column is [None].
67    ///
68    /// Returns a new column with the unwrapped type.
69    pub fn filter_some<Typ: 'static>(
70        &mut self,
71        val: impl IntoExpr<'inner, S, Typ = Option<Typ>>,
72    ) -> Expr<'inner, S, Typ> {
73        let val = val.into_expr();
74        Rc::make_mut(&mut self.ast)
75            .filters
76            .push(val.is_some().inner);
77
78        Expr::adhoc(move |b| val.inner.build_expr(b))
79    }
80}