From: Mike Bayer Date: Wed, 22 Feb 2006 00:28:59 +0000 (+0000) Subject: fix to EagerLoad where it late-initializes its eager chain, thereby not getting messe... X-Git-Tag: rel_0_1_1~9 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=24e22e2e5a20c6dea4e8030feb1f579b7dfc2bcd;p=thirdparty%2Fsqlalchemy%2Fsqlalchemy.git fix to EagerLoad where it late-initializes its eager chain, thereby not getting messed up by late add_property() calls --- diff --git a/lib/sqlalchemy/mapping/properties.py b/lib/sqlalchemy/mapping/properties.py index f22a01cdbd..d03069f1ec 100644 --- a/lib/sqlalchemy/mapping/properties.py +++ b/lib/sqlalchemy/mapping/properties.py @@ -740,9 +740,6 @@ class EagerLoader(PropertyLoader): 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() @@ -764,6 +761,14 @@ class EagerLoader(PropertyLoader): 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 @@ -783,15 +788,17 @@ class EagerLoader(PropertyLoader): 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: @@ -808,11 +815,15 @@ class EagerLoader(PropertyLoader): 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: diff --git a/lib/sqlalchemy/schema.py b/lib/sqlalchemy/schema.py index 857fc3cf7c..bb996f7d4a 100644 --- a/lib/sqlalchemy/schema.py +++ b/lib/sqlalchemy/schema.py @@ -154,6 +154,12 @@ class Table(SchemaItem): ["%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()] + diff --git a/lib/sqlalchemy/sql.py b/lib/sqlalchemy/sql.py index cf42b2e837..2a1686e12d 100644 --- a/lib/sqlalchemy/sql.py +++ b/lib/sqlalchemy/sql.py @@ -870,7 +870,7 @@ class Join(FromClause): 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: diff --git a/test/eagertest1.py b/test/eagertest1.py new file mode 100644 index 0000000000..ab4a69c1b6 --- /dev/null +++ b/test/eagertest1.py @@ -0,0 +1,60 @@ +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 + +