diff options
| author | Mike Bayer <mike_mp@zzzcomputing.com> | 2006-06-22 22:23:57 +0000 |
|---|---|---|
| committer | Mike Bayer <mike_mp@zzzcomputing.com> | 2006-06-22 22:23:57 +0000 |
| commit | ad7ffd767d26aef8caba3e52b8c3c1114ec6709c (patch) | |
| tree | 8039bb3553aa64a6710cf37a442338f9e9412605 | |
| parent | 0e0cedaf9dc085f61949fbe93f389f5a1f5b9cf8 (diff) | |
| download | sqlalchemy-ad7ffd767d26aef8caba3e52b8c3c1114ec6709c.tar.gz | |
fixes to inheritance firing off dependency processors correctly + unittest
| -rw-r--r-- | CHANGES | 2 | ||||
| -rw-r--r-- | lib/sqlalchemy/orm/dependency.py | 11 | ||||
| -rw-r--r-- | lib/sqlalchemy/orm/properties.py | 2 | ||||
| -rw-r--r-- | lib/sqlalchemy/orm/unitofwork.py | 7 | ||||
| -rw-r--r-- | test/orm/inheritance.py | 59 |
5 files changed, 72 insertions, 9 deletions
@@ -15,6 +15,8 @@ the previous Session. - utterly remarkable: added a single space between 'CREATE TABLE' and '(<the rest of it>' 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 067e842c3..6eca75ae1 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 846c7d125..6be563393 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 dcaf750de..e243b3b31 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 095763867..842a63a26 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() |
