Skip to content

Commit 9d4d6ee

Browse files
committed
ENH: Add order of operations to boolean evaluation
1 parent d83d1bc commit 9d4d6ee

4 files changed

Lines changed: 46 additions & 8 deletions

File tree

dataframe_sql/grammar/sql.grammar

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -90,9 +90,12 @@ alias: NAME -> alias_string
9090
_window_name: NAME
9191
limit_count: integer -> limit_count
9292
skip_rows: integer
93-
bool_expression: bool_expression "AND"i bool_expression -> bool_and
94-
| bool_expression "OR"i bool_expression -> bool_or
95-
| comparison_type
93+
bool_expression: bool_parentheses
94+
| bool_expression "AND"i bool_parentheses -> bool_and
95+
| bool_expression "OR"i bool_parentheses -> bool_or
96+
bool_parentheses: comparison_type
97+
| "(" bool_expression "AND"i comparison_type ")" -> bool_and
98+
| "(" bool_expression "OR"i comparison_type ")" -> bool_or
9699
comparison_type: equals | not_equals | greater_than | less_than | greater_than_or_equal | less_than_or_equal | between | in_expr | not_in_expr
97100
equals: expression_math "=" expression_math
98101
not_equals: expression_math ("<>" | "!=") expression_math

dataframe_sql/parsing/sql_parser.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -521,6 +521,9 @@ def bool_and(self, truth_series_pair: List[Value]) -> ValueWithPlan:
521521
f"{plans[0]} & {plans[1]}",
522522
)
523523

524+
def bool_parentheses(self, bool_expression_in_list: list):
525+
return bool_expression_in_list[0]
526+
524527
def bool_or(self, truth_series_pair):
525528
"""
526529
Return the truth value of the series pair
@@ -1166,7 +1169,7 @@ def join_expression(self, *args):
11661169
join_type = "outer"
11671170

11681171
# Check that there is a column from both sides
1169-
column_comparison = join_condition.children[0].children
1172+
column_comparison = join_condition.children[0].children[0].children
11701173
column1 = str(column_comparison[0].children)
11711174
column2 = str(column_comparison[1].children)
11721175

dataframe_sql/sql_objects.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -244,6 +244,24 @@ def __init__(self, value, execution_plan):
244244
def __repr__(self):
245245
return Value.__repr__(self) + ")"
246246

247+
def __or__(self, other):
248+
if not isinstance(other, Value):
249+
raise Exception(f"Operator | is not supported between type {type(other)} "
250+
f"and type ValueWithPlan")
251+
252+
return ValueWithPlan(self.get_value() | other.get_value(),
253+
f"{self.get_plan_representation()} | "
254+
f"{other.get_plan_representation()}")
255+
256+
def __and__(self, other):
257+
if not isinstance(other, Value):
258+
raise Exception(f"Operator && is not supported between type {type(other)} "
259+
f"and type ValueWithPlan")
260+
261+
ValueWithPlan(self.get_value() & other.get_value(),
262+
f"{self.get_plan_representation()} & "
263+
f"{other.get_plan_representation()}")
264+
247265
def get_plan_representation(self) -> str:
248266
return self.execution_plan
249267

dataframe_sql/tests/pandas_sql_functionality_test.py

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1394,7 +1394,7 @@ def test_sql_data_types():
13941394
tm.assert_frame_equal(pandas_frame, my_frame)
13951395

13961396

1397-
def test_order_of_operations_no_parens():
1397+
def test_math_order_of_operations_no_parens():
13981398
"""
13991399
Test math parentheses
14001400
:return:
@@ -1410,14 +1410,14 @@ def test_order_of_operations_no_parens():
14101410
tm.assert_frame_equal(pandas_frame, my_frame)
14111411

14121412

1413-
def test_order_of_operations_with_parens():
1413+
def test_math_order_of_operations_with_parens():
14141414
"""
14151415
Test math parentheses
14161416
:return:
14171417
"""
14181418

14191419
my_frame = query(
1420-
"select 20 * (avocado_id + 3) / (20 + avocado_id) as my_math from " "avocado"
1420+
"select 20 * (avocado_id + 3) / (20 + avocado_id) as my_math from avocado"
14211421
)
14221422

14231423
pandas_frame = AVOCADO.copy()[["avocado_id"]]
@@ -1429,10 +1429,24 @@ def test_order_of_operations_with_parens():
14291429

14301430
tm.assert_frame_equal(pandas_frame, my_frame)
14311431

1432+
def test_boolean_order_of_operations_with_parens():
1433+
"""
1434+
Test boolean order of operations with parentheses
1435+
:return:
1436+
"""
1437+
my_frame = query(
1438+
"select * from forest_fires "
1439+
"where (month = 'oct' and day = 'fri') or "
1440+
"(month = 'nov' and day = 'tue')"
1441+
)
1442+
1443+
1444+
1445+
14321446

14331447
if __name__ == "__main__":
14341448
register_env_tables()
14351449

1436-
test_order_of_operations_with_parens()
1450+
test_right_joins()
14371451

14381452
remove_env_tables()

0 commit comments

Comments
 (0)