From: Mike Bayer Date: Sat, 9 Jan 2016 15:10:20 +0000 (-0500) Subject: - Fixed regression since 0.9 where the 0.9 style loader options X-Git-Tag: rel_1_1_0b1~84^2~52 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=c7ae0daf0ed24e2697d6f948db2d9fdc5953c795;p=thirdparty%2Fsqlalchemy%2Fsqlalchemy.git - 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 --- diff --git a/doc/build/changelog/changelog_10.rst b/doc/build/changelog/changelog_10.rst index debcf1eadd..4d017cfb15 100644 --- a/doc/build/changelog/changelog_10.rst +++ b/doc/build/changelog/changelog_10.rst @@ -19,6 +19,16 @@ :version: 1.0.12 :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 b60e47bb39..0252a65f98 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 3467328e3a..f083679416 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 29087fdb86..7f449c40ac 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