use crate::utils::{direct_function_translation, wrap_timestamp};
use crate::TranslationRegistry;
use hamelin_lib::func::defs::{
AtTimezone, Day, DayOfWeek, FromMillis, FromNanos, FromUnixtimeMicros, FromUnixtimeMillis,
FromUnixtimeNanos, FromUnixtimeSeconds, Hour, Minute, Month, Now, Second, ToMillis, ToNanos,
ToUnixtime, Today, Tomorrow, Ts, Year, Yesterday,
};
use hamelin_lib::sql::expression::apply::FunctionCallApply;
use hamelin_lib::sql::expression::extract::{ExtractField, ExtractFunction};
use hamelin_lib::sql::expression::literal::{
IntegerLiteral, IntervalLiteral, StringLiteral, TimestampLiteral, Unit,
};
use hamelin_lib::sql::expression::operator::Operator;
use hamelin_lib::sql::expression::{apply::BinaryOperatorApply, Cast, Leaf, SQLExpression};
use hamelin_lib::sql::types::SQLBaseType;
pub fn register(registry: &mut TranslationRegistry) {
registry.register::<Now>(direct_function_translation);
registry.register::<Today>(|_, _| {
Ok(FunctionCallApply::with_two(
"date_trunc",
StringLiteral::new("day").into(),
FunctionCallApply::with_no_arguments("now").into(),
)
.into())
});
registry.register::<Yesterday>(|_, _| {
Ok(FunctionCallApply::with_two(
"date_trunc",
StringLiteral::new("day").into(),
BinaryOperatorApply::new(
Operator::Minus,
FunctionCallApply::with_no_arguments("now").into(),
IntervalLiteral::new("1", Unit::Day).into(),
)
.into(),
)
.into())
});
registry.register::<Tomorrow>(|_, _| {
Ok(FunctionCallApply::with_two(
"date_trunc",
StringLiteral::new("day").into(),
BinaryOperatorApply::new(
Operator::Plus,
FunctionCallApply::with_no_arguments("now").into(),
IntervalLiteral::new("1", Unit::Day).into(),
)
.into(),
)
.into())
});
registry.register::<Ts>(|_, mut bindings| {
let timestamp = bindings.take()?;
match timestamp.sql {
SQLExpression::Leaf(Leaf::StringLiteral(l)) => {
Ok(TimestampLiteral::from_string_literal(&l)?.into())
}
other => Ok(wrap_timestamp(other)),
}
});
registry.register::<Year>(|_, mut bindings| {
let timestamp = bindings.take()?;
Ok(ExtractFunction::new(ExtractField::Year, timestamp.sql).into())
});
registry.register::<Month>(|_, mut bindings| {
let timestamp = bindings.take()?;
Ok(ExtractFunction::new(ExtractField::Month, timestamp.sql).into())
});
registry.register::<Day>(|_, mut bindings| {
let timestamp = bindings.take()?;
Ok(ExtractFunction::new(ExtractField::Day, timestamp.sql).into())
});
registry.register::<DayOfWeek>(|_, mut bindings| {
let timestamp = bindings.take()?;
Ok(ExtractFunction::new(ExtractField::DayOfWeek, timestamp.sql).into())
});
registry.register::<Hour>(|_, mut bindings| {
let timestamp = bindings.take()?;
Ok(ExtractFunction::new(ExtractField::Hour, timestamp.sql).into())
});
registry.register::<Minute>(|_, mut bindings| {
let timestamp = bindings.take()?;
Ok(ExtractFunction::new(ExtractField::Minute, timestamp.sql).into())
});
registry.register::<Second>(|_, mut bindings| {
let timestamp = bindings.take()?;
Ok(ExtractFunction::new(ExtractField::Second, timestamp.sql).into())
});
registry.register::<AtTimezone>(|_, mut bindings| {
let timestamp = bindings.take()?;
let timezone = bindings.take()?;
Ok(FunctionCallApply::with_two("at_timezone", timestamp.sql, timezone.sql).into())
});
registry.register::<ToMillis>(|_, mut bindings| {
let interval = bindings.take()?;
Ok(FunctionCallApply::with_one("to_milliseconds", interval.sql).into())
});
registry.register::<ToNanos>(|_, mut bindings| {
let interval = bindings.take()?;
Ok(BinaryOperatorApply::new(
Operator::Asterisk,
FunctionCallApply::with_one("to_milliseconds", interval.sql).into(),
IntegerLiteral::from_int(1000000).into(),
)
.into())
});
registry.register::<FromMillis>(|_, mut bindings| {
let millis = bindings.take()?;
Ok(BinaryOperatorApply::new(
Operator::Asterisk,
BinaryOperatorApply::new(
Operator::Slash,
Cast::new(millis.sql, SQLBaseType::Double.into()).into(),
IntegerLiteral::from_int(1000).into(),
)
.into(),
IntervalLiteral::new("1", Unit::Second).into(),
)
.into())
});
registry.register::<FromNanos>(|_, mut bindings| {
let nanos = bindings.take()?;
Ok(BinaryOperatorApply::new(
Operator::Asterisk,
BinaryOperatorApply::new(
Operator::Slash,
Cast::new(nanos.sql, SQLBaseType::Double.into()).into(),
IntegerLiteral::from_int(1000000000).into(),
)
.into(),
IntervalLiteral::new("1", Unit::Second).into(),
)
.into())
});
registry.register::<FromUnixtimeSeconds>(|_, mut bindings| {
let seconds = bindings.take()?;
Ok(FunctionCallApply::with_one("from_unixtime", seconds.sql).into())
});
registry.register::<FromUnixtimeMillis>(|_, mut bindings| {
let millis = bindings.take()?;
Ok(FunctionCallApply::with_one(
"from_unixtime_nanos",
BinaryOperatorApply::new(
Operator::Asterisk,
millis.sql,
IntegerLiteral::from_int(1000000).into(),
)
.into(),
)
.into())
});
registry.register::<FromUnixtimeMicros>(|_, mut bindings| {
let micros = bindings.take()?;
Ok(FunctionCallApply::with_one(
"from_unixtime_nanos",
BinaryOperatorApply::new(
Operator::Asterisk,
micros.sql,
IntegerLiteral::from_int(1000).into(),
)
.into(),
)
.into())
});
registry.register::<FromUnixtimeNanos>(direct_function_translation);
registry.register::<ToUnixtime>(direct_function_translation);
}