Code review fixes

This commit is contained in:
Yoav Cohen 2025-07-01 15:00:02 +02:00
parent 8d0cb499ad
commit 0b74460e27
4 changed files with 48 additions and 11 deletions

View file

@ -1125,13 +1125,7 @@ pub enum Expr {
/// [DuckDb](https://duckdb.org/docs/sql/functions/lambda.html)
Lambda(LambdaFunction),
/// Checks membership of a value in a JSON array
///
/// Syntax:
/// ```sql
/// <value> MEMBER OF(<array>)
/// ```
/// [MySQL](https://dev.mysql.com/doc/refman/8.4/en/json-search-functions.html#operator_member-of)
MemberOf(Box<Expr>, Box<Expr>),
MemberOf(MemberOf),
}
impl Expr {
@ -1920,7 +1914,7 @@ impl fmt::Display for Expr {
}
Expr::Prior(expr) => write!(f, "PRIOR {expr}"),
Expr::Lambda(lambda) => write!(f, "{lambda}"),
Expr::MemberOf(value, array) => write!(f, "{value} MEMBER OF({array})"),
Expr::MemberOf(member_of) => write!(f, "{member_of}"),
}
}
}
@ -9840,6 +9834,27 @@ impl fmt::Display for NullInclusion {
}
}
/// Checks membership of a value in a JSON array
///
/// Syntax:
/// ```sql
/// <value> MEMBER OF(<array>)
/// ```
/// [MySQL](https://dev.mysql.com/doc/refman/8.4/en/json-search-functions.html#operator_member-of)
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
pub struct MemberOf {
pub value: Box<Expr>,
pub array: Box<Expr>,
}
impl fmt::Display for MemberOf {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{} MEMBER OF({})", self.value, self.array)
}
}
#[cfg(test)]
mod tests {
use crate::tokenizer::Location;

View file

@ -1619,7 +1619,7 @@ impl Spanned for Expr {
Expr::OuterJoin(expr) => expr.span(),
Expr::Prior(expr) => expr.span(),
Expr::Lambda(_) => Span::empty(),
Expr::MemberOf(value, array) => value.span().union(&array.span()),
Expr::MemberOf(member_of) => member_of.value.span().union(&member_of.array.span()),
}
}
}

View file

@ -3614,7 +3614,10 @@ impl<'a> Parser<'a> {
let _ = self.expect_token(&Token::LParen);
let expr2 = self.parse_expr()?;
let _ = self.expect_token(&Token::RParen);
Ok(Expr::MemberOf(Box::new(expr), Box::new(expr2)))
Ok(Expr::MemberOf(MemberOf {
value: Box::new(expr),
array: Box::new(expr2),
}))
} else {
self.expected("OF after MEMBER", self.peek_token())
}

View file

@ -4113,5 +4113,24 @@ fn parse_alter_table_drop_index() {
#[test]
fn parse_json_member_of() {
mysql().verified_stmt(r#"SELECT 17 MEMBER OF('[23, "abc", 17, "ab", 10]')"#);
mysql().verified_stmt(r#"SELECT 'ab' MEMBER OF('[23, "abc", 17, "ab", 10]')"#);
let sql = r#"SELECT 'ab' MEMBER OF('[23, "abc", 17, "ab", 10]')"#;
let stmt = mysql().verified_stmt(sql);
match stmt {
Statement::Query(query) => {
let select = query.body.as_select().unwrap();
assert_eq!(
select.projection,
vec![SelectItem::UnnamedExpr(Expr::MemberOf(MemberOf {
value: Box::new(Expr::Value(
Value::SingleQuotedString("ab".to_string()).into()
)),
array: Box::new(Expr::Value(
Value::SingleQuotedString(r#"[23, "abc", 17, "ab", 10]"#.to_string())
.into()
)),
}))]
);
}
_ => panic!("Unexpected statement {stmt}"),
}
}