Commits

Mike Bayer committed 1100382

- Added support for literal rendering of boolean values, e.g.
"true" / "false" or "1" / "0".
- added Boolean tests to the test suite

Comments (0)

Files changed (4)

doc/build/changelog/changelog_09.rst

     .. change::
         :tags: feature, sql
 
+        Added support for literal rendering of boolean values, e.g.
+        "true" / "false" or "1" / "0".
+
+    .. change::
+        :tags: feature, sql
+
         Added a new feature :func:`.schema.conv`, the purpose of which is to
         mark a constraint name as already having had a naming convention applied.
         This token will be used by Alembic migrations as of Alembic 0.6.4

lib/sqlalchemy/sql/sqltypes.py

     def python_type(self):
         return bool
 
+    def literal_processor(self, dialect):
+        if dialect.supports_native_boolean:
+            def process(value):
+                return "true" if value else "false"
+        else:
+            def process(value):
+                return str(1 if value else 0)
+        return process
+
     def bind_processor(self, dialect):
         if dialect.supports_native_boolean:
             return None

lib/sqlalchemy/testing/suite/test_types.py

 from ..config import requirements
 from sqlalchemy import Integer, Unicode, UnicodeText, select
 from sqlalchemy import Date, DateTime, Time, MetaData, String, \
-            Text, Numeric, Float, literal
+            Text, Numeric, Float, literal, Boolean
 from ..schema import Table, Column
 from ... import testing
 import decimal
         )
 
 
+class BooleanTest(_LiteralRoundTripFixture, fixtures.TablesTest):
+    __multiple__ = True
+
+    @classmethod
+    def define_tables(cls, metadata):
+        Table('boolean_table', metadata,
+            Column('id', Integer, primary_key=True, autoincrement=False),
+            Column('value', Boolean),
+            Column('unconstrained_value', Boolean(create_constraint=False)),
+            )
+
+    def test_render_literal_bool(self):
+        self._literal_round_trip(
+            Boolean(),
+            [True, False],
+            [True, False]
+        )
+
+    def test_round_trip(self):
+        boolean_table = self.tables.boolean_table
+
+        config.db.execute(
+            boolean_table.insert(),
+            {
+                'id': 1,
+                'value': True,
+                'unconstrained_value': False
+            }
+        )
+
+        row = config.db.execute(
+                    select([
+                            boolean_table.c.value,
+                            boolean_table.c.unconstrained_value
+                    ])
+                ).first()
+
+        eq_(
+            row,
+            (True, False)
+        )
+        assert isinstance(row[0], bool)
+
+    def test_null(self):
+        boolean_table = self.tables.boolean_table
+
+        config.db.execute(
+            boolean_table.insert(),
+            {
+                'id': 1,
+                'value': None,
+                'unconstrained_value': None
+            }
+        )
+
+        row = config.db.execute(
+                    select([
+                            boolean_table.c.value,
+                            boolean_table.c.unconstrained_value
+                    ])
+                ).first()
+
+        eq_(
+            row,
+            (None, None)
+        )
+
+
+
 
 __all__ = ('UnicodeVarcharTest', 'UnicodeTextTest',
             'DateTest', 'DateTimeTest', 'TextTest',
             'NumericTest', 'IntegerTest',
             'DateTimeHistoricTest', 'DateTimeCoercedToDateTimeTest',
             'TimeMicrosecondsTest', 'TimeTest', 'DateTimeMicrosecondsTest',
-            'DateHistoricTest', 'StringTest')
+            'DateHistoricTest', 'StringTest', 'BooleanTest')

test/sql/test_types.py

         eq_(row['non_native_interval'], None)
 
 
-class BooleanTest(fixtures.TestBase, AssertsExecutionResults, AssertsCompiledSQL):
+class BooleanTest(fixtures.TablesTest, AssertsExecutionResults, AssertsCompiledSQL):
+    """test edge cases for booleans.  Note that the main boolean test suite
+    is now in testing/suite/test_types.py
+
+    """
     @classmethod
-    def setup_class(cls):
-        global bool_table
-        metadata = MetaData(testing.db)
-        bool_table = Table('booltest', metadata,
+    def define_tables(cls, metadata):
+        Table('boolean_table', metadata,
             Column('id', Integer, primary_key=True, autoincrement=False),
             Column('value', Boolean),
             Column('unconstrained_value', Boolean(create_constraint=False)),
             )
-        bool_table.create()
-
-    @classmethod
-    def teardown_class(cls):
-        bool_table.drop()
-
-    def teardown(self):
-        bool_table.delete().execute()
-
-    def test_boolean(self):
-        bool_table.insert().execute(id=1, value=True)
-        bool_table.insert().execute(id=2, value=False)
-        bool_table.insert().execute(id=3, value=True)
-        bool_table.insert().execute(id=4, value=True)
-        bool_table.insert().execute(id=5, value=True)
-        bool_table.insert().execute(id=6, value=None)
-
-        res = select([bool_table.c.id, bool_table.c.value]).where(
-            bool_table.c.value == True
-            ).order_by(bool_table.c.id).execute().fetchall()
-        eq_(res, [(1, True), (3, True), (4, True), (5, True)])
-
-        res2 = select([bool_table.c.id, bool_table.c.value]).where(
-                    bool_table.c.value == False).execute().fetchall()
-        eq_(res2, [(2, False)])
-
-        res3 = select([bool_table.c.id, bool_table.c.value]).\
-                order_by(bool_table.c.id).\
-                execute().fetchall()
-        eq_(res3, [(1, True), (2, False),
-                    (3, True), (4, True),
-                    (5, True), (6, None)])
-
-        # ensure we're getting True/False, not just ints
-        assert res3[0][1] is True
-        assert res3[1][1] is False
 
     @testing.fails_on('mysql',
             "The CHECK clause is parsed but ignored by all storage engines.")
     def test_constraint(self):
         assert_raises((exc.IntegrityError, exc.ProgrammingError),
                         testing.db.execute,
-                        "insert into booltest (id, value) values(1, 5)")
+                        "insert into boolean_table (id, value) values(1, 5)")
 
     @testing.skip_if(lambda: testing.db.dialect.supports_native_boolean)
     def test_unconstrained(self):
         testing.db.execute(
-            "insert into booltest (id, unconstrained_value) values (1, 5)")
+            "insert into boolean_table (id, unconstrained_value) values (1, 5)")
 
     def test_non_native_constraint_custom_type(self):
         class Foob(object):