mirror of
https://github.com/apache/datafusion-sqlparser-rs.git
synced 2025-09-02 12:17:21 +00:00
Snowflake: Support semi-structured data (#693)
* Support parse json in snowflake * MR Review * Lint * Try to fix right as value * Fix tests * Fix lint * Add generic dialect * Add support in key location
This commit is contained in:
parent
27c3ec87db
commit
93a050e5f0
4 changed files with 40 additions and 1 deletions
|
@ -187,6 +187,8 @@ pub enum JsonOperator {
|
|||
HashArrow,
|
||||
/// #>> Extracts JSON sub-object at the specified path as text
|
||||
HashLongArrow,
|
||||
/// : Colon is used by Snowflake (Which is similar to LongArrow)
|
||||
Colon,
|
||||
}
|
||||
|
||||
impl fmt::Display for JsonOperator {
|
||||
|
@ -204,6 +206,9 @@ impl fmt::Display for JsonOperator {
|
|||
JsonOperator::HashLongArrow => {
|
||||
write!(f, "#>>")
|
||||
}
|
||||
JsonOperator::Colon => {
|
||||
write!(f, ":")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -757,7 +762,11 @@ impl fmt::Display for Expr {
|
|||
operator,
|
||||
right,
|
||||
} => {
|
||||
if operator == &JsonOperator::Colon {
|
||||
write!(f, "{}{}{}", left, operator, right)
|
||||
} else {
|
||||
write!(f, "{} {} {}", left, operator, right)
|
||||
}
|
||||
}
|
||||
Expr::CompositeAccess { expr, key } => {
|
||||
write!(f, "{}.{}", expr, key)
|
||||
|
|
|
@ -45,6 +45,8 @@ pub enum Value {
|
|||
Null,
|
||||
/// `?` or `$` Prepared statement arg placeholder
|
||||
Placeholder(String),
|
||||
/// Add support of snowflake field:key - key should be a value
|
||||
UnQuotedString(String),
|
||||
}
|
||||
|
||||
impl fmt::Display for Value {
|
||||
|
@ -59,6 +61,7 @@ impl fmt::Display for Value {
|
|||
Value::Boolean(v) => write!(f, "{}", v),
|
||||
Value::Null => write!(f, "NULL"),
|
||||
Value::Placeholder(v) => write!(f, "{}", v),
|
||||
Value::UnQuotedString(v) => write!(f, "{}", v),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1427,6 +1427,12 @@ impl<'a> Parser<'a> {
|
|||
return self.parse_array_index(expr);
|
||||
}
|
||||
self.parse_map_access(expr)
|
||||
} else if Token::Colon == tok {
|
||||
Ok(Expr::JsonAccess {
|
||||
left: Box::new(expr),
|
||||
operator: JsonOperator::Colon,
|
||||
right: Box::new(Expr::Value(self.parse_value()?)),
|
||||
})
|
||||
} else if Token::Arrow == tok
|
||||
|| Token::LongArrow == tok
|
||||
|| Token::HashArrow == tok
|
||||
|
@ -1628,6 +1634,7 @@ impl<'a> Parser<'a> {
|
|||
Token::Plus | Token::Minus => Ok(Self::PLUS_MINUS_PREC),
|
||||
Token::Mul | Token::Div | Token::Mod | Token::StringConcat => Ok(40),
|
||||
Token::DoubleColon => Ok(50),
|
||||
Token::Colon => Ok(50),
|
||||
Token::ExclamationMark => Ok(50),
|
||||
Token::LBracket
|
||||
| Token::LongArrow
|
||||
|
@ -3446,6 +3453,10 @@ impl<'a> Parser<'a> {
|
|||
Some('\'') => Ok(Value::SingleQuotedString(w.value)),
|
||||
_ => self.expected("A value?", Token::Word(w))?,
|
||||
},
|
||||
// Case when Snowflake Semi-structured data like key:value
|
||||
Keyword::NoKeyword | Keyword::LOCATION if dialect_of!(self is SnowflakeDialect | GenericDialect) => {
|
||||
Ok(Value::UnQuotedString(w.value))
|
||||
}
|
||||
_ => self.expected("a concrete value", Token::Word(w)),
|
||||
},
|
||||
// The call to n.parse() returns a bigdecimal when the
|
||||
|
|
|
@ -143,6 +143,22 @@ fn test_single_table_in_parenthesis_with_alias() {
|
|||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_json_using_colon() {
|
||||
let sql = "SELECT a:b FROM t";
|
||||
let select = snowflake().verified_only_select(sql);
|
||||
assert_eq!(
|
||||
SelectItem::UnnamedExpr(Expr::JsonAccess {
|
||||
left: Box::new(Expr::Identifier(Ident::new("a"))),
|
||||
operator: JsonOperator::Colon,
|
||||
right: Box::new(Expr::Value(Value::UnQuotedString("b".to_string()))),
|
||||
}),
|
||||
select.projection[0]
|
||||
);
|
||||
|
||||
snowflake().one_statement_parses_to("SELECT a:b::int FROM t", "SELECT CAST(a:b AS INT) FROM t");
|
||||
}
|
||||
|
||||
fn snowflake() -> TestedDialects {
|
||||
TestedDialects {
|
||||
dialects: vec![Box::new(SnowflakeDialect {})],
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue