From 12028fb9e7826e13cd41b9992ca04a05598a22f2 Mon Sep 17 00:00:00 2001 From: Mike Bayer Date: Sat, 10 Sep 2005 18:50:33 +0000 Subject: [PATCH] basic many to many... --- lib/sqlalchemy/mapper.py | 63 ++++++++++++++++++++++++++--------- lib/sqlalchemy/objectstore.py | 13 +++----- test/mapper.py | 30 +++++++++++++---- 3 files changed, 76 insertions(+), 30 deletions(-) diff --git a/lib/sqlalchemy/mapper.py b/lib/sqlalchemy/mapper.py index a12c01304e..9a7cf0044e 100644 --- a/lib/sqlalchemy/mapper.py +++ b/lib/sqlalchemy/mapper.py @@ -501,7 +501,8 @@ class PropertyLoader(MapperProperty): def register_dependencies(self, objlist, uow): if self.secondaryjoin is not None: - pass + uow.register_dependency(self.parent, self.mapper, None, None) + uow.register_dependency(self.mapper, None, self, objlist) elif self.foreignkey.table == self.target: uow.register_dependency(self.parent, self.mapper, self, objlist) elif self.foreignkey.table == self.parent.table: @@ -509,33 +510,63 @@ class PropertyLoader(MapperProperty): else: raise " no foreign key ?" - def process_dependencies(self, deplist): + def process_dependencies(self, deplist, uow): - for obj in deplist: + def getlist(obj): if self.uselist: - childlist = objectstore.uow().register_list_attribute(obj, self.key) + return uow.register_list_attribute(obj, self.key) else: - childlist = objectstore.uow().register_attribute(obj, self.key) + return uow.register_attribute(obj, self.key) - if self.secondaryjoin is not None: - pass - elif self.foreignkey.table == self.target: - setter = ForeignKeySetter(self.parent, self.mapper, self.parent.table, self.target, self.secondary, obj) + setter = ForeignKeySetter(self.parent, self.mapper, self.parent.table, self.target, self.secondary) + + if self.secondaryjoin is not None: + print "secondaries !" + secondary_delete = [] + secondary_insert = [] + for obj in deplist: + childlist = getlist(obj) for child in childlist.added_items(): setter.obj = obj setter.child = child setter.associationrow = {} self.primaryjoin.accept_visitor(setter) - - elif self.foreignkey.table == self.parent.table: - setter = ForeignKeySetter(self.parent, self.mapper, self.parent.table, self.target, self.secondary, None) + self.secondaryjoin.accept_visitor(setter) + secondary_insert.append(setter.associationrow) + for child in childlist.deleted_items(): + setter.obj = obj + setter.child = child + setter.associationrow = {} + setter.clearkeys = True + self.primaryjoin.accept_visitor(setter) + self.secondaryjoin.accept_visitor(setter) + secondary_delete.append(setter.associationrow) + if len(secondary_delete): + statement = self.secondary.delete(sql.and_(*[c == sql.bindparam(c.key) for c in self.secondary.c])) + statement.echo = self.mapper.echo + statement.execute(*secondary_delete) + if len(secondary_insert): + statement = self.secondary.insert() + statement.echo = self.mapper.echo + statement.execute(*secondary_insert) + elif self.foreignkey.table == self.target: + for obj in deplist: + childlist = getlist(obj) + for child in childlist.added_items(): + setter.obj = obj + setter.child = child + setter.associationrow = {} + self.primaryjoin.accept_visitor(setter) + elif self.foreignkey.table == self.parent.table: + for obj in deplist: + childlist = getlist(obj) for child in childlist.added_items(): setter.obj = child setter.child = obj setter.associationrow = {} self.primaryjoin.accept_visitor(setter) - else: - raise " no foreign key ?" + else: + raise " no foreign key ?" def save(self, obj, traverse): # saves child objects @@ -748,13 +779,13 @@ class ForeignKeySetter(sql.ClauseVisitor): """traverses a join condition of a parent/child object or two objects attached by an association table and sets properties on either the child object or an association table row according to the join properties.""" - def __init__(self, parentmapper, childmapper, primarytable, secondarytable, associationtable, obj): + def __init__(self, parentmapper, childmapper, primarytable, secondarytable, associationtable): self.parentmapper = parentmapper self.childmapper = childmapper self.primarytable = primarytable self.secondarytable = secondarytable self.associationtable = associationtable - self.obj = obj + self.obj = None self.associationrow = {} self.clearkeys = False self.child = None diff --git a/lib/sqlalchemy/objectstore.py b/lib/sqlalchemy/objectstore.py index 31b3f9a221..2a9617e743 100644 --- a/lib/sqlalchemy/objectstore.py +++ b/lib/sqlalchemy/objectstore.py @@ -181,10 +181,6 @@ class UnitOfWork(object): def is_dirty(self, obj): if not self.dirty.contains(obj): - # if we know nothing about this object, register it as dirty (or new ?) - if not self.clean.contains(obj): - self.register_new(obj) - return True return False else: return True @@ -229,16 +225,17 @@ class UnitOfWork(object): for obj in obj_list: mapper.save_obj(obj) for dep in deplist: - (processor, list) = dep - processor.process_dependencies(list) + (processor, stuff_to_process) = dep + processor.process_dependencies(stuff_to_process, self) self.new.clear() self.dirty.clear() - def register_dependency(self, obj, dependency, processor, list): + def register_dependency(self, obj, dependency, processor, stuff_to_process): self.dependencies[(obj, dependency)] = True deplist = self.dependencies.setdefault(obj, []) - deplist.append((processor, list)) + if processor is not None: + deplist.append((processor, stuff_to_process)) uow = util.ScopedRegistry(lambda: UnitOfWork(), "thread") \ No newline at end of file diff --git a/test/mapper.py b/test/mapper.py index fa6814f75b..f6819135a0 100644 --- a/test/mapper.py +++ b/test/mapper.py @@ -382,14 +382,29 @@ class SaveTest(AssertMixin): m = mapper(Address, addresses, properties = dict( user = relation(User, users, foreignkey = addresses.c.user_id, primaryjoin = users.c.user_id == addresses.c.user_id, lazy = True, uselist = False) )) - a = Address() - a.email_address = 'themaster@foo.com' - a.user = User() - a.user.user_name = 'thesub' + data = [ + {'user_name' : 'thesub' , 'email_address' : 'bar@foo.com'}, + {'user_name' : 'assdkfj' , 'email_address' : 'thesdf@asdf.com'}, + {'user_name' : 'n4knd' , 'email_address' : 'asf3@bar.org'}, + {'user_name' : 'v88f4' , 'email_address' : 'adsd5@llala.net'}, + {'user_name' : 'asdf8d' , 'email_address' : 'theater@foo.com'} + ] + objects = [] + for elem in data: + a = Address() + a.email_address = elem['email_address'] + a.user = User() + a.user.user_name = elem['user_name'] + objects.append(a) + + objectstore.uow().commit() + objects[2].email_address = 'imnew@foo.bar' + objects[3].user = User() + objects[3].user.user_name = 'imnewlyadded' + objectstore.uow().commit() return - m.save(a) l = sql.select([users, addresses], sql.and_(users.c.user_id==addresses.c.address_id, addresses.c.address_id==a.address_id)).execute() r = engine.ResultProxy(l) @@ -485,7 +500,10 @@ class SaveTest(AssertMixin): klist = keywordmapper.select(keywords.c.name.in_('blue', 'big', 'round')) for k in klist: item.keywords.append(k) - m.save(item) + + objectstore.uow().commit() + return + l = m.select(items.c.item_id == item.item_id) self.assert_result(l, Item, -- 2.47.2