[Sqlalchemy-commits] [1817] sqlalchemy/trunk/test/orm: the "check for orphans" step will cascade th
Brought to you by:
zzzeek
From: <co...@sq...> - 2006-08-22 21:52:53
|
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head><style type="text/css"><!-- #msg dl { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; } #msg dt { float: left; width: 6em; font-weight: bold; } #msg dt:after { content:':';} #msg dl, #msg dt, #msg ul, #msg li { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; } #msg dl a { font-weight: bold} #msg dl a:link { color:#fc3; } #msg dl a:active { color:#ff0; } #msg dl a:visited { color:#cc6; } h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; } #msg pre { overflow: auto; background: #ffc; border: 1px #fc0 solid; padding: 6px; } #msg ul, pre { overflow: auto; } #patch { width: 100%; } #patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;} #patch .propset h4, #patch .binary h4 {margin:0;} #patch pre {padding:0;line-height:1.2em;margin:0;} #patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;} #patch .propset .diff, #patch .binary .diff {padding:10px 0;} #patch span {display:block;padding:0 10px;} #patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;} #patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;} #patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;} #patch .lines, .info {color:#888;background:#fff;} --></style> <title>[1817] sqlalchemy/trunk/test/orm: the "check for orphans" step will cascade the delete operation to child objects.</title> </head> <body> <div id="msg"> <dl> <dt>Revision</dt> <dd>1817</dd> <dt>Author</dt> <dd>zzzeek</dd> <dt>Date</dt> <dd>2006-08-22 17:52:12 -0500 (Tue, 22 Aug 2006)</dd> </dl> <h3>Log Message</h3> <pre>the "check for orphans" step will cascade the delete operation to child objects.</pre> <h3>Modified Paths</h3> <ul> <li><a href="#sqlalchemytrunklibsqlalchemyormunitofworkpy">sqlalchemy/trunk/lib/sqlalchemy/orm/unitofwork.py</a></li> <li><a href="#sqlalchemytrunktestormsessionpy">sqlalchemy/trunk/test/orm/session.py</a></li> </ul> </div> <div id="patch"> <h3>Diff</h3> <a id="sqlalchemytrunklibsqlalchemyormunitofworkpy"></a> <div class="modfile"><h4>Modified: sqlalchemy/trunk/lib/sqlalchemy/orm/unitofwork.py (1816 => 1817)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/lib/sqlalchemy/orm/unitofwork.py 2006-08-22 18:58:01 UTC (rev 1816) +++ sqlalchemy/trunk/lib/sqlalchemy/orm/unitofwork.py 2006-08-22 22:52:12 UTC (rev 1817) </span><span class="lines">@@ -180,18 +180,24 @@ </span><span class="cx"> else: </span><span class="cx"> objset = None </span><span class="cx"> </span><ins>+ processed = util.Set() </ins><span class="cx"> for obj in [n for n in self.new] + [d for d in self.dirty]: </span><span class="cx"> if objset is not None and not obj in objset: </span><span class="cx"> continue </span><del>- if obj in self.deleted: </del><ins>+ if obj in self.deleted or obj in processed: </ins><span class="cx"> continue </span><span class="cx"> if object_mapper(obj)._is_orphan(obj): </span><del>- flush_context.register_object(obj, isdelete=True) </del><ins>+ for c in [obj] + list(object_mapper(obj).cascade_iterator('delete', obj)): + if c in processed: + continue + flush_context.register_object(c, isdelete=True) + processed.add(c) </ins><span class="cx"> else: </span><span class="cx"> flush_context.register_object(obj) </span><del>- </del><ins>+ processed.add(obj) + </ins><span class="cx"> for obj in self.deleted: </span><del>- if objset is not None and not obj in objset: </del><ins>+ if (objset is not None and not obj in objset) or obj in processed: </ins><span class="cx"> continue </span><span class="cx"> flush_context.register_object(obj, isdelete=True) </span><span class="cx"> </span></span></pre></div> <a id="sqlalchemytrunktestormsessionpy"></a> <div class="modfile"><h4>Modified: sqlalchemy/trunk/test/orm/session.py (1816 => 1817)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/test/orm/session.py 2006-08-22 18:58:01 UTC (rev 1816) +++ sqlalchemy/trunk/test/orm/session.py 2006-08-22 22:52:12 UTC (rev 1817) </span><span class="lines">@@ -9,7 +9,7 @@ </span><span class="cx"> from sqlalchemy import * </span><span class="cx"> </span><span class="cx"> </span><del>-class SessionTest(AssertMixin): </del><ins>+class OrphanDeletionTest(AssertMixin): </ins><span class="cx"> </span><span class="cx"> def setUpAll(self): </span><span class="cx"> db.echo = False </span><span class="lines">@@ -58,5 +58,66 @@ </span><span class="cx"> assert a.address_id is None, "Error: address should not be persistent" </span><span class="cx"> </span><span class="cx"> </span><ins>+class CascadingOrphanDeletionTest(AssertMixin): + def setUpAll(self): + global meta, orders, items, attributes + meta = BoundMetaData(db) + + orders = Table('orders', meta, + Column('id', Integer, Sequence('order_id_seq'), primary_key = True), + Column('name', VARCHAR(50)), + + ) + items = Table('items', meta, + Column('id', Integer, Sequence('item_id_seq'), primary_key = True), + Column('order_id', Integer, ForeignKey(orders.c.id), nullable=False), + Column('name', VARCHAR(50)), + + ) + attributes = Table('attributes', meta, + Column('id', Integer, Sequence('attribute_id_seq'), primary_key = True), + Column('item_id', Integer, ForeignKey(items.c.id), nullable=False), + Column('name', VARCHAR(50)), + + ) + + def setUp(self): + meta.create_all() + def tearDown(self): + meta.drop_all() + + def testdeletechildwithchild(self): + class Order(object): pass + class Item(object): pass + class Attribute(object): pass + + attrMapper = mapper(Attribute, attributes) + itemMapper = mapper(Item, items, properties=dict( + attributes=relation(attrMapper, cascade="all,delete-orphan", backref="item") + )) + orderMapper = mapper(Order, orders, properties=dict( + items=relation(itemMapper, cascade="all,delete-orphan", backref="order") + )) + + s = create_session(echo_uow=True) + order = Order() + s.save(order) + + item = Item() + attr = Attribute() + item.attributes.append(attr) + + order.items.append(item) + order.items.remove(item) # item is an orphan, but attr is not so flush() tries to save attr + s.flush() + + assert item.id is None + assert attr.id is None + + + + + + </ins><span class="cx"> if __name__ == "__main__": </span><span class="cx"> testbase.main() </span></span></pre> </div> </div> </body> </html> |