From: Mike Bayer Date: Thu, 22 Jun 2006 22:23:57 +0000 (+0000) Subject: fixes to inheritance firing off dependency processors correctly + unittest X-Git-Tag: rel_0_2_4~16 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=ad7ffd767d26aef8caba3e52b8c3c1114ec6709c;p=thirdparty%2Fsqlalchemy%2Fsqlalchemy.git fixes to inheritance firing off dependency processors correctly + unittest --- diff --git a/CHANGES b/CHANGES index 0efbac11b6..0192527795 100644 --- a/CHANGES +++ b/CHANGES @@ -15,6 +15,8 @@ the previous Session. - utterly remarkable: added a single space between 'CREATE TABLE' and '(' since *thats how MySQL indicates a non- reserved word tablename.....* [ticket:206] +- more fixes to inheritance, related to many-to-many relations +properly saving 0.2.3 - overhaul to mapper compilation to be deferred. this allows mappers diff --git a/lib/sqlalchemy/orm/dependency.py b/lib/sqlalchemy/orm/dependency.py index 067e842c35..6eca75ae1d 100644 --- a/lib/sqlalchemy/orm/dependency.py +++ b/lib/sqlalchemy/orm/dependency.py @@ -85,7 +85,7 @@ class DependencyProcessor(object): class OneToManyDP(DependencyProcessor): def register_dependencies(self, uowcommit): if self.post_update: - stub = MapperStub(self.mapper) + stub = MapperStub(self.parent, self.mapper, self.key) uowcommit.register_dependency(self.mapper, stub) uowcommit.register_dependency(self.parent, stub) uowcommit.register_processor(stub, self, self.parent) @@ -179,7 +179,7 @@ class OneToManyDP(DependencyProcessor): class ManyToOneDP(DependencyProcessor): def register_dependencies(self, uowcommit): if self.post_update: - stub = MapperStub(self.mapper) + stub = MapperStub(self.parent, self.mapper, self.key) uowcommit.register_dependency(self.mapper, stub) uowcommit.register_dependency(self.parent, stub) uowcommit.register_processor(stub, self, self.parent) @@ -249,7 +249,7 @@ class ManyToManyDP(DependencyProcessor): # if we are the "backref" half of a two-way backref # relationship, let the other mapper handle inserting the rows return - stub = MapperStub(self.mapper) + stub = MapperStub(self.parent, self.mapper, self.key) uowcommit.register_dependency(self.parent, stub) uowcommit.register_dependency(self.mapper, stub) uowcommit.register_processor(stub, self, self.parent) @@ -304,7 +304,7 @@ class AssociationDP(OneToManyDP): # association/parent->stub->self, then we process the child # elments after the 'stub' save, which is before our own # mapper's save. - stub = MapperStub(self.association) + stub = MapperStub(self.parent, self.association, self.key) uowcommit.register_dependency(self.parent, stub) uowcommit.register_dependency(self.association, stub) uowcommit.register_dependency(stub, self.mapper) @@ -371,7 +371,8 @@ class MapperStub(object): The Task objects in the objectstore module treat it just like any other Mapper, but in fact it only serves as a "dependency" placeholder for the many-to-many update task.""" - def __init__(self, mapper): + __metaclass__ = util.ArgSingleton + def __init__(self, parent, mapper, key): self.mapper = mapper self._inheriting_mappers = [] def register_dependencies(self, uowcommit): diff --git a/lib/sqlalchemy/orm/properties.py b/lib/sqlalchemy/orm/properties.py index 846c7d125b..6be5633932 100644 --- a/lib/sqlalchemy/orm/properties.py +++ b/lib/sqlalchemy/orm/properties.py @@ -315,7 +315,7 @@ class PropertyLoader(mapper.MapperProperty): def register_dependencies(self, uowcommit): self._dependency_processor.register_dependencies(uowcommit) - + def _compile_synchronizers(self): """assembles a list of 'synchronization rules', which are instructions on how to populate the objects on each side of a relationship. This is done when a PropertyLoader is diff --git a/lib/sqlalchemy/orm/unitofwork.py b/lib/sqlalchemy/orm/unitofwork.py index dcaf750dea..e243b3b313 100644 --- a/lib/sqlalchemy/orm/unitofwork.py +++ b/lib/sqlalchemy/orm/unitofwork.py @@ -313,8 +313,6 @@ class UOWTransaction(object): this method returns or creates the single per-transaction instance of UOWTask that exists for that mapper.""" try: - if isinstance(mapper, UOWTask): - raise "wha" return self.tasks[mapper] except KeyError: if dontcreate: @@ -364,6 +362,11 @@ class UOWTransaction(object): # print "TASK OBJ:", obj # for elem in task.get_elements(polymorphic=True): # print "POLYMORPHIC TASK OBJ:", elem.obj + + # insure that we have a UOWTask for every mapper that will be involved + # in the topological sort + [self.get_task_by_mapper(m) for m in self._get_noninheriting_mappers()] + #print "-----------------------------" # pre-execute dependency processors. this process may # result in new tasks, objects and/or dependency processors being added, diff --git a/test/orm/inheritance.py b/test/orm/inheritance.py index 0957638676..842a63a266 100644 --- a/test/orm/inheritance.py +++ b/test/orm/inheritance.py @@ -412,6 +412,63 @@ class InheritTest6(testbase.AssertMixin): q = sess.query(Bar) self.assert_(len(q.selectfirst().lazy) == 1) self.assert_(len(q.selectfirst().eager) == 1) - + + +class InheritTest7(testbase.AssertMixin): + """test dependency sorting among inheriting mappers""" + def setUpAll(self): + global users, roles, user_roles, admins, metadata + metadata=BoundMetaData(testbase.db) + users = Table('user', metadata, + Column('id', Integer, primary_key=True), + Column('email', String(128)), + Column('password', String(16)), + ) + + roles = Table('role', metadata, + Column('id', Integer, primary_key=True), + Column('description', String(32)) + ) + + user_roles = Table('user_role', metadata, + Column('user_id', Integer, ForeignKey('user.id'), primary_key=True), + Column('role_id', Integer, ForeignKey('role.id'), primary_key=True) + ) + + admins = Table('admin', metadata, + Column('id', Integer, primary_key=True), + Column('user_id', Integer, ForeignKey('user.id')) + ) + metadata.create_all() + def tearDownAll(self): + metadata.drop_all() + + def testbasic(self): + class User(object):pass + class Role(object):pass + class Admin(User):pass + role_mapper = mapper(Role, roles) + user_mapper = mapper(User, users, properties = { + 'roles' : relation(Role, secondary=user_roles, lazy=False, private=False) + } + ) + admin_mapper = mapper(Admin, admins, inherits=user_mapper) + sess = create_session() + adminrole = Role('admin') + sess.save(adminrole) + sess.flush() + + # create an Admin, and append a Role. the dependency processors + # corresponding to the "roles" attribute for the Admin mapper and the User mapper + # have to insure that two dependency processors dont fire off and insert the + # many to many row twice. + a = Admin() + a.roles.append(adminrole) + a.password = 'admin' + sess.save(a) + sess.flush() + + assert user_roles.count().scalar() == 1 + if __name__ == "__main__": testbase.main()