]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
Index should extract __clause_element__() early
authorMike Bayer <mike_mp@zzzcomputing.com>
Fri, 29 Jul 2016 22:17:43 +0000 (18:17 -0400)
committerMike Bayer <mike_mp@zzzcomputing.com>
Sat, 30 Jul 2016 14:11:53 +0000 (10:11 -0400)
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

doc/build/changelog/changelog_11.rst
lib/sqlalchemy/sql/schema.py
test/sql/test_metadata.py

index 9a65e66a29094ab1e741fb48e3cc71e6f1fc1bcf..70ebccc5562b382bda59a478cf3fd3c254be43d0 100644 (file)
         :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
index 55d0b74e61bbc4eb5ae50f5d05f9d2c4dc763f30..2c5daa17cdd890b0c58e03e78736a116d7c7d262 100644 (file)
@@ -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:
index d6e5a5dd4bd13a6ac81746c6af16915ce514abe7..cf7f7628a19ea815ec2f4fe76cdd50ccc25f1192 100644 (file)
@@ -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()
         )