1. idank
  2. sqlalchemy

Commits

Mike Bayer  committed 1dc9a22

fix to EagerLoad where it late-initializes its eager chain, thereby not getting messed up by late add_property() calls

  • Participants
  • Parent commits 0df4f88
  • Branches default

Comments (0)

Files changed (4)

File lib/sqlalchemy/mapping/properties.py

View file
  • Ignore whitespace
     def do_init_subclass(self, key, parent, recursion_stack=None):
         parent._has_eager = True
 
-        if recursion_stack is None:
-            recursion_stack = {}
-    
         self.eagertarget = self.target.alias()
         if self.secondary:
             self.eagersecondary = self.secondary.alias()
         else:
             self.eager_order_by = None
 
+
+    def _create_eager_chain(self, in_chain=False, recursion_stack=None):
+        if not in_chain and getattr(self, '_eager_chained', False):
+            return
+            
+        if recursion_stack is None:
+            recursion_stack = {}
+
         eagerprops = []
         # create a new "eager chain", starting from this eager loader and descending downwards
         # through all sub-eagerloaders.  this will copy all those eagerloaders and have them set up
                         continue
                     p = prop.copy()
                     self.mapper.props[prop.key] = p
-                    #print "we are:", id(self), self.target.name, (self.secondary and self.secondary.name or "None"), self.parent.table.name
-                    #print "prop is",id(prop), prop.target.name, (prop.secondary and prop.secondary.name or "None"), prop.parent.table.name
+#                    print "we are:", id(self), self.target.name, (self.secondary and self.secondary.name or "None"), self.parent.table.name
+#                    print "prop is",id(prop), prop.target.name, (prop.secondary and prop.secondary.name or "None"), prop.parent.table.name
                     p.do_init_subclass(prop.key, prop.parent, recursion_stack)
+                    p._create_eager_chain(in_chain=True, recursion_stack=recursion_stack)
                     p.eagerprimary = p.eagerprimary.copy_container()
-                    aliasizer = Aliasizer(p.parent.table, aliases={p.parent.table:self.eagertarget})
-                    p.eagerprimary.accept_visitor(aliasizer)
+#                    aliasizer = Aliasizer(p.parent.table, aliases={p.parent.table:self.eagertarget})
+                    p.eagerprimary.accept_visitor(self.aliasizer)
                     #print "new eagertqarget", p.eagertarget.name, (p.secondary and p.secondary.name or "none"), p.parent.table.name
             finally:
                 del recursion_stack[self.parent.table]
+        self._eager_chained = True
                 
     def _aliasize_orderby(self, orderby, copy=True):
         if copy:
     def setup(self, key, statement, eagertable=None, **options):
         """add a left outer join to the statement thats being constructed"""
 
+        # initialize the eager chains late in the game
+        self._create_eager_chain()
+
         if hasattr(statement, '_outerjoin'):
             towrap = statement._outerjoin
         else:
             towrap = self.parent.table
 
+ #       print "hello, towrap", str(towrap)
         if self.secondaryjoin is not None:
             statement._outerjoin = sql.outerjoin(towrap, self.eagersecondary, self.eagerprimary).outerjoin(self.eagertarget, self.eagersecondaryjoin)
             if self.order_by is False and self.secondary.default_order_by() is not None:

File lib/sqlalchemy/schema.py

View file
  • Ignore whitespace
         ["%s=%s" % (k, repr(getattr(self, k))) for k in ['schema']]
        , ',\n')
     
+    def __str__(self):
+        if self.schema is None:
+            return self.name
+        else:
+            return self.schema + "." + self.name
+        
     def hash_key(self):
         return "Table(%s)" % string.join(
         [repr(self.name)] + [self.engine.hash_key()] +

File lib/sqlalchemy/sql.py

View file
  • Ignore whitespace
                     crit.append(secondary._get_col_by_original(fk.column) == fk.parent)
                     self.foreignkey = fk.parent
         if len(crit) == 0:
-            raise ArgumentError("Cant find any foreign key relationships between '%s' (%s) and '%s' (%s)" % (primary.name, repr(primary), secondary.name, repr(secondary)))
+            raise ArgumentError("Cant find any foreign key relationships between '%s' and '%s'" % (primary.name, secondary.name))
         elif len(crit) == 1:
             return (crit[0])
         else:

File test/eagertest1.py

View file
  • Ignore whitespace
+from sqlalchemy import *
+
+class Part(object):pass
+class Design(object):pass
+class DesignType(object):pass
+class InheritedPart(object):pass
+
+engine = create_engine('sqlite://', echo=True)
+
+designType = Table('design_types', engine, 
+	Column('design_type_id', Integer, primary_key=True),
+	)
+
+design =Table('design', engine, 
+	Column('design_id', Integer, primary_key=True),
+	Column('design_type_id', Integer, ForeignKey('design_types.design_type_id')))
+
+part = Table('parts', engine, 
+	Column('part_id', Integer, primary_key=True),
+	Column('design_id', Integer, ForeignKey('design.design_id')),
+	Column('design_type_id', Integer, ForeignKey('design_types.design_type_id')))
+	
+inheritedPart = Table('inherited_part', engine,
+	Column('ip_id', Integer, primary_key=True),
+	Column('part_id', Integer, ForeignKey('parts.part_id')),
+	Column('design_id', Integer, ForeignKey('design.design_id')),
+	)
+
+designType.create()
+design.create()
+part.create()
+inheritedPart.create()
+	
+assign_mapper(Part, part)
+
+assign_mapper(InheritedPart, inheritedPart, properties=dict(
+	part=relation(Part, lazy=False)
+))
+
+assign_mapper(Design, design, properties=dict(
+	parts=relation(Part, private=True, backref="design"),
+	inheritedParts=relation(InheritedPart, private=True, backref="design"),
+))
+
+assign_mapper(DesignType, designType, properties=dict(
+#	designs=relation(Design, private=True, backref="type"),
+))
+
+Design.mapper.add_property("type", relation(DesignType, lazy=False, backref="designs"))
+Part.mapper.add_property("design", relation(Design, lazy=False, backref="parts"))
+#Part.mapper.add_property("designType", relation(DesignType))
+
+d = Design()
+objectstore.commit()
+objectstore.clear()
+print "lets go !\n\n\n"
+x = Design.get(1)
+x.inheritedParts
+
+