1use crate::dialect::{Dialect, DialectTypes};
13use crate::sql::SQL;
14use crate::traits::SQLParam;
15use crate::types::{Array, Numeric};
16use crate::{MySQLDialect, PostgresDialect, SQLiteDialect};
17use drizzle_types::mysql::types::{
18 BigInt as MyBigInt, BigIntUnsigned as MyBigIntUnsigned, Decimal as MyDecimal,
19 Double as MyDouble, Float as MyFloat, Int as MyInt, IntUnsigned as MyIntUnsigned,
20 MediumInt as MyMediumInt, MediumIntUnsigned as MyMediumIntUnsigned, SmallInt as MySmallInt,
21 SmallIntUnsigned as MySmallIntUnsigned, TinyInt as MyTinyInt,
22 TinyIntUnsigned as MyTinyIntUnsigned, Year as MyYear,
23};
24use drizzle_types::postgres::types::{
25 Boolean as PgBoolean, Float4, Float8, Int2, Int4, Int8, Numeric as PgNumeric,
26};
27use drizzle_types::sqlite::types::{
28 Integer as SqliteInteger, Numeric as SqliteNumeric, Real as SqliteReal,
29};
30
31use super::math::pg_double;
32use super::{Agg, Expr, NonNull, Null, SQLExpr, Scalar};
33
34#[diagnostic::on_unimplemented(
43 message = "no aggregate policy for `{Self}` on this dialect",
44 label = "aggregate result type is not defined for this SQL type/dialect"
45)]
46pub trait AggregatePolicy<D>: Numeric {
47 type Sum: crate::types::DataType;
48 type Avg: crate::types::DataType;
49}
50
51#[diagnostic::on_unimplemented(
52 message = "no statistical aggregate policy for `{Self}` on this dialect",
53 label = "stddev/variance result type is not defined for this SQL type/dialect"
54)]
55pub trait StatisticalAggregatePolicy<D>: Numeric {
56 type StddevPop: crate::types::DataType;
57 type StddevSamp: crate::types::DataType;
58 type VarPop: crate::types::DataType;
59 type VarSamp: crate::types::DataType;
60}
61
62#[diagnostic::on_unimplemented(
63 message = "boolean aggregates are not supported for `{Self}` on this dialect",
64 label = "use a boolean expression with a dialect that supports BOOL_AND/BOOL_OR"
65)]
66pub trait BooleanAggregatePolicy<D>: crate::types::DataType {}
67
68#[diagnostic::on_unimplemented(
69 message = "this aggregate is not available for this dialect",
70 label = "use a dialect-specific alternative"
71)]
72pub trait PostgresAggregateSupport {}
73
74#[diagnostic::on_unimplemented(
75 message = "this aggregate is not available for this dialect",
76 label = "use a dialect-specific alternative"
77)]
78pub trait SQLiteAggregateSupport {}
79
80#[diagnostic::on_unimplemented(
81 message = "GROUP_CONCAT is not available for this dialect",
82 label = "use the dialect's native string aggregate"
83)]
84pub trait GroupConcatSupport {}
85
86#[diagnostic::on_unimplemented(
87 message = "no COUNT return type defined for this dialect",
88 label = "COUNT result type is not configured for this dialect marker"
89)]
90pub trait CountPolicy {
91 type Count: crate::types::DataType;
93}
94
95mod count_arg_private {
96 use super::SQLParam;
97
98 pub trait Sealed<'a, V: SQLParam> {}
99
100 impl<'a, V: SQLParam> Sealed<'a, V> for () {}
101
102 impl<'a, V, E> Sealed<'a, V> for E
103 where
104 V: SQLParam + 'a,
105 E: crate::traits::ToSQL<'a, V> + crate::row::ExprValueType,
106 {
107 }
108}
109
110#[doc(hidden)]
116pub trait CountArg<'a, V: SQLParam>: count_arg_private::Sealed<'a, V> {
117 fn count_sql(self) -> SQL<'a, V>;
118}
119
120impl<'a, V: SQLParam + 'a> CountArg<'a, V> for () {
121 fn count_sql(self) -> SQL<'a, V> {
122 SQL::raw("COUNT(*)")
123 }
124}
125
126impl<'a, V, E> CountArg<'a, V> for E
127where
128 V: SQLParam + 'a,
129 E: crate::traits::ToSQL<'a, V> + crate::row::ExprValueType,
130{
131 fn count_sql(self) -> SQL<'a, V> {
132 SQL::func("COUNT", self.into_sql().parens_if_subquery())
133 }
134}
135
136impl CountPolicy for SQLiteDialect {
137 type Count = drizzle_types::sqlite::types::Integer;
138}
139
140impl CountPolicy for PostgresDialect {
141 type Count = drizzle_types::postgres::types::Int8;
142}
143
144impl CountPolicy for MySQLDialect {
145 type Count = drizzle_types::mysql::types::BigInt;
146}
147
148#[diagnostic::on_unimplemented(
149 message = "no floating-point return type defined for this dialect",
150 label = "PERCENT_RANK/CUME_DIST result type is not configured for this dialect marker"
151)]
152pub trait FloatPolicy {
153 type Float: crate::types::DataType;
156}
157
158impl FloatPolicy for SQLiteDialect {
159 type Float = drizzle_types::sqlite::types::Real;
160}
161
162impl FloatPolicy for PostgresDialect {
163 type Float = drizzle_types::postgres::types::Float8;
164}
165
166impl FloatPolicy for MySQLDialect {
167 type Float = drizzle_types::mysql::types::Double;
168}
169
170macro_rules! mysql_aggregate_policy {
171 ($output:ty; $($ty:ty),+ $(,)?) => {
172 $(
173 impl AggregatePolicy<MySQLDialect> for $ty {
174 type Sum = $output;
175 type Avg = $output;
176 }
177 )+
178 };
179}
180
181mysql_aggregate_policy!(MyDecimal;
182 MyTinyInt,
183 MyTinyIntUnsigned,
184 MySmallInt,
185 MySmallIntUnsigned,
186 MyMediumInt,
187 MyMediumIntUnsigned,
188 MyInt,
189 MyIntUnsigned,
190 MyBigInt,
191 MyBigIntUnsigned,
192 MyYear,
193 MyDecimal,
194);
195
196mysql_aggregate_policy!(MyDouble; MyFloat, MyDouble);
197
198macro_rules! mysql_statistical_aggregate_policy {
199 ($($ty:ty),+ $(,)?) => {
200 $(
201 impl StatisticalAggregatePolicy<MySQLDialect> for $ty {
202 type StddevPop = MyDouble;
203 type StddevSamp = MyDouble;
204 type VarPop = MyDouble;
205 type VarSamp = MyDouble;
206 }
207 )+
208 };
209}
210
211mysql_statistical_aggregate_policy!(
212 MyTinyInt,
213 MyTinyIntUnsigned,
214 MySmallInt,
215 MySmallIntUnsigned,
216 MyMediumInt,
217 MyMediumIntUnsigned,
218 MyInt,
219 MyIntUnsigned,
220 MyBigInt,
221 MyBigIntUnsigned,
222 MyYear,
223 MyDecimal,
224 MyFloat,
225 MyDouble,
226);
227
228impl AggregatePolicy<SQLiteDialect> for SqliteInteger {
229 type Sum = Self;
230 type Avg = SqliteReal;
231}
232impl AggregatePolicy<SQLiteDialect> for SqliteReal {
233 type Sum = Self;
234 type Avg = Self;
235}
236impl AggregatePolicy<SQLiteDialect> for SqliteNumeric {
237 type Sum = Self;
238 type Avg = SqliteReal;
239}
240impl AggregatePolicy<SQLiteDialect> for drizzle_types::sqlite::types::Any {
241 type Sum = Self;
242 type Avg = SqliteReal;
243}
244
245impl StatisticalAggregatePolicy<PostgresDialect> for Int2 {
246 type StddevPop = Float8;
247 type StddevSamp = Float8;
248 type VarPop = Float8;
249 type VarSamp = Float8;
250}
251impl StatisticalAggregatePolicy<PostgresDialect> for Int4 {
252 type StddevPop = Float8;
253 type StddevSamp = Float8;
254 type VarPop = Float8;
255 type VarSamp = Float8;
256}
257impl StatisticalAggregatePolicy<PostgresDialect> for Int8 {
258 type StddevPop = Float8;
259 type StddevSamp = Float8;
260 type VarPop = Float8;
261 type VarSamp = Float8;
262}
263impl StatisticalAggregatePolicy<PostgresDialect> for Float4 {
264 type StddevPop = Float8;
265 type StddevSamp = Float8;
266 type VarPop = Float8;
267 type VarSamp = Float8;
268}
269impl StatisticalAggregatePolicy<PostgresDialect> for Float8 {
270 type StddevPop = Self;
271 type StddevSamp = Self;
272 type VarPop = Self;
273 type VarSamp = Self;
274}
275impl StatisticalAggregatePolicy<PostgresDialect> for PgNumeric {
276 type StddevPop = Float8;
277 type StddevSamp = Float8;
278 type VarPop = Float8;
279 type VarSamp = Float8;
280}
281
282impl BooleanAggregatePolicy<PostgresDialect> for PgBoolean {}
283
284impl PostgresAggregateSupport for PostgresDialect {}
285impl SQLiteAggregateSupport for SQLiteDialect {}
286impl GroupConcatSupport for SQLiteDialect {}
287impl GroupConcatSupport for MySQLDialect {}
288
289impl AggregatePolicy<PostgresDialect> for Int2 {
290 type Sum = Int8;
291 type Avg = Float8;
292}
293impl AggregatePolicy<PostgresDialect> for Int4 {
294 type Sum = Int8;
295 type Avg = Float8;
296}
297impl AggregatePolicy<PostgresDialect> for Int8 {
298 type Sum = Self;
299 type Avg = Float8;
300}
301impl AggregatePolicy<PostgresDialect> for Float4 {
302 type Sum = Float8;
303 type Avg = Float8;
304}
305impl AggregatePolicy<PostgresDialect> for Float8 {
306 type Sum = Self;
307 type Avg = Self;
308}
309impl AggregatePolicy<PostgresDialect> for PgNumeric {
310 type Sum = Self;
311 type Avg = Self;
312}
313
314pub fn count<'a, V, A>(
338 arg: A,
339) -> SQLExpr<'a, V, <V::DialectMarker as CountPolicy>::Count, NonNull, Agg>
340where
341 V: SQLParam + 'a,
342 V::DialectMarker: CountPolicy,
343 A: CountArg<'a, V>,
344{
345 SQLExpr::new(arg.count_sql())
346}
347
348pub fn count_distinct<'a, V, E>(
353 expr: E,
354) -> SQLExpr<'a, V, <V::DialectMarker as CountPolicy>::Count, NonNull, Agg>
355where
356 V: SQLParam + 'a,
357 V::DialectMarker: CountPolicy,
358 E: Expr<'a, V>,
359{
360 SQLExpr::new(SQL::func(
361 "COUNT",
362 SQL::raw("DISTINCT").append(expr.into_expr_sql()),
363 ))
364}
365
366pub fn sum<'a, V, E>(
390 expr: E,
391) -> SQLExpr<'a, V, <E::SQLType as AggregatePolicy<V::DialectMarker>>::Sum, Null, Agg>
392where
393 V: SQLParam + 'a,
394 E: Expr<'a, V>,
395 E::SQLType: AggregatePolicy<V::DialectMarker>,
396{
397 SQLExpr::new(SQL::func("SUM", expr.into_expr_sql()))
398}
399
400pub fn sum_distinct<'a, V, E>(
405 expr: E,
406) -> SQLExpr<'a, V, <E::SQLType as AggregatePolicy<V::DialectMarker>>::Sum, Null, Agg>
407where
408 V: SQLParam + 'a,
409 E: Expr<'a, V>,
410 E::SQLType: AggregatePolicy<V::DialectMarker>,
411{
412 SQLExpr::new(SQL::func(
413 "SUM",
414 SQL::raw("DISTINCT").append(expr.into_expr_sql()),
415 ))
416}
417
418pub fn avg<'a, V, E>(
439 expr: E,
440) -> SQLExpr<'a, V, <E::SQLType as AggregatePolicy<V::DialectMarker>>::Avg, Null, Agg>
441where
442 V: SQLParam + 'a,
443 E: Expr<'a, V>,
444 E::SQLType: AggregatePolicy<V::DialectMarker>,
445{
446 SQLExpr::new(SQL::func("AVG", expr.into_expr_sql()))
447}
448
449pub fn avg_distinct<'a, V, E>(
453 expr: E,
454) -> SQLExpr<'a, V, <E::SQLType as AggregatePolicy<V::DialectMarker>>::Avg, Null, Agg>
455where
456 V: SQLParam + 'a,
457 E: Expr<'a, V>,
458 E::SQLType: AggregatePolicy<V::DialectMarker>,
459{
460 SQLExpr::new(SQL::func(
461 "AVG",
462 SQL::raw("DISTINCT").append(expr.into_expr_sql()),
463 ))
464}
465
466pub fn min<'a, V, E>(expr: E) -> SQLExpr<'a, V, E::SQLType, Null, Agg>
488where
489 V: SQLParam + 'a,
490 E: Expr<'a, V>,
491{
492 SQLExpr::new(SQL::func("MIN", expr.into_expr_sql()))
493}
494
495pub fn max<'a, V, E>(expr: E) -> SQLExpr<'a, V, E::SQLType, Null, Agg>
513where
514 V: SQLParam + 'a,
515 E: Expr<'a, V>,
516{
517 SQLExpr::new(SQL::func("MAX", expr.into_expr_sql()))
518}
519
520pub fn stddev_pop<'a, V, E>(
543 expr: E,
544) -> SQLExpr<
545 'a,
546 V,
547 <E::SQLType as StatisticalAggregatePolicy<V::DialectMarker>>::StddevPop,
548 Null,
549 Agg,
550>
551where
552 V: SQLParam + 'a,
553 E: Expr<'a, V>,
554 E::SQLType: StatisticalAggregatePolicy<V::DialectMarker>,
555{
556 SQLExpr::new(pg_double(SQL::func("STDDEV_POP", expr.into_expr_sql())))
557}
558
559pub fn stddev_samp<'a, V, E>(
578 expr: E,
579) -> SQLExpr<
580 'a,
581 V,
582 <E::SQLType as StatisticalAggregatePolicy<V::DialectMarker>>::StddevSamp,
583 Null,
584 Agg,
585>
586where
587 V: SQLParam + 'a,
588 E: Expr<'a, V>,
589 E::SQLType: StatisticalAggregatePolicy<V::DialectMarker>,
590{
591 SQLExpr::new(pg_double(SQL::func("STDDEV_SAMP", expr.into_expr_sql())))
592}
593
594pub fn var_pop<'a, V, E>(
613 expr: E,
614) -> SQLExpr<'a, V, <E::SQLType as StatisticalAggregatePolicy<V::DialectMarker>>::VarPop, Null, Agg>
615where
616 V: SQLParam + 'a,
617 E: Expr<'a, V>,
618 E::SQLType: StatisticalAggregatePolicy<V::DialectMarker>,
619{
620 SQLExpr::new(pg_double(SQL::func("VAR_POP", expr.into_expr_sql())))
621}
622
623pub fn var_samp<'a, V, E>(
642 expr: E,
643) -> SQLExpr<'a, V, <E::SQLType as StatisticalAggregatePolicy<V::DialectMarker>>::VarSamp, Null, Agg>
644where
645 V: SQLParam + 'a,
646 E: Expr<'a, V>,
647 E::SQLType: StatisticalAggregatePolicy<V::DialectMarker>,
648{
649 SQLExpr::new(pg_double(SQL::func("VAR_SAMP", expr.into_expr_sql())))
650}
651
652pub fn variance<'a, V, E>(
654 expr: E,
655) -> SQLExpr<'a, V, <E::SQLType as StatisticalAggregatePolicy<V::DialectMarker>>::VarSamp, Null, Agg>
656where
657 V: SQLParam + 'a,
658 E: Expr<'a, V>,
659 E::SQLType: StatisticalAggregatePolicy<V::DialectMarker>,
660{
661 SQLExpr::new(pg_double(SQL::func(
662 match V::DIALECT {
663 Dialect::MySQL => "VAR_SAMP",
664 Dialect::SQLite | Dialect::PostgreSQL => "VARIANCE",
665 },
666 expr.into_expr_sql(),
667 )))
668}
669
670pub fn bool_and<'a, V, E>(
672 expr: E,
673) -> SQLExpr<'a, V, <V::DialectMarker as DialectTypes>::Bool, Null, Agg>
674where
675 V: SQLParam + 'a,
676 V::DialectMarker: PostgresAggregateSupport,
677 E: Expr<'a, V>,
678 E::SQLType: BooleanAggregatePolicy<V::DialectMarker>,
679{
680 SQLExpr::new(SQL::func("BOOL_AND", expr.into_expr_sql()))
681}
682
683pub fn bool_or<'a, V, E>(
685 expr: E,
686) -> SQLExpr<'a, V, <V::DialectMarker as DialectTypes>::Bool, Null, Agg>
687where
688 V: SQLParam + 'a,
689 V::DialectMarker: PostgresAggregateSupport,
690 E: Expr<'a, V>,
691 E::SQLType: BooleanAggregatePolicy<V::DialectMarker>,
692{
693 SQLExpr::new(SQL::func("BOOL_OR", expr.into_expr_sql()))
694}
695
696pub fn json_agg<'a, V, E>(
698 expr: E,
699) -> SQLExpr<'a, V, <V::DialectMarker as DialectTypes>::Json, Null, Agg>
700where
701 V: SQLParam + 'a,
702 V::DialectMarker: PostgresAggregateSupport,
703 E: Expr<'a, V>,
704{
705 SQLExpr::new(SQL::func("JSON_AGG", expr.into_expr_sql()))
706}
707
708pub fn jsonb_agg<'a, V, E>(
710 expr: E,
711) -> SQLExpr<'a, V, <V::DialectMarker as DialectTypes>::Jsonb, Null, Agg>
712where
713 V: SQLParam + 'a,
714 V::DialectMarker: PostgresAggregateSupport,
715 E: Expr<'a, V>,
716{
717 SQLExpr::new(SQL::func("JSONB_AGG", expr.into_expr_sql()))
718}
719
720pub fn array_agg<'a, V, E>(expr: E) -> SQLExpr<'a, V, Array<E::SQLType>, Null, Agg>
722where
723 V: SQLParam + 'a,
724 V::DialectMarker: PostgresAggregateSupport,
725 E: Expr<'a, V>,
726{
727 SQLExpr::new(SQL::func("ARRAY_AGG", expr.into_expr_sql()))
728}
729
730pub fn total<'a, V, E>(
750 expr: E,
751) -> SQLExpr<'a, V, <V::DialectMarker as DialectTypes>::Double, NonNull, Agg>
752where
753 V: SQLParam + 'a,
754 V::DialectMarker: SQLiteAggregateSupport,
755 E: Expr<'a, V>,
756 E::SQLType: Numeric,
757{
758 SQLExpr::new(SQL::func("TOTAL", expr.into_expr_sql()))
759}
760
761pub fn group_concat<'a, V, E>(
769 expr: E,
770) -> SQLExpr<'a, V, <V::DialectMarker as DialectTypes>::Text, Null, Agg>
771where
772 V: SQLParam + 'a,
773 V::DialectMarker: GroupConcatSupport,
774 E: Expr<'a, V>,
775 E::SQLType: crate::types::Textual,
776{
777 SQLExpr::new(SQL::func("GROUP_CONCAT", expr.into_expr_sql()))
778}
779
780pub fn string_agg<'a, V, E, D>(
782 expr: E,
783 delimiter: D,
784) -> SQLExpr<'a, V, <V::DialectMarker as DialectTypes>::Text, Null, Agg>
785where
786 V: SQLParam + 'a,
787 V::DialectMarker: PostgresAggregateSupport,
788 E: Expr<'a, V>,
789 E::SQLType: crate::types::Textual,
790 D: Expr<'a, V>,
791 D::SQLType: crate::types::Textual,
792{
793 SQLExpr::new(SQL::func(
794 "STRING_AGG",
795 expr.into_expr_sql()
796 .push(crate::Token::COMMA)
797 .append(delimiter.into_expr_sql()),
798 ))
799}
800
801pub fn every<'a, V, E>(
820 expr: E,
821) -> SQLExpr<'a, V, <V::DialectMarker as DialectTypes>::Bool, Null, Agg>
822where
823 V: SQLParam + 'a,
824 V::DialectMarker: PostgresAggregateSupport,
825 E: Expr<'a, V>,
826 E::SQLType: BooleanAggregatePolicy<V::DialectMarker>,
827{
828 SQLExpr::new(SQL::func("EVERY", expr.into_expr_sql()))
829}
830
831pub fn json_object_agg<'a, V, K, Val>(
844 key: K,
845 value: Val,
846) -> SQLExpr<'a, V, <V::DialectMarker as DialectTypes>::Json, Null, Agg>
847where
848 V: SQLParam + 'a,
849 V::DialectMarker: PostgresAggregateSupport,
850 K: Expr<'a, V>,
851 Val: Expr<'a, V>,
852{
853 SQLExpr::new(SQL::func(
854 "JSON_OBJECT_AGG",
855 key.into_expr_sql()
856 .push(crate::Token::COMMA)
857 .append(value.into_expr_sql()),
858 ))
859}
860
861pub fn jsonb_object_agg<'a, V, K, Val>(
874 key: K,
875 value: Val,
876) -> SQLExpr<'a, V, <V::DialectMarker as DialectTypes>::Jsonb, Null, Agg>
877where
878 V: SQLParam + 'a,
879 V::DialectMarker: PostgresAggregateSupport,
880 K: Expr<'a, V>,
881 Val: Expr<'a, V>,
882{
883 SQLExpr::new(SQL::func(
884 "JSONB_OBJECT_AGG",
885 key.into_expr_sql()
886 .push(crate::Token::COMMA)
887 .append(value.into_expr_sql()),
888 ))
889}
890
891pub fn distinct<'a, V, E>(expr: E) -> SQLExpr<'a, V, E::SQLType, E::Nullable, Scalar>
899where
900 V: SQLParam + 'a,
901 E: Expr<'a, V>,
902{
903 SQLExpr::new(SQL::raw("DISTINCT").append(expr.into_expr_sql()))
904}