rust_query/
rows.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
use std::marker::PhantomData;

use sea_query::{Expr, SimpleExpr};

use crate::{
    ast::MySelect,
    db::Join,
    value::{operations::Assume, IntoColumn},
    Column, Table,
};

/// [Rows] keeps track of all rows in the current query.
///
/// This is the base type for other query types like [crate::args::Aggregate] and [crate::args::Query].
/// It contains most query functionality like joining tables and doing sub-queries.
///
/// [Rows] mutability is only about which rows are included.
/// Adding new columns does not require mutating [Rows].
pub struct Rows<'inner, S> {
    // we might store 'inner
    pub(crate) phantom: PhantomData<fn(&'inner S) -> &'inner S>,
    pub(crate) ast: MySelect,
}

impl<'inner, S> Rows<'inner, S> {
    /// Join a table, this is like a super simple [Iterator::flat_map] but for queries.
    ///
    /// After this operation [Rows] has rows for the combinations of each original row with each row of the table.
    /// (Also called the "Carthesian product")
    ///
    /// For convenience there is also [Table::join].
    pub fn join<T: Table<Schema = S>>(&mut self) -> Column<'inner, S, T> {
        let alias = self.ast.scope.new_alias();
        self.ast.tables.push((T::NAME.to_owned(), alias));
        IntoColumn::into_column(Join::new(alias))
    }

    pub(crate) fn join_custom<T: Table>(&mut self, t: T) -> Join<'inner, T> {
        let alias = self.ast.scope.new_alias();
        self.ast.tables.push((t.name(), alias));
        Join::new(alias)
    }

    // Join a vector of values.
    // pub fn vec<V: Column<'inner>>(&mut self, vec: Vec<V>) -> Join<'inner, V::Typ> {
    //     todo!()
    // }

    /// Filter rows based on a column.
    pub fn filter(&mut self, prop: impl IntoColumn<'inner, S, Typ = bool>) {
        self.filter_private(prop.build_expr(self.ast.builder()));
    }

    fn filter_private(&mut self, prop: SimpleExpr) {
        self.ast.filters.push(Box::new(prop));
    }

    /// Filter out rows where this column is [None].
    ///
    /// Returns a new column with the unwrapped type.
    pub fn filter_some<Typ>(
        &mut self,
        val: impl IntoColumn<'inner, S, Typ = Option<Typ>>,
    ) -> Column<'inner, S, Typ> {
        self.filter_private(Expr::expr(val.build_expr(self.ast.builder())).is_not_null());
        Assume(val).into_column()
    }
}