summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Bayer <mike_mp@zzzcomputing.com>2007-11-18 05:16:52 +0000
committerMike Bayer <mike_mp@zzzcomputing.com>2007-11-18 05:16:52 +0000
commit79aa1a6b258a84443540b8bb68c8d64deb936ef9 (patch)
treedd145ce1240d8d43cca46b8e4047ef397b599e27
parent43d476ce60339f3369847191988b96b3f3665f44 (diff)
downloadsqlalchemy-79aa1a6b258a84443540b8bb68c8d64deb936ef9.tar.gz
fixed both group-deferred attributes and expired attributes to not
blow away changes made on attributes before the load takes place
-rw-r--r--lib/sqlalchemy/orm/attributes.py3
-rw-r--r--lib/sqlalchemy/orm/strategies.py14
-rw-r--r--test/orm/expire.py14
-rw-r--r--test/orm/mapper.py22
4 files changed, 45 insertions, 8 deletions
diff --git a/lib/sqlalchemy/orm/attributes.py b/lib/sqlalchemy/orm/attributes.py
index 7c760f15a..6cf2b74e9 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 dfd1efa36..eb88c0497 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 430117725..7f0e9002b 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 5ed479594..6fbca004b 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"""