]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
- Fixed bug that would prevent "subqueryload" from
authorMike Bayer <mike_mp@zzzcomputing.com>
Tue, 14 Sep 2010 02:55:54 +0000 (22:55 -0400)
committerMike Bayer <mike_mp@zzzcomputing.com>
Tue, 14 Sep 2010 02:55:54 +0000 (22:55 -0400)
    working correctly with single table inheritance
    for a relationship from a subclass - the "where
    type in (x, y, z)" only gets placed on the inside,
    instead of repeatedly.

  - When using from_self() with single table inheritance,
    the "where type in (x, y, z)" is placed on the outside
    of the query only, instead of repeatedly.   May make
    some more adjustments to this.

CHANGES
lib/sqlalchemy/orm/query.py
lib/sqlalchemy/orm/strategies.py
test/orm/inheritance/test_single.py

diff --git a/CHANGES b/CHANGES
index a39fac9f0b0830f3f8191e29dd6602dc7646dfc3..657695c7e4e1b2717494c051abce3fc959ea182d 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -47,7 +47,18 @@ CHANGES
   - Placing passive_deletes=True on a many-to-one emits
     a warning, since you probably intended to put it on
     the one-to-many side.
-    
+  
+  - Fixed bug that would prevent "subqueryload" from
+    working correctly with single table inheritance 
+    for a relationship from a subclass - the "where 
+    type in (x, y, z)" only gets placed on the inside,
+    instead of repeatedly.
+    
+  - When using from_self() with single table inheritance,
+    the "where type in (x, y, z)" is placed on the outside
+    of the query only, instead of repeatedly.   May make
+    some more adjustments to this.
+        
 0.6.4
 =====
 - orm
index 6c5e8c81ca1969061d5c57879624705dfbc83907..b22a10b55ecb0c6f1c839fa3c92e65f74d63402c 100644 (file)
@@ -98,6 +98,7 @@ class Query(object):
     _attributes = util.frozendict()
     _with_options = ()
     _with_hints = ()
+    _enable_single_crit = True
     
     def __init__(self, entities, session=None):
         self.session = session
@@ -701,12 +702,17 @@ class Query(object):
 
         """
         fromclause = self.with_labels().enable_eagerloads(False).\
+                                    _enable_single_crit(False).\
                                     statement.correlate(None)
         q = self._from_selectable(fromclause)
         if entities:
             q._set_entities(entities)
         return q
-    
+
+    @_generative()
+    def _enable_single_crit(self, val):
+        self._enable_single_crit = val
+        
     @_generative()
     def _from_selectable(self, fromclause):
         for attr in ('_statement', '_criterion', '_order_by', '_group_by',
@@ -1936,7 +1942,8 @@ class Query(object):
         else:
             from_obj = context.froms
 
-        self._adjust_for_single_inheritance(context)
+        if self._enable_single_crit:
+            self._adjust_for_single_inheritance(context)
 
         whereclause  = context.whereclause
 
@@ -2273,7 +2280,8 @@ class Query(object):
             # i.e. when each _MappedEntity has its own FROM
             froms = context.froms   
 
-        self._adjust_for_single_inheritance(context)
+        if self._enable_single_crit:
+            self._adjust_for_single_inheritance(context)
 
         if not context.primary_columns:
             if self._only_load_props:
@@ -2405,6 +2413,7 @@ class Query(object):
         selected from the total results.
 
         """
+            
         for entity, (mapper, adapter, s, i, w) in \
                             self._mapper_adapter_map.iteritems():
             single_crit = mapper._single_table_criterion
index b0a18b7ddcbb80675c5160a822e0b1f406cbcd39..3e6b6a21f63e05ceebfd2d367e98713eed831005 100644 (file)
@@ -765,6 +765,7 @@ class SubqueryLoader(AbstractRelationshipLoader):
             ("orig_query", SubqueryLoader): orig_query,
             ('subquery_path', None) : subq_path
         }
+        q = q._enable_single_crit(False)
 
         # figure out what's being joined.  a.k.a. the fun part
         to_join = [
index 4b7078eb51d96cf6c0b507cdcc59a12c409d075d..42043095402f62beb030519d84b4b38b7f069bf1 100644 (file)
@@ -8,7 +8,7 @@ from test.orm._base import MappedTest, ComparableEntity
 from sqlalchemy.test.schema import Table, Column
 
 
-class SingleInheritanceTest(MappedTest):
+class SingleInheritanceTest(testing.AssertsCompiledSQL, MappedTest):
     @classmethod
     def define_tables(cls, metadata):
         Table('employees', metadata,
@@ -26,6 +26,7 @@ class SingleInheritanceTest(MappedTest):
 
     @classmethod
     def setup_classes(cls):
+        global Employee, Manager, Engineer, JuniorEngineer
         class Employee(ComparableEntity):
             pass
         class Manager(Employee):
@@ -114,6 +115,31 @@ class SingleInheritanceTest(MappedTest):
         #    session.query(Employee.name, Manager.manager_data, Engineer.engineer_info).all(), 
         #    []
         # )
+
+    @testing.resolve_artifact_names
+    def test_from_self(self):
+        sess = create_session()
+        self.assert_compile(sess.query(Engineer).from_self(),
+                            'SELECT anon_1.employees_employee_id AS '
+                            'anon_1_employees_employee_id, '
+                            'anon_1.employees_name AS '
+                            'anon_1_employees_name, '
+                            'anon_1.employees_manager_data AS '
+                            'anon_1_employees_manager_data, '
+                            'anon_1.employees_engineer_info AS '
+                            'anon_1_employees_engineer_info, '
+                            'anon_1.employees_type AS '
+                            'anon_1_employees_type FROM (SELECT '
+                            'employees.employee_id AS '
+                            'employees_employee_id, employees.name AS '
+                            'employees_name, employees.manager_data AS '
+                            'employees_manager_data, '
+                            'employees.engineer_info AS '
+                            'employees_engineer_info, employees.type '
+                            'AS employees_type FROM employees) AS '
+                            'anon_1 WHERE anon_1.employees_type IN '
+                            '(:type_1, :type_2)',
+                            use_default_dialect=True)
         
     @testing.resolve_artifact_names
     def test_select_from(self):
@@ -182,6 +208,54 @@ class SingleInheritanceTest(MappedTest):
         assert len(rq.join(Report.employee.of_type(Manager)).all()) == 1
         assert len(rq.join(Report.employee.of_type(Engineer)).all()) == 0
 
+class RelationshipFromSingleTest(testing.AssertsCompiledSQL, MappedTest):
+    @classmethod
+    def define_tables(cls, metadata):
+        Table('employee', metadata,
+            Column('id', Integer, primary_key=True, test_needs_autoincrement=True),
+            Column('name', String(50)),
+            Column('type', String(20)),
+        )
+        
+        Table('employee_stuff', metadata,
+            Column('id', Integer, primary_key=True, test_needs_autoincrement=True),
+            Column('employee_id', Integer, ForeignKey('employee.id')),
+            Column('name', String(50)),
+        )
+    
+    @classmethod
+    def setup_classes(cls):
+        class Employee(ComparableEntity):
+            pass
+        class Manager(Employee):
+            pass
+        class Stuff(ComparableEntity):
+            pass
+
+    @testing.resolve_artifact_names
+    def test_subquery_load(self):
+        mapper(Employee, employee, polymorphic_on=employee.c.type, polymorphic_identity='employee')
+        mapper(Manager, inherits=Employee, polymorphic_identity='manager', properties={
+            'stuff':relationship(Stuff)
+        })
+        mapper(Stuff, employee_stuff)
+        
+        sess = create_session()
+        context = sess.query(Manager).options(subqueryload('stuff'))._compile_context()
+        subq = context.attributes[('subquery', (class_mapper(Employee), 'stuff'))]
+
+        self.assert_compile(subq,
+                            'SELECT employee_stuff.id AS '
+                            'employee_stuff_id, employee_stuff.employee'
+                            '_id AS employee_stuff_employee_id, '
+                            'employee_stuff.name AS '
+                            'employee_stuff_name, anon_1.employee_id '
+                            'AS anon_1_employee_id FROM (SELECT '
+                            'employee.id AS employee_id FROM employee '
+                            'WHERE employee.type IN (?)) AS anon_1 '
+                            'JOIN employee_stuff ON anon_1.employee_id '
+                            '= employee_stuff.employee_id ORDER BY '
+                            'anon_1.employee_id')
 
 class RelationshipToSingleTest(MappedTest):
     @classmethod