Skip to content

Commit a2e57b9

Browse files
committed
sql_parser: expr in expression refactored
1 parent 1a7eb70 commit a2e57b9

File tree

3 files changed

+104
-93
lines changed

3 files changed

+104
-93
lines changed

src/ast/expression/mod.rs

+10-4
Original file line numberDiff line numberDiff line change
@@ -150,9 +150,6 @@ pub enum BinaryMatchingExpression {
150150
/// For NOT $BinaryMatchingExpression use cases
151151
Not(Box<BinaryMatchingExpression>),
152152

153-
/// In
154-
In(InExpression),
155-
156153
/// Between
157154
Between(BetweenExpression),
158155
}
@@ -249,9 +246,18 @@ pub struct BetweenExpression {
249246
pub upper_bound: Box<Expression>,
250247
}
251248

249+
#[derive(Debug, PartialEq, Clone)]
250+
pub struct InExpression {
251+
pub expression: Box<Expression>,
252+
253+
pub in_expression: InExpressionType,
254+
255+
pub is_not: bool,
256+
}
257+
252258
/// An in expression
253259
#[derive(Debug, PartialEq, Clone)]
254-
pub enum InExpression {
260+
pub enum InExpressionType {
255261
/// Empty
256262
Empty,
257263

src/parser/expression/in_expr.rs

+88-82
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
use crate::parser::errors::ParsingError;
22
use crate::{
3-
parser::select::SelectStatementParser, BinaryMatchingExpression, Expression, Identifier,
4-
InExpression, Keyword, Parser, TokenType,
3+
parser::select::SelectStatementParser, Expression, InExpression, Keyword, Parser, TokenType,
54
};
5+
use crate::{IdentifierParser, InExpressionType};
66

77
use super::ExpressionParser;
88

@@ -13,6 +13,11 @@ pub trait InExpressionParser {
1313
expression: Expression,
1414
is_not: bool,
1515
) -> Result<Expression, ParsingError>;
16+
17+
fn parse_in_expression_within_parenthesis(&mut self) -> Result<InExpressionType, ParsingError>;
18+
19+
fn parse_in_expression_without_parenthesis(&mut self)
20+
-> Result<InExpressionType, ParsingError>;
1621
}
1722

1823
impl InExpressionParser for Parser<'_> {
@@ -24,61 +29,57 @@ impl InExpressionParser for Parser<'_> {
2429
self.consume_as_keyword(Keyword::In)?;
2530

2631
let in_expression = if self.peek_as(TokenType::LeftParen).is_ok() {
27-
// Consume the left parenthesis
28-
self.consume_as(TokenType::LeftParen)?;
32+
self.parse_in_expression_within_parenthesis()?
33+
} else {
34+
self.parse_in_expression_without_parenthesis()?
35+
};
2936

30-
let result = if self.peek_as(TokenType::RightParen).is_ok() {
31-
BinaryMatchingExpression::In(InExpression::Empty)
32-
} else if let Ok(Keyword::Select) = self.peek_as_keyword() {
33-
// The IN expression is a subquery
34-
let select_statement = self.parse_select_statement()?;
35-
BinaryMatchingExpression::In(InExpression::Select(select_statement))
36-
} else {
37-
let expressions = self.parse_comma_separated_expressions()?;
38-
BinaryMatchingExpression::In(InExpression::Expression(expressions))
39-
};
37+
Ok(Expression::InExpression(InExpression {
38+
expression: Box::new(expression),
39+
in_expression,
40+
is_not,
41+
}))
42+
}
4043

41-
// Consume the enclosing right parenthesis
42-
self.consume_as(TokenType::RightParen)?;
43-
result
44-
} else {
45-
// Parse expressions like $expr IN $schema.table or schema.function(*args)
46-
let id1 = self.peek_as_id()?;
47-
self.consume_as_id()?;
44+
fn parse_in_expression_within_parenthesis(&mut self) -> Result<InExpressionType, ParsingError> {
45+
// Consume the left parenthesis
46+
self.consume_as(TokenType::LeftParen)?;
4847

49-
let identifier = if self.consume_as(TokenType::Dot).is_ok() {
50-
let id2 = self.peek_as_id()?;
51-
self.consume_as_id()?;
52-
Identifier::Compound(vec![id1.to_string(), id2.to_string()])
53-
} else {
54-
Identifier::Single(id1.to_string())
55-
};
48+
let result = if self.peek_as(TokenType::RightParen).is_ok() {
49+
InExpressionType::Empty
50+
} else if let Ok(Keyword::Select) = self.peek_as_keyword() {
51+
// The IN expression is a subquery
52+
let select_statement = self.parse_select_statement()?;
53+
InExpressionType::Select(select_statement)
54+
} else {
55+
let expressions = self.parse_comma_separated_expressions()?;
56+
InExpressionType::Expression(expressions)
57+
};
5658

57-
if self.consume_as(TokenType::LeftParen).is_ok() {
58-
if self.consume_as(TokenType::RightParen).is_ok() {
59-
BinaryMatchingExpression::In(InExpression::TableFunction(identifier, vec![]))
60-
} else {
61-
let args = self.parse_comma_separated_expressions()?;
59+
// Consume the enclosing right parenthesis
60+
self.consume_as(TokenType::RightParen)?;
61+
Ok(result)
62+
}
6263

63-
self.consume_as(TokenType::RightParen)?;
64+
fn parse_in_expression_without_parenthesis(
65+
&mut self,
66+
) -> Result<InExpressionType, ParsingError> {
67+
// Parse expressions like $expr IN $schema.table or $schema.function(*args)
68+
let identifier = self.parse_identifier()?;
6469

65-
BinaryMatchingExpression::In(InExpression::TableFunction(identifier, args))
66-
}
70+
if self.consume_as(TokenType::LeftParen).is_ok() {
71+
if self.consume_as(TokenType::RightParen).is_ok() {
72+
Ok(InExpressionType::TableFunction(identifier, vec![]))
6773
} else {
68-
BinaryMatchingExpression::In(InExpression::Identity(identifier))
69-
}
70-
};
74+
let args = self.parse_comma_separated_expressions()?;
7175

72-
let in_expression = if is_not {
73-
BinaryMatchingExpression::Not(Box::new(in_expression))
74-
} else {
75-
in_expression
76-
};
76+
self.consume_as(TokenType::RightParen)?;
7777

78-
Ok(Expression::BinaryMatchingExpression(
79-
Box::new(expression),
80-
in_expression,
81-
))
78+
Ok(InExpressionType::TableFunction(identifier, args))
79+
}
80+
} else {
81+
Ok(InExpressionType::Identity(identifier))
82+
}
8283
}
8384
}
8485

@@ -87,50 +88,53 @@ mod expression_with_in_statement_tests {
8788
use crate::parser::test_utils::run_sunny_day_test;
8889
use crate::select::test_utils::select_expr;
8990
use crate::{
90-
BinaryMatchingExpression, BinaryOp, Expression, Identifier, InExpression, Select,
91-
SelectBody, SelectItem, SelectStatement,
91+
BinaryOp, Expression, Identifier, InExpression, InExpressionType, Select, SelectBody,
92+
SelectItem, SelectStatement,
9293
};
9394

9495
use crate::parser::expression::test_utils::*;
9596

96-
fn in_expr(expression: Expression, in_expression: InExpression, is_not: bool) -> Expression {
97-
let in_expression = if is_not {
98-
BinaryMatchingExpression::Not(Box::new(BinaryMatchingExpression::In(in_expression)))
99-
} else {
100-
BinaryMatchingExpression::In(in_expression)
101-
};
102-
103-
Expression::BinaryMatchingExpression(Box::new(expression), in_expression)
97+
fn in_expr(
98+
expression: Expression,
99+
in_expression: InExpressionType,
100+
is_not: bool,
101+
) -> Expression {
102+
Expression::InExpression(InExpression {
103+
expression: Box::new(expression),
104+
in_expression,
105+
is_not,
106+
})
104107
}
105108

106109
#[test]
107110
fn in_empty() {
108111
run_sunny_day_test(
109112
"SELECT 1 IN ();",
110-
select_expr(in_expr(numeric_expr("1"), InExpression::Empty, false)).into(),
113+
select_expr(in_expr(numeric_expr("1"), InExpressionType::Empty, false)).into(),
111114
);
112115

113116
run_sunny_day_test(
114117
"SELECT 1 NOT IN ();",
115-
select_expr(in_expr(numeric_expr("1"), InExpression::Empty, true)).into(),
118+
select_expr(in_expr(numeric_expr("1"), InExpressionType::Empty, true)).into(),
116119
);
117120
}
118121

119122
#[test]
120123
fn in_select() {
121-
let mut select_statement = Select::default();
122-
select_statement.columns = vec![SelectItem::Expression(numeric_expr("2"))];
124+
let mut select = Select::default();
125+
select.columns = vec![SelectItem::Expression(numeric_expr("2"))];
126+
let select_statement = SelectStatement {
127+
with_cte: None,
128+
select: SelectBody::Select(select),
129+
order_by: None,
130+
limit: None,
131+
};
123132

124133
run_sunny_day_test(
125134
"SELECT 1 IN (SELECT 2);",
126135
select_expr(in_expr(
127136
numeric_expr("1"),
128-
InExpression::Select(SelectStatement {
129-
with_cte: None,
130-
select: SelectBody::Select(select_statement),
131-
order_by: None,
132-
limit: None,
133-
}),
137+
InExpressionType::Select(select_statement),
134138
false,
135139
))
136140
.into(),
@@ -143,7 +147,7 @@ mod expression_with_in_statement_tests {
143147
"SELECT 1 IN (2, 3, 4 + 5);",
144148
select_expr(in_expr(
145149
numeric_expr("1"),
146-
InExpression::Expression(vec![
150+
InExpressionType::Expression(vec![
147151
numeric_expr("2"),
148152
numeric_expr("3"),
149153
binary_op(BinaryOp::Plus, numeric_expr("4"), numeric_expr("5")),
@@ -156,19 +160,21 @@ mod expression_with_in_statement_tests {
156160

157161
#[test]
158162
fn not_in_select() {
159-
let mut select_statement = Select::default();
160-
select_statement.columns = vec![SelectItem::Expression(numeric_expr("2"))];
163+
let mut select = Select::default();
164+
select.columns = vec![SelectItem::Expression(numeric_expr("2"))];
165+
166+
let select_statement = SelectStatement {
167+
with_cte: None,
168+
select: SelectBody::Select(select),
169+
order_by: None,
170+
limit: None,
171+
};
161172

162173
run_sunny_day_test(
163174
"SELECT 1 NOT IN (SELECT 2);",
164175
select_expr(in_expr(
165176
numeric_expr("1"),
166-
InExpression::Select(SelectStatement {
167-
with_cte: None,
168-
select: SelectBody::Select(select_statement),
169-
order_by: None,
170-
limit: None,
171-
}),
177+
InExpressionType::Select(select_statement),
172178
true,
173179
))
174180
.into(),
@@ -181,7 +187,7 @@ mod expression_with_in_statement_tests {
181187
"SELECT 1 NOT IN table_name;",
182188
select_expr(in_expr(
183189
numeric_expr("1"),
184-
InExpression::Identity(Identifier::Single("table_name".to_string())),
190+
InExpressionType::Identity(Identifier::Single("table_name".to_string())),
185191
true,
186192
))
187193
.into(),
@@ -194,7 +200,7 @@ mod expression_with_in_statement_tests {
194200
"SELECT 1 NOT IN schema_name.table_name;",
195201
select_expr(in_expr(
196202
numeric_expr("1"),
197-
InExpression::Identity(Identifier::Compound(vec![
203+
InExpressionType::Identity(Identifier::Compound(vec![
198204
"schema_name".to_string(),
199205
"table_name".to_string(),
200206
])),
@@ -210,7 +216,7 @@ mod expression_with_in_statement_tests {
210216
"SELECT 1 NOT IN schema_name.table_function();",
211217
select_expr(in_expr(
212218
numeric_expr("1"),
213-
InExpression::TableFunction(
219+
InExpressionType::TableFunction(
214220
Identifier::Compound(vec![
215221
"schema_name".to_string(),
216222
"table_function".to_string(),
@@ -229,7 +235,7 @@ mod expression_with_in_statement_tests {
229235
"SELECT 1 NOT IN schema_name.table_function(1, 2, 3);",
230236
select_expr(in_expr(
231237
numeric_expr("1"),
232-
InExpression::TableFunction(
238+
InExpressionType::TableFunction(
233239
Identifier::Compound(vec![
234240
"schema_name".to_string(),
235241
"table_function".to_string(),
@@ -248,7 +254,7 @@ mod expression_with_in_statement_tests {
248254
"SELECT 1 NOT IN table_function(1+2, 3*4);",
249255
select_expr(in_expr(
250256
numeric_expr("1"),
251-
InExpression::TableFunction(
257+
InExpressionType::TableFunction(
252258
Identifier::Single("table_function".to_string()),
253259
vec![
254260
binary_op(BinaryOp::Plus, numeric_expr("1"), numeric_expr("2")),

src/parser/select/mod.rs

+6-7
Original file line numberDiff line numberDiff line change
@@ -278,7 +278,7 @@ mod where_clause_tests {
278278
use super::test_utils::{select, select_star_from};
279279
use crate::expression::test_utils::{binary_op, expr_list, identifier_expr, numeric_expr};
280280
use crate::parser::test_utils::*;
281-
use crate::{BinaryMatchingExpression, BinaryOp, Expression, Identifier, InExpression};
281+
use crate::{BinaryOp, Expression, Identifier, InExpression, InExpressionType};
282282

283283
#[test]
284284
fn select_where_clause() {
@@ -333,12 +333,11 @@ mod where_clause_tests {
333333
fn select_where_clause_with_subquery() {
334334
let subquery = select_star_from(Identifier::Single("table_2".to_string()));
335335

336-
let expression = Expression::BinaryMatchingExpression(
337-
Box::new(identifier_expr(&["col1"])),
338-
BinaryMatchingExpression::Not(Box::new(BinaryMatchingExpression::In(
339-
InExpression::Select(subquery),
340-
))),
341-
);
336+
let expression = Expression::InExpression(InExpression {
337+
expression: Box::new(identifier_expr(&["col1"])),
338+
in_expression: InExpressionType::Select(subquery),
339+
is_not: true,
340+
});
342341
let mut expected_statement = select();
343342
expected_statement.where_clause = Some(Box::new(expression));
344343
run_sunny_day_test(

0 commit comments

Comments
 (0)