summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Bayer <mike_mp@zzzcomputing.com>2016-01-09 10:10:20 -0500
committerMike Bayer <mike_mp@zzzcomputing.com>2016-01-09 10:10:20 -0500
commitc7ae0daf0ed24e2697d6f948db2d9fdc5953c795 (patch)
tree424c000be8adb806ebf3198bf32837dbeeb8699c
parent89facbed8855d1443dbe37919ff0645aea640ed0 (diff)
downloadsqlalchemy-c7ae0daf0ed24e2697d6f948db2d9fdc5953c795.tar.gz
- Fixed regression since 0.9 where the 0.9 style loader options
system failed to accommodate for multiple :func:`.undefer_group` loader options in a single query. Multiple :func:`.undefer_group` options will now be taken into account even against the same entity. fixes #3623
-rw-r--r--doc/build/changelog/changelog_10.rst10
-rw-r--r--lib/sqlalchemy/orm/strategies.py2
-rw-r--r--lib/sqlalchemy/orm/strategy_options.py25
-rw-r--r--test/orm/test_deferred.py58
4 files changed, 91 insertions, 4 deletions
diff --git a/doc/build/changelog/changelog_10.rst b/doc/build/changelog/changelog_10.rst
index debcf1ead..4d017cfb1 100644
--- a/doc/build/changelog/changelog_10.rst
+++ b/doc/build/changelog/changelog_10.rst
@@ -20,6 +20,16 @@
:released:
.. change::
+ :tags: bug, orm
+ :tickets: 3623
+
+ Fixed regression since 0.9 where the 0.9 style loader options
+ system failed to accommodate for multiple :func:`.undefer_group`
+ loader options in a single query. Multiple :func:`.undefer_group`
+ options will now be taken into account even against the same
+ entity.
+
+ .. change::
:tags: bug, mssql, firebird
:tickets: 3622
diff --git a/lib/sqlalchemy/orm/strategies.py b/lib/sqlalchemy/orm/strategies.py
index b60e47bb3..0252a65f9 100644
--- a/lib/sqlalchemy/orm/strategies.py
+++ b/lib/sqlalchemy/orm/strategies.py
@@ -238,7 +238,7 @@ class DeferredColumnLoader(LoaderStrategy):
(
loadopt and
self.group and
- loadopt.local_opts.get('undefer_group', False) == self.group
+ loadopt.local_opts.get('undefer_group_%s' % self.group, False)
)
or
(
diff --git a/lib/sqlalchemy/orm/strategy_options.py b/lib/sqlalchemy/orm/strategy_options.py
index 3467328e3..f08367941 100644
--- a/lib/sqlalchemy/orm/strategy_options.py
+++ b/lib/sqlalchemy/orm/strategy_options.py
@@ -88,6 +88,7 @@ class Load(Generative, MapperOption):
cloned.local_opts = {}
return cloned
+ _merge_into_path = False
strategy = None
propagate_to_loaders = False
@@ -214,7 +215,15 @@ class Load(Generative, MapperOption):
cloned._set_path_strategy()
def _set_path_strategy(self):
- if self.path.has_entity:
+ if self._merge_into_path:
+ # special helper for undefer_group
+ existing = self.path.get(self.context, "loader")
+ if existing:
+ existing.local_opts.update(self.local_opts)
+ else:
+ self.path.set(self.context, "loader", self)
+
+ elif self.path.has_entity:
self.path.parent.set(self.context, "loader", self)
else:
self.path.set(self.context, "loader", self)
@@ -411,11 +420,20 @@ class _UnboundLoad(Load):
if effective_path.is_token:
for path in effective_path.generate_for_superclasses():
- if self._is_chain_link:
+ if self._merge_into_path:
+ # special helper for undefer_group
+ existing = path.get(context, "loader")
+ if existing:
+ existing.local_opts.update(self.local_opts)
+ else:
+ path.set(context, "loader", loader)
+ elif self._is_chain_link:
path.setdefault(context, "loader", loader)
else:
path.set(context, "loader", loader)
else:
+ # only supported for the undefer_group() wildcard opt
+ assert not self._merge_into_path
if self._is_chain_link:
effective_path.setdefault(context, "loader", loader)
else:
@@ -1025,10 +1043,11 @@ def undefer_group(loadopt, name):
:func:`.orm.undefer`
"""
+ loadopt._merge_into_path = True
return loadopt.set_column_strategy(
"*",
None,
- {"undefer_group": name}
+ {"undefer_group_%s" % name: True}
)
diff --git a/test/orm/test_deferred.py b/test/orm/test_deferred.py
index 29087fdb8..7f449c40a 100644
--- a/test/orm/test_deferred.py
+++ b/test/orm/test_deferred.py
@@ -320,6 +320,64 @@ class DeferredOptionsTest(AssertsCompiledSQL, _fixtures.FixtureTest):
"FROM orders ORDER BY orders.id",
{})])
+ def test_undefer_group_multi(self):
+ orders, Order = self.tables.orders, self.classes.Order
+
+ mapper(Order, orders, properties=util.OrderedDict([
+ ('userident', deferred(orders.c.user_id, group='primary')),
+ ('description', deferred(orders.c.description, group='primary')),
+ ('opened', deferred(orders.c.isopen, group='secondary'))
+ ]
+ ))
+
+ sess = create_session()
+ q = sess.query(Order).order_by(Order.id)
+ def go():
+ l = q.options(
+ undefer_group('primary'), undefer_group('secondary')).all()
+ o2 = l[2]
+ eq_(o2.opened, 1)
+ eq_(o2.userident, 7)
+ eq_(o2.description, 'order 3')
+
+ self.sql_eq_(go, [
+ ("SELECT orders.user_id AS orders_user_id, "
+ "orders.description AS orders_description, "
+ "orders.isopen AS orders_isopen, "
+ "orders.id AS orders_id, "
+ "orders.address_id AS orders_address_id "
+ "FROM orders ORDER BY orders.id",
+ {})])
+
+ def test_undefer_group_multi_pathed(self):
+ orders, Order = self.tables.orders, self.classes.Order
+
+ mapper(Order, orders, properties=util.OrderedDict([
+ ('userident', deferred(orders.c.user_id, group='primary')),
+ ('description', deferred(orders.c.description, group='primary')),
+ ('opened', deferred(orders.c.isopen, group='secondary'))
+ ]
+ ))
+
+ sess = create_session()
+ q = sess.query(Order).order_by(Order.id)
+ def go():
+ l = q.options(
+ Load(Order).undefer_group('primary').undefer_group('secondary')).all()
+ o2 = l[2]
+ eq_(o2.opened, 1)
+ eq_(o2.userident, 7)
+ eq_(o2.description, 'order 3')
+
+ self.sql_eq_(go, [
+ ("SELECT orders.user_id AS orders_user_id, "
+ "orders.description AS orders_description, "
+ "orders.isopen AS orders_isopen, "
+ "orders.id AS orders_id, "
+ "orders.address_id AS orders_address_id "
+ "FROM orders ORDER BY orders.id",
+ {})])
+
def test_undefer_star(self):
orders, Order = self.tables.orders, self.classes.Order