Consolidate MapAccess, and Subscript into CompoundExpr to handle the complex field access chain (#1551)

This commit is contained in:
Jax Liu 2024-12-22 22:28:44 +08:00 committed by GitHub
parent cd898cb6a4
commit 0647a4aa82
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 455 additions and 287 deletions

View file

@ -37,8 +37,8 @@ use sqlparser::dialect::{
};
use sqlparser::keywords::{Keyword, ALL_KEYWORDS};
use sqlparser::parser::{Parser, ParserError, ParserOptions};
use sqlparser::tokenizer::Span;
use sqlparser::tokenizer::Tokenizer;
use sqlparser::tokenizer::{Location, Span};
use test_utils::{
all_dialects, all_dialects_where, alter_table_op, assert_eq_vec, call, expr_from_projection,
join, number, only, table, table_alias, table_from_name, TestedDialects,
@ -2939,6 +2939,31 @@ fn parse_window_function_null_treatment_arg() {
);
}
#[test]
fn test_compound_expr() {
let supported_dialects = TestedDialects::new(vec![
Box::new(GenericDialect {}),
Box::new(DuckDbDialect {}),
Box::new(BigQueryDialect {}),
]);
let sqls = [
"SELECT abc[1].f1 FROM t",
"SELECT abc[1].f1.f2 FROM t",
"SELECT f1.abc[1] FROM t",
"SELECT f1.f2.abc[1] FROM t",
"SELECT f1.abc[1].f2 FROM t",
"SELECT named_struct('a', 1, 'b', 2).a",
"SELECT named_struct('a', 1, 'b', 2).a",
"SELECT make_array(1, 2, 3)[1]",
"SELECT make_array(named_struct('a', 1))[1].a",
"SELECT abc[1][-1].a.b FROM t",
"SELECT abc[1][-1].a.b[1] FROM t",
];
for sql in sqls {
supported_dialects.verified_stmt(sql);
}
}
#[test]
fn parse_negative_value() {
let sql1 = "SELECT -1";
@ -10174,20 +10199,39 @@ fn parse_map_access_expr() {
Box::new(ClickHouseDialect {}),
]);
let expr = dialects.verified_expr(sql);
let expected = Expr::MapAccess {
column: Expr::Identifier(Ident::new("users")).into(),
keys: vec![
MapAccessKey {
key: Expr::UnaryOp {
let expected = Expr::CompoundFieldAccess {
root: Box::new(Expr::Identifier(Ident::with_span(
Span::new(Location::of(1, 1), Location::of(1, 6)),
"users",
))),
access_chain: vec![
AccessExpr::Subscript(Subscript::Index {
index: Expr::UnaryOp {
op: UnaryOperator::Minus,
expr: Expr::Value(number("1")).into(),
},
syntax: MapAccessSyntax::Bracket,
},
MapAccessKey {
key: call("safe_offset", [Expr::Value(number("2"))]),
syntax: MapAccessSyntax::Bracket,
},
}),
AccessExpr::Subscript(Subscript::Index {
index: Expr::Function(Function {
name: ObjectName(vec![Ident::with_span(
Span::new(Location::of(1, 11), Location::of(1, 22)),
"safe_offset",
)]),
parameters: FunctionArguments::None,
args: FunctionArguments::List(FunctionArgumentList {
duplicate_treatment: None,
args: vec![FunctionArg::Unnamed(FunctionArgExpr::Expr(Expr::Value(
number("2"),
)))],
clauses: vec![],
}),
filter: None,
null_treatment: None,
over: None,
within_group: vec![],
uses_odbc_syntax: false,
}),
}),
],
};
assert_eq!(expr, expected);
@ -10977,8 +11021,8 @@ fn test_map_syntax() {
check(
"MAP {'a': 10, 'b': 20}['a']",
Expr::Subscript {
expr: Box::new(Expr::Map(Map {
Expr::CompoundFieldAccess {
root: Box::new(Expr::Map(Map {
entries: vec![
MapEntry {
key: Box::new(Expr::Value(Value::SingleQuotedString("a".to_owned()))),
@ -10990,9 +11034,9 @@ fn test_map_syntax() {
},
],
})),
subscript: Box::new(Subscript::Index {
access_chain: vec![AccessExpr::Subscript(Subscript::Index {
index: Expr::Value(Value::SingleQuotedString("a".to_owned())),
}),
})],
},
);