From: Mike Bayer Date: Sun, 18 Nov 2007 05:16:52 +0000 (+0000) Subject: fixed both group-deferred attributes and expired attributes to not X-Git-Tag: rel_0_4_1~15 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=79aa1a6b258a84443540b8bb68c8d64deb936ef9;p=thirdparty%2Fsqlalchemy%2Fsqlalchemy.git fixed both group-deferred attributes and expired attributes to not blow away changes made on attributes before the load takes place --- diff --git a/lib/sqlalchemy/orm/attributes.py b/lib/sqlalchemy/orm/attributes.py index 7c760f15a8..6cf2b74e97 100644 --- a/lib/sqlalchemy/orm/attributes.py +++ b/lib/sqlalchemy/orm/attributes.py @@ -618,7 +618,8 @@ class InstanceState(object): self.callables[key] = callable_ def __fire_trigger(self): - self.trigger(self.obj(), self.expired_attributes) + instance = self.obj() + self.trigger(instance, [k for k in self.expired_attributes if k not in self.dict]) for k in self.expired_attributes: self.callables.pop(k, None) self.expired_attributes.clear() diff --git a/lib/sqlalchemy/orm/strategies.py b/lib/sqlalchemy/orm/strategies.py index dfd1efa36e..eb88c04975 100644 --- a/lib/sqlalchemy/orm/strategies.py +++ b/lib/sqlalchemy/orm/strategies.py @@ -100,7 +100,7 @@ class ColumnLoader(LoaderStrategy): strategy = self.parent_property._get_strategy(DeferredColumnLoader) # full list of ColumnProperty objects to be loaded in the deferred fetch - props = [p for p in mapper.iterate_properties if isinstance(p.strategy, ColumnLoader) and p.columns[0].table in needs_tables] + props = [p.key for p in mapper.iterate_properties if isinstance(p.strategy, ColumnLoader) and p.columns[0].table in needs_tables] # TODO: we are somewhat duplicating efforts from mapper._get_poly_select_loader # and should look for ways to simplify. @@ -188,10 +188,12 @@ class DeferredColumnLoader(LoaderStrategy): if props is not None: group = props elif self.group is not None: - group = [p for p in localparent.iterate_properties if isinstance(p.strategy, DeferredColumnLoader) and p.group==self.group] + group = [p.key for p in localparent.iterate_properties if isinstance(p.strategy, DeferredColumnLoader) and p.group==self.group] else: - group = [self.parent_property] - + group = [self.parent_property.key] + + group = [k for k in group if k not in instance.__dict__] + if self._should_log_debug: self.logger.debug("deferred load %s group %s" % (mapperutil.attribute_str(instance, self.key), group and ','.join([p.key for p in group]) or 'None')) @@ -201,10 +203,10 @@ class DeferredColumnLoader(LoaderStrategy): if create_statement is None: ident = instance._instance_key[1] - session.query(localparent)._get(None, ident=ident, only_load_props=[p.key for p in group], refresh_instance=instance) + session.query(localparent)._get(None, ident=ident, only_load_props=group, refresh_instance=instance) else: statement, params = create_statement(instance) - session.query(localparent).from_statement(statement).params(params)._get(None, only_load_props=[p.key for p in group], refresh_instance=instance) + session.query(localparent).from_statement(statement).params(params)._get(None, only_load_props=group, refresh_instance=instance) return attributes.ATTR_WAS_SET return lazyload diff --git a/test/orm/expire.py b/test/orm/expire.py index 430117725c..7f0e9002bb 100644 --- a/test/orm/expire.py +++ b/test/orm/expire.py @@ -62,6 +62,20 @@ class ExpireTest(FixtureTest): sess.flush() sess.clear() assert sess.query(User).get(7).name == 'somenewname' + + def test_expire_preserves_changes(self): + """test that the expire load operation doesn't revert post-expire changes""" + + mapper(Order, orders) + sess = create_session() + o = sess.query(Order).get(3) + sess.expire(o) + + o.description = "order 3 modified" + def go(): + assert o.isopen == 1 + self.assert_sql_count(testbase.db, go, 1) + assert o.description == 'order 3 modified' def test_expire_committed(self): """test that the committed state of the attribute receives the most recent DB data""" diff --git a/test/orm/mapper.py b/test/orm/mapper.py index 5ed4795941..6fbca004b9 100644 --- a/test/orm/mapper.py +++ b/test/orm/mapper.py @@ -729,7 +729,27 @@ class DeferredTest(MapperSuperTest): def go(): sess.flush() self.assert_sql_count(testbase.db, go, 0) - + + def test_preserve_changes(self): + """test that the deferred load operation doesn't revert modifications on attributes""" + + mapper(Order, orders, properties = { + 'userident':deferred(orders.c.user_id, group='primary'), + 'description':deferred(orders.c.description, group='primary'), + 'opened':deferred(orders.c.isopen, group='primary') + }) + sess = create_session() + o = sess.query(Order).get(3) + assert 'userident' not in o.__dict__ + o.description = 'somenewdescription' + assert o.description == 'somenewdescription' + def go(): + assert o.opened == 1 + self.assert_sql_count(testbase.db, go, 1) + assert o.description == 'somenewdescription' + assert o in sess.dirty + + def test_commitsstate(self): """test that when deferred elements are loaded via a group, they get the proper CommittedState and dont result in changes being committed"""