Skip to content

Commit ae25dce

Browse files
committed
Split operators by arity
It is useful downstream to have two separate enums, one for unary operators and one for binary operators, so that the compiler can check exhaustiveness. Otherwise downstream consumers need to manually encode which operators are unary and which operators are binary when matching on an Operator enum.
1 parent 9e33cea commit ae25dce

File tree

4 files changed

+85
-71
lines changed

4 files changed

+85
-71
lines changed

src/sqlast/mod.rs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,10 @@ pub use self::query::{
2727
Cte, Fetch, Join, JoinConstraint, JoinOperator, SQLOrderByExpr, SQLQuery, SQLSelect,
2828
SQLSelectItem, SQLSetExpr, SQLSetOperator, SQLValues, TableAlias, TableFactor, TableWithJoins,
2929
};
30+
pub use self::sql_operator::{SQLBinaryOperator, SQLUnaryOperator};
3031
pub use self::sqltype::SQLType;
3132
pub use self::value::{SQLDateTimeField, Value};
3233

33-
pub use self::sql_operator::SQLOperator;
34-
3534
/// Like `vec.join(", ")`, but for any types implementing ToString.
3635
fn comma_separated_string<I>(iter: I) -> String
3736
where
@@ -92,12 +91,12 @@ pub enum ASTNode {
9291
/// Binary operation e.g. `1 + 1` or `foo > bar`
9392
SQLBinaryOp {
9493
left: Box<ASTNode>,
95-
op: SQLOperator,
94+
op: SQLBinaryOperator,
9695
right: Box<ASTNode>,
9796
},
9897
/// Unary operation e.g. `NOT foo`
9998
SQLUnaryOp {
100-
op: SQLOperator,
99+
op: SQLUnaryOperator,
101100
expr: Box<ASTNode>,
102101
},
103102
/// CAST an expression to a different data type e.g. `CAST(foo AS VARCHAR(123))`

src/sqlast/sql_operator.rs

Lines changed: 36 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,27 @@
1010
// See the License for the specific language governing permissions and
1111
// limitations under the License.
1212

13-
/// SQL Operator
13+
/// Unary operators
1414
#[derive(Debug, Clone, PartialEq, Hash)]
15-
pub enum SQLOperator {
15+
pub enum SQLUnaryOperator {
16+
Plus,
17+
Minus,
18+
Not,
19+
}
20+
21+
impl ToString for SQLUnaryOperator {
22+
fn to_string(&self) -> String {
23+
match self {
24+
SQLUnaryOperator::Plus => "+".to_string(),
25+
SQLUnaryOperator::Minus => "-".to_string(),
26+
SQLUnaryOperator::Not => "NOT".to_string(),
27+
}
28+
}
29+
}
30+
31+
/// Binary operators
32+
#[derive(Debug, Clone, PartialEq, Hash)]
33+
pub enum SQLBinaryOperator {
1634
Plus,
1735
Minus,
1836
Multiply,
@@ -26,30 +44,28 @@ pub enum SQLOperator {
2644
NotEq,
2745
And,
2846
Or,
29-
Not,
3047
Like,
3148
NotLike,
3249
}
3350

34-
impl ToString for SQLOperator {
51+
impl ToString for SQLBinaryOperator {
3552
fn to_string(&self) -> String {
3653
match self {
37-
SQLOperator::Plus => "+".to_string(),
38-
SQLOperator::Minus => "-".to_string(),
39-
SQLOperator::Multiply => "*".to_string(),
40-
SQLOperator::Divide => "/".to_string(),
41-
SQLOperator::Modulus => "%".to_string(),
42-
SQLOperator::Gt => ">".to_string(),
43-
SQLOperator::Lt => "<".to_string(),
44-
SQLOperator::GtEq => ">=".to_string(),
45-
SQLOperator::LtEq => "<=".to_string(),
46-
SQLOperator::Eq => "=".to_string(),
47-
SQLOperator::NotEq => "<>".to_string(),
48-
SQLOperator::And => "AND".to_string(),
49-
SQLOperator::Or => "OR".to_string(),
50-
SQLOperator::Not => "NOT".to_string(),
51-
SQLOperator::Like => "LIKE".to_string(),
52-
SQLOperator::NotLike => "NOT LIKE".to_string(),
54+
SQLBinaryOperator::Plus => "+".to_string(),
55+
SQLBinaryOperator::Minus => "-".to_string(),
56+
SQLBinaryOperator::Multiply => "*".to_string(),
57+
SQLBinaryOperator::Divide => "/".to_string(),
58+
SQLBinaryOperator::Modulus => "%".to_string(),
59+
SQLBinaryOperator::Gt => ">".to_string(),
60+
SQLBinaryOperator::Lt => "<".to_string(),
61+
SQLBinaryOperator::GtEq => ">=".to_string(),
62+
SQLBinaryOperator::LtEq => "<=".to_string(),
63+
SQLBinaryOperator::Eq => "=".to_string(),
64+
SQLBinaryOperator::NotEq => "<>".to_string(),
65+
SQLBinaryOperator::And => "AND".to_string(),
66+
SQLBinaryOperator::Or => "OR".to_string(),
67+
SQLBinaryOperator::Like => "LIKE".to_string(),
68+
SQLBinaryOperator::NotLike => "NOT LIKE".to_string(),
5369
}
5470
}
5571
}

src/sqlparser.rs

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -184,7 +184,7 @@ impl Parser {
184184
"EXTRACT" => self.parse_extract_expression(),
185185
"INTERVAL" => self.parse_literal_interval(),
186186
"NOT" => Ok(ASTNode::SQLUnaryOp {
187-
op: SQLOperator::Not,
187+
op: SQLUnaryOperator::Not,
188188
expr: Box::new(self.parse_subexpr(Self::UNARY_NOT_PREC)?),
189189
}),
190190
"TIME" => Ok(ASTNode::SQLValue(Value::Time(self.parse_literal_string()?))),
@@ -225,9 +225,9 @@ impl Parser {
225225
Token::Mult => Ok(ASTNode::SQLWildcard),
226226
tok @ Token::Minus | tok @ Token::Plus => {
227227
let op = if tok == Token::Plus {
228-
SQLOperator::Plus
228+
SQLUnaryOperator::Plus
229229
} else {
230-
SQLOperator::Minus
230+
SQLUnaryOperator::Minus
231231
};
232232
Ok(ASTNode::SQLUnaryOp {
233233
op,
@@ -513,24 +513,24 @@ impl Parser {
513513
let tok = self.next_token().unwrap(); // safe as EOF's precedence is the lowest
514514

515515
let regular_binary_operator = match tok {
516-
Token::Eq => Some(SQLOperator::Eq),
517-
Token::Neq => Some(SQLOperator::NotEq),
518-
Token::Gt => Some(SQLOperator::Gt),
519-
Token::GtEq => Some(SQLOperator::GtEq),
520-
Token::Lt => Some(SQLOperator::Lt),
521-
Token::LtEq => Some(SQLOperator::LtEq),
522-
Token::Plus => Some(SQLOperator::Plus),
523-
Token::Minus => Some(SQLOperator::Minus),
524-
Token::Mult => Some(SQLOperator::Multiply),
525-
Token::Mod => Some(SQLOperator::Modulus),
526-
Token::Div => Some(SQLOperator::Divide),
516+
Token::Eq => Some(SQLBinaryOperator::Eq),
517+
Token::Neq => Some(SQLBinaryOperator::NotEq),
518+
Token::Gt => Some(SQLBinaryOperator::Gt),
519+
Token::GtEq => Some(SQLBinaryOperator::GtEq),
520+
Token::Lt => Some(SQLBinaryOperator::Lt),
521+
Token::LtEq => Some(SQLBinaryOperator::LtEq),
522+
Token::Plus => Some(SQLBinaryOperator::Plus),
523+
Token::Minus => Some(SQLBinaryOperator::Minus),
524+
Token::Mult => Some(SQLBinaryOperator::Multiply),
525+
Token::Mod => Some(SQLBinaryOperator::Modulus),
526+
Token::Div => Some(SQLBinaryOperator::Divide),
527527
Token::SQLWord(ref k) => match k.keyword.as_ref() {
528-
"AND" => Some(SQLOperator::And),
529-
"OR" => Some(SQLOperator::Or),
530-
"LIKE" => Some(SQLOperator::Like),
528+
"AND" => Some(SQLBinaryOperator::And),
529+
"OR" => Some(SQLBinaryOperator::Or),
530+
"LIKE" => Some(SQLBinaryOperator::Like),
531531
"NOT" => {
532532
if self.parse_keyword("LIKE") {
533-
Some(SQLOperator::NotLike)
533+
Some(SQLBinaryOperator::NotLike)
534534
} else {
535535
None
536536
}

tests/sqlparser_common.rs

Lines changed: 28 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,7 @@ fn parse_delete_statement() {
169169
#[test]
170170
fn parse_where_delete_statement() {
171171
use self::ASTNode::*;
172-
use self::SQLOperator::*;
172+
use self::SQLBinaryOperator::*;
173173

174174
let sql = "DELETE FROM foo WHERE name = 5";
175175
match verified_stmt(sql) {
@@ -288,7 +288,7 @@ fn parse_column_aliases() {
288288
ref alias,
289289
} = only(&select.projection)
290290
{
291-
assert_eq!(&SQLOperator::Plus, op);
291+
assert_eq!(&SQLBinaryOperator::Plus, op);
292292
assert_eq!(&ASTNode::SQLValue(Value::Long(1)), right.as_ref());
293293
assert_eq!("newname", alias);
294294
} else {
@@ -337,7 +337,7 @@ fn parse_select_count_distinct() {
337337
&ASTNode::SQLFunction(SQLFunction {
338338
name: SQLObjectName(vec!["COUNT".to_string()]),
339339
args: vec![ASTNode::SQLUnaryOp {
340-
op: SQLOperator::Plus,
340+
op: SQLUnaryOperator::Plus,
341341
expr: Box::new(ASTNode::SQLIdentifier("x".to_string()))
342342
}],
343343
over: None,
@@ -404,7 +404,7 @@ fn parse_projection_nested_type() {
404404
#[test]
405405
fn parse_escaped_single_quote_string_predicate() {
406406
use self::ASTNode::*;
407-
use self::SQLOperator::*;
407+
use self::SQLBinaryOperator::*;
408408
let sql = "SELECT id, fname, lname FROM customer \
409409
WHERE salary <> 'Jim''s salary'";
410410
let ast = verified_only_select(sql);
@@ -423,7 +423,7 @@ fn parse_escaped_single_quote_string_predicate() {
423423
#[test]
424424
fn parse_compound_expr_1() {
425425
use self::ASTNode::*;
426-
use self::SQLOperator::*;
426+
use self::SQLBinaryOperator::*;
427427
let sql = "a + b * c";
428428
assert_eq!(
429429
SQLBinaryOp {
@@ -442,7 +442,7 @@ fn parse_compound_expr_1() {
442442
#[test]
443443
fn parse_compound_expr_2() {
444444
use self::ASTNode::*;
445-
use self::SQLOperator::*;
445+
use self::SQLBinaryOperator::*;
446446
let sql = "a * b + c";
447447
assert_eq!(
448448
SQLBinaryOp {
@@ -461,17 +461,16 @@ fn parse_compound_expr_2() {
461461
#[test]
462462
fn parse_unary_math() {
463463
use self::ASTNode::*;
464-
use self::SQLOperator::*;
465464
let sql = "- a + - b";
466465
assert_eq!(
467466
SQLBinaryOp {
468467
left: Box::new(SQLUnaryOp {
469-
op: Minus,
468+
op: SQLUnaryOperator::Minus,
470469
expr: Box::new(SQLIdentifier("a".to_string())),
471470
}),
472-
op: Plus,
471+
op: SQLBinaryOperator::Plus,
473472
right: Box::new(SQLUnaryOp {
474-
op: Minus,
473+
op: SQLUnaryOperator::Minus,
475474
expr: Box::new(SQLIdentifier("b".to_string())),
476475
}),
477476
},
@@ -505,14 +504,14 @@ fn parse_not_precedence() {
505504
// NOT has higher precedence than OR/AND, so the following must parse as (NOT true) OR true
506505
let sql = "NOT true OR true";
507506
assert_matches!(verified_expr(sql), SQLBinaryOp {
508-
op: SQLOperator::Or,
507+
op: SQLBinaryOperator::Or,
509508
..
510509
});
511510

512511
// But NOT has lower precedence than comparison operators, so the following parses as NOT (a IS NULL)
513512
let sql = "NOT a IS NULL";
514513
assert_matches!(verified_expr(sql), SQLUnaryOp {
515-
op: SQLOperator::Not,
514+
op: SQLUnaryOperator::Not,
516515
..
517516
});
518517

@@ -521,7 +520,7 @@ fn parse_not_precedence() {
521520
assert_eq!(
522521
verified_expr(sql),
523522
SQLUnaryOp {
524-
op: SQLOperator::Not,
523+
op: SQLUnaryOperator::Not,
525524
expr: Box::new(SQLBetween {
526525
expr: Box::new(SQLValue(Value::Long(1))),
527526
low: Box::new(SQLValue(Value::Long(1))),
@@ -536,10 +535,10 @@ fn parse_not_precedence() {
536535
assert_eq!(
537536
verified_expr(sql),
538537
SQLUnaryOp {
539-
op: SQLOperator::Not,
538+
op: SQLUnaryOperator::Not,
540539
expr: Box::new(SQLBinaryOp {
541540
left: Box::new(SQLValue(Value::SingleQuotedString("a".into()))),
542-
op: SQLOperator::NotLike,
541+
op: SQLBinaryOperator::NotLike,
543542
right: Box::new(SQLValue(Value::SingleQuotedString("b".into()))),
544543
}),
545544
},
@@ -550,7 +549,7 @@ fn parse_not_precedence() {
550549
assert_eq!(
551550
verified_expr(sql),
552551
SQLUnaryOp {
553-
op: SQLOperator::Not,
552+
op: SQLUnaryOperator::Not,
554553
expr: Box::new(SQLInList {
555554
expr: Box::new(SQLIdentifier("a".into())),
556555
list: vec![SQLValue(Value::SingleQuotedString("a".into()))],
@@ -572,9 +571,9 @@ fn parse_like() {
572571
ASTNode::SQLBinaryOp {
573572
left: Box::new(ASTNode::SQLIdentifier("name".to_string())),
574573
op: if negated {
575-
SQLOperator::NotLike
574+
SQLBinaryOperator::NotLike
576575
} else {
577-
SQLOperator::Like
576+
SQLBinaryOperator::Like
578577
},
579578
right: Box::new(ASTNode::SQLValue(Value::SingleQuotedString(
580579
"%a".to_string()
@@ -594,9 +593,9 @@ fn parse_like() {
594593
ASTNode::SQLIsNull(Box::new(ASTNode::SQLBinaryOp {
595594
left: Box::new(ASTNode::SQLIdentifier("name".to_string())),
596595
op: if negated {
597-
SQLOperator::NotLike
596+
SQLBinaryOperator::NotLike
598597
} else {
599-
SQLOperator::Like
598+
SQLBinaryOperator::Like
600599
},
601600
right: Box::new(ASTNode::SQLValue(Value::SingleQuotedString(
602601
"%a".to_string()
@@ -672,7 +671,7 @@ fn parse_between() {
672671
#[test]
673672
fn parse_between_with_expr() {
674673
use self::ASTNode::*;
675-
use self::SQLOperator::*;
674+
use self::SQLBinaryOperator::*;
676675
let sql = "SELECT * FROM t WHERE 1 BETWEEN 1 + 2 AND 3 + 4 IS NULL";
677676
let select = verified_only_select(sql);
678677
assert_eq!(
@@ -699,14 +698,14 @@ fn parse_between_with_expr() {
699698
ASTNode::SQLBinaryOp {
700699
left: Box::new(ASTNode::SQLBinaryOp {
701700
left: Box::new(ASTNode::SQLValue(Value::Long(1))),
702-
op: SQLOperator::Eq,
701+
op: SQLBinaryOperator::Eq,
703702
right: Box::new(ASTNode::SQLValue(Value::Long(1))),
704703
}),
705-
op: SQLOperator::And,
704+
op: SQLBinaryOperator::And,
706705
right: Box::new(ASTNode::SQLBetween {
707706
expr: Box::new(ASTNode::SQLBinaryOp {
708707
left: Box::new(ASTNode::SQLValue(Value::Long(1))),
709-
op: SQLOperator::Plus,
708+
op: SQLBinaryOperator::Plus,
710709
right: Box::new(ASTNode::SQLIdentifier("x".to_string())),
711710
}),
712711
low: Box::new(ASTNode::SQLValue(Value::Long(1))),
@@ -1365,7 +1364,7 @@ fn parse_delimited_identifiers() {
13651364
#[test]
13661365
fn parse_parens() {
13671366
use self::ASTNode::*;
1368-
use self::SQLOperator::*;
1367+
use self::SQLBinaryOperator::*;
13691368
let sql = "(a + b) - (c + d)";
13701369
assert_eq!(
13711370
SQLBinaryOp {
@@ -1389,7 +1388,7 @@ fn parse_parens() {
13891388
fn parse_searched_case_expression() {
13901389
let sql = "SELECT CASE WHEN bar IS NULL THEN 'null' WHEN bar = 0 THEN '=0' WHEN bar >= 0 THEN '>=0' ELSE '<0' END FROM foo";
13911390
use self::ASTNode::{SQLBinaryOp, SQLCase, SQLIdentifier, SQLIsNull, SQLValue};
1392-
use self::SQLOperator::*;
1391+
use self::SQLBinaryOperator::*;
13931392
let select = verified_only_select(sql);
13941393
assert_eq!(
13951394
&SQLCase {
@@ -1557,7 +1556,7 @@ fn parse_joins_on() {
15571556
},
15581557
join_operator: f(JoinConstraint::On(ASTNode::SQLBinaryOp {
15591558
left: Box::new(ASTNode::SQLIdentifier("c1".into())),
1560-
op: SQLOperator::Eq,
1559+
op: SQLBinaryOperator::Eq,
15611560
right: Box::new(ASTNode::SQLIdentifier("c2".into())),
15621561
})),
15631562
}
@@ -1921,7 +1920,7 @@ fn parse_scalar_subqueries() {
19211920
use self::ASTNode::*;
19221921
let sql = "(SELECT 1) + (SELECT 2)";
19231922
assert_matches!(verified_expr(sql), SQLBinaryOp {
1924-
op: SQLOperator::Plus, ..
1923+
op: SQLBinaryOperator::Plus, ..
19251924
//left: box SQLSubquery { .. },
19261925
//right: box SQLSubquery { .. },
19271926
});
@@ -1941,7 +1940,7 @@ fn parse_exists_subquery() {
19411940
let select = verified_only_select(sql);
19421941
assert_eq!(
19431942
ASTNode::SQLUnaryOp {
1944-
op: SQLOperator::Not,
1943+
op: SQLUnaryOperator::Not,
19451944
expr: Box::new(ASTNode::SQLExists(Box::new(expected_inner))),
19461945
},
19471946
select.selection.unwrap(),

0 commit comments

Comments
 (0)