]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
- Fixed a variety of synonym()-related regressions
authorMike Bayer <mike_mp@zzzcomputing.com>
Fri, 16 Sep 2011 00:18:26 +0000 (20:18 -0400)
committerMike Bayer <mike_mp@zzzcomputing.com>
Fri, 16 Sep 2011 00:18:26 +0000 (20:18 -0400)
    from 0.6:
        - making a synonym against a synonym now works.
        - synonyms made against a relationship() can
          be passed to query.join(), options sent
          to query.options(), passed by name
          to query.with_parent().
- revised the approach taken earlier to just
propagate "property" out from the proxied attr the same
way queryable attribute does.

CHANGES
lib/sqlalchemy/orm/attributes.py
lib/sqlalchemy/orm/descriptor_props.py
lib/sqlalchemy/orm/query.py
lib/sqlalchemy/orm/util.py
test/orm/test_joins.py
test/orm/test_query.py

diff --git a/CHANGES b/CHANGES
index 58525eb75a8253a9c0e04436b209d5d9206fee11..26b7c1428706444ab486418a38151913ab9e91b2 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -15,12 +15,13 @@ CHANGES
      when the Session.is_active is True.
      [ticket:2241]
 
-  - Fixed previously untested function which regressed
-    in 0.7, can now make a synonym() of a synonym()
-    again.
-
-  - Another previously unknown feature from 0.6, synonyms
-    of relationship() can again be passed to join().
+  - Fixed a variety of synonym()-related regressions
+    from 0.6:
+        - making a synonym against a synonym now works.
+        - synonyms made against a relationship() can
+          be passed to query.join(), options sent
+          to query.options(), passed by name
+          to query.with_parent().
 
   - Identity map .discard() uses dict.pop(,None) 
     internally instead of "del" to avoid KeyError/warning 
index 42fdf7e7f82fc420f30f7f3d65d4a673a7ba7e09..2ecd233a78dbe629106e7d08cc7c81e41851e36a 100644 (file)
@@ -193,6 +193,10 @@ def create_proxied_attribute(descriptor):
             self.adapter = adapter
             self.__doc__ = doc
 
+        @property
+        def property(self):
+            return self.comparator.property
+
         @util.memoized_property
         def comparator(self):
             if util.callable(self._comparator):
index 302c374c3cf18b6761b0ef2b3a2a6eb55aa87bdc..cb31fadac0f77cbd4b494267945ceb6f5ec68e24 100644 (file)
@@ -67,7 +67,6 @@ class DescriptorProperty(MapperProperty):
                         lambda: self._comparator_factory(mapper),
                         doc=self.doc
                     )
-        proxy_attr.property = self
         proxy_attr.impl = _ProxyImpl(self.key)
         mapper.class_manager.instrument_attribute(self.key, proxy_attr)
 
@@ -355,17 +354,11 @@ class SynonymProperty(DescriptorProperty):
     def _proxied_property(self):
         return getattr(self.parent.class_, self.name).property
 
-    @property
-    def _synonym_resolved_property(self):
-        return self._proxied_property
-
     def _comparator_factory(self, mapper):
         prop = self._proxied_property
 
         if self.comparator_factory:
             comp = self.comparator_factory(prop, mapper)
-        elif isinstance(prop, DescriptorProperty):
-            comp = prop._comparator_factory(mapper)
         else:
             comp = prop.comparator_factory(prop, mapper)
         return comp
index 20c8280d14f84d301d826b25ea7acb7f5d8ea555..6ef6c3b573773417b8da28f77f62095a420f4692 100644 (file)
@@ -1582,16 +1582,16 @@ class Query(object):
 
             if isinstance(onclause, interfaces.PropComparator):
                 if right_entity is None:
-                    right_entity = onclause.property._synonym_resolved_property.mapper
+                    right_entity = onclause.property.mapper
                     of_type = getattr(onclause, '_of_type', None)
                     if of_type:
                         right_entity = of_type
                     else:
-                        right_entity = onclause.property._synonym_resolved_property.mapper
+                        right_entity = onclause.property.mapper
 
                 left_entity = onclause.parententity
 
-                prop = onclause.property._synonym_resolved_property
+                prop = onclause.property
                 if not isinstance(onclause,  attributes.QueryableAttribute):
                     onclause = prop
 
index d7c8b20a2fa41a94595cd208f36de14cb453c78a..4708852ea1fde3b84defafe5bb4db6e575e67ec8 100644 (file)
@@ -459,7 +459,7 @@ def with_parent(instance, prop):
     """
     if isinstance(prop, basestring):
         mapper = object_mapper(instance)
-        prop = mapper.get_property(prop)
+        prop = getattr(mapper.class_, prop).property
     elif isinstance(prop, attributes.QueryableAttribute):
         prop = prop.property
 
index af35912f7951475fab86b358c510d70258ed33db..ccd42c10bd536793ad3bf18c69540d9f0ae51737 100644 (file)
@@ -405,7 +405,8 @@ class JoinTest(QueryTest, AssertsCompiledSQL):
         )
 
     def test_multi_tuple_form(self):
-        """test the 'tuple' form of join, now superseded by the two-element join() form.
+        """test the 'tuple' form of join, now superseded 
+        by the two-element join() form.
 
         Not deprecating this style as of yet.
 
index ec4a328e0b51bc8fbe6f11dedc08ca1a52bdee3b..45390d896c7b7392d5ea9a4dbb1d1ff408dc73a0 100644 (file)
@@ -1780,7 +1780,8 @@ class SynonymTest(QueryTest):
             'name_syn':synonym('name'),
             'addresses':relationship(Address),
             'orders':relationship(Order, backref='user'), # o2m, m2o
-            'orders_syn':synonym('orders')
+            'orders_syn':synonym('orders'),
+            'orders_syn_2':synonym('orders_syn')
         })
         mapper(Address, addresses)
         mapper(Order, orders, properties={
@@ -1793,20 +1794,52 @@ class SynonymTest(QueryTest):
         })
         mapper(Keyword, keywords)
 
+    def test_options(self):
+        User, Order = self.classes.User, self.classes.Order
+
+        s = create_session()
+        def go():
+            result = s.query(User).filter_by(name='jack').\
+                        options(joinedload(User.orders_syn)).all()
+            eq_(result, [
+                User(id=7, name='jack', orders=[
+                    Order(description=u'order 1'), 
+                    Order(description=u'order 3'), 
+                    Order(description=u'order 5')
+                ])
+            ])
+        self.assert_sql_count(testing.db, go, 1)
+
+    def test_options_syn_of_syn(self):
+        User, Order = self.classes.User, self.classes.Order
+
+        s = create_session()
+        def go():
+            result = s.query(User).filter_by(name='jack').\
+                        options(joinedload(User.orders_syn_2)).all()
+            eq_(result, [
+                User(id=7, name='jack', orders=[
+                    Order(description=u'order 1'), 
+                    Order(description=u'order 3'), 
+                    Order(description=u'order 5')
+                ])
+            ])
+        self.assert_sql_count(testing.db, go, 1)
+
     def test_joins(self):
         User = self.classes.User
 
         for j in (
             ['orders', 'items'],
             ['orders_syn', 'items'],
+            ['orders_syn_2', 'items'],
             ['orders', 'items_syn'],
             ['orders_syn', 'items_syn'],
+            ['orders_syn_2', 'items_syn'],
         ):
             result = create_session().query(User).join(*j).filter_by(id=3).all()
             assert [User(id=7, name='jack'), User(id=9, name='fred')] == result
 
-    @testing.fails_if(lambda: True, "0.7 regression, may not support "
-                                "synonyms for relationship")
     def test_with_parent(self):
         Order, User = self.classes.Order, self.classes.User
 
@@ -1814,7 +1847,9 @@ class SynonymTest(QueryTest):
             ('name', 'orders'),
             ('name_syn', 'orders'),
             ('name', 'orders_syn'),
+            ('name', 'orders_syn_2'),
             ('name_syn', 'orders_syn'),
+            ('name_syn', 'orders_syn_2'),
         ):
             sess = create_session()
             q = sess.query(User)
@@ -1822,7 +1857,8 @@ class SynonymTest(QueryTest):
             u1 = q.filter_by(**{nameprop:'jack'}).one()
 
             o = sess.query(Order).with_parent(u1, property=orderprop).all()
-            assert [Order(description="order 1"), Order(description="order 3"), Order(description="order 5")] == o
+            assert [Order(description="order 1"), 
+                    Order(description="order 3"), Order(description="order 5")] == o
 
 
 class ImmediateTest(_fixtures.FixtureTest):