Replace Method and CompositeAccess with CompoundFieldAccess (#1716)

This commit is contained in:
Ifeanyi Ubah 2025-02-19 18:49:42 +01:00 committed by GitHub
parent c75a992621
commit 3e90a18f6d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 348 additions and 264 deletions

View file

@ -73,6 +73,23 @@ fn parse_numeric_literal_underscore() {
);
}
#[test]
fn parse_function_object_name() {
let select = verified_only_select("SELECT a.b.c.d(1, 2, 3) FROM T");
let Expr::Function(func) = expr_from_projection(&select.projection[0]) else {
unreachable!()
};
assert_eq!(
ObjectName::from(
["a", "b", "c", "d"]
.into_iter()
.map(Ident::new)
.collect::<Vec<_>>()
),
func.name,
);
}
#[test]
fn parse_insert_values() {
let row = vec![
@ -936,6 +953,44 @@ fn parse_select_distinct_tuple() {
);
}
#[test]
fn parse_outer_join_operator() {
let dialects = all_dialects_where(|d| d.supports_outer_join_operator());
let select = dialects.verified_only_select("SELECT 1 FROM T WHERE a = b (+)");
assert_eq!(
select.selection,
Some(Expr::BinaryOp {
left: Box::new(Expr::Identifier(Ident::new("a"))),
op: BinaryOperator::Eq,
right: Box::new(Expr::OuterJoin(Box::new(Expr::Identifier(Ident::new("b")))))
})
);
let select = dialects.verified_only_select("SELECT 1 FROM T WHERE t1.c1 = t2.c2.d3 (+)");
assert_eq!(
select.selection,
Some(Expr::BinaryOp {
left: Box::new(Expr::CompoundIdentifier(vec![
Ident::new("t1"),
Ident::new("c1")
])),
op: BinaryOperator::Eq,
right: Box::new(Expr::OuterJoin(Box::new(Expr::CompoundIdentifier(vec![
Ident::new("t2"),
Ident::new("c2"),
Ident::new("d3"),
]))))
})
);
let res = dialects.parse_sql_statements("SELECT 1 FROM T WHERE 1 = 2 (+)");
assert_eq!(
ParserError::ParserError("Expected: column identifier before (+), found: 2".to_string()),
res.unwrap_err()
);
}
#[test]
fn parse_select_distinct_on() {
let sql = "SELECT DISTINCT ON (album_id) name FROM track ORDER BY album_id, milliseconds";
@ -12623,68 +12678,76 @@ fn test_try_convert() {
#[test]
fn parse_method_select() {
let dialects = all_dialects_where(|d| d.supports_methods());
let _ = dialects.verified_only_select(
let _ = verified_only_select(
"SELECT LEFT('abc', 1).value('.', 'NVARCHAR(MAX)').value('.', 'NVARCHAR(MAX)') AS T",
);
let _ = dialects.verified_only_select("SELECT STUFF((SELECT ',' + name FROM sys.objects FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)'), 1, 1, '') AS T");
let _ = dialects
.verified_only_select("SELECT CAST(column AS XML).value('.', 'NVARCHAR(MAX)') AS T");
let _ = verified_only_select("SELECT STUFF((SELECT ',' + name FROM sys.objects FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)'), 1, 1, '') AS T");
let _ = verified_only_select("SELECT CAST(column AS XML).value('.', 'NVARCHAR(MAX)') AS T");
// `CONVERT` support
let dialects = all_dialects_where(|d| {
d.supports_methods() && d.supports_try_convert() && d.convert_type_before_value()
});
let dialects =
all_dialects_where(|d| d.supports_try_convert() && d.convert_type_before_value());
let _ = dialects.verified_only_select("SELECT CONVERT(XML, '<Book>abc</Book>').value('.', 'NVARCHAR(MAX)').value('.', 'NVARCHAR(MAX)') AS T");
}
#[test]
fn parse_method_expr() {
let dialects = all_dialects_where(|d| d.supports_methods());
let expr = dialects
.verified_expr("LEFT('abc', 1).value('.', 'NVARCHAR(MAX)').value('.', 'NVARCHAR(MAX)')");
let expr =
verified_expr("LEFT('abc', 1).value('.', 'NVARCHAR(MAX)').value('.', 'NVARCHAR(MAX)')");
match expr {
Expr::Method(Method { expr, method_chain }) => {
assert!(matches!(*expr, Expr::Function(_)));
Expr::CompoundFieldAccess { root, access_chain } => {
assert!(matches!(*root, Expr::Function(_)));
assert!(matches!(
method_chain[..],
[Function { .. }, Function { .. }]
access_chain[..],
[
AccessExpr::Dot(Expr::Function(_)),
AccessExpr::Dot(Expr::Function(_))
]
));
}
_ => unreachable!(),
}
let expr = dialects.verified_expr(
let expr = verified_expr(
"(SELECT ',' + name FROM sys.objects FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)')",
);
match expr {
Expr::Method(Method { expr, method_chain }) => {
assert!(matches!(*expr, Expr::Subquery(_)));
assert!(matches!(method_chain[..], [Function { .. }]));
Expr::CompoundFieldAccess { root, access_chain } => {
assert!(matches!(*root, Expr::Subquery(_)));
assert!(matches!(
access_chain[..],
[AccessExpr::Dot(Expr::Function(_))]
));
}
_ => unreachable!(),
}
let expr = dialects.verified_expr("CAST(column AS XML).value('.', 'NVARCHAR(MAX)')");
let expr = verified_expr("CAST(column AS XML).value('.', 'NVARCHAR(MAX)')");
match expr {
Expr::Method(Method { expr, method_chain }) => {
assert!(matches!(*expr, Expr::Cast { .. }));
assert!(matches!(method_chain[..], [Function { .. }]));
Expr::CompoundFieldAccess { root, access_chain } => {
assert!(matches!(*root, Expr::Cast { .. }));
assert!(matches!(
access_chain[..],
[AccessExpr::Dot(Expr::Function(_))]
));
}
_ => unreachable!(),
}
// `CONVERT` support
let dialects = all_dialects_where(|d| {
d.supports_methods() && d.supports_try_convert() && d.convert_type_before_value()
});
let dialects =
all_dialects_where(|d| d.supports_try_convert() && d.convert_type_before_value());
let expr = dialects.verified_expr(
"CONVERT(XML, '<Book>abc</Book>').value('.', 'NVARCHAR(MAX)').value('.', 'NVARCHAR(MAX)')",
);
match expr {
Expr::Method(Method { expr, method_chain }) => {
assert!(matches!(*expr, Expr::Convert { .. }));
Expr::CompoundFieldAccess { root, access_chain } => {
assert!(matches!(*root, Expr::Convert { .. }));
assert!(matches!(
method_chain[..],
[Function { .. }, Function { .. }]
access_chain[..],
[
AccessExpr::Dot(Expr::Function(_)),
AccessExpr::Dot(Expr::Function(_))
]
));
}
_ => unreachable!(),