From: Mike Bayer Date: Fri, 29 Jul 2016 22:17:43 +0000 (-0400) Subject: Index should extract __clause_element__() early X-Git-Tag: rel_1_1_0~62^2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=6327c59d4f34947128bd9b2860a1732a6932b4d7;p=thirdparty%2Fsqlalchemy%2Fsqlalchemy.git 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 --- diff --git a/doc/build/changelog/changelog_11.rst b/doc/build/changelog/changelog_11.rst index 9a65e66a29..70ebccc556 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 55d0b74e61..2c5daa17cd 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 d6e5a5dd4b..cf7f7628a1 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() )