1use crate::dialect::DialectTypes;
13use crate::sql::SQL;
14use crate::traits::SQLParam;
15use crate::types::{Array, Numeric};
16use crate::{PostgresDialect, SQLiteDialect};
17use drizzle_types::postgres::types::{
18 Boolean as PgBoolean, Float4, Float8, Int2, Int4, Int8, Numeric as PgNumeric,
19};
20use drizzle_types::sqlite::types::{
21 Integer as SqliteInteger, Numeric as SqliteNumeric, Real as SqliteReal,
22};
23
24use super::{Agg, Expr, NonNull, Null, SQLExpr, Scalar};
25
26#[diagnostic::on_unimplemented(
35 message = "no aggregate policy for `{Self}` on this dialect",
36 label = "aggregate result type is not defined for this SQL type/dialect"
37)]
38pub trait AggregatePolicy<D>: Numeric {
39 type Sum: crate::types::DataType;
40 type Avg: crate::types::DataType;
41}
42
43#[diagnostic::on_unimplemented(
44 message = "no statistical aggregate policy for `{Self}` on this dialect",
45 label = "stddev/variance result type is not defined for this SQL type/dialect"
46)]
47pub trait StatisticalAggregatePolicy<D>: Numeric {
48 type StddevPop: crate::types::DataType;
49 type StddevSamp: crate::types::DataType;
50 type VarPop: crate::types::DataType;
51 type VarSamp: crate::types::DataType;
52}
53
54#[diagnostic::on_unimplemented(
55 message = "boolean aggregates are not supported for `{Self}` on this dialect",
56 label = "use a boolean expression with a dialect that supports BOOL_AND/BOOL_OR"
57)]
58pub trait BooleanAggregatePolicy<D>: crate::types::DataType {}
59
60#[diagnostic::on_unimplemented(
61 message = "this aggregate is not available for this dialect",
62 label = "use a dialect-specific alternative"
63)]
64pub trait PostgresAggregateSupport {}
65
66#[diagnostic::on_unimplemented(
67 message = "this aggregate is not available for this dialect",
68 label = "use a dialect-specific alternative"
69)]
70pub trait SQLiteAggregateSupport {}
71
72#[diagnostic::on_unimplemented(
73 message = "no COUNT return type defined for this dialect",
74 label = "COUNT result type is not configured for this dialect marker"
75)]
76pub trait CountPolicy {
77 type Count: crate::types::DataType;
79}
80
81mod count_arg_private {
82 use super::SQLParam;
83
84 pub trait Sealed<'a, V: SQLParam> {}
85
86 impl<'a, V: SQLParam> Sealed<'a, V> for () {}
87
88 impl<'a, V, E> Sealed<'a, V> for E
89 where
90 V: SQLParam + 'a,
91 E: crate::traits::ToSQL<'a, V> + crate::row::ExprValueType,
92 {
93 }
94}
95
96#[doc(hidden)]
102pub trait CountArg<'a, V: SQLParam>: count_arg_private::Sealed<'a, V> {
103 fn count_sql(self) -> SQL<'a, V>;
104}
105
106impl<'a, V: SQLParam + 'a> CountArg<'a, V> for () {
107 fn count_sql(self) -> SQL<'a, V> {
108 SQL::raw("COUNT(*)")
109 }
110}
111
112impl<'a, V, E> CountArg<'a, V> for E
113where
114 V: SQLParam + 'a,
115 E: crate::traits::ToSQL<'a, V> + crate::row::ExprValueType,
116{
117 fn count_sql(self) -> SQL<'a, V> {
118 SQL::func("COUNT", self.into_sql().parens_if_subquery())
119 }
120}
121
122impl CountPolicy for SQLiteDialect {
123 type Count = drizzle_types::sqlite::types::Integer;
124}
125
126impl CountPolicy for PostgresDialect {
127 type Count = drizzle_types::postgres::types::Int8;
128}
129
130#[diagnostic::on_unimplemented(
131 message = "no floating-point return type defined for this dialect",
132 label = "PERCENT_RANK/CUME_DIST result type is not configured for this dialect marker"
133)]
134pub trait FloatPolicy {
135 type Float: crate::types::DataType;
138}
139
140impl FloatPolicy for SQLiteDialect {
141 type Float = drizzle_types::sqlite::types::Real;
142}
143
144impl FloatPolicy for PostgresDialect {
145 type Float = drizzle_types::postgres::types::Float8;
146}
147
148impl AggregatePolicy<SQLiteDialect> for SqliteInteger {
149 type Sum = Self;
150 type Avg = SqliteReal;
151}
152impl AggregatePolicy<SQLiteDialect> for SqliteReal {
153 type Sum = Self;
154 type Avg = Self;
155}
156impl AggregatePolicy<SQLiteDialect> for SqliteNumeric {
157 type Sum = Self;
158 type Avg = SqliteReal;
159}
160impl AggregatePolicy<SQLiteDialect> for drizzle_types::sqlite::types::Any {
161 type Sum = Self;
162 type Avg = SqliteReal;
163}
164
165impl StatisticalAggregatePolicy<PostgresDialect> for Int2 {
166 type StddevPop = Float8;
167 type StddevSamp = Float8;
168 type VarPop = Float8;
169 type VarSamp = Float8;
170}
171impl StatisticalAggregatePolicy<PostgresDialect> for Int4 {
172 type StddevPop = Float8;
173 type StddevSamp = Float8;
174 type VarPop = Float8;
175 type VarSamp = Float8;
176}
177impl StatisticalAggregatePolicy<PostgresDialect> for Int8 {
178 type StddevPop = Float8;
179 type StddevSamp = Float8;
180 type VarPop = Float8;
181 type VarSamp = Float8;
182}
183impl StatisticalAggregatePolicy<PostgresDialect> for Float4 {
184 type StddevPop = Float8;
185 type StddevSamp = Float8;
186 type VarPop = Float8;
187 type VarSamp = Float8;
188}
189impl StatisticalAggregatePolicy<PostgresDialect> for Float8 {
190 type StddevPop = Self;
191 type StddevSamp = Self;
192 type VarPop = Self;
193 type VarSamp = Self;
194}
195impl StatisticalAggregatePolicy<PostgresDialect> for PgNumeric {
196 type StddevPop = Float8;
197 type StddevSamp = Float8;
198 type VarPop = Float8;
199 type VarSamp = Float8;
200}
201
202impl BooleanAggregatePolicy<PostgresDialect> for PgBoolean {}
203
204impl PostgresAggregateSupport for PostgresDialect {}
205impl SQLiteAggregateSupport for SQLiteDialect {}
206
207impl AggregatePolicy<PostgresDialect> for Int2 {
208 type Sum = Int8;
209 type Avg = Float8;
210}
211impl AggregatePolicy<PostgresDialect> for Int4 {
212 type Sum = Int8;
213 type Avg = Float8;
214}
215impl AggregatePolicy<PostgresDialect> for Int8 {
216 type Sum = Self;
217 type Avg = Float8;
218}
219impl AggregatePolicy<PostgresDialect> for Float4 {
220 type Sum = Float8;
221 type Avg = Float8;
222}
223impl AggregatePolicy<PostgresDialect> for Float8 {
224 type Sum = Self;
225 type Avg = Self;
226}
227impl AggregatePolicy<PostgresDialect> for PgNumeric {
228 type Sum = Self;
229 type Avg = Self;
230}
231
232pub fn count<'a, V, A>(
256 arg: A,
257) -> SQLExpr<'a, V, <V::DialectMarker as CountPolicy>::Count, NonNull, Agg>
258where
259 V: SQLParam + 'a,
260 V::DialectMarker: CountPolicy,
261 A: CountArg<'a, V>,
262{
263 SQLExpr::new(arg.count_sql())
264}
265
266pub fn count_distinct<'a, V, E>(
271 expr: E,
272) -> SQLExpr<'a, V, <V::DialectMarker as CountPolicy>::Count, NonNull, Agg>
273where
274 V: SQLParam + 'a,
275 V::DialectMarker: CountPolicy,
276 E: Expr<'a, V>,
277{
278 SQLExpr::new(SQL::func(
279 "COUNT",
280 SQL::raw("DISTINCT").append(expr.into_expr_sql()),
281 ))
282}
283
284pub fn sum<'a, V, E>(
308 expr: E,
309) -> SQLExpr<'a, V, <E::SQLType as AggregatePolicy<V::DialectMarker>>::Sum, Null, Agg>
310where
311 V: SQLParam + 'a,
312 E: Expr<'a, V>,
313 E::SQLType: AggregatePolicy<V::DialectMarker>,
314{
315 SQLExpr::new(SQL::func("SUM", expr.into_expr_sql()))
316}
317
318pub fn sum_distinct<'a, V, E>(
323 expr: E,
324) -> SQLExpr<'a, V, <E::SQLType as AggregatePolicy<V::DialectMarker>>::Sum, Null, Agg>
325where
326 V: SQLParam + 'a,
327 E: Expr<'a, V>,
328 E::SQLType: AggregatePolicy<V::DialectMarker>,
329{
330 SQLExpr::new(SQL::func(
331 "SUM",
332 SQL::raw("DISTINCT").append(expr.into_expr_sql()),
333 ))
334}
335
336pub fn avg<'a, V, E>(
357 expr: E,
358) -> SQLExpr<'a, V, <E::SQLType as AggregatePolicy<V::DialectMarker>>::Avg, Null, Agg>
359where
360 V: SQLParam + 'a,
361 E: Expr<'a, V>,
362 E::SQLType: AggregatePolicy<V::DialectMarker>,
363{
364 SQLExpr::new(SQL::func("AVG", expr.into_expr_sql()))
365}
366
367pub fn avg_distinct<'a, V, E>(
371 expr: E,
372) -> SQLExpr<'a, V, <E::SQLType as AggregatePolicy<V::DialectMarker>>::Avg, Null, Agg>
373where
374 V: SQLParam + 'a,
375 E: Expr<'a, V>,
376 E::SQLType: AggregatePolicy<V::DialectMarker>,
377{
378 SQLExpr::new(SQL::func(
379 "AVG",
380 SQL::raw("DISTINCT").append(expr.into_expr_sql()),
381 ))
382}
383
384pub fn min<'a, V, E>(expr: E) -> SQLExpr<'a, V, E::SQLType, Null, Agg>
406where
407 V: SQLParam + 'a,
408 E: Expr<'a, V>,
409{
410 SQLExpr::new(SQL::func("MIN", expr.into_expr_sql()))
411}
412
413pub fn max<'a, V, E>(expr: E) -> SQLExpr<'a, V, E::SQLType, Null, Agg>
431where
432 V: SQLParam + 'a,
433 E: Expr<'a, V>,
434{
435 SQLExpr::new(SQL::func("MAX", expr.into_expr_sql()))
436}
437
438pub fn stddev_pop<'a, V, E>(
461 expr: E,
462) -> SQLExpr<
463 'a,
464 V,
465 <E::SQLType as StatisticalAggregatePolicy<V::DialectMarker>>::StddevPop,
466 Null,
467 Agg,
468>
469where
470 V: SQLParam + 'a,
471 E: Expr<'a, V>,
472 E::SQLType: StatisticalAggregatePolicy<V::DialectMarker>,
473{
474 SQLExpr::new(SQL::func("STDDEV_POP", expr.into_expr_sql()))
475}
476
477pub fn stddev_samp<'a, V, E>(
496 expr: E,
497) -> SQLExpr<
498 'a,
499 V,
500 <E::SQLType as StatisticalAggregatePolicy<V::DialectMarker>>::StddevSamp,
501 Null,
502 Agg,
503>
504where
505 V: SQLParam + 'a,
506 E: Expr<'a, V>,
507 E::SQLType: StatisticalAggregatePolicy<V::DialectMarker>,
508{
509 SQLExpr::new(SQL::func("STDDEV_SAMP", expr.into_expr_sql()))
510}
511
512pub fn var_pop<'a, V, E>(
531 expr: E,
532) -> SQLExpr<'a, V, <E::SQLType as StatisticalAggregatePolicy<V::DialectMarker>>::VarPop, Null, Agg>
533where
534 V: SQLParam + 'a,
535 E: Expr<'a, V>,
536 E::SQLType: StatisticalAggregatePolicy<V::DialectMarker>,
537{
538 SQLExpr::new(SQL::func("VAR_POP", expr.into_expr_sql()))
539}
540
541pub fn var_samp<'a, V, E>(
560 expr: E,
561) -> SQLExpr<'a, V, <E::SQLType as StatisticalAggregatePolicy<V::DialectMarker>>::VarSamp, Null, Agg>
562where
563 V: SQLParam + 'a,
564 E: Expr<'a, V>,
565 E::SQLType: StatisticalAggregatePolicy<V::DialectMarker>,
566{
567 SQLExpr::new(SQL::func("VAR_SAMP", expr.into_expr_sql()))
568}
569
570pub fn variance<'a, V, E>(
572 expr: E,
573) -> SQLExpr<'a, V, <E::SQLType as StatisticalAggregatePolicy<V::DialectMarker>>::VarSamp, Null, Agg>
574where
575 V: SQLParam + 'a,
576 E: Expr<'a, V>,
577 E::SQLType: StatisticalAggregatePolicy<V::DialectMarker>,
578{
579 SQLExpr::new(SQL::func("VARIANCE", expr.into_expr_sql()))
580}
581
582pub fn bool_and<'a, V, E>(
584 expr: E,
585) -> SQLExpr<'a, V, <V::DialectMarker as DialectTypes>::Bool, Null, Agg>
586where
587 V: SQLParam + 'a,
588 V::DialectMarker: PostgresAggregateSupport,
589 E: Expr<'a, V>,
590 E::SQLType: BooleanAggregatePolicy<V::DialectMarker>,
591{
592 SQLExpr::new(SQL::func("BOOL_AND", expr.into_expr_sql()))
593}
594
595pub fn bool_or<'a, V, E>(
597 expr: E,
598) -> SQLExpr<'a, V, <V::DialectMarker as DialectTypes>::Bool, Null, Agg>
599where
600 V: SQLParam + 'a,
601 V::DialectMarker: PostgresAggregateSupport,
602 E: Expr<'a, V>,
603 E::SQLType: BooleanAggregatePolicy<V::DialectMarker>,
604{
605 SQLExpr::new(SQL::func("BOOL_OR", expr.into_expr_sql()))
606}
607
608pub fn json_agg<'a, V, E>(
610 expr: E,
611) -> SQLExpr<'a, V, <V::DialectMarker as DialectTypes>::Json, Null, Agg>
612where
613 V: SQLParam + 'a,
614 V::DialectMarker: PostgresAggregateSupport,
615 E: Expr<'a, V>,
616{
617 SQLExpr::new(SQL::func("JSON_AGG", expr.into_expr_sql()))
618}
619
620pub fn jsonb_agg<'a, V, E>(
622 expr: E,
623) -> SQLExpr<'a, V, <V::DialectMarker as DialectTypes>::Jsonb, Null, Agg>
624where
625 V: SQLParam + 'a,
626 V::DialectMarker: PostgresAggregateSupport,
627 E: Expr<'a, V>,
628{
629 SQLExpr::new(SQL::func("JSONB_AGG", expr.into_expr_sql()))
630}
631
632pub fn array_agg<'a, V, E>(expr: E) -> SQLExpr<'a, V, Array<E::SQLType>, Null, Agg>
634where
635 V: SQLParam + 'a,
636 V::DialectMarker: PostgresAggregateSupport,
637 E: Expr<'a, V>,
638{
639 SQLExpr::new(SQL::func("ARRAY_AGG", expr.into_expr_sql()))
640}
641
642pub fn total<'a, V, E>(
662 expr: E,
663) -> SQLExpr<'a, V, <V::DialectMarker as DialectTypes>::Double, NonNull, Agg>
664where
665 V: SQLParam + 'a,
666 V::DialectMarker: SQLiteAggregateSupport,
667 E: Expr<'a, V>,
668 E::SQLType: Numeric,
669{
670 SQLExpr::new(SQL::func("TOTAL", expr.into_expr_sql()))
671}
672
673pub fn group_concat<'a, V, E>(
681 expr: E,
682) -> SQLExpr<'a, V, <V::DialectMarker as DialectTypes>::Text, Null, Agg>
683where
684 V: SQLParam + 'a,
685 V::DialectMarker: SQLiteAggregateSupport,
686 E: Expr<'a, V>,
687 E::SQLType: crate::types::Textual,
688{
689 SQLExpr::new(SQL::func("GROUP_CONCAT", expr.into_expr_sql()))
690}
691
692pub fn string_agg<'a, V, E, D>(
694 expr: E,
695 delimiter: D,
696) -> SQLExpr<'a, V, <V::DialectMarker as DialectTypes>::Text, Null, Agg>
697where
698 V: SQLParam + 'a,
699 V::DialectMarker: PostgresAggregateSupport,
700 E: Expr<'a, V>,
701 E::SQLType: crate::types::Textual,
702 D: Expr<'a, V>,
703 D::SQLType: crate::types::Textual,
704{
705 SQLExpr::new(SQL::func(
706 "STRING_AGG",
707 expr.into_expr_sql()
708 .push(crate::Token::COMMA)
709 .append(delimiter.into_expr_sql()),
710 ))
711}
712
713pub fn every<'a, V, E>(
732 expr: E,
733) -> SQLExpr<'a, V, <V::DialectMarker as DialectTypes>::Bool, Null, Agg>
734where
735 V: SQLParam + 'a,
736 V::DialectMarker: PostgresAggregateSupport,
737 E: Expr<'a, V>,
738 E::SQLType: BooleanAggregatePolicy<V::DialectMarker>,
739{
740 SQLExpr::new(SQL::func("EVERY", expr.into_expr_sql()))
741}
742
743pub fn json_object_agg<'a, V, K, Val>(
756 key: K,
757 value: Val,
758) -> SQLExpr<'a, V, <V::DialectMarker as DialectTypes>::Json, Null, Agg>
759where
760 V: SQLParam + 'a,
761 V::DialectMarker: PostgresAggregateSupport,
762 K: Expr<'a, V>,
763 Val: Expr<'a, V>,
764{
765 SQLExpr::new(SQL::func(
766 "JSON_OBJECT_AGG",
767 key.into_expr_sql()
768 .push(crate::Token::COMMA)
769 .append(value.into_expr_sql()),
770 ))
771}
772
773pub fn jsonb_object_agg<'a, V, K, Val>(
786 key: K,
787 value: Val,
788) -> SQLExpr<'a, V, <V::DialectMarker as DialectTypes>::Jsonb, Null, Agg>
789where
790 V: SQLParam + 'a,
791 V::DialectMarker: PostgresAggregateSupport,
792 K: Expr<'a, V>,
793 Val: Expr<'a, V>,
794{
795 SQLExpr::new(SQL::func(
796 "JSONB_OBJECT_AGG",
797 key.into_expr_sql()
798 .push(crate::Token::COMMA)
799 .append(value.into_expr_sql()),
800 ))
801}
802
803pub fn distinct<'a, V, E>(expr: E) -> SQLExpr<'a, V, E::SQLType, E::Nullable, Scalar>
811where
812 V: SQLParam + 'a,
813 E: Expr<'a, V>,
814{
815 SQLExpr::new(SQL::raw("DISTINCT").append(expr.into_expr_sql()))
816}