Skip to content

Commit

Permalink
fix!: remove parensless lambda from generic
Browse files Browse the repository at this point in the history
  • Loading branch information
gstvg committed Jan 29, 2025
1 parent 94e71ff commit 848dc65
Show file tree
Hide file tree
Showing 7 changed files with 59 additions and 8 deletions.
4 changes: 4 additions & 0 deletions src/dialect/clickhouse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,4 +75,8 @@ impl Dialect for ClickHouseDialect {
fn supports_lambda_functions(&self) -> bool {
true
}

fn supports_parensless_lambda_functions(&self) -> bool {
true
}
}
4 changes: 4 additions & 0 deletions src/dialect/databricks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,10 @@ impl Dialect for DatabricksDialect {
true
}

fn supports_parensless_lambda_functions(&self) -> bool {
true
}

// https://docs.databricks.com/en/sql/language-manual/sql-ref-syntax-qry-select.html#syntax
fn supports_select_wildcard_except(&self) -> bool {
true
Expand Down
4 changes: 4 additions & 0 deletions src/dialect/duckdb.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,10 @@ impl Dialect for DuckDbDialect {
true
}

fn supports_parensless_lambda_functions(&self) -> bool {
true
}

// DuckDB is compatible with PostgreSQL syntax for this statement,
// although not all features may be implemented.
fn supports_explain_with_utility_options(&self) -> bool {
Expand Down
11 changes: 10 additions & 1 deletion src/dialect/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -340,12 +340,21 @@ pub trait Dialect: Debug + Any {
/// Returns true if the dialect supports lambda functions, for example:
///
/// ```sql
/// SELECT transform(array(1, 2, 3), x -> x + 1); -- returns [2,3,4]
/// SELECT transform(array(1, 2, 3), (x) -> x + 1); -- returns [2,3,4]
/// ```
fn supports_lambda_functions(&self) -> bool {
false
}

/// Returns true if the dialect supports lambda functions without parentheses for a single argument, for example:
///
/// ```sql
/// SELECT transform(array(1, 2, 3), x -> x + 1); -- returns [2,3,4]
/// ```
fn supports_parensless_lambda_functions(&self) -> bool {
false
}

/// Returns true if the dialect supports method calls, for example:
///
/// ```sql
Expand Down
2 changes: 1 addition & 1 deletion src/parser/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1268,7 +1268,7 @@ impl<'a> Parser<'a> {
value: self.parse_introduced_string_value()?,
})
}
Token::Arrow if self.dialect.supports_lambda_functions() => {
Token::Arrow if self.dialect.supports_parensless_lambda_functions() => {
self.expect_token(&Token::Arrow)?;
Ok(Expr::Lambda(LambdaFunction {
params: OneOrManyWithParens::One(w.clone().into_ident(w_span)),
Expand Down
32 changes: 31 additions & 1 deletion tests/sqlparser_common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13348,5 +13348,35 @@ fn test_lambdas() {
dialects.verified_expr(
"map_zip_with(map(1, 'a', 2, 'b'), map(1, 'x', 2, 'y'), (k, v1, v2) -> concat(v1, v2))",
);
dialects.verified_expr("transform(array(1, 2, 3), x -> x + 1)");
dialects.verified_expr("transform(array(1, 2, 3), (x) -> x + 1)");
}

#[test]
fn test_parensless_lambdas() {
let dialects = all_dialects_where(|d| d.supports_parensless_lambda_functions());

pretty_assertions::assert_eq!(
call(
"transform",
[
call(
"array",
[
Expr::Value(Value::Number("1".to_owned(), false)),
Expr::Value(Value::Number("2".to_owned(), false)),
Expr::Value(Value::Number("3".to_owned(), false)),
]
),
Expr::Lambda(LambdaFunction {
params: OneOrManyWithParens::One(Ident::new("x")),
body: Box::new(Expr::BinaryOp {
left: Box::new(Expr::Identifier(Ident::new("x"))),
op: BinaryOperator::Plus,
right: Box::new(Expr::Value(Value::Number("1".to_owned(), false)))
})
})
]
),
dialects.verified_expr("transform(array(1, 2, 3), x -> x + 1)")
);
}
10 changes: 5 additions & 5 deletions tests/sqlparser_postgres.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2749,7 +2749,7 @@ fn test_json() {
);

let sql = "SELECT params -> 'name' FROM events";
let select = pg().verified_only_select(sql);
let select = pg_and_generic().verified_only_select(sql);
assert_eq!(
SelectItem::UnnamedExpr(Expr::BinaryOp {
left: Box::new(Expr::Identifier(Ident::new("params"))),
Expand All @@ -2760,7 +2760,7 @@ fn test_json() {
);

let sql = "SELECT info -> 'items' ->> 'product' FROM orders";
let select = pg().verified_only_select(sql);
let select = pg_and_generic().verified_only_select(sql);
assert_eq!(
SelectItem::UnnamedExpr(Expr::BinaryOp {
left: Box::new(Expr::BinaryOp {
Expand All @@ -2778,7 +2778,7 @@ fn test_json() {

// the RHS can be a number (array element access)
let sql = "SELECT obj -> 42";
let select = pg().verified_only_select(sql);
let select = pg_and_generic().verified_only_select(sql);
assert_eq!(
SelectItem::UnnamedExpr(Expr::BinaryOp {
left: Box::new(Expr::Identifier(Ident::new("obj"))),
Expand All @@ -2790,7 +2790,7 @@ fn test_json() {

// the RHS can be an identifier
let sql = "SELECT obj -> key";
let select = pg().verified_only_select(sql);
let select = pg_and_generic().verified_only_select(sql);
assert_eq!(
SelectItem::UnnamedExpr(Expr::BinaryOp {
left: Box::new(Expr::Identifier(Ident::new("obj"))),
Expand All @@ -2802,7 +2802,7 @@ fn test_json() {

// -> operator has lower precedence than arithmetic ops
let sql = "SELECT obj -> 3 * 2";
let select = pg().verified_only_select(sql);
let select = pg_and_generic().verified_only_select(sql);
assert_eq!(
SelectItem::UnnamedExpr(Expr::BinaryOp {
left: Box::new(Expr::Identifier(Ident::new("obj"))),
Expand Down

0 comments on commit 848dc65

Please sign in to comment.