Add support for arbitrary map access expr (#1179)

This commit is contained in:
Ifeanyi Ubah 2024-04-09 23:21:22 +02:00 committed by GitHub
parent 127be97369
commit eda86d8ed7
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 194 additions and 116 deletions

View file

@ -1402,39 +1402,48 @@ fn bigquery_and_generic() -> TestedDialects {
}
#[test]
fn parse_map_access_offset() {
let sql = "SELECT d[offset(0)]";
let _select = bigquery().verified_only_select(sql);
assert_eq!(
_select.projection[0],
SelectItem::UnnamedExpr(Expr::MapAccess {
column: Box::new(Expr::Identifier(Ident {
value: "d".to_string(),
quote_style: None,
})),
keys: vec![Expr::Function(Function {
name: ObjectName(vec!["offset".into()]),
args: vec![FunctionArg::Unnamed(FunctionArgExpr::Expr(Expr::Value(
number("0")
))),],
null_treatment: None,
filter: None,
over: None,
distinct: false,
special: false,
order_by: vec![],
})],
})
);
fn parse_map_access_expr() {
let sql = "users[-1][safe_offset(2)].a.b";
let expr = bigquery().verified_expr(sql);
// test other operators
for sql in [
"SELECT d[SAFE_OFFSET(0)]",
"SELECT d[ORDINAL(0)]",
"SELECT d[SAFE_ORDINAL(0)]",
] {
bigquery().verified_only_select(sql);
fn map_access_key(key: Expr, syntax: MapAccessSyntax) -> MapAccessKey {
MapAccessKey { key, syntax }
}
let expected = Expr::MapAccess {
column: Expr::Identifier(Ident::new("users")).into(),
keys: vec![
map_access_key(
Expr::UnaryOp {
op: UnaryOperator::Minus,
expr: Expr::Value(number("1")).into(),
},
MapAccessSyntax::Bracket,
),
map_access_key(
Expr::Function(Function {
name: ObjectName(vec![Ident::new("safe_offset")]),
args: vec![FunctionArg::Unnamed(FunctionArgExpr::Expr(Expr::Value(
number("2"),
)))],
filter: None,
null_treatment: None,
over: None,
distinct: false,
special: false,
order_by: vec![],
}),
MapAccessSyntax::Bracket,
),
map_access_key(
Expr::CompoundIdentifier(vec![Ident::new("a"), Ident::new("b")]),
MapAccessSyntax::Period,
),
],
};
assert_eq!(expr, expected);
let sql = "SELECT myfunc()[-1].a[SAFE_OFFSET(2)].b";
bigquery().verified_only_select(sql);
}
#[test]

View file

@ -39,23 +39,26 @@ fn parse_map_access_expr() {
value: "string_values".to_string(),
quote_style: None,
})),
keys: vec![Expr::Function(Function {
name: ObjectName(vec!["indexOf".into()]),
args: vec![
FunctionArg::Unnamed(FunctionArgExpr::Expr(Expr::Identifier(Ident::new(
"string_names"
)))),
FunctionArg::Unnamed(FunctionArgExpr::Expr(Expr::Value(
Value::SingleQuotedString("endpoint".to_string())
))),
],
null_treatment: None,
filter: None,
over: None,
distinct: false,
special: false,
order_by: vec![],
})],
keys: vec![MapAccessKey {
key: Expr::Function(Function {
name: ObjectName(vec!["indexOf".into()]),
args: vec![
FunctionArg::Unnamed(FunctionArgExpr::Expr(Expr::Identifier(
Ident::new("string_names")
))),
FunctionArg::Unnamed(FunctionArgExpr::Expr(Expr::Value(
Value::SingleQuotedString("endpoint".to_string())
))),
],
null_treatment: None,
filter: None,
over: None,
distinct: false,
special: false,
order_by: vec![],
}),
syntax: MapAccessSyntax::Bracket
}],
})],
into: None,
from: vec![TableWithJoins {
@ -80,23 +83,26 @@ fn parse_map_access_expr() {
right: Box::new(BinaryOp {
left: Box::new(MapAccess {
column: Box::new(Identifier(Ident::new("string_value"))),
keys: vec![Expr::Function(Function {
name: ObjectName(vec![Ident::new("indexOf")]),
args: vec![
FunctionArg::Unnamed(FunctionArgExpr::Expr(Expr::Identifier(
Ident::new("string_name")
))),
FunctionArg::Unnamed(FunctionArgExpr::Expr(Expr::Value(
Value::SingleQuotedString("app".to_string())
))),
],
null_treatment: None,
filter: None,
over: None,
distinct: false,
special: false,
order_by: vec![],
})],
keys: vec![MapAccessKey {
key: Expr::Function(Function {
name: ObjectName(vec![Ident::new("indexOf")]),
args: vec![
FunctionArg::Unnamed(FunctionArgExpr::Expr(Expr::Identifier(
Ident::new("string_name")
))),
FunctionArg::Unnamed(FunctionArgExpr::Expr(Expr::Value(
Value::SingleQuotedString("app".to_string())
))),
],
null_treatment: None,
filter: None,
over: None,
distinct: false,
special: false,
order_by: vec![],
}),
syntax: MapAccessSyntax::Bracket
}],
}),
op: BinaryOperator::NotEq,
right: Box::new(Expr::Value(Value::SingleQuotedString("foo".to_string()))),

View file

@ -8643,3 +8643,45 @@ fn test_buffer_reuse() {
p.parse_statements().unwrap();
let _ = p.into_tokens();
}
#[test]
fn parse_map_access_expr() {
let sql = "users[-1][safe_offset(2)]";
let dialects = TestedDialects {
dialects: vec![Box::new(BigQueryDialect {}), Box::new(ClickHouseDialect {})],
options: None,
};
let expr = dialects.verified_expr(sql);
let expected = Expr::MapAccess {
column: Expr::Identifier(Ident::new("users")).into(),
keys: vec![
MapAccessKey {
key: Expr::UnaryOp {
op: UnaryOperator::Minus,
expr: Expr::Value(number("1")).into(),
},
syntax: MapAccessSyntax::Bracket,
},
MapAccessKey {
key: Expr::Function(Function {
name: ObjectName(vec![Ident::new("safe_offset")]),
args: vec![FunctionArg::Unnamed(FunctionArgExpr::Expr(Expr::Value(
number("2"),
)))],
filter: None,
null_treatment: None,
over: None,
distinct: false,
special: false,
order_by: vec![],
}),
syntax: MapAccessSyntax::Bracket,
},
],
};
assert_eq!(expr, expected);
for sql in ["users[1]", "a[array_length(b) - 1 + 2][c + 3][d * 4]"] {
let _ = dialects.verified_expr(sql);
}
}