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()
}
}