Skip to main content

drizzle_core/expr/
agg.rs

1//! Aggregate functions: `COUNT`, `SUM`, `AVG`, `MIN`, `MAX` and friends.
2//!
3//! Every function here returns an aggregate expression ([`Agg`]). Query
4//! builders use that to reject a SELECT list that mixes aggregates and plain
5//! columns without a matching `GROUP BY`. Calling `.over(...)` on an aggregate
6//! turns it into a window function (see [`window`](super::window())).
7//!
8//! # Type safety
9//!
10//! - [`count`], [`min`] and [`max`] accept any expression.
11//! - [`sum`], [`avg`] and the statistical functions need a numeric argument.
12//!   Their result type depends on the dialect (see [`AggregatePolicy`]).
13//! - Functions that exist on only some databases (`TOTAL`, `GROUP_CONCAT`,
14//!   `STRING_AGG`, `BOOL_AND`, ...) do not compile for the others.
15//!
16//! Except for `COUNT` and `TOTAL`, aggregates are nullable: they return NULL
17//! for an empty group.
18
19use crate::dialect::{Dialect, DialectTypes};
20use crate::dialect::{DialectSupports, feature};
21use crate::sql::SQL;
22use crate::traits::SQLParam;
23use crate::types::{Array, Numeric};
24use crate::{MySQLDialect, PostgresDialect, SQLiteDialect};
25use drizzle_types::mysql::types::{
26    BigInt as MyBigInt, BigIntUnsigned as MyBigIntUnsigned, Decimal as MyDecimal,
27    Double as MyDouble, Float as MyFloat, Int as MyInt, IntUnsigned as MyIntUnsigned,
28    MediumInt as MyMediumInt, MediumIntUnsigned as MyMediumIntUnsigned, SmallInt as MySmallInt,
29    SmallIntUnsigned as MySmallIntUnsigned, TinyInt as MyTinyInt,
30    TinyIntUnsigned as MyTinyIntUnsigned, Year as MyYear,
31};
32use drizzle_types::postgres::types::{
33    Boolean as PgBoolean, Float4, Float8, Int2, Int4, Int8, Numeric as PgNumeric,
34};
35use drizzle_types::sqlite::types::{
36    Integer as SqliteInteger, Numeric as SqliteNumeric, Real as SqliteReal,
37};
38
39use super::ExprSources;
40use super::math::pg_double;
41use super::{Agg, Expr, NonNull, Null, SQLExpr, Scalar};
42use crate::scope::ScopeOnly;
43
44// =============================================================================
45// Dialect Aggregate Policy
46// =============================================================================
47
48/// Result types of [`sum`] and [`avg`] for a numeric SQL type on dialect `D`.
49///
50/// | Dialect | Input | `SUM` | `AVG` |
51/// |---|---|---|---|
52/// | SQLite | `INTEGER` | `INTEGER` | `REAL` |
53/// | SQLite | `REAL` | `REAL` | `REAL` |
54/// | SQLite | `NUMERIC`, `ANY` | same as input | `REAL` |
55/// | PostgreSQL | `int2`, `int4` | `int8` | `float8` |
56/// | PostgreSQL | `int8` | `int8` | `float8` |
57/// | PostgreSQL | `float4`, `float8` | `float8` | `float8` |
58/// | PostgreSQL | `numeric` | `numeric` | `numeric` |
59/// | MySQL | integer types, `DECIMAL` | `DECIMAL` | `DECIMAL` |
60/// | MySQL | `FLOAT`, `DOUBLE` | `DOUBLE` | `DOUBLE` |
61///
62/// These are the declared types; the SQL is not cast. PostgreSQL itself
63/// returns `numeric` for `AVG` of an integer type and for `SUM` of `int8`,
64/// and `real` for `SUM` of `float4`, so wrap such a result in
65/// [`cast`](super::cast) before decoding it.
66#[diagnostic::on_unimplemented(
67    message = "no aggregate policy for `{Self}` on this dialect",
68    label = "aggregate result type is not defined for this SQL type/dialect"
69)]
70pub trait AggregatePolicy<D>: Numeric {
71    /// Result type of `SUM`.
72    type Sum: crate::types::DataType;
73    /// Result type of `AVG`.
74    type Avg: crate::types::DataType;
75}
76
77/// Result types of the standard deviation and variance aggregates for a
78/// numeric SQL type on dialect `D`.
79///
80/// On PostgreSQL every result is `float8`; on MySQL it is `DOUBLE`. SQLite
81/// has no built-in statistical aggregates, so it does not implement this
82/// trait.
83#[diagnostic::on_unimplemented(
84    message = "no statistical aggregate policy for `{Self}` on this dialect",
85    label = "stddev/variance result type is not defined for this SQL type/dialect"
86)]
87pub trait StatisticalAggregatePolicy<D>: Numeric {
88    /// Result type of `STDDEV_POP`.
89    type StddevPop: crate::types::DataType;
90    /// Result type of `STDDEV_SAMP`.
91    type StddevSamp: crate::types::DataType;
92    /// Result type of `VAR_POP`.
93    type VarPop: crate::types::DataType;
94    /// Result type of `VAR_SAMP` / `VARIANCE`.
95    type VarSamp: crate::types::DataType;
96}
97
98/// SQL types that `BOOL_AND`, `BOOL_OR` and `EVERY` accept on dialect `D`.
99///
100/// Only PostgreSQL's `boolean` implements it.
101#[diagnostic::on_unimplemented(
102    message = "boolean aggregates are not supported for `{Self}` on this dialect",
103    label = "use a boolean expression with a dialect that supports BOOL_AND/BOOL_OR"
104)]
105pub trait BooleanAggregatePolicy<D>: crate::types::DataType {}
106
107mod count_arg_private {
108    use super::SQLParam;
109
110    pub trait Sealed<'a, V: SQLParam> {}
111
112    impl<'a, V: SQLParam> Sealed<'a, V> for () {}
113
114    impl<'a, V, E> Sealed<'a, V> for E
115    where
116        V: SQLParam + 'a,
117        E: crate::traits::ToSQL<'a, V> + crate::row::ExprValueType,
118    {
119    }
120}
121
122/// Argument accepted by [`count`]: `()` for `COUNT(*)`, or an expression.
123///
124/// Sealed. It lets `count(())` work without making `()` a general SQL
125/// expression.
126#[doc(hidden)]
127pub trait CountArg<'a, V: SQLParam>: count_arg_private::Sealed<'a, V> + ExprSources {
128    /// Renders the `COUNT(...)` call.
129    fn count_sql(self) -> SQL<'a, V>;
130}
131
132impl<'a, V: SQLParam + 'a> CountArg<'a, V> for () {
133    fn count_sql(self) -> SQL<'a, V> {
134        SQL::raw("COUNT(*)")
135    }
136}
137
138impl<'a, V, E> CountArg<'a, V> for E
139where
140    V: SQLParam + 'a,
141    E: crate::traits::ToSQL<'a, V> + crate::row::ExprValueType + ExprSources,
142{
143    fn count_sql(self) -> SQL<'a, V> {
144        SQL::func("COUNT", self.into_sql().parens_if_subquery())
145    }
146}
147
148macro_rules! mysql_aggregate_policy {
149    ($output:ty; $($ty:ty),+ $(,)?) => {
150        $(
151            impl AggregatePolicy<MySQLDialect> for $ty {
152                type Sum = $output;
153                type Avg = $output;
154            }
155        )+
156    };
157}
158
159mysql_aggregate_policy!(MyDecimal;
160    MyTinyInt,
161    MyTinyIntUnsigned,
162    MySmallInt,
163    MySmallIntUnsigned,
164    MyMediumInt,
165    MyMediumIntUnsigned,
166    MyInt,
167    MyIntUnsigned,
168    MyBigInt,
169    MyBigIntUnsigned,
170    MyYear,
171    MyDecimal,
172);
173
174mysql_aggregate_policy!(MyDouble; MyFloat, MyDouble);
175
176macro_rules! mysql_statistical_aggregate_policy {
177    ($($ty:ty),+ $(,)?) => {
178        $(
179            impl StatisticalAggregatePolicy<MySQLDialect> for $ty {
180                type StddevPop = MyDouble;
181                type StddevSamp = MyDouble;
182                type VarPop = MyDouble;
183                type VarSamp = MyDouble;
184            }
185        )+
186    };
187}
188
189mysql_statistical_aggregate_policy!(
190    MyTinyInt,
191    MyTinyIntUnsigned,
192    MySmallInt,
193    MySmallIntUnsigned,
194    MyMediumInt,
195    MyMediumIntUnsigned,
196    MyInt,
197    MyIntUnsigned,
198    MyBigInt,
199    MyBigIntUnsigned,
200    MyYear,
201    MyDecimal,
202    MyFloat,
203    MyDouble,
204);
205
206impl AggregatePolicy<SQLiteDialect> for SqliteInteger {
207    type Sum = Self;
208    type Avg = SqliteReal;
209}
210impl AggregatePolicy<SQLiteDialect> for SqliteReal {
211    type Sum = Self;
212    type Avg = Self;
213}
214impl AggregatePolicy<SQLiteDialect> for SqliteNumeric {
215    type Sum = Self;
216    type Avg = SqliteReal;
217}
218impl AggregatePolicy<SQLiteDialect> for drizzle_types::sqlite::types::Any {
219    type Sum = Self;
220    type Avg = SqliteReal;
221}
222
223impl StatisticalAggregatePolicy<PostgresDialect> for Int2 {
224    type StddevPop = Float8;
225    type StddevSamp = Float8;
226    type VarPop = Float8;
227    type VarSamp = Float8;
228}
229impl StatisticalAggregatePolicy<PostgresDialect> for Int4 {
230    type StddevPop = Float8;
231    type StddevSamp = Float8;
232    type VarPop = Float8;
233    type VarSamp = Float8;
234}
235impl StatisticalAggregatePolicy<PostgresDialect> for Int8 {
236    type StddevPop = Float8;
237    type StddevSamp = Float8;
238    type VarPop = Float8;
239    type VarSamp = Float8;
240}
241impl StatisticalAggregatePolicy<PostgresDialect> for Float4 {
242    type StddevPop = Float8;
243    type StddevSamp = Float8;
244    type VarPop = Float8;
245    type VarSamp = Float8;
246}
247impl StatisticalAggregatePolicy<PostgresDialect> for Float8 {
248    type StddevPop = Self;
249    type StddevSamp = Self;
250    type VarPop = Self;
251    type VarSamp = Self;
252}
253impl StatisticalAggregatePolicy<PostgresDialect> for PgNumeric {
254    type StddevPop = Float8;
255    type StddevSamp = Float8;
256    type VarPop = Float8;
257    type VarSamp = Float8;
258}
259
260impl BooleanAggregatePolicy<PostgresDialect> for PgBoolean {}
261
262impl DialectSupports<feature::PostgresAggregate> for PostgresDialect {}
263impl DialectSupports<feature::SQLiteAggregate> for SQLiteDialect {}
264impl DialectSupports<feature::GroupConcat> for SQLiteDialect {}
265impl DialectSupports<feature::GroupConcat> for MySQLDialect {}
266
267impl AggregatePolicy<PostgresDialect> for Int2 {
268    type Sum = Int8;
269    type Avg = Float8;
270}
271impl AggregatePolicy<PostgresDialect> for Int4 {
272    type Sum = Int8;
273    type Avg = Float8;
274}
275impl AggregatePolicy<PostgresDialect> for Int8 {
276    type Sum = Self;
277    type Avg = Float8;
278}
279impl AggregatePolicy<PostgresDialect> for Float4 {
280    type Sum = Float8;
281    type Avg = Float8;
282}
283impl AggregatePolicy<PostgresDialect> for Float8 {
284    type Sum = Self;
285    type Avg = Self;
286}
287impl AggregatePolicy<PostgresDialect> for PgNumeric {
288    type Sum = Self;
289    type Avg = Self;
290}
291
292// =============================================================================
293// COUNT
294// =============================================================================
295
296/// Row or value count (`COUNT`).
297///
298/// `count(())` renders `COUNT(*)` and counts rows. `count(expr)` renders
299/// `COUNT(expr)` and counts non-NULL values. The result is the dialect's
300/// big-integer type, never NULL, and an aggregate.
301///
302/// # Examples
303///
304/// ```rust
305/// # use drizzle_core::dialect::{Dialect, DialectTypes, SQLiteDialect as D};
306/// # use drizzle_core::{ColumnRef, SQL, SQLParam, expr::*};
307/// # #[derive(Clone, Debug)] struct Value(String);
308/// # impl SQLParam for Value { const DIALECT: Dialect = Dialect::SQLite; type DialectMarker = D; }
309/// # impl<X: ToString> From<X> for Value { fn from(v: X) -> Self { Value(v.to_string()) } }
310/// # impl From<Value> for std::borrow::Cow<'_, Value> { fn from(v: Value) -> Self { Self::Owned(v) } }
311/// # type C<X, N = NonNull> = &'static SQLExpr<'static, Value, X, N>;
312/// # fn col<X: drizzle_core::types::DataType, N: Nullability>(c: &'static str) -> C<X, N> { Box::leak(Box::new(SQLExpr::new(SQL::column(ColumnRef::sql("users", c))))) }
313/// # type Int = <D as DialectTypes>::Int; type Text = <D as DialectTypes>::Text; type Real = <D as DialectTypes>::Double;
314/// # struct Users { id: C<Int>, age: C<Int>, name: C<Text>, email: C<Text, Null>, score: C<Real, Null>, active: C<<D as DialectTypes>::Bool>, created_at: C<<D as DialectTypes>::Timestamp> }
315/// # let users = Users { id: col("id"), age: col("age"), name: col("name"), email: col("email"), score: col("score"), active: col("active"), created_at: col("created_at") };
316/// assert_eq!(count::<Value, _>(()).sql(), "COUNT(*)");
317/// assert_eq!(count(users.email).sql(), r#"COUNT ("users"."email")"#);
318/// ```
319pub fn count<'a, V, A>(
320    arg: A,
321) -> SQLExpr<'a, V, <V::DialectMarker as DialectTypes>::BigInt, NonNull, Agg, ScopeOnly<A::Sources>>
322where
323    V: SQLParam + 'a,
324    A: CountArg<'a, V>,
325{
326    SQLExpr::new(arg.count_sql())
327}
328
329/// Count of distinct non-NULL values (`COUNT(DISTINCT expr)`).
330///
331/// Accepts any expression. The result is the dialect's big-integer type,
332/// never NULL, and an aggregate.
333///
334/// # Examples
335///
336/// ```rust
337/// # use drizzle_core::dialect::{Dialect, DialectTypes, SQLiteDialect as D};
338/// # use drizzle_core::{ColumnRef, SQL, SQLParam, expr::*};
339/// # #[derive(Clone, Debug)] struct Value(String);
340/// # impl SQLParam for Value { const DIALECT: Dialect = Dialect::SQLite; type DialectMarker = D; }
341/// # impl<X: ToString> From<X> for Value { fn from(v: X) -> Self { Value(v.to_string()) } }
342/// # impl From<Value> for std::borrow::Cow<'_, Value> { fn from(v: Value) -> Self { Self::Owned(v) } }
343/// # type C<X, N = NonNull> = &'static SQLExpr<'static, Value, X, N>;
344/// # fn col<X: drizzle_core::types::DataType, N: Nullability>(c: &'static str) -> C<X, N> { Box::leak(Box::new(SQLExpr::new(SQL::column(ColumnRef::sql("users", c))))) }
345/// # type Int = <D as DialectTypes>::Int; type Text = <D as DialectTypes>::Text; type Real = <D as DialectTypes>::Double;
346/// # struct Users { id: C<Int>, age: C<Int>, name: C<Text>, email: C<Text, Null>, score: C<Real, Null>, active: C<<D as DialectTypes>::Bool>, created_at: C<<D as DialectTypes>::Timestamp> }
347/// # let users = Users { id: col("id"), age: col("age"), name: col("name"), email: col("email"), score: col("score"), active: col("active"), created_at: col("created_at") };
348/// let names = count_distinct(users.name);
349/// assert_eq!(names.sql(), r#"COUNT (DISTINCT "users"."name")"#);
350/// ```
351pub fn count_distinct<'a, V, E>(
352    expr: E,
353) -> SQLExpr<'a, V, <V::DialectMarker as DialectTypes>::BigInt, NonNull, Agg, ScopeOnly<E::Sources>>
354where
355    V: SQLParam + 'a,
356    E: Expr<'a, V>,
357{
358    SQLExpr::new(SQL::func(
359        "COUNT",
360        SQL::raw("DISTINCT").append(expr.into_expr_sql()),
361    ))
362}
363
364// =============================================================================
365// SUM
366// =============================================================================
367
368/// Sum of numeric values (`SUM`).
369///
370/// The argument must be numeric. The result type depends on the dialect (see
371/// [`AggregatePolicy`]): for example, PostgreSQL widens `int4` to `int8`. The
372/// result is nullable (`SUM` of no rows is NULL) and an aggregate.
373///
374/// # Examples
375///
376/// ```rust
377/// # use drizzle_core::dialect::{Dialect, DialectTypes, SQLiteDialect as D};
378/// # use drizzle_core::{ColumnRef, SQL, SQLParam, expr::*};
379/// # #[derive(Clone, Debug)] struct Value(String);
380/// # impl SQLParam for Value { const DIALECT: Dialect = Dialect::SQLite; type DialectMarker = D; }
381/// # impl<X: ToString> From<X> for Value { fn from(v: X) -> Self { Value(v.to_string()) } }
382/// # impl From<Value> for std::borrow::Cow<'_, Value> { fn from(v: Value) -> Self { Self::Owned(v) } }
383/// # type C<X, N = NonNull> = &'static SQLExpr<'static, Value, X, N>;
384/// # fn col<X: drizzle_core::types::DataType, N: Nullability>(c: &'static str) -> C<X, N> { Box::leak(Box::new(SQLExpr::new(SQL::column(ColumnRef::sql("users", c))))) }
385/// # type Int = <D as DialectTypes>::Int; type Text = <D as DialectTypes>::Text; type Real = <D as DialectTypes>::Double;
386/// # struct Users { id: C<Int>, age: C<Int>, name: C<Text>, email: C<Text, Null>, score: C<Real, Null>, active: C<<D as DialectTypes>::Bool>, created_at: C<<D as DialectTypes>::Timestamp> }
387/// # let users = Users { id: col("id"), age: col("age"), name: col("name"), email: col("email"), score: col("score"), active: col("active"), created_at: col("created_at") };
388/// assert_eq!(sum(users.age).sql(), r#"SUM ("users"."age")"#);
389/// ```
390///
391/// # Type safety
392///
393/// Summing a text column does not compile:
394///
395/// ```rust,compile_fail
396/// # use drizzle_core::dialect::{Dialect, DialectTypes, SQLiteDialect as D};
397/// # use drizzle_core::{ColumnRef, SQL, SQLParam, expr::*};
398/// # #[derive(Clone, Debug)] struct Value(String);
399/// # impl SQLParam for Value { const DIALECT: Dialect = Dialect::SQLite; type DialectMarker = D; }
400/// # impl<X: ToString> From<X> for Value { fn from(v: X) -> Self { Value(v.to_string()) } }
401/// # impl From<Value> for std::borrow::Cow<'_, Value> { fn from(v: Value) -> Self { Self::Owned(v) } }
402/// # type C<X, N = NonNull> = &'static SQLExpr<'static, Value, X, N>;
403/// # fn col<X: drizzle_core::types::DataType, N: Nullability>(c: &'static str) -> C<X, N> { Box::leak(Box::new(SQLExpr::new(SQL::column(ColumnRef::sql("users", c))))) }
404/// # type Int = <D as DialectTypes>::Int; type Text = <D as DialectTypes>::Text; type Real = <D as DialectTypes>::Double;
405/// # struct Users { id: C<Int>, age: C<Int>, name: C<Text>, email: C<Text, Null>, score: C<Real, Null>, active: C<<D as DialectTypes>::Bool>, created_at: C<<D as DialectTypes>::Timestamp> }
406/// # let users = Users { id: col("id"), age: col("age"), name: col("name"), email: col("email"), score: col("score"), active: col("active"), created_at: col("created_at") };
407/// let wrong = sum(users.name);
408/// ```
409#[allow(clippy::type_complexity)]
410pub fn sum<'a, V, E>(
411    expr: E,
412) -> SQLExpr<'a, V, <E::SQLType as AggregatePolicy<V::DialectMarker>>::Sum, Null, Agg, E::Sources>
413where
414    V: SQLParam + 'a,
415    E: Expr<'a, V>,
416    E::SQLType: AggregatePolicy<V::DialectMarker>,
417{
418    SQLExpr::new(SQL::func("SUM", expr.into_expr_sql()))
419}
420
421/// Sum of distinct numeric values (`SUM(DISTINCT expr)`).
422///
423/// Same typing as [`sum`].
424///
425/// # Examples
426///
427/// ```rust
428/// # use drizzle_core::dialect::{Dialect, DialectTypes, SQLiteDialect as D};
429/// # use drizzle_core::{ColumnRef, SQL, SQLParam, expr::*};
430/// # #[derive(Clone, Debug)] struct Value(String);
431/// # impl SQLParam for Value { const DIALECT: Dialect = Dialect::SQLite; type DialectMarker = D; }
432/// # impl<X: ToString> From<X> for Value { fn from(v: X) -> Self { Value(v.to_string()) } }
433/// # impl From<Value> for std::borrow::Cow<'_, Value> { fn from(v: Value) -> Self { Self::Owned(v) } }
434/// # type C<X, N = NonNull> = &'static SQLExpr<'static, Value, X, N>;
435/// # fn col<X: drizzle_core::types::DataType, N: Nullability>(c: &'static str) -> C<X, N> { Box::leak(Box::new(SQLExpr::new(SQL::column(ColumnRef::sql("users", c))))) }
436/// # type Int = <D as DialectTypes>::Int; type Text = <D as DialectTypes>::Text; type Real = <D as DialectTypes>::Double;
437/// # struct Users { id: C<Int>, age: C<Int>, name: C<Text>, email: C<Text, Null>, score: C<Real, Null>, active: C<<D as DialectTypes>::Bool>, created_at: C<<D as DialectTypes>::Timestamp> }
438/// # let users = Users { id: col("id"), age: col("age"), name: col("name"), email: col("email"), score: col("score"), active: col("active"), created_at: col("created_at") };
439/// assert_eq!(sum_distinct(users.age).sql(), r#"SUM (DISTINCT "users"."age")"#);
440/// ```
441#[allow(clippy::type_complexity)]
442pub fn sum_distinct<'a, V, E>(
443    expr: E,
444) -> SQLExpr<'a, V, <E::SQLType as AggregatePolicy<V::DialectMarker>>::Sum, Null, Agg, E::Sources>
445where
446    V: SQLParam + 'a,
447    E: Expr<'a, V>,
448    E::SQLType: AggregatePolicy<V::DialectMarker>,
449{
450    SQLExpr::new(SQL::func(
451        "SUM",
452        SQL::raw("DISTINCT").append(expr.into_expr_sql()),
453    ))
454}
455
456// =============================================================================
457// AVG
458// =============================================================================
459
460/// Average of numeric values (`AVG`).
461///
462/// The argument must be numeric. The result type depends on the dialect (see
463/// [`AggregatePolicy`]): SQLite returns `REAL`, PostgreSQL `float8` (or
464/// `numeric` for `numeric` input), MySQL `DECIMAL` for integers. The result
465/// is nullable (`AVG` of no rows is NULL) and an aggregate. On PostgreSQL,
466/// `AVG` of an integer column actually returns `numeric`; cast it to `float8`
467/// to decode it as declared.
468///
469/// # Examples
470///
471/// ```rust
472/// # use drizzle_core::dialect::{Dialect, DialectTypes, SQLiteDialect as D};
473/// # use drizzle_core::{ColumnRef, SQL, SQLParam, expr::*};
474/// # #[derive(Clone, Debug)] struct Value(String);
475/// # impl SQLParam for Value { const DIALECT: Dialect = Dialect::SQLite; type DialectMarker = D; }
476/// # impl<X: ToString> From<X> for Value { fn from(v: X) -> Self { Value(v.to_string()) } }
477/// # impl From<Value> for std::borrow::Cow<'_, Value> { fn from(v: Value) -> Self { Self::Owned(v) } }
478/// # type C<X, N = NonNull> = &'static SQLExpr<'static, Value, X, N>;
479/// # fn col<X: drizzle_core::types::DataType, N: Nullability>(c: &'static str) -> C<X, N> { Box::leak(Box::new(SQLExpr::new(SQL::column(ColumnRef::sql("users", c))))) }
480/// # type Int = <D as DialectTypes>::Int; type Text = <D as DialectTypes>::Text; type Real = <D as DialectTypes>::Double;
481/// # struct Users { id: C<Int>, age: C<Int>, name: C<Text>, email: C<Text, Null>, score: C<Real, Null>, active: C<<D as DialectTypes>::Bool>, created_at: C<<D as DialectTypes>::Timestamp> }
482/// # let users = Users { id: col("id"), age: col("age"), name: col("name"), email: col("email"), score: col("score"), active: col("active"), created_at: col("created_at") };
483/// assert_eq!(avg(users.age).sql(), r#"AVG ("users"."age")"#);
484/// ```
485///
486/// # Type safety
487///
488/// Averaging a text column does not compile:
489///
490/// ```rust,compile_fail
491/// # use drizzle_core::dialect::{Dialect, DialectTypes, SQLiteDialect as D};
492/// # use drizzle_core::{ColumnRef, SQL, SQLParam, expr::*};
493/// # #[derive(Clone, Debug)] struct Value(String);
494/// # impl SQLParam for Value { const DIALECT: Dialect = Dialect::SQLite; type DialectMarker = D; }
495/// # impl<X: ToString> From<X> for Value { fn from(v: X) -> Self { Value(v.to_string()) } }
496/// # impl From<Value> for std::borrow::Cow<'_, Value> { fn from(v: Value) -> Self { Self::Owned(v) } }
497/// # type C<X, N = NonNull> = &'static SQLExpr<'static, Value, X, N>;
498/// # fn col<X: drizzle_core::types::DataType, N: Nullability>(c: &'static str) -> C<X, N> { Box::leak(Box::new(SQLExpr::new(SQL::column(ColumnRef::sql("users", c))))) }
499/// # type Int = <D as DialectTypes>::Int; type Text = <D as DialectTypes>::Text; type Real = <D as DialectTypes>::Double;
500/// # struct Users { id: C<Int>, age: C<Int>, name: C<Text>, email: C<Text, Null>, score: C<Real, Null>, active: C<<D as DialectTypes>::Bool>, created_at: C<<D as DialectTypes>::Timestamp> }
501/// # let users = Users { id: col("id"), age: col("age"), name: col("name"), email: col("email"), score: col("score"), active: col("active"), created_at: col("created_at") };
502/// let wrong = avg(users.name);
503/// ```
504#[allow(clippy::type_complexity)]
505pub fn avg<'a, V, E>(
506    expr: E,
507) -> SQLExpr<'a, V, <E::SQLType as AggregatePolicy<V::DialectMarker>>::Avg, Null, Agg, E::Sources>
508where
509    V: SQLParam + 'a,
510    E: Expr<'a, V>,
511    E::SQLType: AggregatePolicy<V::DialectMarker>,
512{
513    SQLExpr::new(SQL::func("AVG", expr.into_expr_sql()))
514}
515
516/// Average of distinct numeric values (`AVG(DISTINCT expr)`).
517///
518/// Same typing as [`avg`].
519///
520/// # Examples
521///
522/// ```rust
523/// # use drizzle_core::dialect::{Dialect, DialectTypes, SQLiteDialect as D};
524/// # use drizzle_core::{ColumnRef, SQL, SQLParam, expr::*};
525/// # #[derive(Clone, Debug)] struct Value(String);
526/// # impl SQLParam for Value { const DIALECT: Dialect = Dialect::SQLite; type DialectMarker = D; }
527/// # impl<X: ToString> From<X> for Value { fn from(v: X) -> Self { Value(v.to_string()) } }
528/// # impl From<Value> for std::borrow::Cow<'_, Value> { fn from(v: Value) -> Self { Self::Owned(v) } }
529/// # type C<X, N = NonNull> = &'static SQLExpr<'static, Value, X, N>;
530/// # fn col<X: drizzle_core::types::DataType, N: Nullability>(c: &'static str) -> C<X, N> { Box::leak(Box::new(SQLExpr::new(SQL::column(ColumnRef::sql("users", c))))) }
531/// # type Int = <D as DialectTypes>::Int; type Text = <D as DialectTypes>::Text; type Real = <D as DialectTypes>::Double;
532/// # struct Users { id: C<Int>, age: C<Int>, name: C<Text>, email: C<Text, Null>, score: C<Real, Null>, active: C<<D as DialectTypes>::Bool>, created_at: C<<D as DialectTypes>::Timestamp> }
533/// # let users = Users { id: col("id"), age: col("age"), name: col("name"), email: col("email"), score: col("score"), active: col("active"), created_at: col("created_at") };
534/// assert_eq!(avg_distinct(users.age).sql(), r#"AVG (DISTINCT "users"."age")"#);
535/// ```
536#[allow(clippy::type_complexity)]
537pub fn avg_distinct<'a, V, E>(
538    expr: E,
539) -> SQLExpr<'a, V, <E::SQLType as AggregatePolicy<V::DialectMarker>>::Avg, Null, Agg, E::Sources>
540where
541    V: SQLParam + 'a,
542    E: Expr<'a, V>,
543    E::SQLType: AggregatePolicy<V::DialectMarker>,
544{
545    SQLExpr::new(SQL::func(
546        "AVG",
547        SQL::raw("DISTINCT").append(expr.into_expr_sql()),
548    ))
549}
550
551// =============================================================================
552// MIN / MAX
553// =============================================================================
554
555/// Smallest value (`MIN`).
556///
557/// Accepts any expression. The result has the argument's SQL type, is
558/// nullable (`MIN` of no rows is NULL), and is an aggregate.
559///
560/// # Examples
561///
562/// ```rust
563/// # use drizzle_core::dialect::{Dialect, DialectTypes, SQLiteDialect as D};
564/// # use drizzle_core::{ColumnRef, SQL, SQLParam, expr::*};
565/// # #[derive(Clone, Debug)] struct Value(String);
566/// # impl SQLParam for Value { const DIALECT: Dialect = Dialect::SQLite; type DialectMarker = D; }
567/// # impl<X: ToString> From<X> for Value { fn from(v: X) -> Self { Value(v.to_string()) } }
568/// # impl From<Value> for std::borrow::Cow<'_, Value> { fn from(v: Value) -> Self { Self::Owned(v) } }
569/// # type C<X, N = NonNull> = &'static SQLExpr<'static, Value, X, N>;
570/// # fn col<X: drizzle_core::types::DataType, N: Nullability>(c: &'static str) -> C<X, N> { Box::leak(Box::new(SQLExpr::new(SQL::column(ColumnRef::sql("users", c))))) }
571/// # type Int = <D as DialectTypes>::Int; type Text = <D as DialectTypes>::Text; type Real = <D as DialectTypes>::Double;
572/// # struct Users { id: C<Int>, age: C<Int>, name: C<Text>, email: C<Text, Null>, score: C<Real, Null>, active: C<<D as DialectTypes>::Bool>, created_at: C<<D as DialectTypes>::Timestamp> }
573/// # let users = Users { id: col("id"), age: col("age"), name: col("name"), email: col("email"), score: col("score"), active: col("active"), created_at: col("created_at") };
574/// assert_eq!(min(users.age).sql(), r#"MIN ("users"."age")"#);
575/// ```
576pub fn min<'a, V, E>(expr: E) -> SQLExpr<'a, V, E::SQLType, Null, Agg, E::Sources>
577where
578    V: SQLParam + 'a,
579    E: Expr<'a, V>,
580{
581    SQLExpr::new(SQL::func("MIN", expr.into_expr_sql()))
582}
583
584/// Largest value (`MAX`).
585///
586/// Accepts any expression. The result has the argument's SQL type, is
587/// nullable (`MAX` of no rows is NULL), and is an aggregate.
588///
589/// # Examples
590///
591/// ```rust
592/// # use drizzle_core::dialect::{Dialect, DialectTypes, SQLiteDialect as D};
593/// # use drizzle_core::{ColumnRef, SQL, SQLParam, expr::*};
594/// # #[derive(Clone, Debug)] struct Value(String);
595/// # impl SQLParam for Value { const DIALECT: Dialect = Dialect::SQLite; type DialectMarker = D; }
596/// # impl<X: ToString> From<X> for Value { fn from(v: X) -> Self { Value(v.to_string()) } }
597/// # impl From<Value> for std::borrow::Cow<'_, Value> { fn from(v: Value) -> Self { Self::Owned(v) } }
598/// # type C<X, N = NonNull> = &'static SQLExpr<'static, Value, X, N>;
599/// # fn col<X: drizzle_core::types::DataType, N: Nullability>(c: &'static str) -> C<X, N> { Box::leak(Box::new(SQLExpr::new(SQL::column(ColumnRef::sql("users", c))))) }
600/// # type Int = <D as DialectTypes>::Int; type Text = <D as DialectTypes>::Text; type Real = <D as DialectTypes>::Double;
601/// # struct Users { id: C<Int>, age: C<Int>, name: C<Text>, email: C<Text, Null>, score: C<Real, Null>, active: C<<D as DialectTypes>::Bool>, created_at: C<<D as DialectTypes>::Timestamp> }
602/// # let users = Users { id: col("id"), age: col("age"), name: col("name"), email: col("email"), score: col("score"), active: col("active"), created_at: col("created_at") };
603/// assert_eq!(max(users.age).sql(), r#"MAX ("users"."age")"#);
604/// ```
605pub fn max<'a, V, E>(expr: E) -> SQLExpr<'a, V, E::SQLType, Null, Agg, E::Sources>
606where
607    V: SQLParam + 'a,
608    E: Expr<'a, V>,
609{
610    SQLExpr::new(SQL::func("MAX", expr.into_expr_sql()))
611}
612
613// =============================================================================
614// STATISTICAL FUNCTIONS
615// =============================================================================
616
617/// Population standard deviation (`STDDEV_POP`), on PostgreSQL and MySQL.
618///
619/// The argument must be numeric. The result type comes from
620/// [`StatisticalAggregatePolicy`] (`float8` on PostgreSQL, `DOUBLE` on
621/// MySQL); on PostgreSQL the call is wrapped in
622/// `CAST(... AS DOUBLE PRECISION)`. The result is nullable and an aggregate.
623/// SQLite has no `STDDEV_POP`, so this does not compile for SQLite.
624///
625/// # Examples
626///
627/// ```rust
628/// # use drizzle_core::dialect::{Dialect, DialectTypes, PostgresDialect as D};
629/// # use drizzle_core::{ColumnRef, SQL, SQLParam, expr::*};
630/// # #[derive(Clone, Debug)] struct Value(String);
631/// # impl SQLParam for Value { const DIALECT: Dialect = Dialect::PostgreSQL; type DialectMarker = D; }
632/// # impl<X: ToString> From<X> for Value { fn from(v: X) -> Self { Value(v.to_string()) } }
633/// # impl From<Value> for std::borrow::Cow<'_, Value> { fn from(v: Value) -> Self { Self::Owned(v) } }
634/// # type C<X, N = NonNull> = &'static SQLExpr<'static, Value, X, N>;
635/// # fn col<X: drizzle_core::types::DataType, N: Nullability>(c: &'static str) -> C<X, N> { Box::leak(Box::new(SQLExpr::new(SQL::column(ColumnRef::sql("users", c))))) }
636/// # type Int = <D as DialectTypes>::Int; type Text = <D as DialectTypes>::Text; type Real = <D as DialectTypes>::Double;
637/// # struct Users { id: C<Int>, age: C<Int>, name: C<Text>, email: C<Text, Null>, score: C<Real, Null>, active: C<<D as DialectTypes>::Bool>, created_at: C<<D as DialectTypes>::Timestamp> }
638/// # let users = Users { id: col("id"), age: col("age"), name: col("name"), email: col("email"), score: col("score"), active: col("active"), created_at: col("created_at") };
639/// assert_eq!(
640///     stddev_pop(users.age).sql(),
641///     r#"CAST (STDDEV_POP ("users"."age") AS DOUBLE PRECISION)"#
642/// );
643/// ```
644#[allow(clippy::type_complexity)]
645pub fn stddev_pop<'a, V, E>(
646    expr: E,
647) -> SQLExpr<
648    'a,
649    V,
650    <E::SQLType as StatisticalAggregatePolicy<V::DialectMarker>>::StddevPop,
651    Null,
652    Agg,
653    E::Sources,
654>
655where
656    V: SQLParam + 'a,
657    E: Expr<'a, V>,
658    E::SQLType: StatisticalAggregatePolicy<V::DialectMarker>,
659{
660    SQLExpr::new(pg_double(SQL::func("STDDEV_POP", expr.into_expr_sql())))
661}
662
663/// Sample standard deviation (`STDDEV_SAMP`), on PostgreSQL and MySQL.
664///
665/// The argument must be numeric. The result type comes from
666/// [`StatisticalAggregatePolicy`] (`float8` on PostgreSQL, `DOUBLE` on
667/// MySQL); on PostgreSQL the call is wrapped in
668/// `CAST(... AS DOUBLE PRECISION)`. The result is nullable and an aggregate.
669/// SQLite has no `STDDEV_SAMP`, so this does not compile for SQLite.
670///
671/// # Examples
672///
673/// ```rust
674/// # use drizzle_core::dialect::{Dialect, DialectTypes, PostgresDialect as D};
675/// # use drizzle_core::{ColumnRef, SQL, SQLParam, expr::*};
676/// # #[derive(Clone, Debug)] struct Value(String);
677/// # impl SQLParam for Value { const DIALECT: Dialect = Dialect::PostgreSQL; type DialectMarker = D; }
678/// # impl<X: ToString> From<X> for Value { fn from(v: X) -> Self { Value(v.to_string()) } }
679/// # impl From<Value> for std::borrow::Cow<'_, Value> { fn from(v: Value) -> Self { Self::Owned(v) } }
680/// # type C<X, N = NonNull> = &'static SQLExpr<'static, Value, X, N>;
681/// # fn col<X: drizzle_core::types::DataType, N: Nullability>(c: &'static str) -> C<X, N> { Box::leak(Box::new(SQLExpr::new(SQL::column(ColumnRef::sql("users", c))))) }
682/// # type Int = <D as DialectTypes>::Int; type Text = <D as DialectTypes>::Text; type Real = <D as DialectTypes>::Double;
683/// # struct Users { id: C<Int>, age: C<Int>, name: C<Text>, email: C<Text, Null>, score: C<Real, Null>, active: C<<D as DialectTypes>::Bool>, created_at: C<<D as DialectTypes>::Timestamp> }
684/// # let users = Users { id: col("id"), age: col("age"), name: col("name"), email: col("email"), score: col("score"), active: col("active"), created_at: col("created_at") };
685/// assert_eq!(
686///     stddev_samp(users.age).sql(),
687///     r#"CAST (STDDEV_SAMP ("users"."age") AS DOUBLE PRECISION)"#
688/// );
689/// ```
690#[allow(clippy::type_complexity)]
691pub fn stddev_samp<'a, V, E>(
692    expr: E,
693) -> SQLExpr<
694    'a,
695    V,
696    <E::SQLType as StatisticalAggregatePolicy<V::DialectMarker>>::StddevSamp,
697    Null,
698    Agg,
699    E::Sources,
700>
701where
702    V: SQLParam + 'a,
703    E: Expr<'a, V>,
704    E::SQLType: StatisticalAggregatePolicy<V::DialectMarker>,
705{
706    SQLExpr::new(pg_double(SQL::func("STDDEV_SAMP", expr.into_expr_sql())))
707}
708
709/// Population variance (`VAR_POP`), on PostgreSQL and MySQL.
710///
711/// The argument must be numeric. The result type comes from
712/// [`StatisticalAggregatePolicy`] (`float8` on PostgreSQL, `DOUBLE` on
713/// MySQL); on PostgreSQL the call is wrapped in
714/// `CAST(... AS DOUBLE PRECISION)`. The result is nullable and an aggregate.
715/// SQLite has no `VAR_POP`, so this does not compile for SQLite.
716///
717/// # Examples
718///
719/// ```rust
720/// # use drizzle_core::dialect::{Dialect, DialectTypes, PostgresDialect as D};
721/// # use drizzle_core::{ColumnRef, SQL, SQLParam, expr::*};
722/// # #[derive(Clone, Debug)] struct Value(String);
723/// # impl SQLParam for Value { const DIALECT: Dialect = Dialect::PostgreSQL; type DialectMarker = D; }
724/// # impl<X: ToString> From<X> for Value { fn from(v: X) -> Self { Value(v.to_string()) } }
725/// # impl From<Value> for std::borrow::Cow<'_, Value> { fn from(v: Value) -> Self { Self::Owned(v) } }
726/// # type C<X, N = NonNull> = &'static SQLExpr<'static, Value, X, N>;
727/// # fn col<X: drizzle_core::types::DataType, N: Nullability>(c: &'static str) -> C<X, N> { Box::leak(Box::new(SQLExpr::new(SQL::column(ColumnRef::sql("users", c))))) }
728/// # type Int = <D as DialectTypes>::Int; type Text = <D as DialectTypes>::Text; type Real = <D as DialectTypes>::Double;
729/// # struct Users { id: C<Int>, age: C<Int>, name: C<Text>, email: C<Text, Null>, score: C<Real, Null>, active: C<<D as DialectTypes>::Bool>, created_at: C<<D as DialectTypes>::Timestamp> }
730/// # let users = Users { id: col("id"), age: col("age"), name: col("name"), email: col("email"), score: col("score"), active: col("active"), created_at: col("created_at") };
731/// assert_eq!(
732///     var_pop(users.age).sql(),
733///     r#"CAST (VAR_POP ("users"."age") AS DOUBLE PRECISION)"#
734/// );
735/// ```
736#[allow(clippy::type_complexity)]
737pub fn var_pop<'a, V, E>(
738    expr: E,
739) -> SQLExpr<
740    'a,
741    V,
742    <E::SQLType as StatisticalAggregatePolicy<V::DialectMarker>>::VarPop,
743    Null,
744    Agg,
745    E::Sources,
746>
747where
748    V: SQLParam + 'a,
749    E: Expr<'a, V>,
750    E::SQLType: StatisticalAggregatePolicy<V::DialectMarker>,
751{
752    SQLExpr::new(pg_double(SQL::func("VAR_POP", expr.into_expr_sql())))
753}
754
755/// Sample variance (`VAR_SAMP`), on PostgreSQL and MySQL.
756///
757/// The argument must be numeric. The result type comes from
758/// [`StatisticalAggregatePolicy`] (`float8` on PostgreSQL, `DOUBLE` on
759/// MySQL); on PostgreSQL the call is wrapped in
760/// `CAST(... AS DOUBLE PRECISION)`. The result is nullable and an aggregate.
761/// SQLite has no `VAR_SAMP`, so this does not compile for SQLite.
762///
763/// # Examples
764///
765/// ```rust
766/// # use drizzle_core::dialect::{Dialect, DialectTypes, PostgresDialect as D};
767/// # use drizzle_core::{ColumnRef, SQL, SQLParam, expr::*};
768/// # #[derive(Clone, Debug)] struct Value(String);
769/// # impl SQLParam for Value { const DIALECT: Dialect = Dialect::PostgreSQL; type DialectMarker = D; }
770/// # impl<X: ToString> From<X> for Value { fn from(v: X) -> Self { Value(v.to_string()) } }
771/// # impl From<Value> for std::borrow::Cow<'_, Value> { fn from(v: Value) -> Self { Self::Owned(v) } }
772/// # type C<X, N = NonNull> = &'static SQLExpr<'static, Value, X, N>;
773/// # fn col<X: drizzle_core::types::DataType, N: Nullability>(c: &'static str) -> C<X, N> { Box::leak(Box::new(SQLExpr::new(SQL::column(ColumnRef::sql("users", c))))) }
774/// # type Int = <D as DialectTypes>::Int; type Text = <D as DialectTypes>::Text; type Real = <D as DialectTypes>::Double;
775/// # struct Users { id: C<Int>, age: C<Int>, name: C<Text>, email: C<Text, Null>, score: C<Real, Null>, active: C<<D as DialectTypes>::Bool>, created_at: C<<D as DialectTypes>::Timestamp> }
776/// # let users = Users { id: col("id"), age: col("age"), name: col("name"), email: col("email"), score: col("score"), active: col("active"), created_at: col("created_at") };
777/// assert_eq!(
778///     var_samp(users.age).sql(),
779///     r#"CAST (VAR_SAMP ("users"."age") AS DOUBLE PRECISION)"#
780/// );
781/// ```
782#[allow(clippy::type_complexity)]
783pub fn var_samp<'a, V, E>(
784    expr: E,
785) -> SQLExpr<
786    'a,
787    V,
788    <E::SQLType as StatisticalAggregatePolicy<V::DialectMarker>>::VarSamp,
789    Null,
790    Agg,
791    E::Sources,
792>
793where
794    V: SQLParam + 'a,
795    E: Expr<'a, V>,
796    E::SQLType: StatisticalAggregatePolicy<V::DialectMarker>,
797{
798    SQLExpr::new(pg_double(SQL::func("VAR_SAMP", expr.into_expr_sql())))
799}
800
801/// Sample variance: `VARIANCE` on PostgreSQL, `VAR_SAMP` on MySQL.
802///
803/// Same typing as [`var_samp`].
804///
805/// # Examples
806///
807/// ```rust
808/// # use drizzle_core::dialect::{Dialect, DialectTypes, PostgresDialect as D};
809/// # use drizzle_core::{ColumnRef, SQL, SQLParam, expr::*};
810/// # #[derive(Clone, Debug)] struct Value(String);
811/// # impl SQLParam for Value { const DIALECT: Dialect = Dialect::PostgreSQL; type DialectMarker = D; }
812/// # impl<X: ToString> From<X> for Value { fn from(v: X) -> Self { Value(v.to_string()) } }
813/// # impl From<Value> for std::borrow::Cow<'_, Value> { fn from(v: Value) -> Self { Self::Owned(v) } }
814/// # type C<X, N = NonNull> = &'static SQLExpr<'static, Value, X, N>;
815/// # fn col<X: drizzle_core::types::DataType, N: Nullability>(c: &'static str) -> C<X, N> { Box::leak(Box::new(SQLExpr::new(SQL::column(ColumnRef::sql("users", c))))) }
816/// # type Int = <D as DialectTypes>::Int; type Text = <D as DialectTypes>::Text; type Real = <D as DialectTypes>::Double;
817/// # struct Users { id: C<Int>, age: C<Int>, name: C<Text>, email: C<Text, Null>, score: C<Real, Null>, active: C<<D as DialectTypes>::Bool>, created_at: C<<D as DialectTypes>::Timestamp> }
818/// # let users = Users { id: col("id"), age: col("age"), name: col("name"), email: col("email"), score: col("score"), active: col("active"), created_at: col("created_at") };
819/// assert_eq!(
820///     variance(users.age).sql(),
821///     r#"CAST (VARIANCE ("users"."age") AS DOUBLE PRECISION)"#
822/// );
823/// ```
824#[allow(clippy::type_complexity)]
825pub fn variance<'a, V, E>(
826    expr: E,
827) -> SQLExpr<
828    'a,
829    V,
830    <E::SQLType as StatisticalAggregatePolicy<V::DialectMarker>>::VarSamp,
831    Null,
832    Agg,
833    E::Sources,
834>
835where
836    V: SQLParam + 'a,
837    E: Expr<'a, V>,
838    E::SQLType: StatisticalAggregatePolicy<V::DialectMarker>,
839{
840    SQLExpr::new(pg_double(SQL::func(
841        match V::DIALECT {
842            Dialect::MySQL => "VAR_SAMP",
843            Dialect::SQLite | Dialect::PostgreSQL => "VARIANCE",
844        },
845        expr.into_expr_sql(),
846    )))
847}
848
849/// True when every non-NULL input is true (`BOOL_AND`), on PostgreSQL.
850///
851/// The argument must be `boolean`. The result is the dialect's boolean,
852/// nullable, and an aggregate.
853///
854/// # Examples
855///
856/// ```rust
857/// # use drizzle_core::dialect::{Dialect, DialectTypes, PostgresDialect as D};
858/// # use drizzle_core::{ColumnRef, SQL, SQLParam, expr::*};
859/// # #[derive(Clone, Debug)] struct Value(String);
860/// # impl SQLParam for Value { const DIALECT: Dialect = Dialect::PostgreSQL; type DialectMarker = D; }
861/// # impl<X: ToString> From<X> for Value { fn from(v: X) -> Self { Value(v.to_string()) } }
862/// # impl From<Value> for std::borrow::Cow<'_, Value> { fn from(v: Value) -> Self { Self::Owned(v) } }
863/// # type C<X, N = NonNull> = &'static SQLExpr<'static, Value, X, N>;
864/// # fn col<X: drizzle_core::types::DataType, N: Nullability>(c: &'static str) -> C<X, N> { Box::leak(Box::new(SQLExpr::new(SQL::column(ColumnRef::sql("users", c))))) }
865/// # type Int = <D as DialectTypes>::Int; type Text = <D as DialectTypes>::Text; type Real = <D as DialectTypes>::Double;
866/// # struct Users { id: C<Int>, age: C<Int>, name: C<Text>, email: C<Text, Null>, score: C<Real, Null>, active: C<<D as DialectTypes>::Bool>, created_at: C<<D as DialectTypes>::Timestamp> }
867/// # let users = Users { id: col("id"), age: col("age"), name: col("name"), email: col("email"), score: col("score"), active: col("active"), created_at: col("created_at") };
868/// assert_eq!(bool_and(users.active).sql(), r#"BOOL_AND ("users"."active")"#);
869/// ```
870pub fn bool_and<'a, V, E>(
871    expr: E,
872) -> SQLExpr<'a, V, <V::DialectMarker as DialectTypes>::Bool, Null, Agg, E::Sources>
873where
874    V: SQLParam + 'a,
875    V::DialectMarker: DialectSupports<feature::PostgresAggregate>,
876    E: Expr<'a, V>,
877    E::SQLType: BooleanAggregatePolicy<V::DialectMarker>,
878{
879    SQLExpr::new(SQL::func("BOOL_AND", expr.into_expr_sql()))
880}
881
882/// True when any non-NULL input is true (`BOOL_OR`), on PostgreSQL.
883///
884/// The argument must be `boolean`. The result is the dialect's boolean,
885/// nullable, and an aggregate.
886///
887/// # Examples
888///
889/// ```rust
890/// # use drizzle_core::dialect::{Dialect, DialectTypes, PostgresDialect as D};
891/// # use drizzle_core::{ColumnRef, SQL, SQLParam, expr::*};
892/// # #[derive(Clone, Debug)] struct Value(String);
893/// # impl SQLParam for Value { const DIALECT: Dialect = Dialect::PostgreSQL; type DialectMarker = D; }
894/// # impl<X: ToString> From<X> for Value { fn from(v: X) -> Self { Value(v.to_string()) } }
895/// # impl From<Value> for std::borrow::Cow<'_, Value> { fn from(v: Value) -> Self { Self::Owned(v) } }
896/// # type C<X, N = NonNull> = &'static SQLExpr<'static, Value, X, N>;
897/// # fn col<X: drizzle_core::types::DataType, N: Nullability>(c: &'static str) -> C<X, N> { Box::leak(Box::new(SQLExpr::new(SQL::column(ColumnRef::sql("users", c))))) }
898/// # type Int = <D as DialectTypes>::Int; type Text = <D as DialectTypes>::Text; type Real = <D as DialectTypes>::Double;
899/// # struct Users { id: C<Int>, age: C<Int>, name: C<Text>, email: C<Text, Null>, score: C<Real, Null>, active: C<<D as DialectTypes>::Bool>, created_at: C<<D as DialectTypes>::Timestamp> }
900/// # let users = Users { id: col("id"), age: col("age"), name: col("name"), email: col("email"), score: col("score"), active: col("active"), created_at: col("created_at") };
901/// assert_eq!(bool_or(users.active).sql(), r#"BOOL_OR ("users"."active")"#);
902/// ```
903pub fn bool_or<'a, V, E>(
904    expr: E,
905) -> SQLExpr<'a, V, <V::DialectMarker as DialectTypes>::Bool, Null, Agg, E::Sources>
906where
907    V: SQLParam + 'a,
908    V::DialectMarker: DialectSupports<feature::PostgresAggregate>,
909    E: Expr<'a, V>,
910    E::SQLType: BooleanAggregatePolicy<V::DialectMarker>,
911{
912    SQLExpr::new(SQL::func("BOOL_OR", expr.into_expr_sql()))
913}
914
915/// Collects values into a JSON array (`JSON_AGG`), on PostgreSQL.
916///
917/// Accepts any expression. The result is `json`, nullable, and an aggregate.
918///
919/// # Examples
920///
921/// ```rust
922/// # use drizzle_core::dialect::{Dialect, DialectTypes, PostgresDialect as D};
923/// # use drizzle_core::{ColumnRef, SQL, SQLParam, expr::*};
924/// # #[derive(Clone, Debug)] struct Value(String);
925/// # impl SQLParam for Value { const DIALECT: Dialect = Dialect::PostgreSQL; type DialectMarker = D; }
926/// # impl<X: ToString> From<X> for Value { fn from(v: X) -> Self { Value(v.to_string()) } }
927/// # impl From<Value> for std::borrow::Cow<'_, Value> { fn from(v: Value) -> Self { Self::Owned(v) } }
928/// # type C<X, N = NonNull> = &'static SQLExpr<'static, Value, X, N>;
929/// # fn col<X: drizzle_core::types::DataType, N: Nullability>(c: &'static str) -> C<X, N> { Box::leak(Box::new(SQLExpr::new(SQL::column(ColumnRef::sql("users", c))))) }
930/// # type Int = <D as DialectTypes>::Int; type Text = <D as DialectTypes>::Text; type Real = <D as DialectTypes>::Double;
931/// # struct Users { id: C<Int>, age: C<Int>, name: C<Text>, email: C<Text, Null>, score: C<Real, Null>, active: C<<D as DialectTypes>::Bool>, created_at: C<<D as DialectTypes>::Timestamp> }
932/// # let users = Users { id: col("id"), age: col("age"), name: col("name"), email: col("email"), score: col("score"), active: col("active"), created_at: col("created_at") };
933/// assert_eq!(json_agg(users.name).sql(), r#"JSON_AGG ("users"."name")"#);
934/// ```
935pub fn json_agg<'a, V, E>(
936    expr: E,
937) -> SQLExpr<'a, V, <V::DialectMarker as DialectTypes>::Json, Null, Agg, E::Sources>
938where
939    V: SQLParam + 'a,
940    V::DialectMarker: DialectSupports<feature::PostgresAggregate>,
941    E: Expr<'a, V>,
942{
943    SQLExpr::new(SQL::func("JSON_AGG", expr.into_expr_sql()))
944}
945
946/// Collects values into a JSONB array (`JSONB_AGG`), on PostgreSQL.
947///
948/// Accepts any expression. The result is `jsonb`, nullable, and an aggregate.
949///
950/// # Examples
951///
952/// ```rust
953/// # use drizzle_core::dialect::{Dialect, DialectTypes, PostgresDialect as D};
954/// # use drizzle_core::{ColumnRef, SQL, SQLParam, expr::*};
955/// # #[derive(Clone, Debug)] struct Value(String);
956/// # impl SQLParam for Value { const DIALECT: Dialect = Dialect::PostgreSQL; type DialectMarker = D; }
957/// # impl<X: ToString> From<X> for Value { fn from(v: X) -> Self { Value(v.to_string()) } }
958/// # impl From<Value> for std::borrow::Cow<'_, Value> { fn from(v: Value) -> Self { Self::Owned(v) } }
959/// # type C<X, N = NonNull> = &'static SQLExpr<'static, Value, X, N>;
960/// # fn col<X: drizzle_core::types::DataType, N: Nullability>(c: &'static str) -> C<X, N> { Box::leak(Box::new(SQLExpr::new(SQL::column(ColumnRef::sql("users", c))))) }
961/// # type Int = <D as DialectTypes>::Int; type Text = <D as DialectTypes>::Text; type Real = <D as DialectTypes>::Double;
962/// # struct Users { id: C<Int>, age: C<Int>, name: C<Text>, email: C<Text, Null>, score: C<Real, Null>, active: C<<D as DialectTypes>::Bool>, created_at: C<<D as DialectTypes>::Timestamp> }
963/// # let users = Users { id: col("id"), age: col("age"), name: col("name"), email: col("email"), score: col("score"), active: col("active"), created_at: col("created_at") };
964/// assert_eq!(jsonb_agg(users.name).sql(), r#"JSONB_AGG ("users"."name")"#);
965/// ```
966pub fn jsonb_agg<'a, V, E>(
967    expr: E,
968) -> SQLExpr<'a, V, <V::DialectMarker as DialectTypes>::Jsonb, Null, Agg, E::Sources>
969where
970    V: SQLParam + 'a,
971    V::DialectMarker: DialectSupports<feature::PostgresAggregate>,
972    E: Expr<'a, V>,
973{
974    SQLExpr::new(SQL::func("JSONB_AGG", expr.into_expr_sql()))
975}
976
977/// Collects values into a SQL array (`ARRAY_AGG`), on PostgreSQL.
978///
979/// Accepts any expression. The result is an array of the argument's SQL type,
980/// nullable, and an aggregate.
981///
982/// # Examples
983///
984/// ```rust
985/// # use drizzle_core::dialect::{Dialect, DialectTypes, PostgresDialect as D};
986/// # use drizzle_core::{ColumnRef, SQL, SQLParam, expr::*};
987/// # #[derive(Clone, Debug)] struct Value(String);
988/// # impl SQLParam for Value { const DIALECT: Dialect = Dialect::PostgreSQL; type DialectMarker = D; }
989/// # impl<X: ToString> From<X> for Value { fn from(v: X) -> Self { Value(v.to_string()) } }
990/// # impl From<Value> for std::borrow::Cow<'_, Value> { fn from(v: Value) -> Self { Self::Owned(v) } }
991/// # type C<X, N = NonNull> = &'static SQLExpr<'static, Value, X, N>;
992/// # fn col<X: drizzle_core::types::DataType, N: Nullability>(c: &'static str) -> C<X, N> { Box::leak(Box::new(SQLExpr::new(SQL::column(ColumnRef::sql("users", c))))) }
993/// # type Int = <D as DialectTypes>::Int; type Text = <D as DialectTypes>::Text; type Real = <D as DialectTypes>::Double;
994/// # struct Users { id: C<Int>, age: C<Int>, name: C<Text>, email: C<Text, Null>, score: C<Real, Null>, active: C<<D as DialectTypes>::Bool>, created_at: C<<D as DialectTypes>::Timestamp> }
995/// # let users = Users { id: col("id"), age: col("age"), name: col("name"), email: col("email"), score: col("score"), active: col("active"), created_at: col("created_at") };
996/// assert_eq!(array_agg(users.id).sql(), r#"ARRAY_AGG ("users"."id")"#);
997/// ```
998pub fn array_agg<'a, V, E>(expr: E) -> SQLExpr<'a, V, Array<E::SQLType>, Null, Agg, E::Sources>
999where
1000    V: SQLParam + 'a,
1001    V::DialectMarker: DialectSupports<feature::PostgresAggregate>,
1002    E: Expr<'a, V>,
1003{
1004    SQLExpr::new(SQL::func("ARRAY_AGG", expr.into_expr_sql()))
1005}
1006
1007// =============================================================================
1008// TOTAL (SQLite)
1009// =============================================================================
1010
1011/// Floating-point sum that is never NULL (`TOTAL`), on SQLite.
1012///
1013/// The argument must be numeric. Unlike [`sum`], `TOTAL` of no rows is `0.0`,
1014/// so the result is non-null. It is the dialect's double type and an
1015/// aggregate.
1016///
1017/// # Examples
1018///
1019/// ```rust
1020/// # use drizzle_core::dialect::{Dialect, DialectTypes, SQLiteDialect as D};
1021/// # use drizzle_core::{ColumnRef, SQL, SQLParam, expr::*};
1022/// # #[derive(Clone, Debug)] struct Value(String);
1023/// # impl SQLParam for Value { const DIALECT: Dialect = Dialect::SQLite; type DialectMarker = D; }
1024/// # impl<X: ToString> From<X> for Value { fn from(v: X) -> Self { Value(v.to_string()) } }
1025/// # impl From<Value> for std::borrow::Cow<'_, Value> { fn from(v: Value) -> Self { Self::Owned(v) } }
1026/// # type C<X, N = NonNull> = &'static SQLExpr<'static, Value, X, N>;
1027/// # fn col<X: drizzle_core::types::DataType, N: Nullability>(c: &'static str) -> C<X, N> { Box::leak(Box::new(SQLExpr::new(SQL::column(ColumnRef::sql("users", c))))) }
1028/// # type Int = <D as DialectTypes>::Int; type Text = <D as DialectTypes>::Text; type Real = <D as DialectTypes>::Double;
1029/// # struct Users { id: C<Int>, age: C<Int>, name: C<Text>, email: C<Text, Null>, score: C<Real, Null>, active: C<<D as DialectTypes>::Bool>, created_at: C<<D as DialectTypes>::Timestamp> }
1030/// # let users = Users { id: col("id"), age: col("age"), name: col("name"), email: col("email"), score: col("score"), active: col("active"), created_at: col("created_at") };
1031/// assert_eq!(total(users.age).sql(), r#"TOTAL ("users"."age")"#);
1032/// ```
1033pub fn total<'a, V, E>(
1034    expr: E,
1035) -> SQLExpr<'a, V, <V::DialectMarker as DialectTypes>::Double, NonNull, Agg, ScopeOnly<E::Sources>>
1036where
1037    V: SQLParam + 'a,
1038    V::DialectMarker: DialectSupports<feature::SQLiteAggregate>,
1039    E: Expr<'a, V>,
1040    E::SQLType: Numeric,
1041{
1042    SQLExpr::new(SQL::func("TOTAL", expr.into_expr_sql()))
1043}
1044
1045// =============================================================================
1046// GROUP_CONCAT / STRING_AGG
1047// =============================================================================
1048
1049/// Joins text values with commas (`GROUP_CONCAT`), on SQLite and MySQL.
1050///
1051/// The argument must be text. The result is text, nullable, and an aggregate.
1052/// On PostgreSQL, use [`string_agg`].
1053///
1054/// # Examples
1055///
1056/// ```rust
1057/// # use drizzle_core::dialect::{Dialect, DialectTypes, SQLiteDialect as D};
1058/// # use drizzle_core::{ColumnRef, SQL, SQLParam, expr::*};
1059/// # #[derive(Clone, Debug)] struct Value(String);
1060/// # impl SQLParam for Value { const DIALECT: Dialect = Dialect::SQLite; type DialectMarker = D; }
1061/// # impl<X: ToString> From<X> for Value { fn from(v: X) -> Self { Value(v.to_string()) } }
1062/// # impl From<Value> for std::borrow::Cow<'_, Value> { fn from(v: Value) -> Self { Self::Owned(v) } }
1063/// # type C<X, N = NonNull> = &'static SQLExpr<'static, Value, X, N>;
1064/// # fn col<X: drizzle_core::types::DataType, N: Nullability>(c: &'static str) -> C<X, N> { Box::leak(Box::new(SQLExpr::new(SQL::column(ColumnRef::sql("users", c))))) }
1065/// # type Int = <D as DialectTypes>::Int; type Text = <D as DialectTypes>::Text; type Real = <D as DialectTypes>::Double;
1066/// # struct Users { id: C<Int>, age: C<Int>, name: C<Text>, email: C<Text, Null>, score: C<Real, Null>, active: C<<D as DialectTypes>::Bool>, created_at: C<<D as DialectTypes>::Timestamp> }
1067/// # let users = Users { id: col("id"), age: col("age"), name: col("name"), email: col("email"), score: col("score"), active: col("active"), created_at: col("created_at") };
1068/// assert_eq!(group_concat(users.name).sql(), r#"GROUP_CONCAT ("users"."name")"#);
1069/// ```
1070pub fn group_concat<'a, V, E>(
1071    expr: E,
1072) -> SQLExpr<'a, V, <V::DialectMarker as DialectTypes>::Text, Null, Agg, E::Sources>
1073where
1074    V: SQLParam + 'a,
1075    V::DialectMarker: DialectSupports<feature::GroupConcat>,
1076    E: Expr<'a, V>,
1077    E::SQLType: crate::types::Textual,
1078{
1079    SQLExpr::new(SQL::func("GROUP_CONCAT", expr.into_expr_sql()))
1080}
1081
1082/// Joins text values with a delimiter (`STRING_AGG`), on PostgreSQL.
1083///
1084/// Both arguments must be text. The result is text, nullable, and an
1085/// aggregate. On SQLite and MySQL, use [`group_concat`].
1086///
1087/// # Examples
1088///
1089/// ```rust
1090/// # use drizzle_core::dialect::{Dialect, DialectTypes, PostgresDialect as D};
1091/// # use drizzle_core::{ColumnRef, SQL, SQLParam, expr::*};
1092/// # #[derive(Clone, Debug)] struct Value(String);
1093/// # impl SQLParam for Value { const DIALECT: Dialect = Dialect::PostgreSQL; type DialectMarker = D; }
1094/// # impl<X: ToString> From<X> for Value { fn from(v: X) -> Self { Value(v.to_string()) } }
1095/// # impl From<Value> for std::borrow::Cow<'_, Value> { fn from(v: Value) -> Self { Self::Owned(v) } }
1096/// # type C<X, N = NonNull> = &'static SQLExpr<'static, Value, X, N>;
1097/// # fn col<X: drizzle_core::types::DataType, N: Nullability>(c: &'static str) -> C<X, N> { Box::leak(Box::new(SQLExpr::new(SQL::column(ColumnRef::sql("users", c))))) }
1098/// # type Int = <D as DialectTypes>::Int; type Text = <D as DialectTypes>::Text; type Real = <D as DialectTypes>::Double;
1099/// # struct Users { id: C<Int>, age: C<Int>, name: C<Text>, email: C<Text, Null>, score: C<Real, Null>, active: C<<D as DialectTypes>::Bool>, created_at: C<<D as DialectTypes>::Timestamp> }
1100/// # let users = Users { id: col("id"), age: col("age"), name: col("name"), email: col("email"), score: col("score"), active: col("active"), created_at: col("created_at") };
1101/// let names = string_agg(users.name, ", ");
1102/// assert_eq!(names.sql(), r#"STRING_AGG ("users"."name", $1)"#);
1103/// ```
1104#[allow(clippy::type_complexity)]
1105pub fn string_agg<'a, V, E, D>(
1106    expr: E,
1107    delimiter: D,
1108) -> SQLExpr<'a, V, <V::DialectMarker as DialectTypes>::Text, Null, Agg, (E::Sources, D::Sources)>
1109where
1110    V: SQLParam + 'a,
1111    V::DialectMarker: DialectSupports<feature::PostgresAggregate>,
1112    E: Expr<'a, V>,
1113    E::SQLType: crate::types::Textual,
1114    D: Expr<'a, V>,
1115    D::SQLType: crate::types::Textual,
1116{
1117    SQLExpr::new(SQL::func(
1118        "STRING_AGG",
1119        expr.into_expr_sql()
1120            .push(crate::Token::COMMA)
1121            .append(delimiter.into_expr_sql()),
1122    ))
1123}
1124
1125// =============================================================================
1126// PostgreSQL Aggregate Functions
1127// =============================================================================
1128
1129/// True when every non-NULL input is true (`EVERY`), on PostgreSQL.
1130///
1131/// The SQL-standard spelling of [`bool_and`], with the same typing.
1132///
1133/// # Examples
1134///
1135/// ```rust
1136/// # use drizzle_core::dialect::{Dialect, DialectTypes, PostgresDialect as D};
1137/// # use drizzle_core::{ColumnRef, SQL, SQLParam, expr::*};
1138/// # #[derive(Clone, Debug)] struct Value(String);
1139/// # impl SQLParam for Value { const DIALECT: Dialect = Dialect::PostgreSQL; type DialectMarker = D; }
1140/// # impl<X: ToString> From<X> for Value { fn from(v: X) -> Self { Value(v.to_string()) } }
1141/// # impl From<Value> for std::borrow::Cow<'_, Value> { fn from(v: Value) -> Self { Self::Owned(v) } }
1142/// # type C<X, N = NonNull> = &'static SQLExpr<'static, Value, X, N>;
1143/// # fn col<X: drizzle_core::types::DataType, N: Nullability>(c: &'static str) -> C<X, N> { Box::leak(Box::new(SQLExpr::new(SQL::column(ColumnRef::sql("users", c))))) }
1144/// # type Int = <D as DialectTypes>::Int; type Text = <D as DialectTypes>::Text; type Real = <D as DialectTypes>::Double;
1145/// # struct Users { id: C<Int>, age: C<Int>, name: C<Text>, email: C<Text, Null>, score: C<Real, Null>, active: C<<D as DialectTypes>::Bool>, created_at: C<<D as DialectTypes>::Timestamp> }
1146/// # let users = Users { id: col("id"), age: col("age"), name: col("name"), email: col("email"), score: col("score"), active: col("active"), created_at: col("created_at") };
1147/// assert_eq!(every(users.active).sql(), r#"EVERY ("users"."active")"#);
1148/// ```
1149pub fn every<'a, V, E>(
1150    expr: E,
1151) -> SQLExpr<'a, V, <V::DialectMarker as DialectTypes>::Bool, Null, Agg, E::Sources>
1152where
1153    V: SQLParam + 'a,
1154    V::DialectMarker: DialectSupports<feature::PostgresAggregate>,
1155    E: Expr<'a, V>,
1156    E::SQLType: BooleanAggregatePolicy<V::DialectMarker>,
1157{
1158    SQLExpr::new(SQL::func("EVERY", expr.into_expr_sql()))
1159}
1160
1161/// Collects key/value pairs into a JSON object (`JSON_OBJECT_AGG`), on PostgreSQL.
1162///
1163/// Accepts any key and value expressions. The result is `json`, nullable, and
1164/// an aggregate.
1165///
1166/// # Examples
1167///
1168/// ```rust
1169/// # use drizzle_core::dialect::{Dialect, DialectTypes, PostgresDialect as D};
1170/// # use drizzle_core::{ColumnRef, SQL, SQLParam, expr::*};
1171/// # #[derive(Clone, Debug)] struct Value(String);
1172/// # impl SQLParam for Value { const DIALECT: Dialect = Dialect::PostgreSQL; type DialectMarker = D; }
1173/// # impl<X: ToString> From<X> for Value { fn from(v: X) -> Self { Value(v.to_string()) } }
1174/// # impl From<Value> for std::borrow::Cow<'_, Value> { fn from(v: Value) -> Self { Self::Owned(v) } }
1175/// # type C<X, N = NonNull> = &'static SQLExpr<'static, Value, X, N>;
1176/// # fn col<X: drizzle_core::types::DataType, N: Nullability>(c: &'static str) -> C<X, N> { Box::leak(Box::new(SQLExpr::new(SQL::column(ColumnRef::sql("users", c))))) }
1177/// # type Int = <D as DialectTypes>::Int; type Text = <D as DialectTypes>::Text; type Real = <D as DialectTypes>::Double;
1178/// # struct Users { id: C<Int>, age: C<Int>, name: C<Text>, email: C<Text, Null>, score: C<Real, Null>, active: C<<D as DialectTypes>::Bool>, created_at: C<<D as DialectTypes>::Timestamp> }
1179/// # let users = Users { id: col("id"), age: col("age"), name: col("name"), email: col("email"), score: col("score"), active: col("active"), created_at: col("created_at") };
1180/// let by_name = json_object_agg(users.name, users.age);
1181/// assert_eq!(by_name.sql(), r#"JSON_OBJECT_AGG ("users"."name", "users"."age")"#);
1182/// ```
1183#[allow(clippy::type_complexity)]
1184pub fn json_object_agg<'a, V, K, Val>(
1185    key: K,
1186    value: Val,
1187) -> SQLExpr<'a, V, <V::DialectMarker as DialectTypes>::Json, Null, Agg, (K::Sources, Val::Sources)>
1188where
1189    V: SQLParam + 'a,
1190    V::DialectMarker: DialectSupports<feature::PostgresAggregate>,
1191    K: Expr<'a, V>,
1192    Val: Expr<'a, V>,
1193{
1194    SQLExpr::new(SQL::func(
1195        "JSON_OBJECT_AGG",
1196        key.into_expr_sql()
1197            .push(crate::Token::COMMA)
1198            .append(value.into_expr_sql()),
1199    ))
1200}
1201
1202/// Collects key/value pairs into a JSONB object (`JSONB_OBJECT_AGG`), on PostgreSQL.
1203///
1204/// Accepts any key and value expressions. The result is `jsonb`, nullable,
1205/// and an aggregate.
1206///
1207/// # Examples
1208///
1209/// ```rust
1210/// # use drizzle_core::dialect::{Dialect, DialectTypes, PostgresDialect as D};
1211/// # use drizzle_core::{ColumnRef, SQL, SQLParam, expr::*};
1212/// # #[derive(Clone, Debug)] struct Value(String);
1213/// # impl SQLParam for Value { const DIALECT: Dialect = Dialect::PostgreSQL; type DialectMarker = D; }
1214/// # impl<X: ToString> From<X> for Value { fn from(v: X) -> Self { Value(v.to_string()) } }
1215/// # impl From<Value> for std::borrow::Cow<'_, Value> { fn from(v: Value) -> Self { Self::Owned(v) } }
1216/// # type C<X, N = NonNull> = &'static SQLExpr<'static, Value, X, N>;
1217/// # fn col<X: drizzle_core::types::DataType, N: Nullability>(c: &'static str) -> C<X, N> { Box::leak(Box::new(SQLExpr::new(SQL::column(ColumnRef::sql("users", c))))) }
1218/// # type Int = <D as DialectTypes>::Int; type Text = <D as DialectTypes>::Text; type Real = <D as DialectTypes>::Double;
1219/// # struct Users { id: C<Int>, age: C<Int>, name: C<Text>, email: C<Text, Null>, score: C<Real, Null>, active: C<<D as DialectTypes>::Bool>, created_at: C<<D as DialectTypes>::Timestamp> }
1220/// # let users = Users { id: col("id"), age: col("age"), name: col("name"), email: col("email"), score: col("score"), active: col("active"), created_at: col("created_at") };
1221/// let by_name = jsonb_object_agg(users.name, users.age);
1222/// assert_eq!(by_name.sql(), r#"JSONB_OBJECT_AGG ("users"."name", "users"."age")"#);
1223/// ```
1224#[allow(clippy::type_complexity)]
1225pub fn jsonb_object_agg<'a, V, K, Val>(
1226    key: K,
1227    value: Val,
1228) -> SQLExpr<'a, V, <V::DialectMarker as DialectTypes>::Jsonb, Null, Agg, (K::Sources, Val::Sources)>
1229where
1230    V: SQLParam + 'a,
1231    V::DialectMarker: DialectSupports<feature::PostgresAggregate>,
1232    K: Expr<'a, V>,
1233    Val: Expr<'a, V>,
1234{
1235    SQLExpr::new(SQL::func(
1236        "JSONB_OBJECT_AGG",
1237        key.into_expr_sql()
1238            .push(crate::Token::COMMA)
1239            .append(value.into_expr_sql()),
1240    ))
1241}
1242
1243// =============================================================================
1244// Distinct Wrapper
1245// =============================================================================
1246
1247/// Prefixes an expression with `DISTINCT`.
1248///
1249/// Renders `DISTINCT expr` and keeps the expression's type and nullability.
1250/// Note that it is marked scalar, even when `expr` is an aggregate. For
1251/// aggregates, prefer [`count_distinct`], [`sum_distinct`] and
1252/// [`avg_distinct`].
1253///
1254/// # Examples
1255///
1256/// ```rust
1257/// # use drizzle_core::dialect::{Dialect, DialectTypes, SQLiteDialect as D};
1258/// # use drizzle_core::{ColumnRef, SQL, SQLParam, expr::*};
1259/// # #[derive(Clone, Debug)] struct Value(String);
1260/// # impl SQLParam for Value { const DIALECT: Dialect = Dialect::SQLite; type DialectMarker = D; }
1261/// # impl<X: ToString> From<X> for Value { fn from(v: X) -> Self { Value(v.to_string()) } }
1262/// # impl From<Value> for std::borrow::Cow<'_, Value> { fn from(v: Value) -> Self { Self::Owned(v) } }
1263/// # type C<X, N = NonNull> = &'static SQLExpr<'static, Value, X, N>;
1264/// # fn col<X: drizzle_core::types::DataType, N: Nullability>(c: &'static str) -> C<X, N> { Box::leak(Box::new(SQLExpr::new(SQL::column(ColumnRef::sql("users", c))))) }
1265/// # type Int = <D as DialectTypes>::Int; type Text = <D as DialectTypes>::Text; type Real = <D as DialectTypes>::Double;
1266/// # struct Users { id: C<Int>, age: C<Int>, name: C<Text>, email: C<Text, Null>, score: C<Real, Null>, active: C<<D as DialectTypes>::Bool>, created_at: C<<D as DialectTypes>::Timestamp> }
1267/// # let users = Users { id: col("id"), age: col("age"), name: col("name"), email: col("email"), score: col("score"), active: col("active"), created_at: col("created_at") };
1268/// assert_eq!(distinct(users.name).sql(), r#"DISTINCT "users"."name""#);
1269/// ```
1270pub fn distinct<'a, V, E>(expr: E) -> SQLExpr<'a, V, E::SQLType, E::Nullable, Scalar, E::Sources>
1271where
1272    V: SQLParam + 'a,
1273    E: Expr<'a, V>,
1274{
1275    SQLExpr::new(SQL::raw("DISTINCT").append(expr.into_expr_sql()))
1276}