use crate::PostgresDialect;
use crate::sql::{SQL, Token};
use crate::traits::SQLParam;
use crate::types::Compatible;
use super::{AggOr, AggregateKind, Expr, NonNull, Null, Nullability, SQLExpr};
pub trait NullOr<Rhs: Nullability>: Nullability {
type Output: Nullability;
}
impl NullOr<Self> for NonNull {
type Output = Self;
}
impl NullOr<Null> for NonNull {
type Output = Null;
}
impl NullOr<NonNull> for Null {
type Output = Self;
}
impl NullOr<Self> for Null {
type Output = Self;
}
pub trait NullAnd<Rhs: Nullability>: Nullability {
type Output: Nullability;
}
impl NullAnd<Self> for NonNull {
type Output = Self;
}
impl NullAnd<Null> for NonNull {
type Output = Self;
}
impl NullAnd<NonNull> for Null {
type Output = NonNull;
}
impl NullAnd<Self> for Null {
type Output = Self;
}
#[allow(clippy::type_complexity)]
pub fn coalesce<'a, V, E, D, N>(
expr: E,
default: D,
) -> SQLExpr<'a, V, E::SQLType, N, <E::Aggregate as AggOr<D::Aggregate>>::Output>
where
V: SQLParam + 'a,
E: Expr<'a, V>,
D: Expr<'a, V>,
N: Nullability,
E::SQLType: Compatible<D::SQLType>,
E::Nullable: NullAnd<D::Nullable, Output = N>,
D::Nullable: Nullability,
E::Aggregate: AggOr<D::Aggregate>,
D::Aggregate: AggregateKind,
{
SQLExpr::new(SQL::func(
"COALESCE",
expr.into_expr_sql()
.push(Token::COMMA)
.append(default.into_expr_sql()),
))
}
#[allow(clippy::type_complexity)]
pub fn coalesce_many<'a, V, E, I, N>(
first: E,
rest: I,
) -> SQLExpr<
'a,
V,
E::SQLType,
N,
<E::Aggregate as AggOr<<I::Item as Expr<'a, V>>::Aggregate>>::Output,
>
where
V: SQLParam + 'a,
E: Expr<'a, V>,
N: Nullability,
I: IntoIterator,
I::Item: Expr<'a, V>,
E::SQLType: Compatible<<I::Item as Expr<'a, V>>::SQLType>,
E::Nullable: NullAnd<<I::Item as Expr<'a, V>>::Nullable, Output = N>,
<I::Item as Expr<'a, V>>::Nullable: Nullability,
E::Aggregate: AggOr<<I::Item as Expr<'a, V>>::Aggregate>,
<I::Item as Expr<'a, V>>::Aggregate: AggregateKind,
{
let mut sql = first.into_expr_sql();
for value in rest {
sql = sql.push(Token::COMMA).append(value.into_expr_sql());
}
SQLExpr::new(SQL::func("COALESCE", sql))
}
#[allow(clippy::type_complexity)]
pub fn nullif<'a, V, E1, E2>(
expr1: E1,
expr2: E2,
) -> SQLExpr<'a, V, E1::SQLType, Null, <E1::Aggregate as AggOr<E2::Aggregate>>::Output>
where
V: SQLParam + 'a,
E1: Expr<'a, V>,
E2: Expr<'a, V>,
E1::SQLType: Compatible<E2::SQLType>,
E1::Aggregate: AggOr<E2::Aggregate>,
E2::Aggregate: AggregateKind,
{
SQLExpr::new(SQL::func(
"NULLIF",
expr1
.into_expr_sql()
.push(Token::COMMA)
.append(expr2.into_expr_sql()),
))
}
#[allow(clippy::type_complexity)]
pub fn ifnull<'a, V, E, D, N>(
expr: E,
default: D,
) -> SQLExpr<'a, V, E::SQLType, N, <E::Aggregate as AggOr<D::Aggregate>>::Output>
where
V: SQLParam + 'a,
E: Expr<'a, V>,
D: Expr<'a, V>,
N: Nullability,
E::SQLType: Compatible<D::SQLType>,
E::Nullable: NullAnd<D::Nullable, Output = N>,
D::Nullable: Nullability,
E::Aggregate: AggOr<D::Aggregate>,
D::Aggregate: AggregateKind,
{
SQLExpr::new(SQL::func(
"IFNULL",
expr.into_expr_sql()
.push(Token::COMMA)
.append(default.into_expr_sql()),
))
}
pub trait PostgresNullSupport {}
impl PostgresNullSupport for PostgresDialect {}
#[allow(clippy::type_complexity)]
pub fn greatest<'a, V, L, R>(
left: L,
right: R,
) -> SQLExpr<
'a,
V,
L::SQLType,
<L::Nullable as NullAnd<R::Nullable>>::Output,
<L::Aggregate as AggOr<R::Aggregate>>::Output,
>
where
V: SQLParam + 'a,
V::DialectMarker: PostgresNullSupport,
L: Expr<'a, V>,
R: Expr<'a, V>,
L::SQLType: Compatible<R::SQLType>,
L::Nullable: NullAnd<R::Nullable>,
R::Nullable: Nullability,
L::Aggregate: AggOr<R::Aggregate>,
R::Aggregate: AggregateKind,
{
SQLExpr::new(SQL::func(
"GREATEST",
left.into_expr_sql()
.push(Token::COMMA)
.append(right.into_expr_sql()),
))
}
#[allow(clippy::type_complexity)]
pub fn least<'a, V, L, R>(
left: L,
right: R,
) -> SQLExpr<
'a,
V,
L::SQLType,
<L::Nullable as NullAnd<R::Nullable>>::Output,
<L::Aggregate as AggOr<R::Aggregate>>::Output,
>
where
V: SQLParam + 'a,
V::DialectMarker: PostgresNullSupport,
L: Expr<'a, V>,
R: Expr<'a, V>,
L::SQLType: Compatible<R::SQLType>,
L::Nullable: NullAnd<R::Nullable>,
R::Nullable: Nullability,
L::Aggregate: AggOr<R::Aggregate>,
R::Aggregate: AggregateKind,
{
SQLExpr::new(SQL::func(
"LEAST",
left.into_expr_sql()
.push(Token::COMMA)
.append(right.into_expr_sql()),
))
}