Skip to content

Commit 6df20de

Browse files
committed
Add (very rudimentary) support for the GROUP BY clause
This is not part of the public API, and will almost certainly have breaking changes made to it when we actually properly support this. This commit only exists to give a more sane workaround for #210.
1 parent 340212d commit 6df20de

File tree

8 files changed

+125
-44
lines changed

8 files changed

+125
-44
lines changed
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
simple_clause!(NoGroupByClause, GroupByClause, " GROUP BY ");

diesel/src/query_builder/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ pub mod functions;
88
pub mod nodes;
99
#[macro_use]
1010
mod clause_macro;
11+
mod group_by_clause;
1112
mod limit_clause;
1213
mod offset_clause;
1314
mod order_clause;
Lines changed: 43 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,93 +1,108 @@
11
use expression::*;
22
use expression::aliased::Aliased;
33
use query_builder::{Query, SelectStatement};
4+
use query_builder::group_by_clause::*;
45
use query_builder::limit_clause::*;
56
use query_builder::offset_clause::*;
67
use query_builder::order_clause::*;
78
use query_builder::where_clause::*;
89
use query_dsl::*;
910
use types::{self, Bool};
1011

11-
impl<ST, S, F, W, O, L, Of, Selection, Type> SelectDsl<Selection, Type>
12-
for SelectStatement<ST, S, F, W, O, L, Of> where
12+
impl<ST, S, F, W, O, L, Of, G, Selection, Type> SelectDsl<Selection, Type>
13+
for SelectStatement<ST, S, F, W, O, L, Of, G> where
1314
Selection: Expression,
14-
SelectStatement<Type, Selection, F, W, O, L, Of>: Query<SqlType=Type>,
15+
SelectStatement<Type, Selection, F, W, O, L, Of, G>: Query<SqlType=Type>,
1516
{
16-
type Output = SelectStatement<Type, Selection, F, W, O, L, Of>;
17+
type Output = SelectStatement<Type, Selection, F, W, O, L, Of, G>;
1718

1819
fn select(self, selection: Selection) -> Self::Output {
1920
SelectStatement::new(selection, self.from, self.where_clause, self.order,
20-
self.limit, self.offset)
21+
self.limit, self.offset, self.group_by)
2122
}
2223
}
2324

24-
impl<ST, S, F, W, O, L, Of, Predicate> FilterDsl<Predicate>
25-
for SelectStatement<ST, S, F, W, O, L, Of> where
25+
impl<ST, S, F, W, O, L, Of, G, Predicate> FilterDsl<Predicate>
26+
for SelectStatement<ST, S, F, W, O, L, Of, G> where
2627
Predicate: SelectableExpression<F, SqlType=Bool> + NonAggregate,
2728
W: WhereAnd<Predicate>,
28-
SelectStatement<ST, S, F, W::Output, O, L, Of>: Query,
29+
SelectStatement<ST, S, F, W::Output, O, L, Of, G>: Query,
2930
{
30-
type Output = SelectStatement<ST, S, F, W::Output, O, L, Of>;
31+
type Output = SelectStatement<ST, S, F, W::Output, O, L, Of, G>;
3132

3233
fn filter(self, predicate: Predicate) -> Self::Output {
3334
SelectStatement::new(self.select, self.from, self.where_clause.and(predicate),
34-
self.order, self.limit, self.offset)
35+
self.order, self.limit, self.offset, self.group_by)
3536
}
3637
}
3738

38-
impl<ST, S, F, W, O, L, Of, Expr> OrderDsl<Expr>
39-
for SelectStatement<ST, S, F, W, O, L, Of> where
39+
impl<ST, S, F, W, O, L, Of, G, Expr> OrderDsl<Expr>
40+
for SelectStatement<ST, S, F, W, O, L, Of, G> where
4041
Expr: SelectableExpression<F>,
41-
SelectStatement<ST, S, F, W, OrderClause<Expr>, L, Of>: Query<SqlType=ST>,
42+
SelectStatement<ST, S, F, W, OrderClause<Expr>, L, Of, G>: Query<SqlType=ST>,
4243
{
43-
type Output = SelectStatement<ST, S, F, W, OrderClause<Expr>, L, Of>;
44+
type Output = SelectStatement<ST, S, F, W, OrderClause<Expr>, L, Of, G>;
4445

4546
fn order(self, expr: Expr) -> Self::Output {
4647
let order = OrderClause(expr);
4748
SelectStatement::new(self.select, self.from, self.where_clause, order,
48-
self.limit, self.offset)
49+
self.limit, self.offset, self.group_by)
4950
}
5051
}
5152

5253
#[doc(hidden)]
5354
pub type Limit = <i64 as AsExpression<types::BigInt>>::Expression;
5455

55-
impl<ST, S, F, W, O, L, Of> LimitDsl for SelectStatement<ST, S, F, W, O, L, Of> where
56-
SelectStatement<ST, S, F, W, O, LimitClause<Limit>, Of>: Query<SqlType=ST>,
56+
impl<ST, S, F, W, O, L, Of, G> LimitDsl for SelectStatement<ST, S, F, W, O, L, Of, G> where
57+
SelectStatement<ST, S, F, W, O, LimitClause<Limit>, Of, G>: Query<SqlType=ST>,
5758
{
58-
type Output = SelectStatement<ST, S, F, W, O, LimitClause<Limit>, Of>;
59+
type Output = SelectStatement<ST, S, F, W, O, LimitClause<Limit>, Of, G>;
5960

6061
fn limit(self, limit: i64) -> Self::Output {
6162
let limit_clause = LimitClause(AsExpression::<types::BigInt>::as_expression(limit));
6263
SelectStatement::new(self.select, self.from, self.where_clause,
63-
self.order, limit_clause, self.offset)
64+
self.order, limit_clause, self.offset, self.group_by)
6465
}
6566
}
6667

6768
#[doc(hidden)]
6869
pub type Offset = Limit;
6970

70-
impl<ST, S, F, W, O, L, Of> OffsetDsl for SelectStatement<ST, S, F, W, O, L, Of> where
71-
SelectStatement<ST, S, F, W, O, L, OffsetClause<Offset>>: Query<SqlType=ST>,
71+
impl<ST, S, F, W, O, L, Of, G> OffsetDsl for SelectStatement<ST, S, F, W, O, L, Of, G> where
72+
SelectStatement<ST, S, F, W, O, L, OffsetClause<Offset>, G>: Query<SqlType=ST>,
7273
{
73-
type Output = SelectStatement<ST, S, F, W, O, L, OffsetClause<Offset>>;
74+
type Output = SelectStatement<ST, S, F, W, O, L, OffsetClause<Offset>, G>;
7475

7576
fn offset(self, offset: i64) -> Self::Output {
7677
let offset_clause = OffsetClause(AsExpression::<types::BigInt>::as_expression(offset));
7778
SelectStatement::new(self.select, self.from, self.where_clause,
78-
self.order, self.limit, offset_clause)
79+
self.order, self.limit, offset_clause, self.group_by)
7980
}
8081
}
8182

82-
impl<'a, ST, S, F, W, O, L, Of, Expr> WithDsl<'a, Expr>
83-
for SelectStatement<ST, S, F, W, O, L, Of> where
84-
SelectStatement<ST, S, WithQuerySource<'a, F, Expr>, W, O, L, Of>: Query,
83+
impl<'a, ST, S, F, W, O, L, Of, G, Expr> WithDsl<'a, Expr>
84+
for SelectStatement<ST, S, F, W, O, L, Of, G> where
85+
SelectStatement<ST, S, WithQuerySource<'a, F, Expr>, W, O, L, Of, G>: Query,
8586
{
86-
type Output = SelectStatement<ST, S, WithQuerySource<'a, F, Expr>, W, O, L, Of>;
87+
type Output = SelectStatement<ST, S, WithQuerySource<'a, F, Expr>, W, O, L, Of, G>;
8788

8889
fn with(self, expr: Aliased<'a, Expr>) -> Self::Output {
8990
let source = WithQuerySource::new(self.from, expr);
9091
SelectStatement::new(self.select, source, self.where_clause,
91-
self.order, self.limit, self.offset)
92+
self.order, self.limit, self.offset, self.group_by)
93+
}
94+
}
95+
96+
impl<ST, S, F, W, O, L, Of, G, Expr> GroupByDsl<Expr>
97+
for SelectStatement<ST, S, F, W, O, L, Of, G> where
98+
SelectStatement<ST, S, F, W, O, L, Of, GroupByClause<Expr>>: Query,
99+
Expr: Expression,
100+
{
101+
type Output = SelectStatement<ST, S, F, W, O, L, Of, GroupByClause<Expr>>;
102+
103+
fn group_by(self, expr: Expr) -> Self::Output {
104+
let group_by = GroupByClause(expr);
105+
SelectStatement::new(self.select, self.from, self.where_clause,
106+
self.order, self.limit, self.offset, group_by)
92107
}
93108
}

diesel/src/query_builder/select_statement/mod.rs

Lines changed: 40 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ use expression::*;
55
use query_source::*;
66
use std::marker::PhantomData;
77
use super::{Query, QueryBuilder, QueryFragment, BuildQueryResult};
8+
use super::group_by_clause::NoGroupByClause;
89
use super::limit_clause::NoLimitClause;
910
use super::offset_clause::NoOffsetClause;
1011
use super::order_clause::NoOrderClause;
@@ -20,75 +21,94 @@ pub struct SelectStatement<
2021
Order = NoOrderClause,
2122
Limit = NoLimitClause,
2223
Offset = NoOffsetClause,
24+
GroupBy = NoGroupByClause,
2325
> {
2426
select: Select,
2527
from: From,
2628
where_clause: Where,
2729
order: Order,
2830
limit: Limit,
2931
offset: Offset,
32+
group_by: GroupBy,
3033
_marker: PhantomData<SqlType>,
3134
}
3235

33-
impl<ST, S, F, W, O, L, Of> SelectStatement<ST, S, F, W, O, L, Of> {
34-
pub fn new(select: S, from: F, where_clause: W, order: O, limit: L, offset: Of) -> Self {
36+
impl<ST, S, F, W, O, L, Of, G> SelectStatement<ST, S, F, W, O, L, Of, G> {
37+
pub fn new(
38+
select: S,
39+
from: F,
40+
where_clause: W,
41+
order: O,
42+
limit: L,
43+
offset: Of,
44+
group_by: G,
45+
) -> Self {
3546
SelectStatement {
3647
select: select,
3748
from: from,
3849
where_clause: where_clause,
3950
order: order,
4051
limit: limit,
4152
offset: offset,
53+
group_by: group_by,
4254
_marker: PhantomData,
4355
}
4456
}
4557

4658
pub fn inner_join<T>(self, other: T)
47-
-> SelectStatement<ST, S, InnerJoinSource<F, T>, W, O, L, Of> where
59+
-> SelectStatement<ST, S, InnerJoinSource<F, T>, W, O, L, Of, G> where
4860
T: Table,
4961
F: Table + JoinTo<T, joins::Inner>,
5062
{
5163
SelectStatement::new(self.select, self.from.inner_join(other),
52-
self.where_clause, self.order, self.limit, self.offset)
64+
self.where_clause, self.order, self.limit, self.offset, self.group_by)
5365
}
5466

5567
pub fn left_outer_join<T>(self, other: T)
56-
-> SelectStatement<ST, S, LeftOuterJoinSource<F, T>, W, O, L, Of> where
68+
-> SelectStatement<ST, S, LeftOuterJoinSource<F, T>, W, O, L, Of, G> where
5769
T: Table,
5870
F: Table + JoinTo<T, joins::LeftOuter>,
5971
{
6072
SelectStatement::new(self.select, self.from.left_outer_join(other),
61-
self.where_clause, self.order, self.limit, self.offset)
73+
self.where_clause, self.order, self.limit, self.offset, self.group_by)
6274
}
6375
}
6476

6577
impl<ST, S, F> SelectStatement<ST, S, F> {
6678
pub fn simple(select: S, from: F) -> Self {
67-
SelectStatement::new(select, from, NoWhereClause, NoOrderClause, NoLimitClause, NoOffsetClause)
79+
SelectStatement::new(
80+
select,
81+
from,
82+
NoWhereClause,
83+
NoOrderClause,
84+
NoLimitClause,
85+
NoOffsetClause,
86+
NoGroupByClause,
87+
)
6888
}
6989
}
7090

71-
impl<ST, S, F, W, O, L, Of> Query for SelectStatement<ST, S, F, W, O, L, Of> where
91+
impl<ST, S, F, W, O, L, Of, G> Query for SelectStatement<ST, S, F, W, O, L, Of, G> where
7292
S: SelectableExpression<F, ST>,
7393
{
7494
type SqlType = ST;
7595
}
7696

7797
#[cfg(feature = "postgres")]
78-
impl<ST, S, F, W, O, L, Of> Expression for SelectStatement<ST, S, F, W, O, L, Of> where
98+
impl<ST, S, F, W, O, L, Of, G> Expression for SelectStatement<ST, S, F, W, O, L, Of, G> where
7999
S: SelectableExpression<F, ST>,
80100
{
81101
type SqlType = ::types::Array<ST>;
82102
}
83103

84104
#[cfg(not(feature = "postgres"))]
85-
impl<ST, S, F, W, O, L, Of> Expression for SelectStatement<ST, S, F, W, O, L, Of> where
105+
impl<ST, S, F, W, O, L, Of, G> Expression for SelectStatement<ST, S, F, W, O, L, Of, G> where
86106
S: SelectableExpression<F, ST>,
87107
{
88108
type SqlType = ST;
89109
}
90110

91-
impl<ST, S, F, W, O, L, Of, DB> QueryFragment<DB> for SelectStatement<ST, S, F, W, O, L, Of> where
111+
impl<ST, S, F, W, O, L, Of, DB, G> QueryFragment<DB> for SelectStatement<ST, S, F, W, O, L, Of, G> where
92112
DB: Backend,
93113
S: QueryFragment<DB>,
94114
F: QuerySource,
@@ -97,45 +117,49 @@ impl<ST, S, F, W, O, L, Of, DB> QueryFragment<DB> for SelectStatement<ST, S, F,
97117
O: QueryFragment<DB>,
98118
L: QueryFragment<DB>,
99119
Of: QueryFragment<DB>,
120+
G: QueryFragment<DB>,
100121
{
101122
fn to_sql(&self, out: &mut DB::QueryBuilder) -> BuildQueryResult {
102123
out.push_sql("SELECT ");
103124
try!(self.select.to_sql(out));
104125
out.push_sql(" FROM ");
105126
try!(self.from.from_clause().to_sql(out));
106127
try!(self.where_clause.to_sql(out));
128+
try!(self.group_by.to_sql(out));
107129
try!(self.order.to_sql(out));
108130
try!(self.limit.to_sql(out));
109131
try!(self.offset.to_sql(out));
110132
Ok(())
111133
}
112134
}
113135

114-
impl<ST, S, W, O, L, Of, DB> QueryFragment<DB> for SelectStatement<ST, S, (), W, O, L, Of> where
136+
impl<ST, S, W, O, L, Of, DB, G> QueryFragment<DB> for SelectStatement<ST, S, (), W, O, L, Of, G> where
115137
DB: Backend,
116138
S: QueryFragment<DB>,
117139
W: QueryFragment<DB>,
118140
O: QueryFragment<DB>,
119141
L: QueryFragment<DB>,
120142
Of: QueryFragment<DB>,
143+
G: QueryFragment<DB>,
121144
{
122145
fn to_sql(&self, out: &mut DB::QueryBuilder) -> BuildQueryResult {
123146
out.push_sql("SELECT ");
124147
try!(self.select.to_sql(out));
125148
try!(self.where_clause.to_sql(out));
149+
try!(self.group_by.to_sql(out));
126150
try!(self.order.to_sql(out));
127151
try!(self.limit.to_sql(out));
128152
try!(self.offset.to_sql(out));
129153
Ok(())
130154
}
131155
}
132156

133-
impl<ST, S, F, W, O, L, Of, QS> SelectableExpression<QS> for SelectStatement<ST, S, F, W, O, L, Of> where
134-
SelectStatement<ST, S, F, W, O, L, Of>: Expression,
157+
impl<ST, S, F, W, O, L, Of, QS, G> SelectableExpression<QS> for SelectStatement<ST, S, F, W, O, L, Of, G> where
158+
SelectStatement<ST, S, F, W, O, L, Of, G>: Expression,
135159
{
136160
}
137161

138-
impl<ST, S, F, W, O, L, Of> NonAggregate for SelectStatement<ST, S, F, W, O, L, Of> where
139-
SelectStatement<ST, S, F, W, O, L, Of>: Expression,
162+
impl<ST, S, F, W, O, L, Of, G> NonAggregate for SelectStatement<ST, S, F, W, O, L, Of, G> where
163+
SelectStatement<ST, S, F, W, O, L, Of, G>: Expression,
140164
{
141165
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
use expression::Expression;
2+
use query_builder::{Query, AsQuery};
3+
use query_source::QuerySource;
4+
5+
pub trait GroupByDsl<Expr: Expression> {
6+
type Output: Query;
7+
8+
fn group_by(self, expr: Expr) -> Self::Output;
9+
}
10+
11+
impl<T, Expr> GroupByDsl<Expr> for T where
12+
Expr: Expression,
13+
T: QuerySource + AsQuery,
14+
T::Query: GroupByDsl<Expr>,
15+
{
16+
type Output = <T::Query as GroupByDsl<Expr>>::Output;
17+
18+
fn group_by(self, expr: Expr) -> Self::Output {
19+
self.as_query().group_by(expr)
20+
}
21+
}

diesel/src/query_dsl/mod.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
mod belonging_to_dsl;
22
mod count_dsl;
3+
mod group_by_dsl;
34
#[doc(hidden)]
45
pub mod limit_dsl;
56
#[doc(hidden)]
@@ -16,6 +17,8 @@ mod with_dsl;
1617
pub use self::belonging_to_dsl::BelongingToDsl;
1718
pub use self::count_dsl::CountDsl;
1819
pub use self::filter_dsl::{FilterDsl, FindDsl};
20+
#[doc(hidden)]
21+
pub use self::group_by_dsl::GroupByDsl;
1922
pub use self::limit_dsl::LimitDsl;
2023
pub use self::load_dsl::{LoadDsl, ExecuteDsl};
2124
pub use self::offset_dsl::OffsetDsl;

diesel_tests/tests/group_by.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
use schema::*;
2+
use diesel::*;
3+
4+
#[test]
5+
// This test is a shim for a feature which is not sufficiently implemented. It
6+
// has been added as we have a user who needs a reasonable workaround, but this
7+
// functionality will change and this test is allowed to change post-1.0
8+
fn group_by_generates_group_by_sql() {
9+
let source = users::table.group_by(users::name).select(users::id).filter(users::hair_color.is_null());
10+
let expected_sql = "SELECT `users`.`id` FROM `users` \
11+
WHERE `users`.`hair_color` IS NULL \
12+
GROUP BY `users`.`name`";
13+
14+
assert_eq!(expected_sql, &debug_sql!(source));
15+
}

diesel_tests/tests/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ mod expressions;
1515
mod filter;
1616
mod filter_operators;
1717
mod find;
18+
mod group_by;
1819
mod internal_details;
1920
mod joins;
2021
mod macros;

0 commit comments

Comments
 (0)