]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
- merge from tip
authorMike Bayer <mike_mp@zzzcomputing.com>
Mon, 22 Mar 2010 17:38:44 +0000 (13:38 -0400)
committerMike Bayer <mike_mp@zzzcomputing.com>
Mon, 22 Mar 2010 17:38:44 +0000 (13:38 -0400)
- refine subq loading to use the same approach for m2m/o2m

1  2 
lib/sqlalchemy/orm/interfaces.py
lib/sqlalchemy/orm/strategies.py

index 579101f0d8fa7a3f3e254e9782b25d00db46afd1,579101f0d8fa7a3f3e254e9782b25d00db46afd1..03ebb97c4f57975b1af6b3770f11037a849094c3
@@@ -482,6 -482,6 +482,12 @@@ class MapperProperty(object)
          self.do_init()
          self._compile_finished = True
  
++    @property
++    def class_attribute(self):
++        """Return the class-bound descriptor corresponding to this MapperProperty."""
++        
++        return getattr(self.parent.class_, self.key)
++        
      def do_init(self):
          """Perform subclass-specific initialization post-mapper-creation steps.
  
index f6b36f557ed12fe1cdc831954c064707f8a04314,ce19667c69e967c363d756fec62d597d1b1dee09..00b00be1355672a4eb28f04415b40c3ad4d1f11d
@@@ -576,98 -575,6 +576,81 @@@ class LoadLazyAttribute(object)
              else:
                  return None
  
-         # TODO: shouldn't have to use getattr() to get at
-         # InstrumentedAttributes, or alternatively should not need to
-         # use InstrumentedAttributes with the Query at all (it should accept
-         # the MapperProperty objects as well).
-         
 +class SubqueryLoader(AbstractRelationshipLoader):
 +    def init_class_attribute(self, mapper):
 +        self.parent_property._get_strategy(LazyLoader).init_class_attribute(mapper)
 +    
 +    def setup_query(self, context, entity, path, adapter, 
 +                                column_collection=None, parentmapper=None, **kwargs):
 +
 +        if not context.query._enable_eagerloads:
 +            return
 +
 +        path = path + (self.key,)
 +        
-         local_attr = [getattr(self.parent.class_, key)
-                             for key in 
-                                 [self.parent._get_col_to_prop(c).key for c in local_cols]
-                     ]
 +        local_cols, remote_cols = self._local_remote_columns
 +
-         attr = getattr(self.parent.class_, self.key)
++        local_attr = [
++            self.parent._get_col_to_prop(c).class_attribute
++            for c in local_cols
++        ]
 +        
-         # TODO.  secondary is not supported at all yet.
-         
++        attr = self.parent_property.class_attribute
 +        
 +        # modify the query to just look for parent columns in the join condition
 +        
-         if self.parent_property.secondary is not None:
-             q = q.from_self(self.mapper, *local_attr)
-         else:
-             q = q.from_self(self.mapper) 
 +        # TODO: what happens to options() in the parent query ?  are they going
 +        # to get in the way here ?
 +        
 +        q = context.query._clone()
 +        q._set_entities(local_attr)
-         if self.parent_property.secondary is not None:
-             q = q.order_by(*local_attr)
-         else:
-             q = q.order_by(*remote_cols)
++        
++        q = q.from_self(self.mapper, *local_attr)
++        
 +        q = q.join(attr)
 +                                                    
-         if self.parent_property.secondary is not None:
-             collections = dict((k, [v[0] for v in v]) for k, v in itertools.groupby(
-                               q, 
-                               lambda x:x[1:]
-                           ))
-         else:
-             collections = dict((k, list(v)) for k, v in itertools.groupby(
-                               q, 
-                               lambda x:tuple([getattr(x, key) for key in remote_attr])
-                           ))
++        q = q.order_by(*local_attr)
 +        
 +        if self.parent_property.order_by:
 +            q = q.order_by(*self.parent_property.order_by)
 +        
 +        context.attributes[('subquery', path)] = q
 +    
 +    @property
 +    def _local_remote_columns(self):
 +        if self.parent_property.secondary is None:
 +            return zip(*self.parent_property.local_remote_pairs)
 +        else:
 +            return \
 +                [p[0] for p in self.parent_property.synchronize_pairs],\
 +                [p[0] for p in self.parent_property.secondary_synchronize_pairs]
 +        
 +    def create_row_processor(self, context, path, mapper, row, adapter):
 +        path = path + (self.key,)
 +
 +        local_cols, remote_cols = self._local_remote_columns
 +
 +        local_attr = [self.parent._get_col_to_prop(c).key for c in local_cols]
 +        remote_attr = [self.mapper._get_col_to_prop(c).key for c in remote_cols]
 +
 +        q = context.attributes[('subquery', path)]
 +        
++        collections = dict((k, [v[0] for v in v]) for k, v in itertools.groupby(
++                        q, 
++                        lambda x:x[1:]
++                    ))
 +
 +        
 +        def execute(state, dict_, row):
 +            collection = collections.get(
 +                tuple([row[col] for col in local_cols]), 
 +                ()
 +            )
 +            state.get_impl(self.key).set_committed_value(state, dict_, collection)
 +                
 +        return (execute, None)
 +        
 +
  class EagerLoader(AbstractRelationshipLoader):
      """Strategize a relationship() that loads within the process of the parent object being selected."""