summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/build/changelog/changelog_11.rst14
-rw-r--r--lib/sqlalchemy/sql/type_api.py6
-rw-r--r--test/sql/test_types.py74
3 files changed, 91 insertions, 3 deletions
diff --git a/doc/build/changelog/changelog_11.rst b/doc/build/changelog/changelog_11.rst
index 35e217b33..e9774f925 100644
--- a/doc/build/changelog/changelog_11.rst
+++ b/doc/build/changelog/changelog_11.rst
@@ -21,6 +21,20 @@
.. changelog::
:version: 1.1.9
+ .. change:: 3952
+ :tags: bug, sql
+ :versions: 1.2.0.b1
+ :tickets: 3952
+
+ Fixed regression released in 1.1.5 due to :ticket:`3859` where
+ adjustments to the "right-hand-side" evaluation of an expression
+ based on :class:`.Variant` to honor the underlying type's
+ "right-hand-side" rules caused the :class:`.Variant` type
+ to be inappropriately lost, in those cases when we *do* want the
+ left-hand side type to be transferred directly to the right hand side
+ so that bind-level rules can be applied to the expression's argument.
+
+
.. changelog::
:version: 1.1.8
:released: March 31, 2017
diff --git a/lib/sqlalchemy/sql/type_api.py b/lib/sqlalchemy/sql/type_api.py
index d537e49f0..4b561a705 100644
--- a/lib/sqlalchemy/sql/type_api.py
+++ b/lib/sqlalchemy/sql/type_api.py
@@ -1214,7 +1214,11 @@ class Variant(TypeDecorator):
self.mapping = mapping
def coerce_compared_value(self, operator, value):
- return self.impl.coerce_compared_value(operator, value)
+ result = self.impl.coerce_compared_value(operator, value)
+ if result is self.impl:
+ return self
+ else:
+ return result
def load_dialect_impl(self, dialect):
if dialect.name in self.mapping:
diff --git a/test/sql/test_types.py b/test/sql/test_types.py
index b417e6964..f46ef21cd 100644
--- a/test/sql/test_types.py
+++ b/test/sql/test_types.py
@@ -1,5 +1,5 @@
# coding: utf-8
-from sqlalchemy.testing import eq_, is_, assert_raises, \
+from sqlalchemy.testing import eq_, is_, is_not_, assert_raises, \
assert_raises_message, expect_warnings
import decimal
import datetime
@@ -1006,6 +1006,55 @@ class VariantTest(fixtures.TestBase, AssertsCompiledSQL):
'fooUTWO'
)
+ def test_comparator_variant(self):
+ expr = column('x', self.variant) == "bar"
+ is_(
+ expr.right.type, self.variant
+ )
+
+ @testing.only_on("sqlite")
+ @testing.provide_metadata
+ def test_round_trip(self):
+ variant = self.UTypeOne().with_variant(
+ self.UTypeTwo(), 'sqlite')
+
+ t = Table('t', self.metadata,
+ Column('x', variant)
+ )
+ with testing.db.connect() as conn:
+ t.create(conn)
+
+ conn.execute(
+ t.insert(),
+ x='foo'
+ )
+
+ eq_(
+ conn.scalar(select([t.c.x]).where(t.c.x == 'foo')),
+ 'fooUTWO'
+ )
+
+ @testing.only_on("sqlite")
+ @testing.provide_metadata
+ def test_round_trip_sqlite_datetime(self):
+ variant = DateTime().with_variant(
+ dialects.sqlite.DATETIME(truncate_microseconds=True), 'sqlite')
+
+ t = Table('t', self.metadata,
+ Column('x', variant)
+ )
+ with testing.db.connect() as conn:
+ t.create(conn)
+
+ conn.execute(
+ t.insert(),
+ x=datetime.datetime(2015, 4, 18, 10, 15, 17, 4839)
+ )
+
+ eq_(
+ conn.scalar(select([t.c.x]).where(t.c.x == datetime.datetime(2015, 4, 18, 10, 15, 17, 1059))),
+ datetime.datetime(2015, 4, 18, 10, 15, 17)
+ )
class UnicodeTest(fixtures.TestBase):
@@ -2051,7 +2100,7 @@ class ExpressionTest(
"BIND_INfooBIND_IN6BIND_OUT"
)
- def test_variant_righthand_coercion(self):
+ def test_variant_righthand_coercion_honors_wrapped(self):
my_json_normal = JSON()
my_json_variant = JSON().with_variant(String(), "sqlite")
@@ -2063,10 +2112,31 @@ class ExpressionTest(
expr = tab.c.avalue['foo'] == 'bar'
is_(expr.right.type._type_affinity, String)
+ is_not_(expr.right.type, my_json_normal)
expr = tab.c.bvalue['foo'] == 'bar'
is_(expr.right.type._type_affinity, String)
+ is_not_(expr.right.type, my_json_variant)
+
+ def test_variant_righthand_coercion_returns_self(self):
+ my_datetime_normal = DateTime()
+ my_datetime_variant = DateTime().with_variant(
+ dialects.sqlite.DATETIME(truncate_microseconds=False), "sqlite")
+
+ tab = table(
+ 'test',
+ column('avalue', my_datetime_normal),
+ column('bvalue', my_datetime_variant)
+ )
+ expr = tab.c.avalue == datetime.datetime(2015, 10, 14, 15, 17, 18)
+
+ is_(expr.right.type._type_affinity, DateTime)
+ is_(expr.right.type, my_datetime_normal)
+
+ expr = tab.c.bvalue == datetime.datetime(2015, 10, 14, 15, 17, 18)
+
+ is_(expr.right.type, my_datetime_variant)
def test_bind_typing(self):
from sqlalchemy.sql import column