Improve parsing of JSON accesses on Postgres and Snowflake (#1215)

Co-authored-by: Ifeanyi Ubah <ify1992@yahoo.com>
This commit is contained in:
Joey Hain 2024-04-30 07:49:05 -07:00 committed by GitHub
parent 0606024353
commit 4bfa399919
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 432 additions and 199 deletions

View file

@ -2235,9 +2235,9 @@ fn test_json() {
let sql = "SELECT params ->> 'name' FROM events";
let select = pg().verified_only_select(sql);
assert_eq!(
SelectItem::UnnamedExpr(Expr::JsonAccess {
SelectItem::UnnamedExpr(Expr::BinaryOp {
left: Box::new(Expr::Identifier(Ident::new("params"))),
operator: JsonOperator::LongArrow,
op: BinaryOperator::LongArrow,
right: Box::new(Expr::Value(Value::SingleQuotedString("name".to_string()))),
}),
select.projection[0]
@ -2246,9 +2246,9 @@ fn test_json() {
let sql = "SELECT params -> 'name' FROM events";
let select = pg().verified_only_select(sql);
assert_eq!(
SelectItem::UnnamedExpr(Expr::JsonAccess {
SelectItem::UnnamedExpr(Expr::BinaryOp {
left: Box::new(Expr::Identifier(Ident::new("params"))),
operator: JsonOperator::Arrow,
op: BinaryOperator::Arrow,
right: Box::new(Expr::Value(Value::SingleQuotedString("name".to_string()))),
}),
select.projection[0]
@ -2257,15 +2257,55 @@ fn test_json() {
let sql = "SELECT info -> 'items' ->> 'product' FROM orders";
let select = pg().verified_only_select(sql);
assert_eq!(
SelectItem::UnnamedExpr(Expr::JsonAccess {
left: Box::new(Expr::Identifier(Ident::new("info"))),
operator: JsonOperator::Arrow,
right: Box::new(Expr::JsonAccess {
left: Box::new(Expr::Value(Value::SingleQuotedString("items".to_string()))),
operator: JsonOperator::LongArrow,
right: Box::new(Expr::Value(Value::SingleQuotedString(
"product".to_string()
)))
SelectItem::UnnamedExpr(Expr::BinaryOp {
left: Box::new(Expr::BinaryOp {
left: Box::new(Expr::Identifier(Ident::new("info"))),
op: BinaryOperator::Arrow,
right: Box::new(Expr::Value(Value::SingleQuotedString("items".to_string())))
}),
op: BinaryOperator::LongArrow,
right: Box::new(Expr::Value(Value::SingleQuotedString(
"product".to_string()
))),
}),
select.projection[0]
);
// the RHS can be a number (array element access)
let sql = "SELECT obj -> 42";
let select = pg().verified_only_select(sql);
assert_eq!(
SelectItem::UnnamedExpr(Expr::BinaryOp {
left: Box::new(Expr::Identifier(Ident::new("obj"))),
op: BinaryOperator::Arrow,
right: Box::new(Expr::Value(number("42"))),
}),
select.projection[0]
);
// the RHS can be an identifier
let sql = "SELECT obj -> key";
let select = pg().verified_only_select(sql);
assert_eq!(
SelectItem::UnnamedExpr(Expr::BinaryOp {
left: Box::new(Expr::Identifier(Ident::new("obj"))),
op: BinaryOperator::Arrow,
right: Box::new(Expr::Identifier(Ident::new("key"))),
}),
select.projection[0]
);
// -> operator has lower precedence than arithmetic ops
let sql = "SELECT obj -> 3 * 2";
let select = pg().verified_only_select(sql);
assert_eq!(
SelectItem::UnnamedExpr(Expr::BinaryOp {
left: Box::new(Expr::Identifier(Ident::new("obj"))),
op: BinaryOperator::Arrow,
right: Box::new(Expr::BinaryOp {
left: Box::new(Expr::Value(number("3"))),
op: BinaryOperator::Multiply,
right: Box::new(Expr::Value(number("2"))),
}),
}),
select.projection[0]
@ -2274,9 +2314,9 @@ fn test_json() {
let sql = "SELECT info #> '{a,b,c}' FROM orders";
let select = pg().verified_only_select(sql);
assert_eq!(
SelectItem::UnnamedExpr(Expr::JsonAccess {
SelectItem::UnnamedExpr(Expr::BinaryOp {
left: Box::new(Expr::Identifier(Ident::new("info"))),
operator: JsonOperator::HashArrow,
op: BinaryOperator::HashArrow,
right: Box::new(Expr::Value(Value::SingleQuotedString(
"{a,b,c}".to_string()
))),
@ -2287,9 +2327,9 @@ fn test_json() {
let sql = "SELECT info #>> '{a,b,c}' FROM orders";
let select = pg().verified_only_select(sql);
assert_eq!(
SelectItem::UnnamedExpr(Expr::JsonAccess {
SelectItem::UnnamedExpr(Expr::BinaryOp {
left: Box::new(Expr::Identifier(Ident::new("info"))),
operator: JsonOperator::HashLongArrow,
op: BinaryOperator::HashLongArrow,
right: Box::new(Expr::Value(Value::SingleQuotedString(
"{a,b,c}".to_string()
))),
@ -2300,9 +2340,9 @@ fn test_json() {
let sql = "SELECT info FROM orders WHERE info @> '{\"a\": 1}'";
let select = pg().verified_only_select(sql);
assert_eq!(
Expr::JsonAccess {
Expr::BinaryOp {
left: Box::new(Expr::Identifier(Ident::new("info"))),
operator: JsonOperator::AtArrow,
op: BinaryOperator::AtArrow,
right: Box::new(Expr::Value(Value::SingleQuotedString(
"{\"a\": 1}".to_string()
))),
@ -2313,11 +2353,11 @@ fn test_json() {
let sql = "SELECT info FROM orders WHERE '{\"a\": 1}' <@ info";
let select = pg().verified_only_select(sql);
assert_eq!(
Expr::JsonAccess {
Expr::BinaryOp {
left: Box::new(Expr::Value(Value::SingleQuotedString(
"{\"a\": 1}".to_string()
))),
operator: JsonOperator::ArrowAt,
op: BinaryOperator::ArrowAt,
right: Box::new(Expr::Identifier(Ident::new("info"))),
},
select.selection.unwrap(),
@ -2326,9 +2366,9 @@ fn test_json() {
let sql = "SELECT info #- ARRAY['a', 'b'] FROM orders";
let select = pg().verified_only_select(sql);
assert_eq!(
SelectItem::UnnamedExpr(Expr::JsonAccess {
SelectItem::UnnamedExpr(Expr::BinaryOp {
left: Box::new(Expr::Identifier(Ident::from("info"))),
operator: JsonOperator::HashMinus,
op: BinaryOperator::HashMinus,
right: Box::new(Expr::Array(Array {
elem: vec![
Expr::Value(Value::SingleQuotedString("a".to_string())),
@ -2343,9 +2383,9 @@ fn test_json() {
let sql = "SELECT info FROM orders WHERE info @? '$.a'";
let select = pg().verified_only_select(sql);
assert_eq!(
Expr::JsonAccess {
Expr::BinaryOp {
left: Box::new(Expr::Identifier(Ident::from("info"))),
operator: JsonOperator::AtQuestion,
op: BinaryOperator::AtQuestion,
right: Box::new(Expr::Value(Value::SingleQuotedString("$.a".to_string())),),
},
select.selection.unwrap(),
@ -2354,9 +2394,9 @@ fn test_json() {
let sql = "SELECT info FROM orders WHERE info @@ '$.a'";
let select = pg().verified_only_select(sql);
assert_eq!(
Expr::JsonAccess {
Expr::BinaryOp {
left: Box::new(Expr::Identifier(Ident::from("info"))),
operator: JsonOperator::AtAt,
op: BinaryOperator::AtAt,
right: Box::new(Expr::Value(Value::SingleQuotedString("$.a".to_string())),),
},
select.selection.unwrap(),