Skip to main content

sql_orm_query/
aggregate.rs

1use crate::expr::{Expr, TableRef};
2use crate::join::Join;
3use crate::order::SortDirection;
4use crate::pagination::Pagination;
5use crate::predicate::Predicate;
6use sql_orm_core::{Entity, EntityColumn};
7
8#[derive(Debug, Clone, PartialEq)]
9pub enum AggregateExpr {
10    GroupKey(Expr),
11    CountAll,
12    Count(Expr),
13    Sum(Expr),
14    Avg(Expr),
15    Min(Expr),
16    Max(Expr),
17}
18
19impl AggregateExpr {
20    pub fn group_key(expr: impl Into<Expr>) -> Self {
21        Self::GroupKey(expr.into())
22    }
23
24    pub const fn count_all() -> Self {
25        Self::CountAll
26    }
27
28    pub fn count(expr: impl Into<Expr>) -> Self {
29        Self::Count(expr.into())
30    }
31
32    pub fn sum(expr: impl Into<Expr>) -> Self {
33        Self::Sum(expr.into())
34    }
35
36    pub fn avg(expr: impl Into<Expr>) -> Self {
37        Self::Avg(expr.into())
38    }
39
40    pub fn min(expr: impl Into<Expr>) -> Self {
41        Self::Min(expr.into())
42    }
43
44    pub fn max(expr: impl Into<Expr>) -> Self {
45        Self::Max(expr.into())
46    }
47}
48
49#[derive(Debug, Clone, PartialEq)]
50pub struct AggregateProjection {
51    pub expr: AggregateExpr,
52    pub alias: &'static str,
53}
54
55impl AggregateProjection {
56    pub fn group_key<E: Entity>(column: EntityColumn<E>) -> Self {
57        let alias = column.column_name();
58        Self {
59            expr: AggregateExpr::GroupKey(Expr::from(column)),
60            alias,
61        }
62    }
63
64    pub fn group_key_as(expr: impl Into<Expr>, alias: &'static str) -> Self {
65        Self {
66            expr: AggregateExpr::GroupKey(expr.into()),
67            alias,
68        }
69    }
70
71    pub const fn expr_as(expr: AggregateExpr, alias: &'static str) -> Self {
72        Self { expr, alias }
73    }
74
75    pub fn count_as(alias: &'static str) -> Self {
76        Self::expr_as(AggregateExpr::CountAll, alias)
77    }
78
79    pub fn sum_as(expr: impl Into<Expr>, alias: &'static str) -> Self {
80        Self::expr_as(AggregateExpr::sum(expr), alias)
81    }
82
83    pub fn avg_as(expr: impl Into<Expr>, alias: &'static str) -> Self {
84        Self::expr_as(AggregateExpr::avg(expr), alias)
85    }
86
87    pub fn min_as(expr: impl Into<Expr>, alias: &'static str) -> Self {
88        Self::expr_as(AggregateExpr::min(expr), alias)
89    }
90
91    pub fn max_as(expr: impl Into<Expr>, alias: &'static str) -> Self {
92        Self::expr_as(AggregateExpr::max(expr), alias)
93    }
94}
95
96#[derive(Debug, Clone, PartialEq)]
97pub enum AggregatePredicate {
98    Eq(AggregateExpr, Expr),
99    Ne(AggregateExpr, Expr),
100    Gt(AggregateExpr, Expr),
101    Gte(AggregateExpr, Expr),
102    Lt(AggregateExpr, Expr),
103    Lte(AggregateExpr, Expr),
104    And(Vec<AggregatePredicate>),
105    Or(Vec<AggregatePredicate>),
106    Not(Box<AggregatePredicate>),
107}
108
109impl AggregatePredicate {
110    pub fn eq(left: AggregateExpr, right: impl Into<Expr>) -> Self {
111        Self::Eq(left, right.into())
112    }
113
114    pub fn ne(left: AggregateExpr, right: impl Into<Expr>) -> Self {
115        Self::Ne(left, right.into())
116    }
117
118    pub fn gt(left: AggregateExpr, right: impl Into<Expr>) -> Self {
119        Self::Gt(left, right.into())
120    }
121
122    pub fn gte(left: AggregateExpr, right: impl Into<Expr>) -> Self {
123        Self::Gte(left, right.into())
124    }
125
126    pub fn lt(left: AggregateExpr, right: impl Into<Expr>) -> Self {
127        Self::Lt(left, right.into())
128    }
129
130    pub fn lte(left: AggregateExpr, right: impl Into<Expr>) -> Self {
131        Self::Lte(left, right.into())
132    }
133
134    pub fn and(predicates: Vec<AggregatePredicate>) -> Self {
135        Self::And(predicates)
136    }
137
138    pub fn or(predicates: Vec<AggregatePredicate>) -> Self {
139        Self::Or(predicates)
140    }
141
142    pub fn negate(predicate: AggregatePredicate) -> Self {
143        Self::Not(Box::new(predicate))
144    }
145}
146
147#[derive(Debug, Clone, PartialEq)]
148pub struct AggregateOrderBy {
149    pub expr: AggregateExpr,
150    pub direction: SortDirection,
151}
152
153impl AggregateOrderBy {
154    pub fn new(expr: AggregateExpr, direction: SortDirection) -> Self {
155        Self { expr, direction }
156    }
157
158    pub fn asc(expr: AggregateExpr) -> Self {
159        Self::new(expr, SortDirection::Asc)
160    }
161
162    pub fn desc(expr: AggregateExpr) -> Self {
163        Self::new(expr, SortDirection::Desc)
164    }
165}
166
167#[derive(Debug, Clone, PartialEq)]
168pub struct AggregateQuery {
169    pub from: TableRef,
170    pub joins: Vec<Join>,
171    pub projection: Vec<AggregateProjection>,
172    pub predicate: Option<Predicate>,
173    pub group_by: Vec<Expr>,
174    pub having: Option<AggregatePredicate>,
175    pub order_by: Vec<AggregateOrderBy>,
176    pub pagination: Option<Pagination>,
177}
178
179impl AggregateQuery {
180    pub fn from_entity<E: Entity>() -> Self {
181        Self {
182            from: TableRef::for_entity::<E>(),
183            joins: Vec::new(),
184            projection: Vec::new(),
185            predicate: None,
186            group_by: Vec::new(),
187            having: None,
188            order_by: Vec::new(),
189            pagination: None,
190        }
191    }
192
193    pub fn from_entity_as<E: Entity>(alias: &'static str) -> Self {
194        Self {
195            from: TableRef::for_entity_as::<E>(alias),
196            joins: Vec::new(),
197            projection: Vec::new(),
198            predicate: None,
199            group_by: Vec::new(),
200            having: None,
201            order_by: Vec::new(),
202            pagination: None,
203        }
204    }
205
206    pub fn project<P, I>(mut self, projection: I) -> Self
207    where
208        P: Into<AggregateProjection>,
209        I: IntoIterator<Item = P>,
210    {
211        self.projection = projection.into_iter().map(Into::into).collect();
212        self
213    }
214
215    pub fn group_by<G, I>(mut self, group_by: I) -> Self
216    where
217        G: Into<Expr>,
218        I: IntoIterator<Item = G>,
219    {
220        self.group_by = group_by.into_iter().map(Into::into).collect();
221        self
222    }
223
224    pub fn filter(mut self, predicate: Predicate) -> Self {
225        self.predicate = Some(match self.predicate.take() {
226            Some(existing) => Predicate::and(vec![existing, predicate]),
227            None => predicate,
228        });
229        self
230    }
231
232    pub fn join(mut self, join: Join) -> Self {
233        self.joins.push(join);
234        self
235    }
236
237    pub fn inner_join<E: Entity>(self, on: Predicate) -> Self {
238        self.join(Join::inner_entity::<E>(on))
239    }
240
241    pub fn left_join<E: Entity>(self, on: Predicate) -> Self {
242        self.join(Join::left_entity::<E>(on))
243    }
244
245    pub fn inner_join_as<E: Entity>(self, alias: &'static str, on: Predicate) -> Self {
246        self.join(Join::inner_entity_as::<E>(alias, on))
247    }
248
249    pub fn left_join_as<E: Entity>(self, alias: &'static str, on: Predicate) -> Self {
250        self.join(Join::left_entity_as::<E>(alias, on))
251    }
252
253    pub fn having(mut self, predicate: AggregatePredicate) -> Self {
254        self.having = Some(match self.having.take() {
255            Some(existing) => AggregatePredicate::and(vec![existing, predicate]),
256            None => predicate,
257        });
258        self
259    }
260
261    pub fn order_by(mut self, order: AggregateOrderBy) -> Self {
262        self.order_by.push(order);
263        self
264    }
265
266    pub fn paginate(mut self, pagination: Pagination) -> Self {
267        self.pagination = Some(pagination);
268        self
269    }
270}