]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
this version works with *all* the polymorphic scenarios by putting the subquery into
authorMike Bayer <mike_mp@zzzcomputing.com>
Wed, 24 Mar 2010 16:46:58 +0000 (12:46 -0400)
committerMike Bayer <mike_mp@zzzcomputing.com>
Wed, 24 Mar 2010 16:46:58 +0000 (12:46 -0400)
an aliased(), so that it can be controlled.  self ref breaks now.  will move the
joining out to use orm.join().

lib/sqlalchemy/orm/query.py
lib/sqlalchemy/orm/strategies.py
test/orm/inheritance/test_query.py

index d42a8f86328022b82a7df994a91441fa5f4cb842..c56804847a56cbebc1ad2b9853b76b357d1bd77e 100644 (file)
@@ -1069,8 +1069,7 @@ class Query(object):
             left = self._joinpoint_zero()
 
         if left is right and \
-                not create_aliases and \
-                not self._entity_zero()._subq_aliasing:  # <-- TODO: hack
+                not create_aliases:
             raise sa_exc.InvalidRequestError(
                         "Can't construct a join from %s to %s, they are the same entity" % 
                         (left, right))
index 0e5e2efdfc47eae8455b2f31f50eb3ae7f142797..92b560cd9c3c03666443d55e0df45066ee915c4c 100644 (file)
@@ -699,18 +699,27 @@ class SubqueryLoader(AbstractRelationshipLoader):
         # for the significant columns, not order
         # by anything.
         q = orig_query._clone()
-        q._attributes = {}
-        q._attributes[("orig_query", SubqueryLoader)] = orig_query
+#        q._attributes = {}
+#        q._attributes[("orig_query", SubqueryLoader)] = orig_query
         q._set_entities(q._adapt_col_list(leftmost_attr))
         if q._limit is None and q._offset is None:
             q._order_by = None
-            
-        q = q.from_self(self.mapper)
+        
+        embed_q = q.with_labels().subquery()
+        
+        q = q.session.query(self.mapper)
+        q._attributes = {}
+        q._attributes[("orig_query", SubqueryLoader)] = orig_query
+        
+        left_alias = mapperutil.AliasedClass(leftmost_mapper, embed_q)
+        q = q.select_from(left_alias)
+        
+#        q = q.from_self(self.mapper)
         
         # TODO: this is currently a magic hardcody
         # flag on _MapperEntity.  we should find 
         # a way to turn it into public functionality.
-        q._entities[0]._subq_aliasing = True
+#        q._entities[0]._subq_aliasing = True
 
         q._attributes[('subquery_path', None)] = subq_path
 
@@ -720,8 +729,12 @@ class SubqueryLoader(AbstractRelationshipLoader):
                 ]
 
         if len(to_join) < 2:
+#            local_attr = [
+#                self.parent._get_col_to_prop(c).class_attribute
+#                for c in local_cols
+#            ]
             local_attr = [
-                self.parent._get_col_to_prop(c).class_attribute
+                getattr(left_alias, self.parent._get_col_to_prop(c).key)
                 for c in local_cols
             ]
         else:
@@ -747,6 +760,7 @@ class SubqueryLoader(AbstractRelationshipLoader):
             else:
                 q = q.join(prop.class_attribute, aliased=alias_join)
 
+
         # propagate loader options etc. to the new query
         q = q._with_current_path(subq_path)
         q = q._conditional_options(*orig_query._with_options)
index 5e6375eab7e598b6f19e8cc5a53e2e3090a8c116..7be6de6e3871cbaa261066ce36700b4a3e6ccce8 100644 (file)
@@ -185,6 +185,13 @@ def _produce_test(select_type):
                 eq_(sess.query(Person).all(), all_employees)
             self.assert_sql_count(testing.db, go, {'':14, 'Polymorphic':9}.get(select_type, 10))
 
+        def test_foo(self):
+            sess = create_session()
+            
+            def go():
+                eq_(sess.query(Person).options(subqueryload(Engineer.machines)).all(), all_employees)
+            self.assert_sql_count(testing.db, go, {'':14, 'Unions':8, 'Polymorphic':7}.get(select_type, 8))
+
         def test_primary_eager_aliasing(self):
             sess = create_session()
 
@@ -195,14 +202,11 @@ def _produce_test(select_type):
                 eq_(sess.query(Person).options(eagerload(Engineer.machines))[1:3], all_employees[1:3])
             self.assert_sql_count(testing.db, go, {'':6, 'Polymorphic':3}.get(select_type, 4))
 
-            # additionally, subqueryload() can't handle from_self() on the union.
-            # I'm not too concerned about that.
             sess = create_session()
             
-            @testing.fails_if(lambda:select_type == 'Unions')
             def go():
                 eq_(sess.query(Person).options(subqueryload(Engineer.machines)).all(), all_employees)
-            self.assert_sql_count(testing.db, go, {'':14, 'Unions':3, 'Polymorphic':7}.get(select_type, 8))
+            self.assert_sql_count(testing.db, go, {'':14, 'Unions':8, 'Polymorphic':7}.get(select_type, 8))
 
             sess = create_session()
 
@@ -515,7 +519,6 @@ def _produce_test(select_type):
             self.assert_sql_count(testing.db, go, {'':7, 'Polymorphic':1}.get(select_type, 2))
             
             sess = create_session()
-            @testing.fails_if(lambda: select_type=='Unions')
             def go():
                 eq_(
                         sess.query(Company).options(
@@ -523,7 +526,7 @@ def _produce_test(select_type):
                                             )).all(), 
                                         assert_result)
         
-            self.assert_sql_count(testing.db, go, {'':9, 'Joins':6,'Unions':3,'Polymorphic':5,'AliasedJoins':6}[select_type])
+            self.assert_sql_count(testing.db, go, {'':9, 'Joins':6,'Unions':6,'Polymorphic':5,'AliasedJoins':6}[select_type])
     
         def test_eagerload_on_subclass(self):
             sess = create_session()