use crate::dialect::DialectTypes;
use crate::sql::{SQL, Token};
use crate::traits::SQLParam;
use crate::types::{DataType, Numeric, Temporal, Textual};
use crate::{PostgresDialect, SQLiteDialect};
use drizzle_types::postgres::types::{Timestamp as PgTimestamp, Timestamptz as PgTimestamptz};
use super::{AggOr, Expr, NullOr, Nullability, SQLExpr, Scalar};
#[diagnostic::on_unimplemented(
message = "this date/time function is not available for this dialect",
label = "use a dialect-specific alternative"
)]
pub trait SQLiteDateTimeSupport {}
#[diagnostic::on_unimplemented(
message = "this date/time function is not available for this dialect",
label = "use a dialect-specific alternative"
)]
pub trait PostgresDateTimeSupport {}
#[diagnostic::on_unimplemented(
message = "DATE_TRUNC output type is not defined for `{Self}` on this dialect",
label = "DATE_TRUNC accepts timestamp/timestamptz and preserves the timestamp flavor"
)]
pub trait DateTruncPolicy<D>: Temporal {
type Output: DataType;
}
impl SQLiteDateTimeSupport for SQLiteDialect {}
impl PostgresDateTimeSupport for PostgresDialect {}
impl DateTruncPolicy<PostgresDialect> for PgTimestamptz {
type Output = Self;
}
impl DateTruncPolicy<PostgresDialect> for PgTimestamp {
type Output = Self;
}
#[must_use]
pub fn current_date<'a, V>()
-> SQLExpr<'a, V, <V::DialectMarker as DialectTypes>::Date, super::NonNull, Scalar>
where
V: SQLParam + 'a,
{
SQLExpr::new(SQL::raw("CURRENT_DATE"))
}
#[must_use]
pub fn current_time<'a, V>()
-> SQLExpr<'a, V, <V::DialectMarker as DialectTypes>::Time, super::NonNull, Scalar>
where
V: SQLParam + 'a,
{
SQLExpr::new(SQL::raw("CURRENT_TIME"))
}
#[must_use]
pub fn current_timestamp<'a, V>()
-> SQLExpr<'a, V, <V::DialectMarker as DialectTypes>::TimestampTz, super::NonNull, Scalar>
where
V: SQLParam + 'a,
{
SQLExpr::new(SQL::raw("CURRENT_TIMESTAMP"))
}
pub fn date<'a, V, E>(
expr: E,
) -> SQLExpr<'a, V, <V::DialectMarker as DialectTypes>::Date, E::Nullable, E::Aggregate>
where
V: SQLParam + 'a,
V::DialectMarker: SQLiteDateTimeSupport,
E: Expr<'a, V>,
E::SQLType: Temporal,
{
SQLExpr::new(SQL::func("DATE", expr.into_sql()))
}
pub fn time<'a, V, E>(
expr: E,
) -> SQLExpr<'a, V, <V::DialectMarker as DialectTypes>::Time, E::Nullable, E::Aggregate>
where
V: SQLParam + 'a,
V::DialectMarker: SQLiteDateTimeSupport,
E: Expr<'a, V>,
E::SQLType: Temporal,
{
SQLExpr::new(SQL::func("TIME", expr.into_sql()))
}
pub fn datetime<'a, V, E>(
expr: E,
) -> SQLExpr<'a, V, <V::DialectMarker as DialectTypes>::Timestamp, E::Nullable, E::Aggregate>
where
V: SQLParam + 'a,
V::DialectMarker: SQLiteDateTimeSupport,
E: Expr<'a, V>,
E::SQLType: Temporal,
{
SQLExpr::new(SQL::func("DATETIME", expr.into_sql()))
}
#[allow(clippy::type_complexity)]
pub fn strftime<'a, V, F, E>(
format: F,
expr: E,
) -> SQLExpr<
'a,
V,
<V::DialectMarker as DialectTypes>::Text,
E::Nullable,
<F::Aggregate as AggOr<E::Aggregate>>::Output,
>
where
V: SQLParam + 'a,
V::DialectMarker: SQLiteDateTimeSupport,
F: Expr<'a, V>,
F::SQLType: Textual,
E: Expr<'a, V>,
E::SQLType: Temporal,
F::Aggregate: AggOr<E::Aggregate>,
{
SQLExpr::new(SQL::func(
"STRFTIME",
format.into_sql().push(Token::COMMA).append(expr.into_sql()),
))
}
pub fn julianday<'a, V, E>(
expr: E,
) -> SQLExpr<'a, V, <V::DialectMarker as DialectTypes>::Double, E::Nullable, E::Aggregate>
where
V: SQLParam + 'a,
V::DialectMarker: SQLiteDateTimeSupport,
E: Expr<'a, V>,
E::SQLType: Temporal,
{
SQLExpr::new(SQL::func("JULIANDAY", expr.into_sql()))
}
pub fn unixepoch<'a, V, E>(
expr: E,
) -> SQLExpr<'a, V, <V::DialectMarker as DialectTypes>::BigInt, E::Nullable, E::Aggregate>
where
V: SQLParam + 'a,
V::DialectMarker: SQLiteDateTimeSupport,
E: Expr<'a, V>,
E::SQLType: Temporal,
{
SQLExpr::new(SQL::func("UNIXEPOCH", expr.into_sql()))
}
#[must_use]
pub fn now<'a, V>()
-> SQLExpr<'a, V, <V::DialectMarker as DialectTypes>::TimestampTz, super::NonNull, Scalar>
where
V: SQLParam + 'a,
V::DialectMarker: PostgresDateTimeSupport,
{
SQLExpr::new(SQL::raw("NOW()"))
}
#[allow(clippy::type_complexity)]
pub fn date_trunc<'a, V, P, E>(
precision: P,
expr: E,
) -> SQLExpr<
'a,
V,
<E::SQLType as DateTruncPolicy<V::DialectMarker>>::Output,
E::Nullable,
<P::Aggregate as AggOr<E::Aggregate>>::Output,
>
where
V: SQLParam + 'a,
V::DialectMarker: PostgresDateTimeSupport,
P: Expr<'a, V>,
P::SQLType: Textual,
E: Expr<'a, V>,
E::SQLType: DateTruncPolicy<V::DialectMarker>,
P::Aggregate: AggOr<E::Aggregate>,
{
SQLExpr::new(SQL::func(
"DATE_TRUNC",
precision
.into_sql()
.push(Token::COMMA)
.append(expr.into_sql()),
))
}
pub fn extract<'a, 'f, V, E>(
field: &'f str,
expr: E,
) -> SQLExpr<'a, V, <V::DialectMarker as DialectTypes>::Double, E::Nullable, E::Aggregate>
where
'f: 'a,
V: SQLParam + 'a,
V::DialectMarker: PostgresDateTimeSupport,
E: Expr<'a, V>,
E::SQLType: Temporal,
{
SQLExpr::new(
SQL::raw("EXTRACT(")
.append(SQL::raw(field))
.append(SQL::raw(" FROM "))
.append(expr.into_sql())
.push(Token::RPAREN),
)
}
#[allow(clippy::type_complexity)]
pub fn age<'a, V, E1, E2>(
timestamp1: E1,
timestamp2: E2,
) -> SQLExpr<
'a,
V,
drizzle_types::postgres::types::Interval,
<E1::Nullable as NullOr<E2::Nullable>>::Output,
<E1::Aggregate as AggOr<E2::Aggregate>>::Output,
>
where
V: SQLParam + 'a,
V::DialectMarker: PostgresDateTimeSupport,
E1: Expr<'a, V>,
E1::SQLType: Temporal,
E2: Expr<'a, V>,
E2::SQLType: Temporal,
E1::Nullable: NullOr<E2::Nullable>,
E2::Nullable: Nullability,
E1::Aggregate: AggOr<E2::Aggregate>,
{
SQLExpr::new(SQL::func(
"AGE",
timestamp1
.into_sql()
.push(Token::COMMA)
.append(timestamp2.into_sql()),
))
}
#[allow(clippy::type_complexity)]
pub fn to_char<'a, V, E, F>(
expr: E,
format: F,
) -> SQLExpr<
'a,
V,
<V::DialectMarker as DialectTypes>::Text,
E::Nullable,
<E::Aggregate as AggOr<F::Aggregate>>::Output,
>
where
V: SQLParam + 'a,
V::DialectMarker: PostgresDateTimeSupport,
E: Expr<'a, V>,
E::SQLType: Temporal,
F: Expr<'a, V>,
F::SQLType: Textual,
E::Aggregate: AggOr<F::Aggregate>,
{
SQLExpr::new(SQL::func(
"TO_CHAR",
expr.into_sql().push(Token::COMMA).append(format.into_sql()),
))
}
pub fn to_timestamp<'a, V, E>(expr: E) -> SQLExpr<'a, V, PgTimestamptz, E::Nullable, E::Aggregate>
where
V: SQLParam + 'a,
V::DialectMarker: PostgresDateTimeSupport,
E: Expr<'a, V>,
E::SQLType: Numeric,
{
SQLExpr::new(SQL::func("TO_TIMESTAMP", expr.into_sql()))
}
#[allow(clippy::type_complexity)]
pub fn to_date<'a, V, E, F>(
expr: E,
format: F,
) -> SQLExpr<
'a,
V,
<V::DialectMarker as DialectTypes>::Date,
E::Nullable,
<E::Aggregate as AggOr<F::Aggregate>>::Output,
>
where
V: SQLParam + 'a,
V::DialectMarker: PostgresDateTimeSupport,
E: Expr<'a, V>,
E::SQLType: Textual,
F: Expr<'a, V>,
F::SQLType: Textual,
E::Aggregate: AggOr<F::Aggregate>,
{
SQLExpr::new(SQL::func(
"TO_DATE",
expr.into_sql().push(Token::COMMA).append(format.into_sql()),
))
}
#[allow(clippy::type_complexity)]
pub fn to_number<'a, V, E, F>(
expr: E,
format: F,
) -> SQLExpr<
'a,
V,
drizzle_types::postgres::types::Numeric,
E::Nullable,
<E::Aggregate as AggOr<F::Aggregate>>::Output,
>
where
V: SQLParam + 'a,
V::DialectMarker: PostgresDateTimeSupport,
E: Expr<'a, V>,
E::SQLType: Textual,
F: Expr<'a, V>,
F::SQLType: Textual,
E::Aggregate: AggOr<F::Aggregate>,
{
SQLExpr::new(SQL::func(
"TO_NUMBER",
expr.into_sql().push(Token::COMMA).append(format.into_sql()),
))
}
#[allow(clippy::type_complexity)]
pub fn date_bin<'a, V, S, E, O>(
stride: S,
source: E,
origin: O,
) -> SQLExpr<
'a,
V,
E::SQLType,
<<S::Nullable as NullOr<E::Nullable>>::Output as NullOr<O::Nullable>>::Output,
<<S::Aggregate as AggOr<E::Aggregate>>::Output as AggOr<O::Aggregate>>::Output,
>
where
V: SQLParam + 'a,
V::DialectMarker: PostgresDateTimeSupport,
S: Expr<'a, V>,
E: Expr<'a, V>,
E::SQLType: Temporal,
O: Expr<'a, V>,
O::SQLType: Temporal,
S::Nullable: NullOr<E::Nullable>,
E::Nullable: Nullability,
<S::Nullable as NullOr<E::Nullable>>::Output: NullOr<O::Nullable>,
O::Nullable: Nullability,
S::Aggregate: AggOr<E::Aggregate>,
<S::Aggregate as AggOr<E::Aggregate>>::Output: AggOr<O::Aggregate>,
O::Aggregate: super::AggregateKind,
{
SQLExpr::new(SQL::func(
"DATE_BIN",
stride
.into_sql()
.push(Token::COMMA)
.append(source.into_sql())
.push(Token::COMMA)
.append(origin.into_sql()),
))
}
#[allow(clippy::type_complexity)]
pub fn make_date<'a, V, Y, M, D>(
year: Y,
month: M,
day: D,
) -> SQLExpr<
'a,
V,
<V::DialectMarker as DialectTypes>::Date,
<<Y::Nullable as NullOr<M::Nullable>>::Output as NullOr<D::Nullable>>::Output,
<<Y::Aggregate as AggOr<M::Aggregate>>::Output as AggOr<D::Aggregate>>::Output,
>
where
V: SQLParam + 'a,
V::DialectMarker: PostgresDateTimeSupport,
Y: Expr<'a, V>,
Y::SQLType: Numeric,
M: Expr<'a, V>,
M::SQLType: Numeric,
D: Expr<'a, V>,
D::SQLType: Numeric,
Y::Nullable: NullOr<M::Nullable>,
M::Nullable: Nullability,
<Y::Nullable as NullOr<M::Nullable>>::Output: NullOr<D::Nullable>,
D::Nullable: Nullability,
Y::Aggregate: AggOr<M::Aggregate>,
<Y::Aggregate as AggOr<M::Aggregate>>::Output: AggOr<D::Aggregate>,
D::Aggregate: super::AggregateKind,
{
SQLExpr::new(SQL::func(
"MAKE_DATE",
year.into_sql()
.push(Token::COMMA)
.append(month.into_sql())
.push(Token::COMMA)
.append(day.into_sql()),
))
}
#[allow(clippy::type_complexity)]
pub fn make_timestamp<'a, V, Y, Mo, D, H, Mi, S>(
year: Y,
month: Mo,
day: D,
hour: H,
minute: Mi,
second: S,
) -> SQLExpr<
'a,
V,
<V::DialectMarker as DialectTypes>::Timestamp,
<<<<Y::Nullable as NullOr<Mo::Nullable>>::Output as NullOr<D::Nullable>>::Output as NullOr<
H::Nullable,
>>::Output as NullOr<<Mi::Nullable as NullOr<S::Nullable>>::Output>>::Output,
<<<<Y::Aggregate as AggOr<Mo::Aggregate>>::Output as AggOr<D::Aggregate>>::Output as AggOr<
H::Aggregate,
>>::Output as AggOr<<Mi::Aggregate as AggOr<S::Aggregate>>::Output>>::Output,
>
where
V: SQLParam + 'a,
V::DialectMarker: PostgresDateTimeSupport,
Y: Expr<'a, V>,
Y::SQLType: Numeric,
Mo: Expr<'a, V>,
Mo::SQLType: Numeric,
D: Expr<'a, V>,
D::SQLType: Numeric,
H: Expr<'a, V>,
H::SQLType: Numeric,
Mi: Expr<'a, V>,
Mi::SQLType: Numeric,
S: Expr<'a, V>,
S::SQLType: Numeric,
Y::Nullable: NullOr<Mo::Nullable>,
<Y::Nullable as NullOr<Mo::Nullable>>::Output: NullOr<D::Nullable>,
<<Y::Nullable as NullOr<Mo::Nullable>>::Output as NullOr<D::Nullable>>::Output:
NullOr<H::Nullable>,
Mi::Nullable: NullOr<S::Nullable>,
<<<Y::Nullable as NullOr<Mo::Nullable>>::Output as NullOr<D::Nullable>>::Output as NullOr<
H::Nullable,
>>::Output: NullOr<<Mi::Nullable as NullOr<S::Nullable>>::Output>,
H::Nullable: Nullability,
D::Nullable: Nullability,
Mo::Nullable: Nullability,
S::Nullable: Nullability,
Y::Aggregate: AggOr<Mo::Aggregate>,
<Y::Aggregate as AggOr<Mo::Aggregate>>::Output: AggOr<D::Aggregate>,
<<Y::Aggregate as AggOr<Mo::Aggregate>>::Output as AggOr<D::Aggregate>>::Output:
AggOr<H::Aggregate>,
Mi::Aggregate: AggOr<S::Aggregate>,
<<<Y::Aggregate as AggOr<Mo::Aggregate>>::Output as AggOr<D::Aggregate>>::Output as AggOr<
H::Aggregate,
>>::Output: AggOr<<Mi::Aggregate as AggOr<S::Aggregate>>::Output>,
H::Aggregate: super::AggregateKind,
D::Aggregate: super::AggregateKind,
S::Aggregate: super::AggregateKind,
{
SQLExpr::new(SQL::func(
"MAKE_TIMESTAMP",
year.into_sql()
.push(Token::COMMA)
.append(month.into_sql())
.push(Token::COMMA)
.append(day.into_sql())
.push(Token::COMMA)
.append(hour.into_sql())
.push(Token::COMMA)
.append(minute.into_sql())
.push(Token::COMMA)
.append(second.into_sql()),
))
}
#[must_use]
pub fn localtime<'a, V>()
-> SQLExpr<'a, V, <V::DialectMarker as DialectTypes>::Time, super::NonNull, Scalar>
where
V: SQLParam + 'a,
V::DialectMarker: PostgresDateTimeSupport,
{
SQLExpr::new(SQL::raw("LOCALTIME"))
}
#[must_use]
pub fn localtimestamp<'a, V>() -> SQLExpr<'a, V, PgTimestamp, super::NonNull, Scalar>
where
V: SQLParam + 'a,
V::DialectMarker: PostgresDateTimeSupport,
{
SQLExpr::new(SQL::raw("LOCALTIMESTAMP"))
}
#[must_use]
pub fn clock_timestamp<'a, V>() -> SQLExpr<'a, V, PgTimestamptz, super::NonNull, Scalar>
where
V: SQLParam + 'a,
V::DialectMarker: PostgresDateTimeSupport,
{
SQLExpr::new(SQL::raw("CLOCK_TIMESTAMP()"))
}
#[allow(clippy::type_complexity)]
pub fn timediff<'a, V, E1, E2>(
time1: E1,
time2: E2,
) -> SQLExpr<
'a,
V,
<V::DialectMarker as DialectTypes>::Text,
<E1::Nullable as NullOr<E2::Nullable>>::Output,
<E1::Aggregate as AggOr<E2::Aggregate>>::Output,
>
where
V: SQLParam + 'a,
V::DialectMarker: SQLiteDateTimeSupport,
E1: Expr<'a, V>,
E1::SQLType: Temporal,
E2: Expr<'a, V>,
E2::SQLType: Temporal,
E1::Nullable: NullOr<E2::Nullable>,
E2::Nullable: Nullability,
E1::Aggregate: AggOr<E2::Aggregate>,
{
SQLExpr::new(SQL::func(
"TIMEDIFF",
time1.into_sql().push(Token::COMMA).append(time2.into_sql()),
))
}