From df1ead71114927af198379f7eb142248d55dbcc2 Mon Sep 17 00:00:00 2001 From: Gleb Kisenkov Date: Mon, 9 Jan 2023 19:48:01 +0100 Subject: [PATCH] Added and + or bitwise operators + simple precedence test --- lib/sqlalchemy/sql/compiler.py | 2 ++ lib/sqlalchemy/sql/default_comparator.py | 2 ++ lib/sqlalchemy/sql/operators.py | 24 +++++++++++++++++++++- test/dialect/postgresql/test_compiler.py | 2 +- test/sql/test_operators.py | 26 +++++++++++++++++++----- 5 files changed, 49 insertions(+), 7 deletions(-) diff --git a/lib/sqlalchemy/sql/compiler.py b/lib/sqlalchemy/sql/compiler.py index 755a841374..8beca2f3c5 100644 --- a/lib/sqlalchemy/sql/compiler.py +++ b/lib/sqlalchemy/sql/compiler.py @@ -281,6 +281,8 @@ OPERATORS = { operators.nulls_last_op: " NULLS LAST", # bitwise operators.bitwise_xor_op: " ^ ", + operators.bitwise_or_op: " | ", + operators.bitwise_and_op: " & ", } FUNCTIONS: Dict[Type[Function[Any]], str] = { diff --git a/lib/sqlalchemy/sql/default_comparator.py b/lib/sqlalchemy/sql/default_comparator.py index ff04c6c940..01ca6fb97d 100644 --- a/lib/sqlalchemy/sql/default_comparator.py +++ b/lib/sqlalchemy/sql/default_comparator.py @@ -421,6 +421,8 @@ operator_lookup: Dict[ "div": (_binary_operate, util.EMPTY_DICT), "mod": (_binary_operate, util.EMPTY_DICT), "bitwise_xor_op": (_binary_operate, util.EMPTY_DICT), + "bitwise_or_op": (_binary_operate, util.EMPTY_DICT), + "bitwise_and_op": (_binary_operate, util.EMPTY_DICT), "truediv": (_binary_operate, util.EMPTY_DICT), "floordiv": (_binary_operate, util.EMPTY_DICT), "custom_op": (_custom_op_operate, util.EMPTY_DICT), diff --git a/lib/sqlalchemy/sql/operators.py b/lib/sqlalchemy/sql/operators.py index eb1d9ef8a7..2bc209eaf6 100644 --- a/lib/sqlalchemy/sql/operators.py +++ b/lib/sqlalchemy/sql/operators.py @@ -695,6 +695,16 @@ class ColumnOperators(Operators): return self.operate(bitwise_xor_op, other) + def bitwise_or(self, other): + """Return bitwise OR operation""" + + return self.operate(bitwise_or_op, other) + + def bitwise_and(self, other): + """Return bitwise AND operation""" + + return self.operate(bitwise_and_op, other) + def in_(self, other: Any) -> ColumnOperators: """Implement the ``in`` operator. @@ -2125,6 +2135,16 @@ def bitwise_xor_op(a: Any, b: Any) -> Any: return a.bitwise_xor(b) +@_operator_fn +def bitwise_or_op(a: Any, b: Any) -> Any: + return a.bitwise_or(b) + + +@_operator_fn +def bitwise_and_op(a: Any, b: Any) -> Any: + return a.bitwise_and(b) + + def is_comparison(op: OperatorType) -> bool: return op in _comparison or isinstance(op, custom_op) and op.is_comparison @@ -2205,6 +2225,9 @@ _PRECEDENCE: Dict[OperatorType, int] = { neg: 8, add: 7, sub: 7, + bitwise_xor_op: 7, + bitwise_or_op: 7, + bitwise_and_op: 7, concat_op: 6, filter_op: 6, match_op: 5, @@ -2236,7 +2259,6 @@ _PRECEDENCE: Dict[OperatorType, int] = { is_false: 5, and_: 3, or_: 2, - bitwise_xor_op: 1, # just guessing comma_op: -1, desc_op: 3, asc_op: 3, diff --git a/test/dialect/postgresql/test_compiler.py b/test/dialect/postgresql/test_compiler.py index 9984eb7648..080cfb767d 100644 --- a/test/dialect/postgresql/test_compiler.py +++ b/test/dialect/postgresql/test_compiler.py @@ -2424,7 +2424,7 @@ class CompileTest(fixtures.TestBase, AssertsCompiledSQL): "WHERE usages.date <@ %(date_1)s::DATERANGE", ) - def test_dedicated_bit_xor(self): + def test_bitwise_xor(self): c1 = column("c1", Integer) c2 = column("c2", Integer) self.assert_compile( diff --git a/test/sql/test_operators.py b/test/sql/test_operators.py index 2bf08e6a4b..ce71eba704 100644 --- a/test/sql/test_operators.py +++ b/test/sql/test_operators.py @@ -1768,6 +1768,14 @@ class OperatorPrecedenceTest(fixtures.TestBase, testing.AssertsCompiledSQL): self.assert_compile(op2, "mytable.myid hoho :myid_1 lala :param_1") self.assert_compile(op3, "(mytable.myid hoho :myid_1) lala :param_1") + def test_bitwise_xor_precedence(self): + op1 = self.table1.c.myid.bitwise_xor + op2 = op1(5).op("lala", precedence=6)(4) + op3 = op1(5).op("lala", precedence=8)(4) + + self.assert_compile(op2, "mytable.myid ^ :myid_1 lala :param_1") + self.assert_compile(op3, "(mytable.myid ^ :myid_1) lala :param_1") + def test_is_eq_precedence_flat(self): self.assert_compile( (self.table1.c.name == null()) @@ -4510,18 +4518,26 @@ class AnyAllTest(fixtures.TestBase, testing.AssertsCompiledSQL): class BitOpTest(fixtures.TestBase, testing.AssertsCompiledSQL): - def test_generic_bit_xor(self): + def test_bitwise_xor(self): c1 = column("c1", Integer) c2 = column("c2", Integer) self.assert_compile( - select(c1.op("^")(c2)), + select(c1.bitwise_xor(c2)), "SELECT c1 ^ c2 AS anon_1", ) - def test_dedicated_bit_xor(self): + def test_bitwise_or(self): c1 = column("c1", Integer) c2 = column("c2", Integer) self.assert_compile( - select(c1.bitwise_xor(c2)), - "SELECT c1 ^ c2 AS anon_1", + select(c1.bitwise_or(c2)), + "SELECT c1 | c2 AS anon_1", + ) + + def test_bitwise_and(self): + c1 = column("c1", Integer) + c2 = column("c2", Integer) + self.assert_compile( + select(c1.bitwise_and(c2)), + "SELECT c1 & c2 AS anon_1", ) -- 2.47.3