Skip to main content

drizzle_core/expr/
agg.rs

1//! Type-safe aggregate functions.
2//!
3//! These functions return expressions marked as aggregates, which can be used
4//! to enforce GROUP BY rules at compile time.
5//!
6//! # Type Safety
7//!
8//! - `sum`, `avg`: Require `Numeric` types (Int, `BigInt`, Float, Double)
9//! - `count`: Works with any type
10//! - `min`, `max`: Work with any type (ordered types in SQL)
11
12use crate::dialect::DialectTypes;
13use crate::sql::SQL;
14use crate::traits::SQLParam;
15use crate::types::{Array, Numeric};
16use crate::{PostgresDialect, SQLiteDialect};
17use drizzle_types::postgres::types::{
18    Boolean as PgBoolean, Float4, Float8, Int2, Int4, Int8, Numeric as PgNumeric,
19};
20use drizzle_types::sqlite::types::{
21    Integer as SqliteInteger, Numeric as SqliteNumeric, Real as SqliteReal,
22};
23
24use super::{Agg, Expr, NonNull, Null, SQLExpr, Scalar};
25
26// =============================================================================
27// Dialect Aggregate Policy
28// =============================================================================
29
30/// Dialect-specific aggregate output mapping.
31///
32/// Keeps aggregate output typing in one place so all aggregate functions
33/// follow the same per-dialect policy.
34#[diagnostic::on_unimplemented(
35    message = "no aggregate policy for `{Self}` on this dialect",
36    label = "aggregate result type is not defined for this SQL type/dialect"
37)]
38pub trait AggregatePolicy<D>: Numeric {
39    type Sum: crate::types::DataType;
40    type Avg: crate::types::DataType;
41}
42
43#[diagnostic::on_unimplemented(
44    message = "no statistical aggregate policy for `{Self}` on this dialect",
45    label = "stddev/variance result type is not defined for this SQL type/dialect"
46)]
47pub trait StatisticalAggregatePolicy<D>: Numeric {
48    type StddevPop: crate::types::DataType;
49    type StddevSamp: crate::types::DataType;
50    type VarPop: crate::types::DataType;
51    type VarSamp: crate::types::DataType;
52}
53
54#[diagnostic::on_unimplemented(
55    message = "boolean aggregates are not supported for `{Self}` on this dialect",
56    label = "use a boolean expression with a dialect that supports BOOL_AND/BOOL_OR"
57)]
58pub trait BooleanAggregatePolicy<D>: crate::types::DataType {}
59
60#[diagnostic::on_unimplemented(
61    message = "this aggregate is not available for this dialect",
62    label = "use a dialect-specific alternative"
63)]
64pub trait PostgresAggregateSupport {}
65
66#[diagnostic::on_unimplemented(
67    message = "this aggregate is not available for this dialect",
68    label = "use a dialect-specific alternative"
69)]
70pub trait SQLiteAggregateSupport {}
71
72#[diagnostic::on_unimplemented(
73    message = "no COUNT return type defined for this dialect",
74    label = "COUNT result type is not configured for this dialect marker"
75)]
76pub trait CountPolicy {
77    /// The integer type returned by COUNT (e.g. Integer on `SQLite`, Int8 on `PostgreSQL`).
78    type Count: crate::types::DataType;
79}
80
81mod count_arg_private {
82    use super::SQLParam;
83
84    pub trait Sealed<'a, V: SQLParam> {}
85
86    impl<'a, V: SQLParam> Sealed<'a, V> for () {}
87
88    impl<'a, V, E> Sealed<'a, V> for E
89    where
90        V: SQLParam + 'a,
91        E: crate::traits::ToSQL<'a, V> + crate::row::ExprValueType,
92    {
93    }
94}
95
96/// Argument accepted by [`count`].
97///
98/// This trait is sealed and exists only to support `count(())` for `COUNT(*)`
99/// and `count(expr)` for `COUNT(expr)` without making `()` a general SQL
100/// expression.
101#[doc(hidden)]
102pub trait CountArg<'a, V: SQLParam>: count_arg_private::Sealed<'a, V> {
103    fn count_sql(self) -> SQL<'a, V>;
104}
105
106impl<'a, V: SQLParam + 'a> CountArg<'a, V> for () {
107    fn count_sql(self) -> SQL<'a, V> {
108        SQL::raw("COUNT(*)")
109    }
110}
111
112impl<'a, V, E> CountArg<'a, V> for E
113where
114    V: SQLParam + 'a,
115    E: crate::traits::ToSQL<'a, V> + crate::row::ExprValueType,
116{
117    fn count_sql(self) -> SQL<'a, V> {
118        SQL::func("COUNT", self.into_sql().parens_if_subquery())
119    }
120}
121
122impl CountPolicy for SQLiteDialect {
123    type Count = drizzle_types::sqlite::types::Integer;
124}
125
126impl CountPolicy for PostgresDialect {
127    type Count = drizzle_types::postgres::types::Int8;
128}
129
130#[diagnostic::on_unimplemented(
131    message = "no floating-point return type defined for this dialect",
132    label = "PERCENT_RANK/CUME_DIST result type is not configured for this dialect marker"
133)]
134pub trait FloatPolicy {
135    /// The floating-point type returned by distribution window functions
136    /// like `PERCENT_RANK` and `CUME_DIST` (Real on `SQLite`, Float8 on `PostgreSQL`).
137    type Float: crate::types::DataType;
138}
139
140impl FloatPolicy for SQLiteDialect {
141    type Float = drizzle_types::sqlite::types::Real;
142}
143
144impl FloatPolicy for PostgresDialect {
145    type Float = drizzle_types::postgres::types::Float8;
146}
147
148impl AggregatePolicy<SQLiteDialect> for SqliteInteger {
149    type Sum = Self;
150    type Avg = SqliteReal;
151}
152impl AggregatePolicy<SQLiteDialect> for SqliteReal {
153    type Sum = Self;
154    type Avg = Self;
155}
156impl AggregatePolicy<SQLiteDialect> for SqliteNumeric {
157    type Sum = Self;
158    type Avg = SqliteReal;
159}
160impl AggregatePolicy<SQLiteDialect> for drizzle_types::sqlite::types::Any {
161    type Sum = Self;
162    type Avg = SqliteReal;
163}
164
165impl StatisticalAggregatePolicy<PostgresDialect> for Int2 {
166    type StddevPop = Float8;
167    type StddevSamp = Float8;
168    type VarPop = Float8;
169    type VarSamp = Float8;
170}
171impl StatisticalAggregatePolicy<PostgresDialect> for Int4 {
172    type StddevPop = Float8;
173    type StddevSamp = Float8;
174    type VarPop = Float8;
175    type VarSamp = Float8;
176}
177impl StatisticalAggregatePolicy<PostgresDialect> for Int8 {
178    type StddevPop = Float8;
179    type StddevSamp = Float8;
180    type VarPop = Float8;
181    type VarSamp = Float8;
182}
183impl StatisticalAggregatePolicy<PostgresDialect> for Float4 {
184    type StddevPop = Float8;
185    type StddevSamp = Float8;
186    type VarPop = Float8;
187    type VarSamp = Float8;
188}
189impl StatisticalAggregatePolicy<PostgresDialect> for Float8 {
190    type StddevPop = Self;
191    type StddevSamp = Self;
192    type VarPop = Self;
193    type VarSamp = Self;
194}
195impl StatisticalAggregatePolicy<PostgresDialect> for PgNumeric {
196    type StddevPop = Float8;
197    type StddevSamp = Float8;
198    type VarPop = Float8;
199    type VarSamp = Float8;
200}
201
202impl BooleanAggregatePolicy<PostgresDialect> for PgBoolean {}
203
204impl PostgresAggregateSupport for PostgresDialect {}
205impl SQLiteAggregateSupport for SQLiteDialect {}
206
207impl AggregatePolicy<PostgresDialect> for Int2 {
208    type Sum = Int8;
209    type Avg = Float8;
210}
211impl AggregatePolicy<PostgresDialect> for Int4 {
212    type Sum = Int8;
213    type Avg = Float8;
214}
215impl AggregatePolicy<PostgresDialect> for Int8 {
216    type Sum = Self;
217    type Avg = Float8;
218}
219impl AggregatePolicy<PostgresDialect> for Float4 {
220    type Sum = Float8;
221    type Avg = Float8;
222}
223impl AggregatePolicy<PostgresDialect> for Float8 {
224    type Sum = Self;
225    type Avg = Self;
226}
227impl AggregatePolicy<PostgresDialect> for PgNumeric {
228    type Sum = Self;
229    type Avg = Self;
230}
231
232// =============================================================================
233// COUNT
234// =============================================================================
235
236/// COUNT aggregate.
237///
238/// Pass `()` for `COUNT(*)`, or a column/expression for `COUNT(expr)`.
239///
240/// Returns a `BigInt`, `NonNull` (count is never NULL), Aggregate expression.
241///
242/// # Example
243///
244/// ```rust
245/// # let _ = r####"
246/// use drizzle_core::expr::count;
247///
248/// let all_rows = count(());
249/// // Generates: COUNT(*)
250///
251/// let email_count = count(users.email);
252/// // Generates: COUNT("users"."email")
253/// # "####;
254/// ```
255pub fn count<'a, V, A>(
256    arg: A,
257) -> SQLExpr<'a, V, <V::DialectMarker as CountPolicy>::Count, NonNull, Agg>
258where
259    V: SQLParam + 'a,
260    V::DialectMarker: CountPolicy,
261    A: CountArg<'a, V>,
262{
263    SQLExpr::new(arg.count_sql())
264}
265
266/// COUNT(DISTINCT expr) - counts distinct non-null values.
267///
268/// Returns a `BigInt`, `NonNull`, Aggregate expression.
269/// Works with any expression type.
270pub fn count_distinct<'a, V, E>(
271    expr: E,
272) -> SQLExpr<'a, V, <V::DialectMarker as CountPolicy>::Count, NonNull, Agg>
273where
274    V: SQLParam + 'a,
275    V::DialectMarker: CountPolicy,
276    E: Expr<'a, V>,
277{
278    SQLExpr::new(SQL::func(
279        "COUNT",
280        SQL::raw("DISTINCT").append(expr.into_expr_sql()),
281    ))
282}
283
284// =============================================================================
285// SUM
286// =============================================================================
287
288/// SUM(expr) - sums numeric values.
289///
290/// Requires the expression to be `Numeric` (Int, `BigInt`, Float, Double).
291/// Result type is dialect-aware.
292/// Returns a nullable expression (empty set returns NULL).
293///
294/// # Type Safety
295///
296/// ```rust
297/// # let _ = r####"
298/// // ✅ OK: Numeric column
299/// sum(orders.amount);
300/// // SQLite: same width for integer sums
301/// // PostgreSQL: Int/SmallInt promote to BigInt
302///
303/// // ❌ Compile error: Text is not Numeric
304/// sum(users.name);
305/// # "####;
306/// ```
307pub fn sum<'a, V, E>(
308    expr: E,
309) -> SQLExpr<'a, V, <E::SQLType as AggregatePolicy<V::DialectMarker>>::Sum, Null, Agg>
310where
311    V: SQLParam + 'a,
312    E: Expr<'a, V>,
313    E::SQLType: AggregatePolicy<V::DialectMarker>,
314{
315    SQLExpr::new(SQL::func("SUM", expr.into_expr_sql()))
316}
317
318/// SUM(DISTINCT expr) - sums distinct numeric values.
319///
320/// Requires the expression to be `Numeric`.
321/// Result type is dialect-aware.
322pub fn sum_distinct<'a, V, E>(
323    expr: E,
324) -> SQLExpr<'a, V, <E::SQLType as AggregatePolicy<V::DialectMarker>>::Sum, Null, Agg>
325where
326    V: SQLParam + 'a,
327    E: Expr<'a, V>,
328    E::SQLType: AggregatePolicy<V::DialectMarker>,
329{
330    SQLExpr::new(SQL::func(
331        "SUM",
332        SQL::raw("DISTINCT").append(expr.into_expr_sql()),
333    ))
334}
335
336// =============================================================================
337// AVG
338// =============================================================================
339
340/// AVG(expr) - calculates average of numeric values.
341///
342/// Requires the expression to be `Numeric`.
343/// Always returns Double (SQL standard behavior), nullable.
344///
345/// # Type Safety
346///
347/// ```rust
348/// # let _ = r####"
349/// // ✅ OK: Numeric column
350/// avg(products.price);
351///
352/// // ❌ Compile error: Text is not Numeric
353/// avg(users.name);
354/// # "####;
355/// ```
356pub fn avg<'a, V, E>(
357    expr: E,
358) -> SQLExpr<'a, V, <E::SQLType as AggregatePolicy<V::DialectMarker>>::Avg, Null, Agg>
359where
360    V: SQLParam + 'a,
361    E: Expr<'a, V>,
362    E::SQLType: AggregatePolicy<V::DialectMarker>,
363{
364    SQLExpr::new(SQL::func("AVG", expr.into_expr_sql()))
365}
366
367/// AVG(DISTINCT expr) - calculates average of distinct numeric values.
368///
369/// Requires the expression to be `Numeric`.
370pub fn avg_distinct<'a, V, E>(
371    expr: E,
372) -> SQLExpr<'a, V, <E::SQLType as AggregatePolicy<V::DialectMarker>>::Avg, Null, Agg>
373where
374    V: SQLParam + 'a,
375    E: Expr<'a, V>,
376    E::SQLType: AggregatePolicy<V::DialectMarker>,
377{
378    SQLExpr::new(SQL::func(
379        "AVG",
380        SQL::raw("DISTINCT").append(expr.into_expr_sql()),
381    ))
382}
383
384// =============================================================================
385// MIN / MAX
386// =============================================================================
387
388/// MIN(expr) - finds minimum value.
389///
390/// Works with any expression type (ordered types in SQL).
391/// Preserves the input expression's SQL type.
392/// Result is nullable (empty set returns NULL).
393///
394/// # Example
395///
396/// ```rust
397/// # let _ = r####"
398/// use drizzle_core::expr::min;
399///
400/// let cheapest = min(products.price);
401/// // Generates: MIN("products"."price")
402/// // Returns the same SQL type as products.price
403/// # "####;
404/// ```
405pub fn min<'a, V, E>(expr: E) -> SQLExpr<'a, V, E::SQLType, Null, Agg>
406where
407    V: SQLParam + 'a,
408    E: Expr<'a, V>,
409{
410    SQLExpr::new(SQL::func("MIN", expr.into_expr_sql()))
411}
412
413/// MAX(expr) - finds maximum value.
414///
415/// Works with any expression type (ordered types in SQL).
416/// Preserves the input expression's SQL type.
417/// Result is nullable (empty set returns NULL).
418///
419/// # Example
420///
421/// ```rust
422/// # let _ = r####"
423/// use drizzle_core::expr::max;
424///
425/// let most_expensive = max(products.price);
426/// // Generates: MAX("products"."price")
427/// // Returns the same SQL type as products.price
428/// # "####;
429/// ```
430pub fn max<'a, V, E>(expr: E) -> SQLExpr<'a, V, E::SQLType, Null, Agg>
431where
432    V: SQLParam + 'a,
433    E: Expr<'a, V>,
434{
435    SQLExpr::new(SQL::func("MAX", expr.into_expr_sql()))
436}
437
438// =============================================================================
439// STATISTICAL FUNCTIONS
440// =============================================================================
441
442/// `STDDEV_POP` - population standard deviation.
443///
444/// Calculates the population standard deviation of numeric values.
445/// Requires the expression to be `Numeric`.
446/// Returns Double, nullable (empty set returns NULL).
447///
448/// Note: This function is available in `PostgreSQL`. `SQLite` does not have it built-in.
449///
450/// # Example
451///
452/// ```rust
453/// # let _ = r####"
454/// use drizzle_core::expr::stddev_pop;
455///
456/// let deviation = stddev_pop(measurements.value);
457/// // Generates: STDDEV_POP("measurements"."value")
458/// # "####;
459/// ```
460pub fn stddev_pop<'a, V, E>(
461    expr: E,
462) -> SQLExpr<
463    'a,
464    V,
465    <E::SQLType as StatisticalAggregatePolicy<V::DialectMarker>>::StddevPop,
466    Null,
467    Agg,
468>
469where
470    V: SQLParam + 'a,
471    E: Expr<'a, V>,
472    E::SQLType: StatisticalAggregatePolicy<V::DialectMarker>,
473{
474    SQLExpr::new(SQL::func("STDDEV_POP", expr.into_expr_sql()))
475}
476
477/// `STDDEV_SAMP` / STDDEV - sample standard deviation.
478///
479/// Calculates the sample standard deviation of numeric values.
480/// Requires the expression to be `Numeric`.
481/// Returns Double, nullable (empty set returns NULL).
482///
483/// Note: This function is available in `PostgreSQL`. `SQLite` does not have it built-in.
484///
485/// # Example
486///
487/// ```rust
488/// # let _ = r####"
489/// use drizzle_core::expr::stddev_samp;
490///
491/// let deviation = stddev_samp(measurements.value);
492/// // Generates: STDDEV_SAMP("measurements"."value")
493/// # "####;
494/// ```
495pub fn stddev_samp<'a, V, E>(
496    expr: E,
497) -> SQLExpr<
498    'a,
499    V,
500    <E::SQLType as StatisticalAggregatePolicy<V::DialectMarker>>::StddevSamp,
501    Null,
502    Agg,
503>
504where
505    V: SQLParam + 'a,
506    E: Expr<'a, V>,
507    E::SQLType: StatisticalAggregatePolicy<V::DialectMarker>,
508{
509    SQLExpr::new(SQL::func("STDDEV_SAMP", expr.into_expr_sql()))
510}
511
512/// `VAR_POP` - population variance.
513///
514/// Calculates the population variance of numeric values.
515/// Requires the expression to be `Numeric`.
516/// Returns Double, nullable (empty set returns NULL).
517///
518/// Note: This function is available in `PostgreSQL`. `SQLite` does not have it built-in.
519///
520/// # Example
521///
522/// ```rust
523/// # let _ = r####"
524/// use drizzle_core::expr::var_pop;
525///
526/// let variance = var_pop(measurements.value);
527/// // Generates: VAR_POP("measurements"."value")
528/// # "####;
529/// ```
530pub fn var_pop<'a, V, E>(
531    expr: E,
532) -> SQLExpr<'a, V, <E::SQLType as StatisticalAggregatePolicy<V::DialectMarker>>::VarPop, Null, Agg>
533where
534    V: SQLParam + 'a,
535    E: Expr<'a, V>,
536    E::SQLType: StatisticalAggregatePolicy<V::DialectMarker>,
537{
538    SQLExpr::new(SQL::func("VAR_POP", expr.into_expr_sql()))
539}
540
541/// `VAR_SAMP` / VARIANCE - sample variance.
542///
543/// Calculates the sample variance of numeric values.
544/// Requires the expression to be `Numeric`.
545/// Returns Double, nullable (empty set returns NULL).
546///
547/// Note: This function is available in `PostgreSQL`. `SQLite` does not have it built-in.
548///
549/// # Example
550///
551/// ```rust
552/// # let _ = r####"
553/// use drizzle_core::expr::var_samp;
554///
555/// let variance = var_samp(measurements.value);
556/// // Generates: VAR_SAMP("measurements"."value")
557/// # "####;
558/// ```
559pub fn var_samp<'a, V, E>(
560    expr: E,
561) -> SQLExpr<'a, V, <E::SQLType as StatisticalAggregatePolicy<V::DialectMarker>>::VarSamp, Null, Agg>
562where
563    V: SQLParam + 'a,
564    E: Expr<'a, V>,
565    E::SQLType: StatisticalAggregatePolicy<V::DialectMarker>,
566{
567    SQLExpr::new(SQL::func("VAR_SAMP", expr.into_expr_sql()))
568}
569
570/// VARIANCE - `PostgreSQL` alias for sample variance (`VAR_SAMP`).
571pub fn variance<'a, V, E>(
572    expr: E,
573) -> SQLExpr<'a, V, <E::SQLType as StatisticalAggregatePolicy<V::DialectMarker>>::VarSamp, Null, Agg>
574where
575    V: SQLParam + 'a,
576    E: Expr<'a, V>,
577    E::SQLType: StatisticalAggregatePolicy<V::DialectMarker>,
578{
579    SQLExpr::new(SQL::func("VARIANCE", expr.into_expr_sql()))
580}
581
582/// `BOOL_AND` - true if all non-null inputs are true (`PostgreSQL`).
583pub fn bool_and<'a, V, E>(
584    expr: E,
585) -> SQLExpr<'a, V, <V::DialectMarker as DialectTypes>::Bool, Null, Agg>
586where
587    V: SQLParam + 'a,
588    V::DialectMarker: PostgresAggregateSupport,
589    E: Expr<'a, V>,
590    E::SQLType: BooleanAggregatePolicy<V::DialectMarker>,
591{
592    SQLExpr::new(SQL::func("BOOL_AND", expr.into_expr_sql()))
593}
594
595/// `BOOL_OR` - true if any non-null input is true (`PostgreSQL`).
596pub fn bool_or<'a, V, E>(
597    expr: E,
598) -> SQLExpr<'a, V, <V::DialectMarker as DialectTypes>::Bool, Null, Agg>
599where
600    V: SQLParam + 'a,
601    V::DialectMarker: PostgresAggregateSupport,
602    E: Expr<'a, V>,
603    E::SQLType: BooleanAggregatePolicy<V::DialectMarker>,
604{
605    SQLExpr::new(SQL::func("BOOL_OR", expr.into_expr_sql()))
606}
607
608/// `JSON_AGG` - aggregates values into a JSON array (`PostgreSQL`).
609pub fn json_agg<'a, V, E>(
610    expr: E,
611) -> SQLExpr<'a, V, <V::DialectMarker as DialectTypes>::Json, Null, Agg>
612where
613    V: SQLParam + 'a,
614    V::DialectMarker: PostgresAggregateSupport,
615    E: Expr<'a, V>,
616{
617    SQLExpr::new(SQL::func("JSON_AGG", expr.into_expr_sql()))
618}
619
620/// `JSONB_AGG` - aggregates values into a JSONB array (`PostgreSQL`).
621pub fn jsonb_agg<'a, V, E>(
622    expr: E,
623) -> SQLExpr<'a, V, <V::DialectMarker as DialectTypes>::Jsonb, Null, Agg>
624where
625    V: SQLParam + 'a,
626    V::DialectMarker: PostgresAggregateSupport,
627    E: Expr<'a, V>,
628{
629    SQLExpr::new(SQL::func("JSONB_AGG", expr.into_expr_sql()))
630}
631
632/// `ARRAY_AGG` - aggregates values into a SQL array (`PostgreSQL`).
633pub fn array_agg<'a, V, E>(expr: E) -> SQLExpr<'a, V, Array<E::SQLType>, Null, Agg>
634where
635    V: SQLParam + 'a,
636    V::DialectMarker: PostgresAggregateSupport,
637    E: Expr<'a, V>,
638{
639    SQLExpr::new(SQL::func("ARRAY_AGG", expr.into_expr_sql()))
640}
641
642// =============================================================================
643// TOTAL (SQLite)
644// =============================================================================
645
646/// TOTAL - sums numeric values, returning 0.0 for empty sets (`SQLite`).
647///
648/// Unlike `SUM`, which returns NULL for an empty result set,
649/// `TOTAL` always returns a floating-point value (0.0 for empty sets).
650///
651/// # Example
652///
653/// ```rust
654/// # let _ = r####"
655/// use drizzle_core::expr::total;
656///
657/// // SELECT TOTAL(orders.amount)
658/// let total_amount = total(orders.amount);
659/// # "####;
660/// ```
661pub fn total<'a, V, E>(
662    expr: E,
663) -> SQLExpr<'a, V, <V::DialectMarker as DialectTypes>::Double, NonNull, Agg>
664where
665    V: SQLParam + 'a,
666    V::DialectMarker: SQLiteAggregateSupport,
667    E: Expr<'a, V>,
668    E::SQLType: Numeric,
669{
670    SQLExpr::new(SQL::func("TOTAL", expr.into_expr_sql()))
671}
672
673// =============================================================================
674// GROUP_CONCAT / STRING_AGG
675// =============================================================================
676
677/// `GROUP_CONCAT` - concatenates values into a string (`SQLite`).
678///
679/// Returns Text type, nullable.
680pub fn group_concat<'a, V, E>(
681    expr: E,
682) -> SQLExpr<'a, V, <V::DialectMarker as DialectTypes>::Text, Null, Agg>
683where
684    V: SQLParam + 'a,
685    V::DialectMarker: SQLiteAggregateSupport,
686    E: Expr<'a, V>,
687    E::SQLType: crate::types::Textual,
688{
689    SQLExpr::new(SQL::func("GROUP_CONCAT", expr.into_expr_sql()))
690}
691
692/// `STRING_AGG` - concatenates text values using a delimiter (`PostgreSQL`).
693pub fn string_agg<'a, V, E, D>(
694    expr: E,
695    delimiter: D,
696) -> SQLExpr<'a, V, <V::DialectMarker as DialectTypes>::Text, Null, Agg>
697where
698    V: SQLParam + 'a,
699    V::DialectMarker: PostgresAggregateSupport,
700    E: Expr<'a, V>,
701    E::SQLType: crate::types::Textual,
702    D: Expr<'a, V>,
703    D::SQLType: crate::types::Textual,
704{
705    SQLExpr::new(SQL::func(
706        "STRING_AGG",
707        expr.into_expr_sql()
708            .push(crate::Token::COMMA)
709            .append(delimiter.into_expr_sql()),
710    ))
711}
712
713// =============================================================================
714// PostgreSQL Aggregate Functions
715// =============================================================================
716
717/// EVERY - true if all non-null inputs are true (`PostgreSQL`).
718///
719/// SQL standard alias for `BOOL_AND`.
720///
721/// # Example
722///
723/// ```rust
724/// # let _ = r####"
725/// use drizzle_core::expr::every;
726///
727/// // SELECT EVERY(orders.is_paid)
728/// let all_paid = every(orders.is_paid);
729/// # "####;
730/// ```
731pub fn every<'a, V, E>(
732    expr: E,
733) -> SQLExpr<'a, V, <V::DialectMarker as DialectTypes>::Bool, Null, Agg>
734where
735    V: SQLParam + 'a,
736    V::DialectMarker: PostgresAggregateSupport,
737    E: Expr<'a, V>,
738    E::SQLType: BooleanAggregatePolicy<V::DialectMarker>,
739{
740    SQLExpr::new(SQL::func("EVERY", expr.into_expr_sql()))
741}
742
743/// `JSON_OBJECT_AGG` - aggregates key/value pairs into a JSON object (`PostgreSQL`).
744///
745/// # Example
746///
747/// ```rust
748/// # let _ = r####"
749/// use drizzle_core::expr::json_object_agg;
750///
751/// // SELECT JSON_OBJECT_AGG(settings.key, settings.value)
752/// let obj = json_object_agg(settings.key, settings.value);
753/// # "####;
754/// ```
755pub fn json_object_agg<'a, V, K, Val>(
756    key: K,
757    value: Val,
758) -> SQLExpr<'a, V, <V::DialectMarker as DialectTypes>::Json, Null, Agg>
759where
760    V: SQLParam + 'a,
761    V::DialectMarker: PostgresAggregateSupport,
762    K: Expr<'a, V>,
763    Val: Expr<'a, V>,
764{
765    SQLExpr::new(SQL::func(
766        "JSON_OBJECT_AGG",
767        key.into_expr_sql()
768            .push(crate::Token::COMMA)
769            .append(value.into_expr_sql()),
770    ))
771}
772
773/// `JSONB_OBJECT_AGG` - aggregates key/value pairs into a JSONB object (`PostgreSQL`).
774///
775/// # Example
776///
777/// ```rust
778/// # let _ = r####"
779/// use drizzle_core::expr::jsonb_object_agg;
780///
781/// // SELECT JSONB_OBJECT_AGG(settings.key, settings.value)
782/// let obj = jsonb_object_agg(settings.key, settings.value);
783/// # "####;
784/// ```
785pub fn jsonb_object_agg<'a, V, K, Val>(
786    key: K,
787    value: Val,
788) -> SQLExpr<'a, V, <V::DialectMarker as DialectTypes>::Jsonb, Null, Agg>
789where
790    V: SQLParam + 'a,
791    V::DialectMarker: PostgresAggregateSupport,
792    K: Expr<'a, V>,
793    Val: Expr<'a, V>,
794{
795    SQLExpr::new(SQL::func(
796        "JSONB_OBJECT_AGG",
797        key.into_expr_sql()
798            .push(crate::Token::COMMA)
799            .append(value.into_expr_sql()),
800    ))
801}
802
803// =============================================================================
804// Distinct Wrapper
805// =============================================================================
806
807/// DISTINCT - marks an expression as DISTINCT.
808///
809/// Typically used inside aggregate functions.
810pub fn distinct<'a, V, E>(expr: E) -> SQLExpr<'a, V, E::SQLType, E::Nullable, Scalar>
811where
812    V: SQLParam + 'a,
813    E: Expr<'a, V>,
814{
815    SQLExpr::new(SQL::raw("DISTINCT").append(expr.into_expr_sql()))
816}