.. include:: changelog_07.rst
:start-line: 5
+.. changelog::
+ :version: 1.0.7
+
+ .. change::
+ :tags: bug, orm
+ :tickets: 3466
+
+ Fixed 1.0 regression where the "parent entity" of a synonym-
+ mapped attribute on top of an :func:`.aliased` object would
+ resolve to the original mapper, not the :func:`.aliased`
+ version of it, thereby causing problems for a :class:`.Query`
+ that relies on this attribute (e.g. it's the only representative
+ attribute given in the constructor) to figure out the correct FROM
+ clause for the query.
+
.. changelog::
:version: 1.0.6
:released: June 25, 2015
from .inspection import inspect
from .engine import create_engine, engine_from_config
-__version__ = '1.0.6'
+__version__ = '1.0.7'
def __go(lcls):
def __init__(self, prop, parentmapper, adapt_to_entity=None):
self.prop = self.property = prop
- self._parententity = parentmapper
+ self._parententity = adapt_to_entity or parentmapper
self._adapt_to_entity = adapt_to_entity
def __clause_element__(self):
if self.adapter:
return self.adapter(self.prop.columns[0])
else:
+ # no adapter, so we aren't aliased
+ # assert self._parententity is self._parentmapper
return self.prop.columns[0]._annotate({
"parententity": self._parententity,
"parentmapper": self._parententity})
def _adapt_element(self, elem):
return self._adapter.traverse(elem).\
_annotate({
- 'parententity': self.entity,
+ 'parententity': self,
'parentmapper': self.mapper}
)
)
-class SynonymTest(QueryTest):
+class SynonymTest(QueryTest, AssertsCompiledSQL):
+ __dialect__ = 'default'
@classmethod
def setup_mappers(cls):
Order(description="order 1"), Order(description="order 3"),
Order(description="order 5")] == o
+ def test_froms_aliased_col(self):
+ Address, User = self.classes.Address, self.classes.User
+
+ sess = create_session()
+ ua = aliased(User)
+
+ q = sess.query(ua.name_syn).join(
+ Address, ua.id == Address.user_id)
+ self.assert_compile(
+ q,
+ "SELECT users_1.name AS users_1_name FROM "
+ "users AS users_1 JOIN addresses ON users_1.id = addresses.user_id"
+ )
+
class ImmediateTest(_fixtures.FixtureTest):
run_inserts = 'once'
"WHERE point_1.x > point.x"
)
+ def test_parententity_vs_parentmapper(self):
+ class Point(object):
+ pass
+
+ self._fixture(Point, properties={
+ 'x_syn': synonym("x")
+ })
+ pa = aliased(Point)
+
+ is_(Point.x_syn._parententity, inspect(Point))
+ is_(Point.x._parententity, inspect(Point))
+ is_(Point.x_syn._parentmapper, inspect(Point))
+ is_(Point.x._parentmapper, inspect(Point))
+
+ is_(
+ Point.x_syn.__clause_element__()._annotations['parententity'],
+ inspect(Point))
+ is_(
+ Point.x.__clause_element__()._annotations['parententity'],
+ inspect(Point))
+ is_(
+ Point.x_syn.__clause_element__()._annotations['parentmapper'],
+ inspect(Point))
+ is_(
+ Point.x.__clause_element__()._annotations['parentmapper'],
+ inspect(Point))
+
+ pa = aliased(Point)
+
+ is_(pa.x_syn._parententity, inspect(pa))
+ is_(pa.x._parententity, inspect(pa))
+ is_(pa.x_syn._parentmapper, inspect(Point))
+ is_(pa.x._parentmapper, inspect(Point))
+
+ is_(
+ pa.x_syn.__clause_element__()._annotations['parententity'],
+ inspect(pa)
+ )
+ is_(
+ pa.x.__clause_element__()._annotations['parententity'],
+ inspect(pa)
+ )
+ is_(
+ pa.x_syn.__clause_element__()._annotations['parentmapper'],
+ inspect(Point))
+ is_(
+ pa.x.__clause_element__()._annotations['parentmapper'],
+ inspect(Point))
+
+
class IdentityKeyTest(_fixtures.FixtureTest):
run_inserts = None