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}