summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Bayer <mike_mp@zzzcomputing.com>2016-07-29 18:17:43 -0400
committerMike Bayer <mike_mp@zzzcomputing.com>2016-07-30 10:11:53 -0400
commit6327c59d4f34947128bd9b2860a1732a6932b4d7 (patch)
tree8b68fce14fa450737c6278437f2af75fb7095e1e
parente467e899e126db2db7c25d533aee12d78c2dbdfb (diff)
downloadsqlalchemy-6327c59d4f34947128bd9b2860a1732a6932b4d7.tar.gz
Index should extract __clause_element__() early
Fixed bug where :class:`.Index` would fail to extract columns from compound SQL expressions if those SQL expressions were wrapped inside of an ORM-style ``__clause_element__()`` construct. This bug exists in 1.0.x as well, however in 1.1 is more noticeable as hybrid_property @expression now returns a wrapped element. Fixes: #3763 Change-Id: I992536386503a1fb3f2305790abe008d72c44c4a
-rw-r--r--doc/build/changelog/changelog_11.rst10
-rw-r--r--lib/sqlalchemy/sql/schema.py5
-rw-r--r--test/sql/test_metadata.py24
3 files changed, 37 insertions, 2 deletions
diff --git a/doc/build/changelog/changelog_11.rst b/doc/build/changelog/changelog_11.rst
index 9a65e66a2..70ebccc55 100644
--- a/doc/build/changelog/changelog_11.rst
+++ b/doc/build/changelog/changelog_11.rst
@@ -29,6 +29,16 @@
:meth:`.Query.order_by` has worked for a long time. Pull request
courtesy Iuri Diniz.
+ .. change::
+ :tags: bug, sql
+ :tickets: 3763
+
+ Fixed bug where :class:`.Index` would fail to extract columns from
+ compound SQL expressions if those SQL expressions were wrapped inside
+ of an ORM-style ``__clause_element__()`` construct. This bug
+ exists in 1.0.x as well, however in 1.1 is more noticeable as
+ hybrid_property @expression now returns a wrapped element.
+
.. changelog::
:version: 1.1.0b3
:released: July 26, 2016
diff --git a/lib/sqlalchemy/sql/schema.py b/lib/sqlalchemy/sql/schema.py
index 55d0b74e6..2c5daa17c 100644
--- a/lib/sqlalchemy/sql/schema.py
+++ b/lib/sqlalchemy/sql/schema.py
@@ -2505,7 +2505,10 @@ class ColumnCollectionMixin(object):
for expr in expressions:
strname = None
column = None
- if not isinstance(expr, ClauseElement):
+ if hasattr(expr, '__clause_element__'):
+ expr = expr.__clause_element__()
+
+ if not isinstance(expr, (ColumnElement, TextClause)):
# this assumes a string
strname = expr
else:
diff --git a/test/sql/test_metadata.py b/test/sql/test_metadata.py
index d6e5a5dd4..cf7f7628a 100644
--- a/test/sql/test_metadata.py
+++ b/test/sql/test_metadata.py
@@ -2147,6 +2147,27 @@ class ConstraintTest(fixtures.TestBase):
idx = Index('q', c)
is_(idx.table, None) # lower-case-T table doesn't have indexes
+ def test_clauseelement_extraction_one(self):
+ t = Table('t', MetaData(), Column('x', Integer), Column('y', Integer))
+
+ class MyThing(object):
+ def __clause_element__(self):
+ return t.c.x + 5
+
+ idx = Index('foo', MyThing())
+ self._assert_index_col_x(t, idx)
+
+ def test_clauseelement_extraction_two(self):
+ t = Table('t', MetaData(), Column('x', Integer), Column('y', Integer))
+
+ class MyThing(object):
+ def __clause_element__(self):
+ return t.c.x + 5
+
+ idx = Index('bar', MyThing(), t.c.y)
+
+ eq_(set(t.indexes), set([idx]))
+
def test_table_references(self):
t1, t2, t3 = self._single_fixture()
assert list(t2.c.a.foreign_keys)[0].references(t1)
@@ -2911,8 +2932,9 @@ class ConstraintTest(fixtures.TestBase):
def __clause_element__(self):
return t2
- assert_raises(
+ assert_raises_message(
exc.ArgumentError,
+ "Element Table\('t2', .* is not a string name or column element",
Index, "foo", SomeClass()
)