use crate::dialect::DialectTypes;
use crate::sql::SQL;
use crate::traits::SQLParam;
use crate::types::{Array, Numeric};
use crate::{PostgresDialect, SQLiteDialect};
use drizzle_types::postgres::types::{
Boolean as PgBoolean, Float4, Float8, Int2, Int4, Int8, Numeric as PgNumeric,
};
use drizzle_types::sqlite::types::{
Integer as SqliteInteger, Numeric as SqliteNumeric, Real as SqliteReal,
};
use super::{Agg, Expr, NonNull, Null, SQLExpr, Scalar};
#[diagnostic::on_unimplemented(
message = "no aggregate policy for `{Self}` on this dialect",
label = "aggregate result type is not defined for this SQL type/dialect"
)]
pub trait AggregatePolicy<D>: Numeric {
type Sum: crate::types::DataType;
type Avg: crate::types::DataType;
}
#[diagnostic::on_unimplemented(
message = "no statistical aggregate policy for `{Self}` on this dialect",
label = "stddev/variance result type is not defined for this SQL type/dialect"
)]
pub trait StatisticalAggregatePolicy<D>: Numeric {
type StddevPop: crate::types::DataType;
type StddevSamp: crate::types::DataType;
type VarPop: crate::types::DataType;
type VarSamp: crate::types::DataType;
}
#[diagnostic::on_unimplemented(
message = "boolean aggregates are not supported for `{Self}` on this dialect",
label = "use a boolean expression with a dialect that supports BOOL_AND/BOOL_OR"
)]
pub trait BooleanAggregatePolicy<D>: crate::types::DataType {}
#[diagnostic::on_unimplemented(
message = "this aggregate is not available for this dialect",
label = "use a dialect-specific alternative"
)]
pub trait PostgresAggregateSupport {}
#[diagnostic::on_unimplemented(
message = "this aggregate is not available for this dialect",
label = "use a dialect-specific alternative"
)]
pub trait SQLiteAggregateSupport {}
#[diagnostic::on_unimplemented(
message = "no COUNT return type defined for this dialect",
label = "COUNT result type is not configured for this dialect marker"
)]
pub trait CountPolicy {
type Count: crate::types::DataType;
}
mod count_arg_private {
use super::SQLParam;
pub trait Sealed<'a, V: SQLParam> {}
impl<'a, V: SQLParam> Sealed<'a, V> for () {}
impl<'a, V, E> Sealed<'a, V> for E
where
V: SQLParam + 'a,
E: crate::traits::ToSQL<'a, V> + crate::row::ExprValueType,
{
}
}
#[doc(hidden)]
pub trait CountArg<'a, V: SQLParam>: count_arg_private::Sealed<'a, V> {
fn count_sql(self) -> SQL<'a, V>;
}
impl<'a, V: SQLParam + 'a> CountArg<'a, V> for () {
fn count_sql(self) -> SQL<'a, V> {
SQL::raw("COUNT(*)")
}
}
impl<'a, V, E> CountArg<'a, V> for E
where
V: SQLParam + 'a,
E: crate::traits::ToSQL<'a, V> + crate::row::ExprValueType,
{
fn count_sql(self) -> SQL<'a, V> {
SQL::func("COUNT", self.into_sql().parens_if_subquery())
}
}
impl CountPolicy for SQLiteDialect {
type Count = drizzle_types::sqlite::types::Integer;
}
impl CountPolicy for PostgresDialect {
type Count = drizzle_types::postgres::types::Int8;
}
#[diagnostic::on_unimplemented(
message = "no floating-point return type defined for this dialect",
label = "PERCENT_RANK/CUME_DIST result type is not configured for this dialect marker"
)]
pub trait FloatPolicy {
type Float: crate::types::DataType;
}
impl FloatPolicy for SQLiteDialect {
type Float = drizzle_types::sqlite::types::Real;
}
impl FloatPolicy for PostgresDialect {
type Float = drizzle_types::postgres::types::Float8;
}
impl AggregatePolicy<SQLiteDialect> for SqliteInteger {
type Sum = Self;
type Avg = SqliteReal;
}
impl AggregatePolicy<SQLiteDialect> for SqliteReal {
type Sum = Self;
type Avg = Self;
}
impl AggregatePolicy<SQLiteDialect> for SqliteNumeric {
type Sum = Self;
type Avg = SqliteReal;
}
impl AggregatePolicy<SQLiteDialect> for drizzle_types::sqlite::types::Any {
type Sum = Self;
type Avg = SqliteReal;
}
impl StatisticalAggregatePolicy<PostgresDialect> for Int2 {
type StddevPop = Float8;
type StddevSamp = Float8;
type VarPop = Float8;
type VarSamp = Float8;
}
impl StatisticalAggregatePolicy<PostgresDialect> for Int4 {
type StddevPop = Float8;
type StddevSamp = Float8;
type VarPop = Float8;
type VarSamp = Float8;
}
impl StatisticalAggregatePolicy<PostgresDialect> for Int8 {
type StddevPop = Float8;
type StddevSamp = Float8;
type VarPop = Float8;
type VarSamp = Float8;
}
impl StatisticalAggregatePolicy<PostgresDialect> for Float4 {
type StddevPop = Float8;
type StddevSamp = Float8;
type VarPop = Float8;
type VarSamp = Float8;
}
impl StatisticalAggregatePolicy<PostgresDialect> for Float8 {
type StddevPop = Self;
type StddevSamp = Self;
type VarPop = Self;
type VarSamp = Self;
}
impl StatisticalAggregatePolicy<PostgresDialect> for PgNumeric {
type StddevPop = Float8;
type StddevSamp = Float8;
type VarPop = Float8;
type VarSamp = Float8;
}
impl BooleanAggregatePolicy<PostgresDialect> for PgBoolean {}
impl PostgresAggregateSupport for PostgresDialect {}
impl SQLiteAggregateSupport for SQLiteDialect {}
impl AggregatePolicy<PostgresDialect> for Int2 {
type Sum = Int8;
type Avg = Float8;
}
impl AggregatePolicy<PostgresDialect> for Int4 {
type Sum = Int8;
type Avg = Float8;
}
impl AggregatePolicy<PostgresDialect> for Int8 {
type Sum = Self;
type Avg = Float8;
}
impl AggregatePolicy<PostgresDialect> for Float4 {
type Sum = Float8;
type Avg = Float8;
}
impl AggregatePolicy<PostgresDialect> for Float8 {
type Sum = Self;
type Avg = Self;
}
impl AggregatePolicy<PostgresDialect> for PgNumeric {
type Sum = Self;
type Avg = Self;
}
pub fn count<'a, V, A>(
arg: A,
) -> SQLExpr<'a, V, <V::DialectMarker as CountPolicy>::Count, NonNull, Agg>
where
V: SQLParam + 'a,
V::DialectMarker: CountPolicy,
A: CountArg<'a, V>,
{
SQLExpr::new(arg.count_sql())
}
pub fn count_distinct<'a, V, E>(
expr: E,
) -> SQLExpr<'a, V, <V::DialectMarker as CountPolicy>::Count, NonNull, Agg>
where
V: SQLParam + 'a,
V::DialectMarker: CountPolicy,
E: Expr<'a, V>,
{
SQLExpr::new(SQL::func(
"COUNT",
SQL::raw("DISTINCT").append(expr.into_expr_sql()),
))
}
pub fn sum<'a, V, E>(
expr: E,
) -> SQLExpr<'a, V, <E::SQLType as AggregatePolicy<V::DialectMarker>>::Sum, Null, Agg>
where
V: SQLParam + 'a,
E: Expr<'a, V>,
E::SQLType: AggregatePolicy<V::DialectMarker>,
{
SQLExpr::new(SQL::func("SUM", expr.into_expr_sql()))
}
pub fn sum_distinct<'a, V, E>(
expr: E,
) -> SQLExpr<'a, V, <E::SQLType as AggregatePolicy<V::DialectMarker>>::Sum, Null, Agg>
where
V: SQLParam + 'a,
E: Expr<'a, V>,
E::SQLType: AggregatePolicy<V::DialectMarker>,
{
SQLExpr::new(SQL::func(
"SUM",
SQL::raw("DISTINCT").append(expr.into_expr_sql()),
))
}
pub fn avg<'a, V, E>(
expr: E,
) -> SQLExpr<'a, V, <E::SQLType as AggregatePolicy<V::DialectMarker>>::Avg, Null, Agg>
where
V: SQLParam + 'a,
E: Expr<'a, V>,
E::SQLType: AggregatePolicy<V::DialectMarker>,
{
SQLExpr::new(SQL::func("AVG", expr.into_expr_sql()))
}
pub fn avg_distinct<'a, V, E>(
expr: E,
) -> SQLExpr<'a, V, <E::SQLType as AggregatePolicy<V::DialectMarker>>::Avg, Null, Agg>
where
V: SQLParam + 'a,
E: Expr<'a, V>,
E::SQLType: AggregatePolicy<V::DialectMarker>,
{
SQLExpr::new(SQL::func(
"AVG",
SQL::raw("DISTINCT").append(expr.into_expr_sql()),
))
}
pub fn min<'a, V, E>(expr: E) -> SQLExpr<'a, V, E::SQLType, Null, Agg>
where
V: SQLParam + 'a,
E: Expr<'a, V>,
{
SQLExpr::new(SQL::func("MIN", expr.into_expr_sql()))
}
pub fn max<'a, V, E>(expr: E) -> SQLExpr<'a, V, E::SQLType, Null, Agg>
where
V: SQLParam + 'a,
E: Expr<'a, V>,
{
SQLExpr::new(SQL::func("MAX", expr.into_expr_sql()))
}
pub fn stddev_pop<'a, V, E>(
expr: E,
) -> SQLExpr<
'a,
V,
<E::SQLType as StatisticalAggregatePolicy<V::DialectMarker>>::StddevPop,
Null,
Agg,
>
where
V: SQLParam + 'a,
E: Expr<'a, V>,
E::SQLType: StatisticalAggregatePolicy<V::DialectMarker>,
{
SQLExpr::new(SQL::func("STDDEV_POP", expr.into_expr_sql()))
}
pub fn stddev_samp<'a, V, E>(
expr: E,
) -> SQLExpr<
'a,
V,
<E::SQLType as StatisticalAggregatePolicy<V::DialectMarker>>::StddevSamp,
Null,
Agg,
>
where
V: SQLParam + 'a,
E: Expr<'a, V>,
E::SQLType: StatisticalAggregatePolicy<V::DialectMarker>,
{
SQLExpr::new(SQL::func("STDDEV_SAMP", expr.into_expr_sql()))
}
pub fn var_pop<'a, V, E>(
expr: E,
) -> SQLExpr<'a, V, <E::SQLType as StatisticalAggregatePolicy<V::DialectMarker>>::VarPop, Null, Agg>
where
V: SQLParam + 'a,
E: Expr<'a, V>,
E::SQLType: StatisticalAggregatePolicy<V::DialectMarker>,
{
SQLExpr::new(SQL::func("VAR_POP", expr.into_expr_sql()))
}
pub fn var_samp<'a, V, E>(
expr: E,
) -> SQLExpr<'a, V, <E::SQLType as StatisticalAggregatePolicy<V::DialectMarker>>::VarSamp, Null, Agg>
where
V: SQLParam + 'a,
E: Expr<'a, V>,
E::SQLType: StatisticalAggregatePolicy<V::DialectMarker>,
{
SQLExpr::new(SQL::func("VAR_SAMP", expr.into_expr_sql()))
}
pub fn variance<'a, V, E>(
expr: E,
) -> SQLExpr<'a, V, <E::SQLType as StatisticalAggregatePolicy<V::DialectMarker>>::VarSamp, Null, Agg>
where
V: SQLParam + 'a,
E: Expr<'a, V>,
E::SQLType: StatisticalAggregatePolicy<V::DialectMarker>,
{
SQLExpr::new(SQL::func("VARIANCE", expr.into_expr_sql()))
}
pub fn bool_and<'a, V, E>(
expr: E,
) -> SQLExpr<'a, V, <V::DialectMarker as DialectTypes>::Bool, Null, Agg>
where
V: SQLParam + 'a,
V::DialectMarker: PostgresAggregateSupport,
E: Expr<'a, V>,
E::SQLType: BooleanAggregatePolicy<V::DialectMarker>,
{
SQLExpr::new(SQL::func("BOOL_AND", expr.into_expr_sql()))
}
pub fn bool_or<'a, V, E>(
expr: E,
) -> SQLExpr<'a, V, <V::DialectMarker as DialectTypes>::Bool, Null, Agg>
where
V: SQLParam + 'a,
V::DialectMarker: PostgresAggregateSupport,
E: Expr<'a, V>,
E::SQLType: BooleanAggregatePolicy<V::DialectMarker>,
{
SQLExpr::new(SQL::func("BOOL_OR", expr.into_expr_sql()))
}
pub fn json_agg<'a, V, E>(
expr: E,
) -> SQLExpr<'a, V, <V::DialectMarker as DialectTypes>::Json, Null, Agg>
where
V: SQLParam + 'a,
V::DialectMarker: PostgresAggregateSupport,
E: Expr<'a, V>,
{
SQLExpr::new(SQL::func("JSON_AGG", expr.into_expr_sql()))
}
pub fn jsonb_agg<'a, V, E>(
expr: E,
) -> SQLExpr<'a, V, <V::DialectMarker as DialectTypes>::Jsonb, Null, Agg>
where
V: SQLParam + 'a,
V::DialectMarker: PostgresAggregateSupport,
E: Expr<'a, V>,
{
SQLExpr::new(SQL::func("JSONB_AGG", expr.into_expr_sql()))
}
pub fn array_agg<'a, V, E>(expr: E) -> SQLExpr<'a, V, Array<E::SQLType>, Null, Agg>
where
V: SQLParam + 'a,
V::DialectMarker: PostgresAggregateSupport,
E: Expr<'a, V>,
{
SQLExpr::new(SQL::func("ARRAY_AGG", expr.into_expr_sql()))
}
pub fn total<'a, V, E>(
expr: E,
) -> SQLExpr<'a, V, <V::DialectMarker as DialectTypes>::Double, NonNull, Agg>
where
V: SQLParam + 'a,
V::DialectMarker: SQLiteAggregateSupport,
E: Expr<'a, V>,
E::SQLType: Numeric,
{
SQLExpr::new(SQL::func("TOTAL", expr.into_expr_sql()))
}
pub fn group_concat<'a, V, E>(
expr: E,
) -> SQLExpr<'a, V, <V::DialectMarker as DialectTypes>::Text, Null, Agg>
where
V: SQLParam + 'a,
V::DialectMarker: SQLiteAggregateSupport,
E: Expr<'a, V>,
E::SQLType: crate::types::Textual,
{
SQLExpr::new(SQL::func("GROUP_CONCAT", expr.into_expr_sql()))
}
pub fn string_agg<'a, V, E, D>(
expr: E,
delimiter: D,
) -> SQLExpr<'a, V, <V::DialectMarker as DialectTypes>::Text, Null, Agg>
where
V: SQLParam + 'a,
V::DialectMarker: PostgresAggregateSupport,
E: Expr<'a, V>,
E::SQLType: crate::types::Textual,
D: Expr<'a, V>,
D::SQLType: crate::types::Textual,
{
SQLExpr::new(SQL::func(
"STRING_AGG",
expr.into_expr_sql()
.push(crate::Token::COMMA)
.append(delimiter.into_expr_sql()),
))
}
pub fn every<'a, V, E>(
expr: E,
) -> SQLExpr<'a, V, <V::DialectMarker as DialectTypes>::Bool, Null, Agg>
where
V: SQLParam + 'a,
V::DialectMarker: PostgresAggregateSupport,
E: Expr<'a, V>,
E::SQLType: BooleanAggregatePolicy<V::DialectMarker>,
{
SQLExpr::new(SQL::func("EVERY", expr.into_expr_sql()))
}
pub fn json_object_agg<'a, V, K, Val>(
key: K,
value: Val,
) -> SQLExpr<'a, V, <V::DialectMarker as DialectTypes>::Json, Null, Agg>
where
V: SQLParam + 'a,
V::DialectMarker: PostgresAggregateSupport,
K: Expr<'a, V>,
Val: Expr<'a, V>,
{
SQLExpr::new(SQL::func(
"JSON_OBJECT_AGG",
key.into_expr_sql()
.push(crate::Token::COMMA)
.append(value.into_expr_sql()),
))
}
pub fn jsonb_object_agg<'a, V, K, Val>(
key: K,
value: Val,
) -> SQLExpr<'a, V, <V::DialectMarker as DialectTypes>::Jsonb, Null, Agg>
where
V: SQLParam + 'a,
V::DialectMarker: PostgresAggregateSupport,
K: Expr<'a, V>,
Val: Expr<'a, V>,
{
SQLExpr::new(SQL::func(
"JSONB_OBJECT_AGG",
key.into_expr_sql()
.push(crate::Token::COMMA)
.append(value.into_expr_sql()),
))
}
pub fn distinct<'a, V, E>(expr: E) -> SQLExpr<'a, V, E::SQLType, E::Nullable, Scalar>
where
V: SQLParam + 'a,
E: Expr<'a, V>,
{
SQLExpr::new(SQL::raw("DISTINCT").append(expr.into_expr_sql()))
}