[Sqlalchemy-commits] sqlalchemy: Fully implemented the IS and IS NOT operators with
Brought to you by:
zzzeek
From: <co...@sq...> - 2013-04-22 23:13:36
|
details: http://hg.sqlalchemy.org/sqlalchemy/sqlalchemy/rev/25bb1aaf375a changeset: 9366:25bb1aaf375a user: Mike Bayer <mi...@zz...> date: Mon Apr 22 19:12:47 2013 -0400 description: Fully implemented the IS and IS NOT operators with regards to the True/False constants. An expression like ``col.is_(True)`` will now render ``col IS true`` on the target platform, rather than converting the True/ False constant to an integer bound parameter. This allows the ``is_()`` operator to work on MySQL when given True/False constants. [ticket:2682] Subject: sqlalchemy: merge default details: http://hg.sqlalchemy.org/sqlalchemy/sqlalchemy/rev/65558fb29d61 changeset: 9367:65558fb29d61 user: Mike Bayer <mi...@zz...> date: Mon Apr 22 19:13:00 2013 -0400 description: merge default diffstat: doc/build/changelog/changelog_08.rst | 12 +++++++++ lib/sqlalchemy/sql/expression.py | 46 ++++++++++++++++++++++++++--------- test/sql/test_operators.py | 29 +++++++++++++++++++++- 3 files changed, 74 insertions(+), 13 deletions(-) diffs (146 lines): diff -r fb30a67562ee -r 65558fb29d61 doc/build/changelog/changelog_08.rst --- a/doc/build/changelog/changelog_08.rst Mon Apr 22 17:24:31 2013 -0400 +++ b/doc/build/changelog/changelog_08.rst Mon Apr 22 19:13:00 2013 -0400 @@ -7,6 +7,18 @@ :version: 0.8.1 .. change:: + :tags: bug, sql, mysql + :tickets: 2682 + + Fully implemented the IS and IS NOT operators with + regards to the True/False constants. An expression like + ``col.is_(True)`` will now render ``col IS true`` + on the target platform, rather than converting the True/ + False constant to an integer bound parameter. + This allows the ``is_()`` operator to work on MySQL when + given True/False constants. + + .. change:: :tags: bug, postgresql :tickets: 2681 diff -r fb30a67562ee -r 65558fb29d61 lib/sqlalchemy/sql/expression.py --- a/lib/sqlalchemy/sql/expression.py Mon Apr 22 17:24:31 2013 -0400 +++ b/lib/sqlalchemy/sql/expression.py Mon Apr 22 19:13:00 2013 -0400 @@ -1591,7 +1591,9 @@ def _const_expr(element): - if element is None: + if isinstance(element, (Null, False_, True_)): + return element + elif element is None: return null() elif element is False: return false() @@ -2011,18 +2013,33 @@ return op, other_comparator.type def _boolean_compare(self, expr, op, obj, negate=None, reverse=False, - **kwargs - ): - if obj is None or isinstance(obj, Null): - if op in (operators.eq, operators.is_): - return BinaryExpression(expr, null(), operators.is_, - negate=operators.isnot) - elif op in (operators.ne, operators.isnot): - return BinaryExpression(expr, null(), operators.isnot, - negate=operators.is_) + **kwargs): + if isinstance(obj, (util.NoneType, bool, Null, True_, False_)): + + # allow x ==/!= True/False to be treated as a literal. + # this comes out to "== / != true/false" or "1/0" if those + # constants aren't supported and works on all platforms + if op in (operators.eq, operators.ne) and \ + isinstance(obj, (bool, True_, False_)): + return BinaryExpression(expr, + obj, + op, + type_=sqltypes.BOOLEANTYPE, + negate=negate, modifiers=kwargs) else: - raise exc.ArgumentError("Only '='/'!=' operators can " - "be used with NULL") + # all other None/True/False uses IS, IS NOT + if op in (operators.eq, operators.is_): + return BinaryExpression(expr, _const_expr(obj), + operators.is_, + negate=operators.isnot) + elif op in (operators.ne, operators.isnot): + return BinaryExpression(expr, _const_expr(obj), + operators.isnot, + negate=operators.is_) + else: + raise exc.ArgumentError( + "Only '=', '!=', 'is_()', 'isnot()' operators can " + "be used with None/True/False") else: obj = self._check_literal(expr, op, obj) @@ -3253,6 +3270,8 @@ def __init__(self): self.type = sqltypes.BOOLEANTYPE + def compare(self, other): + return isinstance(other, False_) class True_(ColumnElement): """Represent the ``true`` keyword in a SQL statement. @@ -3266,6 +3285,9 @@ def __init__(self): self.type = sqltypes.BOOLEANTYPE + def compare(self, other): + return isinstance(other, True_) + class ClauseList(ClauseElement): """Describe a list of clauses, separated by an operator. diff -r fb30a67562ee -r 65558fb29d61 test/sql/test_operators.py --- a/test/sql/test_operators.py Mon Apr 22 17:24:31 2013 -0400 +++ b/test/sql/test_operators.py Mon Apr 22 19:13:00 2013 -0400 @@ -1,7 +1,7 @@ from sqlalchemy.testing import fixtures, eq_, is_ from sqlalchemy import testing from sqlalchemy.testing import assert_raises_message -from sqlalchemy.sql import column, desc, asc, literal, collate +from sqlalchemy.sql import column, desc, asc, literal, collate, null, true, false from sqlalchemy.sql.expression import BinaryExpression, \ ClauseList, Grouping, \ UnaryExpression, select, union, func, tuple_ @@ -66,6 +66,33 @@ def test_isnot_null(self): self._do_operate_test(operators.isnot, None) + def test_is_null_const(self): + self._do_operate_test(operators.is_, null()) + + def test_is_true_const(self): + self._do_operate_test(operators.is_, true()) + + def test_is_false_const(self): + self._do_operate_test(operators.is_, false()) + + def test_equals_true(self): + self._do_operate_test(operators.eq, True) + + def test_notequals_true(self): + self._do_operate_test(operators.ne, True) + + def test_is_true(self): + self._do_operate_test(operators.is_, True) + + def test_isnot_true(self): + self._do_operate_test(operators.isnot, True) + + def test_is_false(self): + self._do_operate_test(operators.is_, False) + + def test_isnot_false(self): + self._do_operate_test(operators.isnot, False) + def test_like(self): self._do_operate_test(operators.like_op) |