From: Mike Bayer Date: Fri, 26 Feb 2016 05:20:39 +0000 (-0500) Subject: - Anonymous labeling is applied to a :attr:`.func` construct that is X-Git-Tag: rel_1_1_0b1~98^2~11 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=0210695bd97e76f58d8781b69337816501482fb0;p=thirdparty%2Fsqlalchemy%2Fsqlalchemy.git - Anonymous labeling is applied to a :attr:`.func` construct that is passed to :func:`.column_property`, so that if the same attribute is referred to as a column expression twice the names are de-duped, thus avoiding "ambiguous column" errors. Previously, the ``.label(None)`` would need to be applied in order for the name to be de-anonymized. fixes #3663 --- diff --git a/doc/build/changelog/changelog_10.rst b/doc/build/changelog/changelog_10.rst index 36152c2360..209f13bdc9 100644 --- a/doc/build/changelog/changelog_10.rst +++ b/doc/build/changelog/changelog_10.rst @@ -18,6 +18,17 @@ .. changelog:: :version: 1.0.13 + .. change:: + :tags: bug, orm + :tickets: 3663 + + Anonymous labeling is applied to a :attr:`.func` construct that is + passed to :func:`.column_property`, so that if the same attribute + is referred to as a column expression twice the names are de-duped, + thus avoiding "ambiguous column" errors. Previously, the + ``.label(None)`` would need to be applied in order for the name + to be de-anonymized. + .. change:: :tags: bug, py3k :tickets: 3660 diff --git a/lib/sqlalchemy/sql/elements.py b/lib/sqlalchemy/sql/elements.py index ca822d3104..67a442b0c2 100644 --- a/lib/sqlalchemy/sql/elements.py +++ b/lib/sqlalchemy/sql/elements.py @@ -4006,7 +4006,7 @@ def _cloned_difference(a, b): def _labeled(element): - if not hasattr(element, 'name'): + if not hasattr(element, 'name') or not getattr(element, '_label', None): return element.label(None) else: return element diff --git a/test/orm/test_query.py b/test/orm/test_query.py index c4c62c319a..cdc4ac2c2f 100644 --- a/test/orm/test_query.py +++ b/test/orm/test_query.py @@ -484,7 +484,7 @@ class RawSelectTest(QueryTest, AssertsCompiledSQL): self.assert_compile( select([Foo]).where(Foo.foob == 'somename').order_by(Foo.foob), "SELECT users.id, users.name FROM users " - "WHERE coalesce(users.name) = :coalesce_1 " + "WHERE coalesce(users.name) = :param_1 " "ORDER BY coalesce(users.name)" ) @@ -1593,6 +1593,63 @@ class ColumnPropertyTest(_fixtures.FixtureTest, AssertsCompiledSQL): }, with_polymorphic="*" if polymorphic else None) mapper(Address, addresses) + def _func_fixture(self, label=False): + User = self.classes.User + users = self.tables.users + + if label: + mapper(User, users, properties={ + "foobar": column_property( + func.foob(users.c.name).label(None) + ) + }) + else: + mapper(User, users, properties={ + "foobar": column_property( + func.foob(users.c.name) + ) + }) + + def test_anon_label_function_auto(self): + self._func_fixture() + User = self.classes.User + + s = Session() + + u1 = aliased(User) + self.assert_compile( + s.query(User.foobar, u1.foobar), + "SELECT foob(users.name) AS foob_1, foob(users_1.name) AS foob_2 " + "FROM users, users AS users_1" + ) + + def test_anon_label_function_manual(self): + self._func_fixture(label=True) + User = self.classes.User + + s = Session() + + u1 = aliased(User) + self.assert_compile( + s.query(User.foobar, u1.foobar), + "SELECT foob(users.name) AS foob_1, foob(users_1.name) AS foob_2 " + "FROM users, users AS users_1" + ) + + def test_anon_label_ad_hoc_labeling(self): + self._func_fixture() + User = self.classes.User + + s = Session() + + u1 = aliased(User) + self.assert_compile( + s.query(User.foobar.label('x'), u1.foobar.label('y')), + "SELECT foob(users.name) AS x, foob(users_1.name) AS y " + "FROM users, users AS users_1" + ) + + def test_order_by_column_prop_string(self): User, Address = self.classes("User", "Address") self._fixture(label=True)