1use std::{
2    marker::PhantomData,
3    ops::{Deref, DerefMut},
4    rc::Rc,
5};
6
7use ref_cast::RefCast;
8use sea_query::{Func, SelectStatement, SimpleExpr};
9
10use crate::{
11    Expr, Table,
12    alias::{Field, MyAlias},
13    ast::MySelect,
14    rows::Rows,
15    value::{EqTyp, IntoExpr, MyTyp, NumTyp, Typed, ValueBuilder},
16};
17
18pub struct Aggregate<'outer, 'inner, S> {
20    pub(crate) conds: Vec<(Field, Rc<dyn Fn(ValueBuilder) -> SimpleExpr>)>,
22    pub(crate) query: Rows<'inner, S>,
23    pub(crate) phantom2: PhantomData<fn(&'outer ()) -> &'outer ()>,
25}
26
27impl<'outer, 'inner, S> Deref for Aggregate<'outer, 'inner, S> {
28    type Target = Rows<'inner, S>;
29
30    fn deref(&self) -> &Self::Target {
31        &self.query
32    }
33}
34
35impl<'outer, 'inner, S> DerefMut for Aggregate<'outer, 'inner, S> {
36    fn deref_mut(&mut self) -> &mut Self::Target {
37        &mut self.query
38    }
39}
40
41impl<'outer, 'inner, S: 'static> Aggregate<'outer, 'inner, S> {
42    fn select<T>(&self, expr: impl Into<SimpleExpr>) -> Aggr<S, Option<T>> {
43        let alias = self
44            .ast
45            .select
46            .get_or_init(expr.into(), || self.ast.scope.new_field());
47        Aggr {
48            _p2: PhantomData,
49            select: self.query.ast.build_select(true),
50            field: *alias,
51            conds: self.conds.clone(),
52        }
53    }
54
55    pub fn filter_on<T: EqTyp + 'static>(
57        &mut self,
58        val: impl IntoExpr<'inner, S, Typ = T>,
59        on: impl IntoExpr<'outer, S, Typ = T>,
60    ) {
61        let on = on.into_expr().inner;
62        let val = val.into_expr().inner;
63        let alias = self.ast.scope.new_alias();
64        self.conds
65            .push((Field::U64(alias), Rc::new(move |b| on.build_expr(b))));
66        self.ast
67            .filter_on
68            .push(Box::new((val.build_expr(self.ast.builder()), alias)))
69    }
70
71    pub fn avg(&self, val: impl IntoExpr<'inner, S, Typ = f64>) -> Expr<'outer, S, Option<f64>> {
73        let val = val.into_expr().inner;
74        let expr = Func::avg(val.build_expr(self.ast.builder()));
75        Expr::new(self.select(expr))
76    }
77
78    pub fn max<T>(&self, val: impl IntoExpr<'inner, S, Typ = T>) -> Expr<'outer, S, Option<T>>
80    where
81        T: NumTyp,
82    {
83        let val = val.into_expr().inner;
84        let expr = Func::max(val.build_expr(self.ast.builder()));
85        Expr::new(self.select(expr))
86    }
87
88    pub fn sum<T>(&self, val: impl IntoExpr<'inner, S, Typ = T>) -> Expr<'outer, S, T>
90    where
91        T: NumTyp,
92    {
93        let val = val.into_expr().inner;
94        let expr = Func::sum(val.build_expr(self.ast.builder()));
95        let val = self.select::<T>(expr);
96        Expr::adhoc(move |b| {
97            sea_query::Expr::expr(val.build_expr(b))
98                .if_null(SimpleExpr::Constant(T::ZERO.into_sea_value()))
99        })
100    }
101
102    pub fn count_distinct<T: 'static>(
104        &self,
105        val: impl IntoExpr<'inner, S, Typ = T>,
106    ) -> Expr<'outer, S, i64>
107    where
108        T: EqTyp,
109    {
110        let val = val.into_expr().inner;
111        let expr = Func::count_distinct(val.build_expr(self.ast.builder()));
112        let val = self.select::<i64>(expr);
113        Expr::adhoc(move |b| {
114            sea_query::Expr::expr(val.build_expr(b))
115                .if_null(SimpleExpr::Constant(0i64.into_sea_value()))
116        })
117    }
118
119    pub fn exists(&self) -> Expr<'outer, S, bool> {
121        let expr = SimpleExpr::Constant(1.into_sea_value());
122        let val = self.select::<i64>(expr);
123        Expr::adhoc(move |b| sea_query::Expr::expr(val.build_expr(b)).is_not_null())
124    }
125}
126
127pub struct Aggr<S, T> {
128    pub(crate) _p2: PhantomData<(S, T)>,
129    pub(crate) select: SelectStatement,
130    pub(crate) conds: Vec<(Field, Rc<dyn Fn(ValueBuilder) -> SimpleExpr>)>,
131    pub(crate) field: Field,
132}
133
134impl<S, T> Clone for Aggr<S, T> {
135    fn clone(&self) -> Self {
136        Self {
137            _p2: PhantomData,
138            select: self.select.clone(),
139            conds: self.conds.clone(),
140            field: self.field,
141        }
142    }
143}
144
145impl<S, T: MyTyp> Typed for Aggr<S, T> {
146    type Typ = T;
147    fn build_expr(&self, b: crate::value::ValueBuilder) -> SimpleExpr {
148        sea_query::Expr::col((self.build_table(b), self.field)).into()
149    }
150}
151
152impl<S, T> Aggr<S, T> {
153    fn build_table(&self, b: crate::value::ValueBuilder) -> MyAlias {
154        let conds = self.conds.iter().map(|(field, expr)| (*field, expr(b)));
155        b.get_aggr(self.select.clone(), conds.collect())
156    }
157}
158
159impl<S, T: Table> Deref for Aggr<S, T> {
160    type Target = T::Ext<Self>;
161
162    fn deref(&self) -> &Self::Target {
163        RefCast::ref_cast(self)
164    }
165}
166
167pub fn aggregate<'outer, S, F, R>(f: F) -> R
184where
185    F: for<'inner> FnOnce(&mut Aggregate<'outer, 'inner, S>) -> R,
186{
187    let ast = MySelect::default();
188    let inner = Rows {
189        phantom: PhantomData,
190        ast,
191        _p: PhantomData,
192    };
193    let mut group = Aggregate {
194        conds: Vec::new(),
195        query: inner,
196        phantom2: PhantomData,
197    };
198    f(&mut group)
199}