diff --git a/CHANGELOG.md b/CHANGELOG.md index d94e1132..90c5724f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Changed - some cleaning in the translation of Expr -> ast::Expr [#204](https://github.com/Qrlew/qrlew/issues/204) ## Added +- implemented `DAYNAME`, `FROM_UNIXTIME`, `UNIX_TIMESTAMP`, `DATETIME_DIFF`, `QUARTER` and `DATE_FORMAT` [#202](https://github.com/Qrlew/qrlew/issues/202) - implemented `CURRENT_DATE`, `CURRENT_TIME`, `CURRENT_TIMESTAMP` and `EXTRACT(datepart FROM col)` [#200](https://github.com/Qrlew/qrlew/issues/200) - implemented `DISTINCT` in aggregations [#197](https://github.com/Qrlew/qrlew/issues/197) - Implemented math functions: `PI`, `DEGREES`, `TAN`, `RANDOM`, `LOG10`, `LOG2`, `SQUARE` [#196](https://github.com/Qrlew/qrlew/issues/196) diff --git a/src/data_type/function.rs b/src/data_type/function.rs index c21729a1..987889ac 100644 --- a/src/data_type/function.rs +++ b/src/data_type/function.rs @@ -1157,10 +1157,10 @@ pub fn cast(into: DataType) -> impl Function { match into { DataType::Text(t) if t == data_type::Text::full() => { Pointwise::univariate( - //DataType::Any, DataType::Any, DataType::text(), - |v| v.to_string().into()) + |v| v.to_string().into() + ) } DataType::Float(f) if f == data_type::Float::full() => { Pointwise::univariate( @@ -1203,27 +1203,6 @@ pub fn cast(into: DataType) -> impl Function { } ) } - DataType::Date(d) if d == data_type::Date::full() => { - Pointwise::univariate( - DataType::text(), - DataType::date(), - |v| unimplemented!() - ) - } - DataType::DateTime(d) if d == data_type::DateTime::full() => { - Pointwise::univariate( - DataType::text(), - DataType::date_time(), - |v| unimplemented!() - ) - } - DataType::Time(t) if t == data_type::Time::full() => { - Pointwise::univariate( - DataType::text(), - DataType::time(), - |v| unimplemented!() - ) - } _ => todo!(), } } @@ -1789,7 +1768,7 @@ pub fn regexp_contains() -> impl Function { Unimplemented::new( DataType::structured_from_data_types([DataType::text(), DataType::text()]), DataType::boolean(), - Arc::new(Mutex::new(RefCell::new(|v| unimplemented!()))) + Arc::new(Mutex::new(RefCell::new(|_| unimplemented!()))) ) } @@ -1798,7 +1777,7 @@ pub fn regexp_extract() -> impl Function { Unimplemented::new( DataType::structured_from_data_types([DataType::text(), DataType::text(), DataType::integer(), DataType::integer()]), DataType::optional(DataType::text()), - Arc::new(Mutex::new(RefCell::new(|v| unimplemented!()))) + Arc::new(Mutex::new(RefCell::new(|_| unimplemented!()))) ) } @@ -1807,7 +1786,7 @@ pub fn regexp_replace() -> impl Function { Unimplemented::new( DataType::structured_from_data_types([DataType::text(), DataType::text(), DataType::text()]), DataType::text(), - Arc::new(Mutex::new(RefCell::new(|v| unimplemented!()))) + Arc::new(Mutex::new(RefCell::new(|_| unimplemented!()))) ) } @@ -1816,7 +1795,7 @@ pub fn newid() -> impl Function { Unimplemented::new( DataType::unit(), DataType::text(), - Arc::new(Mutex::new(RefCell::new(|v| unimplemented!()))) + Arc::new(Mutex::new(RefCell::new(|_| unimplemented!()))) ) } @@ -1825,7 +1804,7 @@ pub fn encode() -> impl Function { Unimplemented::new( DataType::structured_from_data_types([DataType::text(), DataType::text()]), DataType::text(), - Arc::new(Mutex::new(RefCell::new(|v| unimplemented!()))) + Arc::new(Mutex::new(RefCell::new(|_| unimplemented!()))) ) } @@ -1834,7 +1813,7 @@ pub fn decode() -> impl Function { Unimplemented::new( DataType::structured_from_data_types([DataType::text(), DataType::text()]), DataType::text(), - Arc::new(Mutex::new(RefCell::new(|v| unimplemented!()))) + Arc::new(Mutex::new(RefCell::new(|_| unimplemented!()))) ) } @@ -1843,7 +1822,7 @@ pub fn unhex() -> impl Function { Unimplemented::new( DataType::text(), DataType::text(), - Arc::new(Mutex::new(RefCell::new(|v| unimplemented!()))) + Arc::new(Mutex::new(RefCell::new(|_| unimplemented!()))) ) } @@ -1852,7 +1831,7 @@ pub fn current_date() -> impl Function { Unimplemented::new( DataType::unit(), DataType::date(), - Arc::new(Mutex::new(RefCell::new(|v| unimplemented!()))) + Arc::new(Mutex::new(RefCell::new(|_| unimplemented!()))) ) } @@ -1860,7 +1839,7 @@ pub fn current_time() -> impl Function { Unimplemented::new( DataType::unit(), DataType::time(), - Arc::new(Mutex::new(RefCell::new(|v| unimplemented!()))) + Arc::new(Mutex::new(RefCell::new(|_| unimplemented!()))) ) } @@ -1868,7 +1847,7 @@ pub fn current_timestamp() -> impl Function { Unimplemented::new( DataType::unit(), DataType::date_time(), - Arc::new(Mutex::new(RefCell::new(|v| unimplemented!()))) + Arc::new(Mutex::new(RefCell::new(|_| unimplemented!()))) ) } @@ -2022,6 +2001,147 @@ pub fn extract_millisecond() -> impl Function { )) } +pub fn dayname() -> impl Function { + Polymorphic::from(( + Pointwise::univariate( + data_type::Date::default(), + DataType::text_values(["Monday".to_string(), "Tuesday".to_string(), "Wednesday".to_string(), "Thursday".to_string(), "Friday".to_string(), "Saturday".to_string(), "Sunday".to_string()]), + |a| (match a.weekday(){ + chrono::Weekday::Mon => "Monday", + chrono::Weekday::Tue => "Tuesday", + chrono::Weekday::Wed => "Wednesday", + chrono::Weekday::Thu => "Thursday", + chrono::Weekday::Fri => "Friday", + chrono::Weekday::Sat => "Saturday", + chrono::Weekday::Sun => "Sunday", + }).to_string().into(), + ), + Pointwise::univariate( + data_type::DateTime::default(), + DataType::text_values(["Monday".to_string(), "Tuesday".to_string(), "Wednesday".to_string(), "Thursday".to_string(), "Friday".to_string(), "Saturday".to_string(), "Sunday".to_string()]), + |a| (match a.weekday(){ + chrono::Weekday::Mon => "Monday", + chrono::Weekday::Tue => "Tuesday", + chrono::Weekday::Wed => "Wednesday", + chrono::Weekday::Thu => "Thursday", + chrono::Weekday::Fri => "Friday", + chrono::Weekday::Sat => "Saturday", + chrono::Weekday::Sun => "Sunday", + }).to_string().into(), + ), + )) +} + +// MySQL FROM_UNIXTIME +pub fn from_unixtime() -> impl Function { + Unimplemented::new( + DataType::structured_from_data_types([DataType::integer(), DataType::text()]), + DataType::sum([DataType::date(), DataType::date_time()]), + Arc::new(Mutex::new(RefCell::new(|_| unimplemented!()))) + ) +} + +// MySQL UNIX_TIMESTAMP +pub fn unix_timestamp() -> impl Function { + Unimplemented::new( + DataType::sum([DataType::date(), DataType::date_time()]), + DataType::integer(), + Arc::new(Mutex::new(RefCell::new(|_| unimplemented!()))) + ) +} + +// MySQL DATE_FORMAT +pub fn date_format() -> impl Function { + Unimplemented::new( + DataType::structured_from_data_types([ + DataType::sum([DataType::date(), DataType::date_time(), DataType::text()]), + DataType::text() + ]), + DataType::text(), + Arc::new(Mutex::new(RefCell::new(|_| unimplemented!()))) + ) +} + +// MySQL Quarter +pub fn quarter() -> impl Function { + Polymorphic::from(( + Pointwise::univariate( + data_type::Date::default(), + DataType::integer_interval(1, 4), + |a| match a.month() { + 1..=3 => 1, + 4..=6 => 2, + 7..=9 => 3, + _ => 4, + }.into() + ), + Pointwise::univariate( + data_type::DateTime::default(), + DataType::integer_interval(1, 4), + |a| match a.month() { + 1..=3 => 1, + 4..=6 => 2, + 7..=9 => 3, + _ => 4, + }.into() + ), + )) +} + +// BigQuery DATETIME_DIFF +// MySQL Quarter +pub fn datetime_diff() -> impl Function { + Unimplemented::new( + DataType::structured_from_data_types([ + DataType::sum([DataType::date(), DataType::date_time(), DataType::text()]), + DataType::sum([DataType::date(), DataType::date_time(), DataType::text()]), + DataType::text() + ]), + DataType::integer(), + Arc::new(Mutex::new(RefCell::new(|_| unimplemented!()))) + ) +} + +// MySQL DATE +pub fn date() -> impl Function { + Polymorphic::from(( + Pointwise::univariate( + data_type::Date::default(), + data_type::Date::default(), + |a| a.into(), + ), + Pointwise::univariate( + data_type::DateTime::default(), + data_type::Date::default(), + |a| a.date().into(), + ), + )) +} + +pub fn cast_as_date() -> impl Function { + Unimplemented::new( + DataType::sum([DataType::text(), DataType::date_time()]), + DataType::date(), + Arc::new(Mutex::new(RefCell::new(|_| unimplemented!()))) + ) +} + +pub fn cast_as_datetime() -> impl Function { + Unimplemented::new( + DataType::sum([DataType::text(), DataType::date()]), + DataType::date(), + Arc::new(Mutex::new(RefCell::new(|_| unimplemented!()))) + ) +} + +pub fn cast_as_time() -> impl Function { + Unimplemented::new( + DataType::sum([DataType::text(), DataType::date_time()]), + DataType::date_time(), + Arc::new(Mutex::new(RefCell::new(|_| unimplemented!()))) + ) +} + // Case function pub fn case() -> impl Function { Case @@ -4256,4 +4376,76 @@ mod tests { println!("im({}) = {}", set, im); assert!(im == DataType::float_values([1000.000, 11000.000])); } + + #[test] + fn test_dayname() { + println!("\nTest dayname"); + let fun = dayname(); + println!("type = {}", fun); + println!("domain = {}", fun.domain()); + println!("co_domain = {}", fun.co_domain()); + println!("data_type = {}", fun.data_type()); + + let set = DataType::date_value( + NaiveDate::from_ymd_opt(2023, 01, 01).unwrap(), + ); + let im = fun.super_image(&set).unwrap(); + println!("im({}) = {}", set, im); + assert!(im == DataType::text_value("Sunday".to_string())); + + let set = DataType::date_time_value( + NaiveDate::from_ymd_opt(2026, 7, 8).unwrap().and_hms_opt(9, 15, 11).unwrap(), + ); + let im = fun.super_image(&set).unwrap(); + println!("im({}) = {}", set, im); + assert!(im == DataType::text_value("Wednesday".to_string())); + } + + #[test] + fn test_quarter() { + println!("\nTest quarter"); + let fun = quarter(); + println!("type = {}", fun); + println!("domain = {}", fun.domain()); + println!("co_domain = {}", fun.co_domain()); + println!("data_type = {}", fun.data_type()); + + let set = DataType::date_value( + NaiveDate::from_ymd_opt(2023, 01, 01).unwrap(), + ); + let im = fun.super_image(&set).unwrap(); + println!("im({}) = {}", set, im); + assert!(im == DataType::integer_value(1)); + + let set = DataType::date_time_value( + NaiveDate::from_ymd_opt(2026, 7, 8).unwrap().and_hms_opt(9, 15, 11).unwrap(), + ); + let im = fun.super_image(&set).unwrap(); + println!("im({}) = {}", set, im); + assert!(im == DataType::integer_value(3)); + } + + #[test] + fn test_date() { + println!("\nTest date"); + let fun = date(); + println!("type = {}", fun); + println!("domain = {}", fun.domain()); + println!("co_domain = {}", fun.co_domain()); + println!("data_type = {}", fun.data_type()); + + let set = DataType::date_value( + NaiveDate::from_ymd_opt(2023, 01, 01).unwrap(), + ); + let im = fun.super_image(&set).unwrap(); + println!("im({}) = {}", set, im); + assert!(im == DataType::date_value(NaiveDate::from_ymd_opt(2023, 01, 01).unwrap())); + + let set = DataType::date_time_value( + NaiveDate::from_ymd_opt(2026, 7, 8).unwrap().and_hms_opt(9, 15, 11).unwrap(), + ); + let im = fun.super_image(&set).unwrap(); + println!("im({}) = {}", set, im); + assert!(im == DataType::date_value(NaiveDate::from_ymd_opt(2026, 7, 8).unwrap())); + } } diff --git a/src/data_type/sql.rs b/src/data_type/sql.rs index 87ab72bf..8b81e22e 100644 --- a/src/data_type/sql.rs +++ b/src/data_type/sql.rs @@ -14,7 +14,7 @@ impl From for ast::DataType { DataType::Bytes(_) => ast::DataType::Blob(None), DataType::Date(_) => ast::DataType::Date, DataType::Time(_) => ast::DataType::Time(None, ast::TimezoneInfo::None), - DataType::DateTime(_) => ast::DataType::Datetime(None), + DataType::DateTime(_) => ast::DataType::Timestamp(None, ast::TimezoneInfo::None), DataType::Optional(o) => ast::DataType::from(o.data_type().clone()), _ => todo!(), } diff --git a/src/expr/function.rs b/src/expr/function.rs index 094ace5e..0a6baa8f 100644 --- a/src/expr/function.rs +++ b/src/expr/function.rs @@ -88,7 +88,14 @@ pub enum Function { ExtractMicrosecond, ExtractMillisecond, ExtractDow, - ExtractWeek + ExtractWeek, + Dayname, + FromUnixtime, + UnixTimestamp, + DateFormat, + Quarter, + DatetimeDiff, + Date } #[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)] @@ -171,6 +178,10 @@ impl Function { | Function::ExtractMillisecond | Function::ExtractDow | Function::ExtractWeek + | Function::Dayname + | Function::UnixTimestamp + | Function::Quarter + | Function::Date // Binary Functions | Function::Pow | Function::Position @@ -185,11 +196,14 @@ impl Function { | Function::RegexpContains | Function::Encode | Function::Decode + | Function::FromUnixtime + | Function::DateFormat // Ternary Function | Function::Case | Function::SubstrWithSize | Function::RegexpExtract | Function::RegexpReplace + | Function::DatetimeDiff // Nary Function | Function::Concat(_) => Style::Function, } @@ -261,7 +275,11 @@ impl Function { | Function::ExtractMicrosecond | Function::ExtractMillisecond | Function::ExtractDow - | Function::ExtractWeek => Arity::Unary, + | Function::ExtractWeek + | Function::Dayname + | Function::UnixTimestamp + | Function::Quarter + | Function::Date => Arity::Unary, // Binary Function Function::Pow | Function::Position @@ -273,11 +291,13 @@ impl Function { | Function::Substr | Function::Round | Function::Trunc - | Function::RegexpContains => { + | Function::RegexpContains + | Function::FromUnixtime + | Function::DateFormat => { Arity::Nary(2) } // Ternary Function - Function::Case | Function::SubstrWithSize | Function::RegexpReplace => Arity::Nary(3), + Function::Case | Function::SubstrWithSize | Function::RegexpReplace | Function::DatetimeDiff => Arity::Nary(3), // Quaternary Function Function::RegexpExtract => Arity::Nary(4), // Nary Function @@ -372,6 +392,10 @@ impl fmt::Display for Function { Function::ExtractMillisecond => "extract_millisecond", Function::ExtractDow => "extract_dow", Function::ExtractWeek => "extract_week", + Function::Dayname => "dayname", + Function::UnixTimestamp => "unix_timestamp", + Function::Quarter => "quarter", + Function::Date => "date", // Binary Functions Function::Pow => "pow", Function::Position => "position", @@ -386,11 +410,14 @@ impl fmt::Display for Function { Function::RegexpContains => "regexp_contains", Function::Encode => "encode", Function::Decode => "decode", + Function::FromUnixtime => "from_unixtime", + Function::DateFormat => "date_format", // Ternary Functions Function::Case => "case", Function::SubstrWithSize => "substr", Function::RegexpExtract => "regexp_extract", Function::RegexpReplace => "regexp_replace", + Function::DatetimeDiff => "datetime_diff", // Nary Functions Function::Concat(_) => "concat", }) diff --git a/src/expr/implementation.rs b/src/expr/implementation.rs index c76e7e5e..14fce802 100644 --- a/src/expr/implementation.rs +++ b/src/expr/implementation.rs @@ -47,14 +47,14 @@ macro_rules! function_implementations { // All functions: // Nullary: Pi, Newid, CurrentDate, CurrentTime, CurrentTimestamp -// Unary: Opposite, Not, Exp, Ln, Abs, Sin, Cos, CharLength, Lower, Upper, Md5, Ceil, Floor, Sign -// Binary: Plus, Minus, Multiply, Divide, Modulo, StringConcat, Gt, Lt, GtEq, LtEq, Eq, NotEq, And, Or, Xor, BitwiseOr, BitwiseAnd, BitwiseXor, Position, Concat, Greatest, Least, Round, Trunc -// Ternary: Case, Position +// Unary: Opposite, Not, Exp, Ln, Abs, Sin, Cos, CharLength, Lower, Upper, Md5, Ceil, Floor, Sign, Dayname, Quarter, Date, UnixTimestamp +// Binary: Plus, Minus, Multiply, Divide, Modulo, StringConcat, Gt, Lt, GtEq, LtEq, Eq, NotEq, And, Or, Xor, BitwiseOr, BitwiseAnd, BitwiseXor, Position, Concat, Greatest, Least, Round, Trunc, DateFormat, FromUnixtime +// Ternary: Case, Position, DateTimeDiff // Quaternary: RegexExtract // Nary: Concat function_implementations!( [Pi, Newid, CurrentDate, CurrentTime, CurrentTimestamp], - [Opposite, Not, Exp, Ln, Log, Abs, Sin, Cos, Sqrt, Md5, Ceil, Floor, Sign, Unhex], + [Opposite, Not, Exp, Ln, Log, Abs, Sin, Cos, Sqrt, Md5, Ceil, Floor, Sign, Unhex, Dayname, Quarter, Date, UnixTimestamp], [ Plus, Minus, @@ -98,9 +98,11 @@ function_implementations!( ExtractMicrosecond, ExtractMillisecond, ExtractDow, - ExtractWeek + ExtractWeek, + DateFormat, + FromUnixtime ], - [Case, Position, SubstrWithSize, RegexpReplace], + [Case, Position, SubstrWithSize, RegexpReplace, DatetimeDiff], [RegexpExtract], x, { diff --git a/src/expr/mod.rs b/src/expr/mod.rs index 0e7f0d7f..96811342 100644 --- a/src/expr/mod.rs +++ b/src/expr/mod.rs @@ -329,7 +329,11 @@ impl_unary_function_constructors!( ExtractMicrosecond, ExtractMillisecond, ExtractDow, - ExtractWeek + ExtractWeek, + Dayname, + Quarter, + Date, + UnixTimestamp ); // TODO Complete that /// Implement binary function constructors @@ -389,7 +393,9 @@ impl_binary_function_constructors!( Round, RegexpContains, Encode, - Decode + Decode, + DateFormat, + FromUnixtime ); /// Implement ternary function constructors @@ -417,7 +423,7 @@ macro_rules! impl_ternary_function_constructors { }; } -impl_ternary_function_constructors!(Case, SubstrWithSize, RegexpReplace); +impl_ternary_function_constructors!(Case, SubstrWithSize, RegexpReplace, DatetimeDiff); /// Implement quaternary function constructors macro_rules! impl_quaternary_function_constructors { diff --git a/src/expr/sql.rs b/src/expr/sql.rs index 0d7a1ee6..472549cf 100644 --- a/src/expr/sql.rs +++ b/src/expr/sql.rs @@ -194,7 +194,14 @@ impl<'a> expr::Visitor<'a, ast::Expr> for FromExprVisitor { | expr::function::Function::Unhex | expr::function::Function::Encode | expr::function::Function::Decode - | expr::function::Function::Newid => ast::Expr::Function(ast::Function { + | expr::function::Function::Newid + | expr::function::Function::Dayname + | expr::function::Function::DateFormat + | expr::function::Function::Quarter + | expr::function::Function::DatetimeDiff + | expr::function::Function::Date + | expr::function::Function::FromUnixtime + | expr::function::Function::UnixTimestamp => ast::Expr::Function(ast::Function { name: ast::ObjectName(vec![ast::Ident::new(function.to_string())]), args: arguments .into_iter() @@ -755,6 +762,30 @@ mod tests { let gen_expr = ast::Expr::from(&expr); println!("ast::expr = {gen_expr}"); assert_eq!(ast_expr, gen_expr); + + let str_expr = "cast(a as date)"; + let ast_expr: ast::Expr = parse_expr(str_expr).unwrap(); + let expr = Expr::try_from(&ast_expr).unwrap(); + println!("expr = {}", expr); + let gen_expr = ast::Expr::from(&expr); + println!("ast::expr = {gen_expr}"); + assert_eq!(ast_expr, gen_expr); + + let str_expr = "cast(a as time)"; + let ast_expr: ast::Expr = parse_expr(str_expr).unwrap(); + let expr = Expr::try_from(&ast_expr).unwrap(); + println!("expr = {}", expr); + let gen_expr = ast::Expr::from(&expr); + println!("ast::expr = {gen_expr}"); + assert_eq!(ast_expr, gen_expr); + + let str_expr = "cast(a as timestamp)"; + let ast_expr: ast::Expr = parse_expr(str_expr).unwrap(); + let expr = Expr::try_from(&ast_expr).unwrap(); + println!("expr = {}", expr); + let gen_expr = ast::Expr::from(&expr); + println!("ast::expr = {gen_expr}"); + assert_eq!(ast_expr, gen_expr); } #[test] @@ -1124,4 +1155,88 @@ mod tests { println!("ast::expr = {gen_expr}"); assert_eq!(gen_expr, ast_expr); } + + #[test] + fn test_datetime_functions() { + // DAYNAME + let str_expr = "dayname(col1)"; + let ast_expr: ast::Expr = parse_expr(str_expr).unwrap(); + let expr = Expr::try_from(&ast_expr).unwrap(); + println!("expr = {}", expr); + let gen_expr = ast::Expr::from(&expr); + println!("ast::expr = {gen_expr}"); + assert_eq!(gen_expr, ast_expr); + + // DATE_FORMAT + let str_expr = "date_format(col1, format_date)"; + let ast_expr: ast::Expr = parse_expr(str_expr).unwrap(); + let expr = Expr::try_from(&ast_expr).unwrap(); + println!("expr = {}", expr); + let gen_expr = ast::Expr::from(&expr); + println!("ast::expr = {gen_expr}"); + assert_eq!(gen_expr, ast_expr); + + // Quarter + let str_expr = "quarter(col1)"; + let ast_expr: ast::Expr = parse_expr(str_expr).unwrap(); + let expr = Expr::try_from(&ast_expr).unwrap(); + println!("expr = {}", expr); + let gen_expr = ast::Expr::from(&expr); + println!("ast::expr = {gen_expr}"); + assert_eq!(gen_expr, ast_expr); + + // datetime_diff + let str_expr = "datetime_diff(col1, col2, col3)"; + let ast_expr: ast::Expr = parse_expr(str_expr).unwrap(); + let expr = Expr::try_from(&ast_expr).unwrap(); + println!("expr = {}", expr); + let gen_expr = ast::Expr::from(&expr); + println!("ast::expr = {gen_expr}"); + assert_eq!(gen_expr, ast_expr); + + // date + let str_expr = "date(col1)"; + let ast_expr: ast::Expr = parse_expr(str_expr).unwrap(); + let expr = Expr::try_from(&ast_expr).unwrap(); + println!("expr = {}", expr); + let gen_expr = ast::Expr::from(&expr); + println!("ast::expr = {gen_expr}"); + assert_eq!(gen_expr, ast_expr); + + // from_unixtime + let str_expr = "from_unixtime(col1, '%Y-%m-%d')"; + let ast_expr: ast::Expr = parse_expr(str_expr).unwrap(); + let expr = Expr::try_from(&ast_expr).unwrap(); + println!("expr = {}", expr); + let gen_expr = ast::Expr::from(&expr); + println!("ast::expr = {gen_expr}"); + assert_eq!(gen_expr, ast_expr); + + let str_expr = "from_unixtime(col1)"; + let ast_expr: ast::Expr = parse_expr(str_expr).unwrap(); + let expr = Expr::try_from(&ast_expr).unwrap(); + println!("expr = {}", expr); + let gen_expr = ast::Expr::from(&expr); + println!("ast::expr = {gen_expr}"); + let true_expr = parse_expr("from_unixtime(col1, '%Y-%m-%d %H:%i:%S')").unwrap(); + assert_eq!(gen_expr, true_expr); + + // unix_timestamp + let str_expr = "unix_timestamp(col1)"; + let ast_expr: ast::Expr = parse_expr(str_expr).unwrap(); + let expr = Expr::try_from(&ast_expr).unwrap(); + println!("expr = {}", expr); + let gen_expr = ast::Expr::from(&expr); + println!("ast::expr = {gen_expr}"); + assert_eq!(gen_expr, ast_expr); + + let str_expr = "unix_timestamp()"; + let ast_expr: ast::Expr = parse_expr(str_expr).unwrap(); + let expr = Expr::try_from(&ast_expr).unwrap(); + println!("expr = {}", expr); + let gen_expr = ast::Expr::from(&expr); + println!("ast::expr = {gen_expr}"); + let true_expr = parse_expr("unix_timestamp(current_timestamp)").unwrap(); + assert_eq!(gen_expr, true_expr); + } } diff --git a/src/sql/expr.rs b/src/sql/expr.rs index 4a754d75..9de07a6b 100644 --- a/src/sql/expr.rs +++ b/src/sql/expr.rs @@ -923,6 +923,27 @@ impl<'a> Visitor<'a, Result> for TryIntoExprVisitor<'a> { "current_date" => Expr::current_date(), "current_time" => Expr::current_time(), "current_timestamp" => Expr::current_timestamp(), + "dayname" => Expr::dayname(flat_args[0].clone()), + "date_format" => Expr::date_format(flat_args[0].clone(), flat_args[1].clone()), + "quarter" => Expr::quarter(flat_args[0].clone()), + "datetime_diff" => Expr::datetime_diff(flat_args[0].clone(), flat_args[1].clone(), flat_args[2].clone()), + "date" => Expr::date(flat_args[0].clone()), + "from_unixtime" => { + let format = if flat_args.len() > 1 { + flat_args[1].clone() + } else { + Expr::val("%Y-%m-%d %H:%i:%S".to_string()) + }; + Expr::from_unixtime(flat_args[0].clone(), format) + }, + "unix_timestamp" => { + let arg = if flat_args.len() > 0 { + flat_args[0].clone() + } else { + Expr::current_timestamp() + }; + Expr::unix_timestamp(arg) + }, // Aggregates "min" => Expr::min(flat_args[0].clone()), "max" => Expr::max(flat_args[0].clone()),