Skip to content

Commit b670e12

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 79c231b commit b670e12

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
@@ -29,11 +29,10 @@ pub use self::query::{
2929
Cte, Fetch, Join, JoinConstraint, JoinOperator, SQLOrderByExpr, SQLQuery, SQLSelect,
3030
SQLSelectItem, SQLSetExpr, SQLSetOperator, SQLValues, TableAlias, TableFactor, TableWithJoins,
3131
};
32+
pub use self::sql_operator::{SQLBinaryOperator, SQLUnaryOperator};
3233
pub use self::sqltype::SQLType;
3334
pub use self::value::{SQLDateTimeField, Value};
3435

35-
pub use self::sql_operator::SQLOperator;
36-
3736
/// Like `vec.join(", ")`, but for any types implementing ToString.
3837
fn comma_separated_string<I>(iter: I) -> String
3938
where
@@ -94,12 +93,12 @@ pub enum ASTNode {
9493
/// Binary operation e.g. `1 + 1` or `foo > bar`
9594
SQLBinaryOp {
9695
left: Box<ASTNode>,
97-
op: SQLOperator,
96+
op: SQLBinaryOperator,
9897
right: Box<ASTNode>,
9998
},
10099
/// Unary operation e.g. `NOT foo`
101100
SQLUnaryOp {
102-
op: SQLOperator,
101+
op: SQLUnaryOperator,
103102
expr: Box<ASTNode>,
104103
},
105104
/// 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
@@ -1,6 +1,24 @@
1-
/// SQL Operator
1+
/// Unary operators
22
#[derive(Debug, Clone, PartialEq, Hash)]
3-
pub enum SQLOperator {
3+
pub enum SQLUnaryOperator {
4+
Plus,
5+
Minus,
6+
Not,
7+
}
8+
9+
impl ToString for SQLUnaryOperator {
10+
fn to_string(&self) -> String {
11+
match self {
12+
SQLUnaryOperator::Plus => "+".to_string(),
13+
SQLUnaryOperator::Minus => "-".to_string(),
14+
SQLUnaryOperator::Not => "NOT".to_string(),
15+
}
16+
}
17+
}
18+
19+
/// Binary operators
20+
#[derive(Debug, Clone, PartialEq, Hash)]
21+
pub enum SQLBinaryOperator {
422
Plus,
523
Minus,
624
Multiply,
@@ -14,30 +32,28 @@ pub enum SQLOperator {
1432
NotEq,
1533
And,
1634
Or,
17-
Not,
1835
Like,
1936
NotLike,
2037
}
2138

22-
impl ToString for SQLOperator {
39+
impl ToString for SQLBinaryOperator {
2340
fn to_string(&self) -> String {
2441
match self {
25-
SQLOperator::Plus => "+".to_string(),
26-
SQLOperator::Minus => "-".to_string(),
27-
SQLOperator::Multiply => "*".to_string(),
28-
SQLOperator::Divide => "/".to_string(),
29-
SQLOperator::Modulus => "%".to_string(),
30-
SQLOperator::Gt => ">".to_string(),
31-
SQLOperator::Lt => "<".to_string(),
32-
SQLOperator::GtEq => ">=".to_string(),
33-
SQLOperator::LtEq => "<=".to_string(),
34-
SQLOperator::Eq => "=".to_string(),
35-
SQLOperator::NotEq => "<>".to_string(),
36-
SQLOperator::And => "AND".to_string(),
37-
SQLOperator::Or => "OR".to_string(),
38-
SQLOperator::Not => "NOT".to_string(),
39-
SQLOperator::Like => "LIKE".to_string(),
40-
SQLOperator::NotLike => "NOT LIKE".to_string(),
42+
SQLBinaryOperator::Plus => "+".to_string(),
43+
SQLBinaryOperator::Minus => "-".to_string(),
44+
SQLBinaryOperator::Multiply => "*".to_string(),
45+
SQLBinaryOperator::Divide => "/".to_string(),
46+
SQLBinaryOperator::Modulus => "%".to_string(),
47+
SQLBinaryOperator::Gt => ">".to_string(),
48+
SQLBinaryOperator::Lt => "<".to_string(),
49+
SQLBinaryOperator::GtEq => ">=".to_string(),
50+
SQLBinaryOperator::LtEq => "<=".to_string(),
51+
SQLBinaryOperator::Eq => "=".to_string(),
52+
SQLBinaryOperator::NotEq => "<>".to_string(),
53+
SQLBinaryOperator::And => "AND".to_string(),
54+
SQLBinaryOperator::Or => "OR".to_string(),
55+
SQLBinaryOperator::Like => "LIKE".to_string(),
56+
SQLBinaryOperator::NotLike => "NOT LIKE".to_string(),
4157
}
4258
}
4359
}

src/sqlparser.rs

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,7 @@ impl Parser {
186186
"EXTRACT" => self.parse_extract_expression(),
187187
"INTERVAL" => self.parse_literal_interval(),
188188
"NOT" => Ok(ASTNode::SQLUnaryOp {
189-
op: SQLOperator::Not,
189+
op: SQLUnaryOperator::Not,
190190
expr: Box::new(self.parse_subexpr(Self::UNARY_NOT_PREC)?),
191191
}),
192192
"TIME" => Ok(ASTNode::SQLValue(Value::Time(self.parse_literal_string()?))),
@@ -227,9 +227,9 @@ impl Parser {
227227
Token::Mult => Ok(ASTNode::SQLWildcard),
228228
tok @ Token::Minus | tok @ Token::Plus => {
229229
let op = if tok == Token::Plus {
230-
SQLOperator::Plus
230+
SQLUnaryOperator::Plus
231231
} else {
232-
SQLOperator::Minus
232+
SQLUnaryOperator::Minus
233233
};
234234
Ok(ASTNode::SQLUnaryOp {
235235
op,
@@ -515,24 +515,24 @@ impl Parser {
515515
let tok = self.next_token().unwrap(); // safe as EOF's precedence is the lowest
516516

517517
let regular_binary_operator = match tok {
518-
Token::Eq => Some(SQLOperator::Eq),
519-
Token::Neq => Some(SQLOperator::NotEq),
520-
Token::Gt => Some(SQLOperator::Gt),
521-
Token::GtEq => Some(SQLOperator::GtEq),
522-
Token::Lt => Some(SQLOperator::Lt),
523-
Token::LtEq => Some(SQLOperator::LtEq),
524-
Token::Plus => Some(SQLOperator::Plus),
525-
Token::Minus => Some(SQLOperator::Minus),
526-
Token::Mult => Some(SQLOperator::Multiply),
527-
Token::Mod => Some(SQLOperator::Modulus),
528-
Token::Div => Some(SQLOperator::Divide),
518+
Token::Eq => Some(SQLBinaryOperator::Eq),
519+
Token::Neq => Some(SQLBinaryOperator::NotEq),
520+
Token::Gt => Some(SQLBinaryOperator::Gt),
521+
Token::GtEq => Some(SQLBinaryOperator::GtEq),
522+
Token::Lt => Some(SQLBinaryOperator::Lt),
523+
Token::LtEq => Some(SQLBinaryOperator::LtEq),
524+
Token::Plus => Some(SQLBinaryOperator::Plus),
525+
Token::Minus => Some(SQLBinaryOperator::Minus),
526+
Token::Mult => Some(SQLBinaryOperator::Multiply),
527+
Token::Mod => Some(SQLBinaryOperator::Modulus),
528+
Token::Div => Some(SQLBinaryOperator::Divide),
529529
Token::SQLWord(ref k) => match k.keyword.as_ref() {
530-
"AND" => Some(SQLOperator::And),
531-
"OR" => Some(SQLOperator::Or),
532-
"LIKE" => Some(SQLOperator::Like),
530+
"AND" => Some(SQLBinaryOperator::And),
531+
"OR" => Some(SQLBinaryOperator::Or),
532+
"LIKE" => Some(SQLBinaryOperator::Like),
533533
"NOT" => {
534534
if self.parse_keyword("LIKE") {
535-
Some(SQLOperator::NotLike)
535+
Some(SQLBinaryOperator::NotLike)
536536
} else {
537537
None
538538
}

tests/sqlparser_common.rs

Lines changed: 28 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,7 @@ fn parse_delete_statement() {
157157
#[test]
158158
fn parse_where_delete_statement() {
159159
use self::ASTNode::*;
160-
use self::SQLOperator::*;
160+
use self::SQLBinaryOperator::*;
161161

162162
let sql = "DELETE FROM foo WHERE name = 5";
163163
match verified_stmt(sql) {
@@ -276,7 +276,7 @@ fn parse_column_aliases() {
276276
ref alias,
277277
} = only(&select.projection)
278278
{
279-
assert_eq!(&SQLOperator::Plus, op);
279+
assert_eq!(&SQLBinaryOperator::Plus, op);
280280
assert_eq!(&ASTNode::SQLValue(Value::Long(1)), right.as_ref());
281281
assert_eq!("newname", alias);
282282
} else {
@@ -325,7 +325,7 @@ fn parse_select_count_distinct() {
325325
&ASTNode::SQLFunction(SQLFunction {
326326
name: SQLObjectName(vec!["COUNT".to_string()]),
327327
args: vec![ASTNode::SQLUnaryOp {
328-
op: SQLOperator::Plus,
328+
op: SQLUnaryOperator::Plus,
329329
expr: Box::new(ASTNode::SQLIdentifier("x".to_string()))
330330
}],
331331
over: None,
@@ -392,7 +392,7 @@ fn parse_projection_nested_type() {
392392
#[test]
393393
fn parse_escaped_single_quote_string_predicate() {
394394
use self::ASTNode::*;
395-
use self::SQLOperator::*;
395+
use self::SQLBinaryOperator::*;
396396
let sql = "SELECT id, fname, lname FROM customer \
397397
WHERE salary <> 'Jim''s salary'";
398398
let ast = verified_only_select(sql);
@@ -411,7 +411,7 @@ fn parse_escaped_single_quote_string_predicate() {
411411
#[test]
412412
fn parse_compound_expr_1() {
413413
use self::ASTNode::*;
414-
use self::SQLOperator::*;
414+
use self::SQLBinaryOperator::*;
415415
let sql = "a + b * c";
416416
assert_eq!(
417417
SQLBinaryOp {
@@ -430,7 +430,7 @@ fn parse_compound_expr_1() {
430430
#[test]
431431
fn parse_compound_expr_2() {
432432
use self::ASTNode::*;
433-
use self::SQLOperator::*;
433+
use self::SQLBinaryOperator::*;
434434
let sql = "a * b + c";
435435
assert_eq!(
436436
SQLBinaryOp {
@@ -449,17 +449,16 @@ fn parse_compound_expr_2() {
449449
#[test]
450450
fn parse_unary_math() {
451451
use self::ASTNode::*;
452-
use self::SQLOperator::*;
453452
let sql = "- a + - b";
454453
assert_eq!(
455454
SQLBinaryOp {
456455
left: Box::new(SQLUnaryOp {
457-
op: Minus,
456+
op: SQLUnaryOperator::Minus,
458457
expr: Box::new(SQLIdentifier("a".to_string())),
459458
}),
460-
op: Plus,
459+
op: SQLBinaryOperator::Plus,
461460
right: Box::new(SQLUnaryOp {
462-
op: Minus,
461+
op: SQLUnaryOperator::Minus,
463462
expr: Box::new(SQLIdentifier("b".to_string())),
464463
}),
465464
},
@@ -493,14 +492,14 @@ fn parse_not_precedence() {
493492
// NOT has higher precedence than OR/AND, so the following must parse as (NOT true) OR true
494493
let sql = "NOT true OR true";
495494
assert_matches!(verified_expr(sql), SQLBinaryOp {
496-
op: SQLOperator::Or,
495+
op: SQLBinaryOperator::Or,
497496
..
498497
});
499498

500499
// But NOT has lower precedence than comparison operators, so the following parses as NOT (a IS NULL)
501500
let sql = "NOT a IS NULL";
502501
assert_matches!(verified_expr(sql), SQLUnaryOp {
503-
op: SQLOperator::Not,
502+
op: SQLUnaryOperator::Not,
504503
..
505504
});
506505

@@ -509,7 +508,7 @@ fn parse_not_precedence() {
509508
assert_eq!(
510509
verified_expr(sql),
511510
SQLUnaryOp {
512-
op: SQLOperator::Not,
511+
op: SQLUnaryOperator::Not,
513512
expr: Box::new(SQLBetween {
514513
expr: Box::new(SQLValue(Value::Long(1))),
515514
low: Box::new(SQLValue(Value::Long(1))),
@@ -524,10 +523,10 @@ fn parse_not_precedence() {
524523
assert_eq!(
525524
verified_expr(sql),
526525
SQLUnaryOp {
527-
op: SQLOperator::Not,
526+
op: SQLUnaryOperator::Not,
528527
expr: Box::new(SQLBinaryOp {
529528
left: Box::new(SQLValue(Value::SingleQuotedString("a".into()))),
530-
op: SQLOperator::NotLike,
529+
op: SQLBinaryOperator::NotLike,
531530
right: Box::new(SQLValue(Value::SingleQuotedString("b".into()))),
532531
}),
533532
},
@@ -538,7 +537,7 @@ fn parse_not_precedence() {
538537
assert_eq!(
539538
verified_expr(sql),
540539
SQLUnaryOp {
541-
op: SQLOperator::Not,
540+
op: SQLUnaryOperator::Not,
542541
expr: Box::new(SQLInList {
543542
expr: Box::new(SQLIdentifier("a".into())),
544543
list: vec![SQLValue(Value::SingleQuotedString("a".into()))],
@@ -560,9 +559,9 @@ fn parse_like() {
560559
ASTNode::SQLBinaryOp {
561560
left: Box::new(ASTNode::SQLIdentifier("name".to_string())),
562561
op: if negated {
563-
SQLOperator::NotLike
562+
SQLBinaryOperator::NotLike
564563
} else {
565-
SQLOperator::Like
564+
SQLBinaryOperator::Like
566565
},
567566
right: Box::new(ASTNode::SQLValue(Value::SingleQuotedString(
568567
"%a".to_string()
@@ -582,9 +581,9 @@ fn parse_like() {
582581
ASTNode::SQLIsNull(Box::new(ASTNode::SQLBinaryOp {
583582
left: Box::new(ASTNode::SQLIdentifier("name".to_string())),
584583
op: if negated {
585-
SQLOperator::NotLike
584+
SQLBinaryOperator::NotLike
586585
} else {
587-
SQLOperator::Like
586+
SQLBinaryOperator::Like
588587
},
589588
right: Box::new(ASTNode::SQLValue(Value::SingleQuotedString(
590589
"%a".to_string()
@@ -660,7 +659,7 @@ fn parse_between() {
660659
#[test]
661660
fn parse_between_with_expr() {
662661
use self::ASTNode::*;
663-
use self::SQLOperator::*;
662+
use self::SQLBinaryOperator::*;
664663
let sql = "SELECT * FROM t WHERE 1 BETWEEN 1 + 2 AND 3 + 4 IS NULL";
665664
let select = verified_only_select(sql);
666665
assert_eq!(
@@ -687,14 +686,14 @@ fn parse_between_with_expr() {
687686
ASTNode::SQLBinaryOp {
688687
left: Box::new(ASTNode::SQLBinaryOp {
689688
left: Box::new(ASTNode::SQLValue(Value::Long(1))),
690-
op: SQLOperator::Eq,
689+
op: SQLBinaryOperator::Eq,
691690
right: Box::new(ASTNode::SQLValue(Value::Long(1))),
692691
}),
693-
op: SQLOperator::And,
692+
op: SQLBinaryOperator::And,
694693
right: Box::new(ASTNode::SQLBetween {
695694
expr: Box::new(ASTNode::SQLBinaryOp {
696695
left: Box::new(ASTNode::SQLValue(Value::Long(1))),
697-
op: SQLOperator::Plus,
696+
op: SQLBinaryOperator::Plus,
698697
right: Box::new(ASTNode::SQLIdentifier("x".to_string())),
699698
}),
700699
low: Box::new(ASTNode::SQLValue(Value::Long(1))),
@@ -1353,7 +1352,7 @@ fn parse_delimited_identifiers() {
13531352
#[test]
13541353
fn parse_parens() {
13551354
use self::ASTNode::*;
1356-
use self::SQLOperator::*;
1355+
use self::SQLBinaryOperator::*;
13571356
let sql = "(a + b) - (c + d)";
13581357
assert_eq!(
13591358
SQLBinaryOp {
@@ -1377,7 +1376,7 @@ fn parse_parens() {
13771376
fn parse_searched_case_expression() {
13781377
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";
13791378
use self::ASTNode::{SQLBinaryOp, SQLCase, SQLIdentifier, SQLIsNull, SQLValue};
1380-
use self::SQLOperator::*;
1379+
use self::SQLBinaryOperator::*;
13811380
let select = verified_only_select(sql);
13821381
assert_eq!(
13831382
&SQLCase {
@@ -1545,7 +1544,7 @@ fn parse_joins_on() {
15451544
},
15461545
join_operator: f(JoinConstraint::On(ASTNode::SQLBinaryOp {
15471546
left: Box::new(ASTNode::SQLIdentifier("c1".into())),
1548-
op: SQLOperator::Eq,
1547+
op: SQLBinaryOperator::Eq,
15491548
right: Box::new(ASTNode::SQLIdentifier("c2".into())),
15501549
})),
15511550
}
@@ -1909,7 +1908,7 @@ fn parse_scalar_subqueries() {
19091908
use self::ASTNode::*;
19101909
let sql = "(SELECT 1) + (SELECT 2)";
19111910
assert_matches!(verified_expr(sql), SQLBinaryOp {
1912-
op: SQLOperator::Plus, ..
1911+
op: SQLBinaryOperator::Plus, ..
19131912
//left: box SQLSubquery { .. },
19141913
//right: box SQLSubquery { .. },
19151914
});
@@ -1929,7 +1928,7 @@ fn parse_exists_subquery() {
19291928
let select = verified_only_select(sql);
19301929
assert_eq!(
19311930
ASTNode::SQLUnaryOp {
1932-
op: SQLOperator::Not,
1931+
op: SQLUnaryOperator::Not,
19331932
expr: Box::new(ASTNode::SQLExists(Box::new(expected_inner))),
19341933
},
19351934
select.selection.unwrap(),

0 commit comments

Comments
 (0)