Skip to content

Commit

Permalink
Fully implemented the IS and IS NOT operators with
Browse files Browse the repository at this point in the history
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]
  • Loading branch information
zzzeek committed Apr 22, 2013
1 parent 63c211f commit 5884c2e
Show file tree
Hide file tree
Showing 3 changed files with 74 additions and 13 deletions.
12 changes: 12 additions & 0 deletions doc/build/changelog/changelog_08.rst
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,18 @@
.. changelog::
: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
Expand Down
46 changes: 34 additions & 12 deletions lib/sqlalchemy/sql/expression.py
Original file line number Diff line number Diff line change
Expand Up @@ -1591,7 +1591,9 @@ def _interpret_as_from(element):


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()
Expand Down Expand Up @@ -2011,18 +2013,33 @@ def _adapt_expression(self, op, other_comparator):
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)

Expand Down Expand Up @@ -3253,6 +3270,8 @@ class False_(ColumnElement):
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.
Expand All @@ -3266,6 +3285,9 @@ class True_(ColumnElement):
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.
Expand Down
29 changes: 28 additions & 1 deletion test/sql/test_operators.py
Original file line number Diff line number Diff line change
@@ -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_
Expand Down Expand Up @@ -66,6 +66,33 @@ def test_is_null(self):
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)

Expand Down

0 comments on commit 5884c2e

Please sign in to comment.