Skip to content

Commit b05004b

Browse files
committed
feat: support datetime_field as expr for bigquery
1 parent 4921846 commit b05004b

4 files changed

Lines changed: 109 additions & 0 deletions

File tree

src/ast/mod.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -924,6 +924,9 @@ pub enum Expr {
924924
syntax: ExtractSyntax,
925925
expr: Box<Expr>,
926926
},
927+
/// In BigQuery, the `DATE_TRUNC` and `DATETIME_TRUNC` functions can be used to truncate a timestamp to a different granularity.
928+
/// e.g. `DATE_TRUNC(CURRENT_DATE(), DAY)`
929+
DateTimeField(DateTimeField),
927930
/// ```sql
928931
/// CEIL(<expr> [TO DateTimeField])
929932
/// ```
@@ -1937,6 +1940,7 @@ impl fmt::Display for Expr {
19371940
Expr::Prior(expr) => write!(f, "PRIOR {expr}"),
19381941
Expr::Lambda(lambda) => write!(f, "{lambda}"),
19391942
Expr::MemberOf(member_of) => write!(f, "{member_of}"),
1943+
Expr::DateTimeField(field) => write!(f, "{field}"),
19401944
}
19411945
}
19421946
}

src/ast/spans.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1625,6 +1625,7 @@ impl Spanned for Expr {
16251625
Expr::Prior(expr) => expr.span(),
16261626
Expr::Lambda(_) => Span::empty(),
16271627
Expr::MemberOf(member_of) => member_of.value.span().union(&member_of.array.span()),
1628+
Expr::DateTimeField(_) => Span::empty(),
16281629
}
16291630
}
16301631
}

src/parser/mod.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14896,6 +14896,12 @@ impl<'a> Parser<'a> {
1489614896
}
1489714897

1489814898
pub fn parse_function_args(&mut self) -> Result<FunctionArg, ParserError> {
14899+
if dialect_of!(self is BigQueryDialect) && self.next_token_is_temporal_unit() {
14900+
let unit = self.parse_date_time_field()?;
14901+
return Ok(FunctionArg::Unnamed(FunctionArgExpr::Expr(
14902+
Expr::DateTimeField(unit),
14903+
)));
14904+
}
1489914905
let arg = if self.dialect.supports_named_fn_args_with_expr_name() {
1490014906
self.maybe_parse(|p| {
1490114907
let name = p.parse_expr()?;

tests/sqlparser_bigquery.rs

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2566,3 +2566,101 @@ fn test_struct_trailing_and_nested_bracket() {
25662566
)
25672567
);
25682568
}
2569+
2570+
#[test]
2571+
fn test_datetime_granularity() {
2572+
let stmt = bigquery().verified_stmt(concat!(
2573+
"SELECT ",
2574+
"DATE_TRUNC(CURRENT_DATE, DAY), ",
2575+
"DATE_TRUNC(CURRENT_DATE, WEEK(MONDAY)) ",
2576+
"FROM my_table",
2577+
));
2578+
match stmt {
2579+
Statement::Query(query) => {
2580+
let body = query.body.as_ref();
2581+
match body {
2582+
SetExpr::Select(select) => {
2583+
let projection = &select.projection;
2584+
assert_eq!(
2585+
projection[0],
2586+
SelectItem::UnnamedExpr(Expr::Function(Function {
2587+
name: ObjectName(vec![ObjectNamePart::Identifier(Ident::new(
2588+
"DATE_TRUNC"
2589+
))]),
2590+
args: FunctionArguments::List(FunctionArgumentList {
2591+
args: vec![
2592+
FunctionArg::Unnamed(FunctionArgExpr::Expr(Expr::Function(
2593+
Function {
2594+
name: ObjectName(vec![ObjectNamePart::Identifier(
2595+
Ident::new("CURRENT_DATE")
2596+
)]),
2597+
args: FunctionArguments::None,
2598+
uses_odbc_syntax: false,
2599+
parameters: FunctionArguments::None,
2600+
filter: None,
2601+
null_treatment: None,
2602+
over: None,
2603+
within_group: vec![],
2604+
}
2605+
))),
2606+
FunctionArg::Unnamed(FunctionArgExpr::Expr(
2607+
Expr::DateTimeField(DateTimeField::Day)
2608+
)),
2609+
],
2610+
clauses: vec![],
2611+
duplicate_treatment: None,
2612+
}),
2613+
uses_odbc_syntax: false,
2614+
parameters: FunctionArguments::None,
2615+
filter: None,
2616+
null_treatment: None,
2617+
over: None,
2618+
within_group: vec![],
2619+
}))
2620+
);
2621+
assert_eq!(
2622+
projection[1],
2623+
SelectItem::UnnamedExpr(Expr::Function(Function {
2624+
name: ObjectName(vec![ObjectNamePart::Identifier(Ident::new(
2625+
"DATE_TRUNC"
2626+
))]),
2627+
args: FunctionArguments::List(FunctionArgumentList {
2628+
args: vec![
2629+
FunctionArg::Unnamed(FunctionArgExpr::Expr(Expr::Function(
2630+
Function {
2631+
name: ObjectName(vec![ObjectNamePart::Identifier(
2632+
Ident::new("CURRENT_DATE")
2633+
)]),
2634+
args: FunctionArguments::None,
2635+
uses_odbc_syntax: false,
2636+
parameters: FunctionArguments::None,
2637+
filter: None,
2638+
null_treatment: None,
2639+
over: None,
2640+
within_group: vec![],
2641+
}
2642+
))),
2643+
FunctionArg::Unnamed(FunctionArgExpr::Expr(
2644+
Expr::DateTimeField(DateTimeField::Week(Some(Ident::new(
2645+
"MONDAY"
2646+
))))
2647+
)),
2648+
],
2649+
clauses: vec![],
2650+
duplicate_treatment: None,
2651+
}),
2652+
uses_odbc_syntax: false,
2653+
parameters: FunctionArguments::None,
2654+
filter: None,
2655+
null_treatment: None,
2656+
over: None,
2657+
within_group: vec![],
2658+
}))
2659+
);
2660+
}
2661+
_ => panic!("Expected a select statement"),
2662+
}
2663+
}
2664+
_ => panic!("Expected a select statement"),
2665+
}
2666+
}

0 commit comments

Comments
 (0)