]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
- a little cleanup to deferred inheritance loading
authorMike Bayer <mike_mp@zzzcomputing.com>
Sun, 28 Oct 2007 04:36:36 +0000 (04:36 +0000)
committerMike Bayer <mike_mp@zzzcomputing.com>
Sun, 28 Oct 2007 04:36:36 +0000 (04:36 +0000)
lib/sqlalchemy/orm/strategies.py

index 757021cd0d365aa5f0a17a70f0b1c857b2d696a5..1c1813311667af1fa3ac2fcb07d344562548dc2a 100644 (file)
@@ -16,6 +16,8 @@ from sqlalchemy.orm import util as mapperutil
 
 
 class ColumnLoader(LoaderStrategy):
+    """Default column loader."""
+    
     def init(self):
         super(ColumnLoader, self).init()
         self.columns = self.parent_property.columns
@@ -82,16 +84,42 @@ class ColumnLoader(LoaderStrategy):
         # our mapped column is not present in the row.  check if we need to initialize a polymorphic
         # row fetcher used by inheritance.
         (hosted_mapper, needs_tables) = selectcontext.attributes.get(('polymorphic_fetch', mapper), (None, None))
+
         if hosted_mapper is None:
             return (None, None, None)
         
         if hosted_mapper.polymorphic_fetch == 'deferred':
             # 'deferred' polymorphic row fetcher, put a callable on the property.
+            # create a deferred column loader which will query the remaining not-yet-loaded tables in an inheritance load.
+            # the mapper for the object creates the WHERE criterion using the mapper who originally 
+            # "hosted" the query and the list of tables which are unloaded between the "hosted" mapper
+            # and this mapper.  (i.e. A->B->C, the query used mapper A.  therefore will need B's and C's tables
+            # in the query).
+            
+            # deferred loader strategy
+            strategy = self.parent_property._get_strategy(DeferredColumnLoader)
+            
+            # full list of ColumnProperty objects to be loaded in the deferred fetch
+            props = [p for p in mapper.iterate_properties if isinstance(p.strategy, ColumnLoader) and p.columns[0].table in needs_tables]
+
+            # TODO: we are somewhat duplicating efforts from mapper._get_poly_select_loader 
+            # and should look for ways to simplify.
+            cond, param_names = mapper._deferred_inheritance_condition(hosted_mapper, needs_tables)
+            statement = sql.select(needs_tables, cond, use_labels=True)
+            def create_statement(instance):
+                params = {}
+                for c in param_names:
+                    params[c.name] = mapper.get_attr_by_column(instance, c)
+                return (statement, params)
+            
             def new_execute(instance, row, isnew, **flags):
                 if isnew:
-                    sessionlib.attribute_manager.init_instance_attribute(instance, self.key, callable_=self._get_deferred_inheritance_loader(instance, mapper, hosted_mapper, needs_tables))
+                    loader = strategy.setup_loader(instance, props=props, create_statement=create_statement)
+                    sessionlib.attribute_manager.init_instance_attribute(instance, self.key, callable_=loader)
+                    
             if self._should_log_debug:
                 self.logger.debug("Returning deferred column fetcher for %s %s" % (mapper, self.key))
+                
             return (new_execute, None, None)
         else:  
             # immediate polymorphic row fetcher.  no processing needed for this row.
@@ -99,41 +127,11 @@ class ColumnLoader(LoaderStrategy):
                 self.logger.debug("Returning no column fetcher for %s %s" % (mapper, self.key))
             return (None, None, None)
 
-    def _get_deferred_inheritance_loader(self, instance, mapper, hosted_mapper, needs_tables):
-        # create a deferred column loader which will query the remaining not-yet-loaded tables in an inheritance load.
-        # the mapper for the object creates the WHERE criterion using the mapper who originally 
-        # "hosted" the query and the list of tables which are unloaded between the "hosted" mapper
-        # and this mapper.  (i.e. A->B->C, the query used mapper A.  therefore will need B's and C's tables
-        # in the query).
-        def create_statement():
-            # TODO: the SELECT statement here should be cached in the selectcontext.  we are somewhat duplicating 
-            # efforts from mapper._get_poly_select_loader as well and should look
-            # for ways to simplify.
-            cond, param_names = mapper._deferred_inheritance_condition(hosted_mapper, needs_tables)
-            statement = sql.select(needs_tables, cond, use_labels=True)
-            params = {}
-            for c in param_names:
-                params[c.name] = mapper.get_attr_by_column(instance, c)
-            return (statement, params)
-            
-        # install the create_statement() callable using the deferred loading strategy
-        strategy = self.parent_property._get_strategy(DeferredColumnLoader)
-
-        # assemble list of all ColumnProperties which will need to be loaded
-        props = [p for p in mapper.iterate_properties if isinstance(p.strategy, ColumnLoader) and p.columns[0].table in needs_tables]
-        
-        # set the deferred loader on the instance attribute
-        return strategy.setup_loader(instance, props=props, create_statement=create_statement)
-
 
 ColumnLoader.logger = logging.class_logger(ColumnLoader)
 
 class DeferredColumnLoader(LoaderStrategy):
-    """Describes an object attribute that corresponds to a table
-    column, which also will *lazy load* its value from the table.
-
-    This is per-column lazy loading.
-    """
+    """Deferred column loader, a per-column or per-column-group lazy loader."""
     
     def create_row_processor(self, selectcontext, mapper, row):
         if self.group is not None and selectcontext.attributes.get(('undefer', self.group), False):
@@ -207,7 +205,7 @@ class DeferredColumnLoader(LoaderStrategy):
                     params[param_map[primary_key].key] = ident[i]
                 statement = sql.select([p.columns[0] for p in group], clause, from_obj=[localparent.mapped_table], use_labels=True)
             else:
-                statement, params = create_statement()
+                statement, params = create_statement(instance)
             
             # TODO: have the "fetch of one row" operation go through the same channels as a query._get()
             # deferred load of several attributes should be a specialized case of a query refresh operation