1use std::{marker::PhantomData, rc::Rc};
2
3use sea_query::{ExprTrait, IntoIden};
4
5use crate::{
6 CustomJoin, Expr, Table,
7 alias::{Field, JoinableTable, TmpTable},
8 ast::MySelect,
9 db::Join,
10 joinable::Joinable,
11 value::{DynTypedExpr, IntoExpr, MyTableRef, MyTyp},
12};
13
14pub struct Rows<'inner, S> {
22 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 pub fn join<T: Table<Schema = S>>(
40 &mut self,
41 j: impl Joinable<'inner, Typ = T>,
42 ) -> Expr<'inner, S, T> {
43 let out = self.join_private::<T>();
44 for (name, val) in j.conds() {
45 let out = out.inner.clone();
46 self.filter(Expr::adhoc(move |b| {
47 sea_query::Expr::col((out.build_table(b), Field::Str(name))).eq((val.func)(b))
48 }));
49 }
50 out
51 }
52
53 #[doc(hidden)]
54 pub fn join_private<T: Table<Schema = S>>(&mut self) -> Expr<'inner, S, T> {
55 self.join_inner(JoinableTable::Normal(T::NAME.into()))
56 }
57
58 pub(crate) fn join_custom<T: CustomJoin<Schema = S>>(&mut self, t: T) -> Expr<'inner, S, T> {
59 self.join_inner(t.name())
60 }
61
62 pub(crate) fn join_tmp<T: Table<Schema = S>>(&mut self, tmp: TmpTable) -> Expr<'inner, S, T> {
63 let tmp_string = tmp.into_iden();
64 self.join_inner(JoinableTable::Normal(tmp_string))
65 }
66
67 fn join_inner<T: Table<Schema = S>>(&mut self, name: JoinableTable) -> Expr<'inner, S, T> {
68 let table_idx = self.ast.tables.len();
69 Rc::make_mut(&mut self.ast).tables.push(name);
70 Expr::new(Join::new(MyTableRef {
71 scope_rc: self.ast.scope_rc.clone(),
72 idx: table_idx,
73 }))
74 }
75
76 pub fn filter(&mut self, prop: impl IntoExpr<'inner, S, Typ = bool>) {
83 let prop = DynTypedExpr::erase(prop);
84 Rc::make_mut(&mut self.ast).filters.push(prop);
85 }
86
87 pub fn filter_some<Typ: MyTyp>(
91 &mut self,
92 val: impl IntoExpr<'inner, S, Typ = Option<Typ>>,
93 ) -> Expr<'inner, S, Typ> {
94 let val = val.into_expr();
95 Rc::make_mut(&mut self.ast)
96 .filters
97 .push(DynTypedExpr::erase(val.is_some()));
98
99 Expr::adhoc_promise(move |b| val.inner.build_expr(b), false)
101 }
102}