use core::marker::PhantomData;
use crate::sql::{SQL, Token};
use crate::traits::SQLParam;
use crate::types::{BooleanLike, Compatible, DataType};
use super::null::NullOr;
use super::{AggOr, AggregateKind, Expr, Null, Nullability, SQLExpr};
#[must_use]
pub fn case<'a, V: SQLParam>() -> CaseInit<'a, V> {
CaseInit {
sql: SQL::from(Token::CASE),
_marker: PhantomData,
}
}
pub struct CaseInit<'a, V: SQLParam> {
sql: SQL<'a, V>,
_marker: PhantomData<V>,
}
impl<'a, V: SQLParam + 'a> CaseInit<'a, V> {
#[allow(clippy::type_complexity)]
pub fn when<C, R>(
self,
condition: C,
result: R,
) -> CaseBuilder<'a, V, R::SQLType, R::Nullable, <C::Aggregate as AggOr<R::Aggregate>>::Output>
where
C: Expr<'a, V>,
R: Expr<'a, V>,
C::SQLType: BooleanLike,
C::Aggregate: AggOr<R::Aggregate>,
{
let sql = self
.sql
.push(Token::WHEN)
.append(condition.into_sql())
.push(Token::THEN)
.append(result.into_sql());
CaseBuilder {
sql,
_marker: PhantomData,
}
}
}
pub struct CaseBuilder<'a, V: SQLParam, T: DataType, N: Nullability, A: AggregateKind> {
sql: SQL<'a, V>,
_marker: PhantomData<(V, T, N, A)>,
}
impl<'a, V, T, N, A> CaseBuilder<'a, V, T, N, A>
where
V: SQLParam + 'a,
T: DataType,
N: Nullability,
A: AggregateKind,
{
#[allow(clippy::type_complexity)]
pub fn when<C, R>(
self,
condition: C,
result: R,
) -> CaseBuilder<
'a,
V,
T,
<N as NullOr<R::Nullable>>::Output,
<<A as AggOr<C::Aggregate>>::Output as AggOr<R::Aggregate>>::Output,
>
where
C: Expr<'a, V>,
R: Expr<'a, V>,
C::SQLType: BooleanLike,
T: Compatible<R::SQLType>,
N: NullOr<R::Nullable>,
R::Nullable: Nullability,
A: AggOr<C::Aggregate>,
<A as AggOr<C::Aggregate>>::Output: AggOr<R::Aggregate>,
C::Aggregate: AggregateKind,
R::Aggregate: AggregateKind,
{
let sql = self
.sql
.push(Token::WHEN)
.append(condition.into_sql())
.push(Token::THEN)
.append(result.into_sql());
CaseBuilder {
sql,
_marker: PhantomData,
}
}
pub fn end(self) -> SQLExpr<'a, V, T, Null, A> {
let sql = self.sql.push(Token::END);
SQLExpr::new(sql)
}
#[allow(clippy::type_complexity)]
pub fn r#else<D>(
self,
default: D,
) -> SQLExpr<'a, V, T, <N as NullOr<D::Nullable>>::Output, <A as AggOr<D::Aggregate>>::Output>
where
D: Expr<'a, V>,
T: Compatible<D::SQLType>,
N: NullOr<D::Nullable>,
D::Nullable: Nullability,
A: AggOr<D::Aggregate>,
D::Aggregate: AggregateKind,
{
let sql = self
.sql
.push(Token::ELSE)
.append(default.into_sql())
.push(Token::END);
SQLExpr::new(sql)
}
}