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
81impl CountPolicy for SQLiteDialect {
82 type Count = drizzle_types::sqlite::types::Integer;
83}
84
85impl CountPolicy for PostgresDialect {
86 type Count = drizzle_types::postgres::types::Int8;
87}
88
89#[diagnostic::on_unimplemented(
90 message = "no floating-point return type defined for this dialect",
91 label = "PERCENT_RANK/CUME_DIST result type is not configured for this dialect marker"
92)]
93pub trait FloatPolicy {
94 type Float: crate::types::DataType;
97}
98
99impl FloatPolicy for SQLiteDialect {
100 type Float = drizzle_types::sqlite::types::Real;
101}
102
103impl FloatPolicy for PostgresDialect {
104 type Float = drizzle_types::postgres::types::Float8;
105}
106
107impl AggregatePolicy<SQLiteDialect> for SqliteInteger {
108 type Sum = Self;
109 type Avg = SqliteReal;
110}
111impl AggregatePolicy<SQLiteDialect> for SqliteReal {
112 type Sum = Self;
113 type Avg = Self;
114}
115impl AggregatePolicy<SQLiteDialect> for SqliteNumeric {
116 type Sum = Self;
117 type Avg = SqliteReal;
118}
119impl AggregatePolicy<SQLiteDialect> for drizzle_types::sqlite::types::Any {
120 type Sum = Self;
121 type Avg = SqliteReal;
122}
123
124impl StatisticalAggregatePolicy<PostgresDialect> for Int2 {
125 type StddevPop = Float8;
126 type StddevSamp = Float8;
127 type VarPop = Float8;
128 type VarSamp = Float8;
129}
130impl StatisticalAggregatePolicy<PostgresDialect> for Int4 {
131 type StddevPop = Float8;
132 type StddevSamp = Float8;
133 type VarPop = Float8;
134 type VarSamp = Float8;
135}
136impl StatisticalAggregatePolicy<PostgresDialect> for Int8 {
137 type StddevPop = Float8;
138 type StddevSamp = Float8;
139 type VarPop = Float8;
140 type VarSamp = Float8;
141}
142impl StatisticalAggregatePolicy<PostgresDialect> for Float4 {
143 type StddevPop = Float8;
144 type StddevSamp = Float8;
145 type VarPop = Float8;
146 type VarSamp = Float8;
147}
148impl StatisticalAggregatePolicy<PostgresDialect> for Float8 {
149 type StddevPop = Self;
150 type StddevSamp = Self;
151 type VarPop = Self;
152 type VarSamp = Self;
153}
154impl StatisticalAggregatePolicy<PostgresDialect> for PgNumeric {
155 type StddevPop = Float8;
156 type StddevSamp = Float8;
157 type VarPop = Float8;
158 type VarSamp = Float8;
159}
160
161impl BooleanAggregatePolicy<PostgresDialect> for PgBoolean {}
162
163impl PostgresAggregateSupport for PostgresDialect {}
164impl SQLiteAggregateSupport for SQLiteDialect {}
165
166impl AggregatePolicy<PostgresDialect> for Int2 {
167 type Sum = Int8;
168 type Avg = Float8;
169}
170impl AggregatePolicy<PostgresDialect> for Int4 {
171 type Sum = Int8;
172 type Avg = Float8;
173}
174impl AggregatePolicy<PostgresDialect> for Int8 {
175 type Sum = Self;
176 type Avg = Float8;
177}
178impl AggregatePolicy<PostgresDialect> for Float4 {
179 type Sum = Float8;
180 type Avg = Float8;
181}
182impl AggregatePolicy<PostgresDialect> for Float8 {
183 type Sum = Self;
184 type Avg = Self;
185}
186impl AggregatePolicy<PostgresDialect> for PgNumeric {
187 type Sum = Self;
188 type Avg = Self;
189}
190
191#[must_use]
210pub fn count_all<'a, V>() -> SQLExpr<'a, V, <V::DialectMarker as CountPolicy>::Count, NonNull, Agg>
211where
212 V: SQLParam + 'a,
213 V::DialectMarker: CountPolicy,
214{
215 SQLExpr::new(SQL::raw("COUNT(*)"))
216}
217
218pub fn count<'a, V, E>(
234 expr: E,
235) -> SQLExpr<'a, V, <V::DialectMarker as CountPolicy>::Count, NonNull, Agg>
236where
237 V: SQLParam + 'a,
238 V::DialectMarker: CountPolicy,
239 E: Expr<'a, V>,
240{
241 SQLExpr::new(SQL::func("COUNT", expr.into_sql()))
242}
243
244pub fn count_distinct<'a, V, E>(
249 expr: E,
250) -> SQLExpr<'a, V, <V::DialectMarker as CountPolicy>::Count, NonNull, Agg>
251where
252 V: SQLParam + 'a,
253 V::DialectMarker: CountPolicy,
254 E: Expr<'a, V>,
255{
256 SQLExpr::new(SQL::func(
257 "COUNT",
258 SQL::raw("DISTINCT").append(expr.into_sql()),
259 ))
260}
261
262pub fn sum<'a, V, E>(
286 expr: E,
287) -> SQLExpr<'a, V, <E::SQLType as AggregatePolicy<V::DialectMarker>>::Sum, Null, Agg>
288where
289 V: SQLParam + 'a,
290 E: Expr<'a, V>,
291 E::SQLType: AggregatePolicy<V::DialectMarker>,
292{
293 SQLExpr::new(SQL::func("SUM", expr.into_sql()))
294}
295
296pub fn sum_distinct<'a, V, E>(
301 expr: E,
302) -> SQLExpr<'a, V, <E::SQLType as AggregatePolicy<V::DialectMarker>>::Sum, Null, Agg>
303where
304 V: SQLParam + 'a,
305 E: Expr<'a, V>,
306 E::SQLType: AggregatePolicy<V::DialectMarker>,
307{
308 SQLExpr::new(SQL::func(
309 "SUM",
310 SQL::raw("DISTINCT").append(expr.into_sql()),
311 ))
312}
313
314pub fn avg<'a, V, E>(
335 expr: E,
336) -> SQLExpr<'a, V, <E::SQLType as AggregatePolicy<V::DialectMarker>>::Avg, Null, Agg>
337where
338 V: SQLParam + 'a,
339 E: Expr<'a, V>,
340 E::SQLType: AggregatePolicy<V::DialectMarker>,
341{
342 SQLExpr::new(SQL::func("AVG", expr.into_sql()))
343}
344
345pub fn avg_distinct<'a, V, E>(
349 expr: E,
350) -> SQLExpr<'a, V, <E::SQLType as AggregatePolicy<V::DialectMarker>>::Avg, Null, Agg>
351where
352 V: SQLParam + 'a,
353 E: Expr<'a, V>,
354 E::SQLType: AggregatePolicy<V::DialectMarker>,
355{
356 SQLExpr::new(SQL::func(
357 "AVG",
358 SQL::raw("DISTINCT").append(expr.into_sql()),
359 ))
360}
361
362pub fn min<'a, V, E>(expr: E) -> SQLExpr<'a, V, E::SQLType, Null, Agg>
384where
385 V: SQLParam + 'a,
386 E: Expr<'a, V>,
387{
388 SQLExpr::new(SQL::func("MIN", expr.into_sql()))
389}
390
391pub fn max<'a, V, E>(expr: E) -> SQLExpr<'a, V, E::SQLType, Null, Agg>
409where
410 V: SQLParam + 'a,
411 E: Expr<'a, V>,
412{
413 SQLExpr::new(SQL::func("MAX", expr.into_sql()))
414}
415
416pub fn stddev_pop<'a, V, E>(
439 expr: E,
440) -> SQLExpr<
441 'a,
442 V,
443 <E::SQLType as StatisticalAggregatePolicy<V::DialectMarker>>::StddevPop,
444 Null,
445 Agg,
446>
447where
448 V: SQLParam + 'a,
449 E: Expr<'a, V>,
450 E::SQLType: StatisticalAggregatePolicy<V::DialectMarker>,
451{
452 SQLExpr::new(SQL::func("STDDEV_POP", expr.into_sql()))
453}
454
455pub fn stddev_samp<'a, V, E>(
474 expr: E,
475) -> SQLExpr<
476 'a,
477 V,
478 <E::SQLType as StatisticalAggregatePolicy<V::DialectMarker>>::StddevSamp,
479 Null,
480 Agg,
481>
482where
483 V: SQLParam + 'a,
484 E: Expr<'a, V>,
485 E::SQLType: StatisticalAggregatePolicy<V::DialectMarker>,
486{
487 SQLExpr::new(SQL::func("STDDEV_SAMP", expr.into_sql()))
488}
489
490pub fn var_pop<'a, V, E>(
509 expr: E,
510) -> SQLExpr<'a, V, <E::SQLType as StatisticalAggregatePolicy<V::DialectMarker>>::VarPop, Null, Agg>
511where
512 V: SQLParam + 'a,
513 E: Expr<'a, V>,
514 E::SQLType: StatisticalAggregatePolicy<V::DialectMarker>,
515{
516 SQLExpr::new(SQL::func("VAR_POP", expr.into_sql()))
517}
518
519pub fn var_samp<'a, V, E>(
538 expr: E,
539) -> SQLExpr<'a, V, <E::SQLType as StatisticalAggregatePolicy<V::DialectMarker>>::VarSamp, Null, Agg>
540where
541 V: SQLParam + 'a,
542 E: Expr<'a, V>,
543 E::SQLType: StatisticalAggregatePolicy<V::DialectMarker>,
544{
545 SQLExpr::new(SQL::func("VAR_SAMP", expr.into_sql()))
546}
547
548pub fn variance<'a, V, E>(
550 expr: E,
551) -> SQLExpr<'a, V, <E::SQLType as StatisticalAggregatePolicy<V::DialectMarker>>::VarSamp, Null, Agg>
552where
553 V: SQLParam + 'a,
554 E: Expr<'a, V>,
555 E::SQLType: StatisticalAggregatePolicy<V::DialectMarker>,
556{
557 SQLExpr::new(SQL::func("VARIANCE", expr.into_sql()))
558}
559
560pub fn bool_and<'a, V, E>(
562 expr: E,
563) -> SQLExpr<'a, V, <V::DialectMarker as DialectTypes>::Bool, Null, Agg>
564where
565 V: SQLParam + 'a,
566 V::DialectMarker: PostgresAggregateSupport,
567 E: Expr<'a, V>,
568 E::SQLType: BooleanAggregatePolicy<V::DialectMarker>,
569{
570 SQLExpr::new(SQL::func("BOOL_AND", expr.into_sql()))
571}
572
573pub fn bool_or<'a, V, E>(
575 expr: E,
576) -> SQLExpr<'a, V, <V::DialectMarker as DialectTypes>::Bool, Null, Agg>
577where
578 V: SQLParam + 'a,
579 V::DialectMarker: PostgresAggregateSupport,
580 E: Expr<'a, V>,
581 E::SQLType: BooleanAggregatePolicy<V::DialectMarker>,
582{
583 SQLExpr::new(SQL::func("BOOL_OR", expr.into_sql()))
584}
585
586pub fn json_agg<'a, V, E>(
588 expr: E,
589) -> SQLExpr<'a, V, <V::DialectMarker as DialectTypes>::Json, Null, Agg>
590where
591 V: SQLParam + 'a,
592 V::DialectMarker: PostgresAggregateSupport,
593 E: Expr<'a, V>,
594{
595 SQLExpr::new(SQL::func("JSON_AGG", expr.into_sql()))
596}
597
598pub fn jsonb_agg<'a, V, E>(
600 expr: E,
601) -> SQLExpr<'a, V, <V::DialectMarker as DialectTypes>::Jsonb, Null, Agg>
602where
603 V: SQLParam + 'a,
604 V::DialectMarker: PostgresAggregateSupport,
605 E: Expr<'a, V>,
606{
607 SQLExpr::new(SQL::func("JSONB_AGG", expr.into_sql()))
608}
609
610pub fn array_agg<'a, V, E>(expr: E) -> SQLExpr<'a, V, Array<E::SQLType>, Null, Agg>
612where
613 V: SQLParam + 'a,
614 V::DialectMarker: PostgresAggregateSupport,
615 E: Expr<'a, V>,
616{
617 SQLExpr::new(SQL::func("ARRAY_AGG", expr.into_sql()))
618}
619
620pub fn total<'a, V, E>(
640 expr: E,
641) -> SQLExpr<'a, V, <V::DialectMarker as DialectTypes>::Double, NonNull, Agg>
642where
643 V: SQLParam + 'a,
644 V::DialectMarker: SQLiteAggregateSupport,
645 E: Expr<'a, V>,
646 E::SQLType: Numeric,
647{
648 SQLExpr::new(SQL::func("TOTAL", expr.into_sql()))
649}
650
651pub fn group_concat<'a, V, E>(
659 expr: E,
660) -> SQLExpr<'a, V, <V::DialectMarker as DialectTypes>::Text, Null, Agg>
661where
662 V: SQLParam + 'a,
663 V::DialectMarker: SQLiteAggregateSupport,
664 E: Expr<'a, V>,
665 E::SQLType: crate::types::Textual,
666{
667 SQLExpr::new(SQL::func("GROUP_CONCAT", expr.into_sql()))
668}
669
670pub fn string_agg<'a, V, E, D>(
672 expr: E,
673 delimiter: D,
674) -> SQLExpr<'a, V, <V::DialectMarker as DialectTypes>::Text, Null, Agg>
675where
676 V: SQLParam + 'a,
677 V::DialectMarker: PostgresAggregateSupport,
678 E: Expr<'a, V>,
679 E::SQLType: crate::types::Textual,
680 D: Expr<'a, V>,
681 D::SQLType: crate::types::Textual,
682{
683 SQLExpr::new(SQL::func(
684 "STRING_AGG",
685 expr.into_sql()
686 .push(crate::Token::COMMA)
687 .append(delimiter.into_sql()),
688 ))
689}
690
691pub fn every<'a, V, E>(
710 expr: E,
711) -> SQLExpr<'a, V, <V::DialectMarker as DialectTypes>::Bool, Null, Agg>
712where
713 V: SQLParam + 'a,
714 V::DialectMarker: PostgresAggregateSupport,
715 E: Expr<'a, V>,
716 E::SQLType: BooleanAggregatePolicy<V::DialectMarker>,
717{
718 SQLExpr::new(SQL::func("EVERY", expr.into_sql()))
719}
720
721pub fn json_object_agg<'a, V, K, Val>(
734 key: K,
735 value: Val,
736) -> SQLExpr<'a, V, <V::DialectMarker as DialectTypes>::Json, Null, Agg>
737where
738 V: SQLParam + 'a,
739 V::DialectMarker: PostgresAggregateSupport,
740 K: Expr<'a, V>,
741 Val: Expr<'a, V>,
742{
743 SQLExpr::new(SQL::func(
744 "JSON_OBJECT_AGG",
745 key.into_sql()
746 .push(crate::Token::COMMA)
747 .append(value.into_sql()),
748 ))
749}
750
751pub fn jsonb_object_agg<'a, V, K, Val>(
764 key: K,
765 value: Val,
766) -> SQLExpr<'a, V, <V::DialectMarker as DialectTypes>::Jsonb, Null, Agg>
767where
768 V: SQLParam + 'a,
769 V::DialectMarker: PostgresAggregateSupport,
770 K: Expr<'a, V>,
771 Val: Expr<'a, V>,
772{
773 SQLExpr::new(SQL::func(
774 "JSONB_OBJECT_AGG",
775 key.into_sql()
776 .push(crate::Token::COMMA)
777 .append(value.into_sql()),
778 ))
779}
780
781pub fn distinct<'a, V, E>(expr: E) -> SQLExpr<'a, V, E::SQLType, E::Nullable, Scalar>
789where
790 V: SQLParam + 'a,
791 E: Expr<'a, V>,
792{
793 SQLExpr::new(SQL::raw("DISTINCT").append(expr.into_sql()))
794}