use crate::dialect::DialectTypes;
use crate::sql::{SQL, Token};
use crate::traits::SQLParam;
use crate::types::{DataType, Integral, Numeric};
use crate::{PostgresDialect, SQLiteDialect};
use drizzle_types::postgres::types::{Float4, Float8, Int2, Int4, Int8, Numeric as PgNumeric};
use drizzle_types::sqlite::types::{
Integer as SqliteInteger, Numeric as SqliteNumeric, Real as SqliteReal,
};
use super::{AggOr, Expr, NullOr, Nullability, SQLExpr, Scalar};
#[diagnostic::on_unimplemented(
message = "this math function is not available for this dialect",
label = "use a dialect-specific alternative"
)]
pub trait SQLiteMathSupport {}
#[diagnostic::on_unimplemented(
message = "this math function is not available for this dialect",
label = "use a dialect-specific alternative"
)]
pub trait PostgresMathSupport {}
impl SQLiteMathSupport for SQLiteDialect {}
impl PostgresMathSupport for PostgresDialect {}
#[diagnostic::on_unimplemented(
message = "no RANDOM return type defined for this dialect",
label = "RANDOM result type is not configured for this dialect marker"
)]
pub trait RandomPolicy {
type Random: DataType;
}
impl RandomPolicy for SQLiteDialect {
type Random = SqliteInteger;
}
impl RandomPolicy for PostgresDialect {
type Random = drizzle_types::postgres::types::Float8;
}
#[diagnostic::on_unimplemented(
message = "no rounding policy for `{Self}` on this dialect",
label = "round/ceil/floor/trunc return type is not defined for this SQL type/dialect"
)]
pub trait RoundingPolicy<D>: Numeric {
type Output: DataType;
}
impl RoundingPolicy<SQLiteDialect> for SqliteInteger {
type Output = SqliteReal;
}
impl RoundingPolicy<SQLiteDialect> for SqliteReal {
type Output = Self;
}
impl RoundingPolicy<SQLiteDialect> for SqliteNumeric {
type Output = SqliteReal;
}
impl RoundingPolicy<PostgresDialect> for Int2 {
type Output = Float8;
}
impl RoundingPolicy<PostgresDialect> for Int4 {
type Output = Float8;
}
impl RoundingPolicy<PostgresDialect> for Int8 {
type Output = Float8;
}
impl RoundingPolicy<PostgresDialect> for Float4 {
type Output = Float8;
}
impl RoundingPolicy<PostgresDialect> for Float8 {
type Output = Self;
}
impl RoundingPolicy<PostgresDialect> for PgNumeric {
type Output = Float8;
}
pub fn abs<'a, V, E>(expr: E) -> SQLExpr<'a, V, E::SQLType, E::Nullable, E::Aggregate>
where
V: SQLParam + 'a,
E: Expr<'a, V>,
E::SQLType: Numeric,
{
SQLExpr::new(SQL::func("ABS", expr.into_sql()))
}
#[allow(clippy::type_complexity)]
pub fn round<'a, V, E>(
expr: E,
) -> SQLExpr<
'a,
V,
<E::SQLType as RoundingPolicy<V::DialectMarker>>::Output,
E::Nullable,
E::Aggregate,
>
where
V: SQLParam + 'a,
E: Expr<'a, V>,
E::SQLType: RoundingPolicy<V::DialectMarker>,
{
SQLExpr::new(SQL::func("ROUND", expr.into_sql()))
}
#[allow(clippy::type_complexity)]
pub fn round_to<'a, V, E, P>(
expr: E,
precision: P,
) -> SQLExpr<
'a,
V,
<E::SQLType as RoundingPolicy<V::DialectMarker>>::Output,
<E::Nullable as NullOr<P::Nullable>>::Output,
<E::Aggregate as AggOr<P::Aggregate>>::Output,
>
where
V: SQLParam + 'a,
E: Expr<'a, V>,
E::SQLType: RoundingPolicy<V::DialectMarker>,
P: Expr<'a, V>,
P::SQLType: Integral,
E::Nullable: NullOr<P::Nullable>,
P::Nullable: Nullability,
E::Aggregate: AggOr<P::Aggregate>,
{
SQLExpr::new(SQL::func(
"ROUND",
expr.into_sql()
.push(Token::COMMA)
.append(precision.into_sql()),
))
}
#[allow(clippy::type_complexity)]
pub fn ceil<'a, V, E>(
expr: E,
) -> SQLExpr<
'a,
V,
<E::SQLType as RoundingPolicy<V::DialectMarker>>::Output,
E::Nullable,
E::Aggregate,
>
where
V: SQLParam + 'a,
E: Expr<'a, V>,
E::SQLType: RoundingPolicy<V::DialectMarker>,
{
SQLExpr::new(SQL::func("CEIL", expr.into_sql()))
}
#[allow(clippy::type_complexity)]
pub fn floor<'a, V, E>(
expr: E,
) -> SQLExpr<
'a,
V,
<E::SQLType as RoundingPolicy<V::DialectMarker>>::Output,
E::Nullable,
E::Aggregate,
>
where
V: SQLParam + 'a,
E: Expr<'a, V>,
E::SQLType: RoundingPolicy<V::DialectMarker>,
{
SQLExpr::new(SQL::func("FLOOR", expr.into_sql()))
}
#[allow(clippy::type_complexity)]
pub fn trunc<'a, V, E>(
expr: E,
) -> SQLExpr<
'a,
V,
<E::SQLType as RoundingPolicy<V::DialectMarker>>::Output,
E::Nullable,
E::Aggregate,
>
where
V: SQLParam + 'a,
E: Expr<'a, V>,
E::SQLType: RoundingPolicy<V::DialectMarker>,
{
SQLExpr::new(SQL::func("TRUNC", expr.into_sql()))
}
pub fn sqrt<'a, V, E>(
expr: E,
) -> SQLExpr<'a, V, <V::DialectMarker as DialectTypes>::Double, E::Nullable, E::Aggregate>
where
V: SQLParam + 'a,
E: Expr<'a, V>,
E::SQLType: Numeric,
{
SQLExpr::new(SQL::func("SQRT", expr.into_sql()))
}
#[allow(clippy::type_complexity)]
pub fn power<'a, V, E1, E2>(
base: E1,
exponent: E2,
) -> SQLExpr<
'a,
V,
<V::DialectMarker as DialectTypes>::Double,
<E1::Nullable as NullOr<E2::Nullable>>::Output,
<E1::Aggregate as AggOr<E2::Aggregate>>::Output,
>
where
V: SQLParam + 'a,
E1: Expr<'a, V>,
E1::SQLType: Numeric,
E2: Expr<'a, V>,
E2::SQLType: Numeric,
E1::Nullable: NullOr<E2::Nullable>,
E2::Nullable: Nullability,
E1::Aggregate: AggOr<E2::Aggregate>,
{
SQLExpr::new(SQL::func(
"POWER",
base.into_sql()
.push(Token::COMMA)
.append(exponent.into_sql()),
))
}
pub fn exp<'a, V, E>(
expr: E,
) -> SQLExpr<'a, V, <V::DialectMarker as DialectTypes>::Double, E::Nullable, E::Aggregate>
where
V: SQLParam + 'a,
E: Expr<'a, V>,
E::SQLType: Numeric,
{
SQLExpr::new(SQL::func("EXP", expr.into_sql()))
}
pub fn ln<'a, V, E>(
expr: E,
) -> SQLExpr<'a, V, <V::DialectMarker as DialectTypes>::Double, E::Nullable, E::Aggregate>
where
V: SQLParam + 'a,
E: Expr<'a, V>,
E::SQLType: Numeric,
{
SQLExpr::new(SQL::func("LN", expr.into_sql()))
}
pub fn log10<'a, V, E>(
expr: E,
) -> SQLExpr<'a, V, <V::DialectMarker as DialectTypes>::Double, E::Nullable, E::Aggregate>
where
V: SQLParam + 'a,
E: Expr<'a, V>,
E::SQLType: Numeric,
{
SQLExpr::new(SQL::func("LOG10", expr.into_sql()))
}
#[allow(clippy::type_complexity)]
pub fn log<'a, V, E1, E2>(
base: E1,
value: E2,
) -> SQLExpr<
'a,
V,
<V::DialectMarker as DialectTypes>::Double,
<E1::Nullable as NullOr<E2::Nullable>>::Output,
<E1::Aggregate as AggOr<E2::Aggregate>>::Output,
>
where
V: SQLParam + 'a,
E1: Expr<'a, V>,
E1::SQLType: Numeric,
E2: Expr<'a, V>,
E2::SQLType: Numeric,
E1::Nullable: NullOr<E2::Nullable>,
E2::Nullable: Nullability,
E1::Aggregate: AggOr<E2::Aggregate>,
{
SQLExpr::new(SQL::func(
"LOG",
base.into_sql().push(Token::COMMA).append(value.into_sql()),
))
}
pub fn sign<'a, V, E>(
expr: E,
) -> SQLExpr<'a, V, <V::DialectMarker as DialectTypes>::Double, E::Nullable, E::Aggregate>
where
V: SQLParam + 'a,
E: Expr<'a, V>,
E::SQLType: Numeric,
{
SQLExpr::new(SQL::func("SIGN", expr.into_sql()))
}
#[allow(clippy::type_complexity)]
pub fn mod_<'a, V, E1, E2>(
dividend: E1,
divisor: E2,
) -> SQLExpr<
'a,
V,
E1::SQLType,
<E1::Nullable as NullOr<E2::Nullable>>::Output,
<E1::Aggregate as AggOr<E2::Aggregate>>::Output,
>
where
V: SQLParam + 'a,
E1: Expr<'a, V>,
E1::SQLType: Numeric,
E2: Expr<'a, V>,
E2::SQLType: Numeric,
E1::Nullable: NullOr<E2::Nullable>,
E2::Nullable: Nullability,
E1::Aggregate: AggOr<E2::Aggregate>,
{
SQLExpr::new(
dividend
.into_sql()
.push(Token::REM)
.append(divisor.into_sql()),
)
}
#[must_use]
pub fn pi<'a, V>()
-> SQLExpr<'a, V, <V::DialectMarker as DialectTypes>::Double, super::NonNull, Scalar>
where
V: SQLParam + 'a,
V::DialectMarker: PostgresMathSupport,
{
SQLExpr::new(SQL::raw("PI()"))
}
#[must_use]
pub fn random<'a, V>()
-> SQLExpr<'a, V, <V::DialectMarker as RandomPolicy>::Random, super::NonNull, Scalar>
where
V: SQLParam + 'a,
V::DialectMarker: RandomPolicy,
{
SQLExpr::new(SQL::raw("RANDOM()"))
}
pub fn log2<'a, V, E>(
expr: E,
) -> SQLExpr<'a, V, <V::DialectMarker as DialectTypes>::Double, E::Nullable, E::Aggregate>
where
V: SQLParam + 'a,
V::DialectMarker: SQLiteMathSupport,
E: Expr<'a, V>,
E::SQLType: Numeric,
{
SQLExpr::new(SQL::func("LOG2", expr.into_sql()))
}