summaryrefslogtreecommitdiff
path: root/lib/sqlalchemy/orm
diff options
context:
space:
mode:
authormike bayer <mike_mp@zzzcomputing.com>2021-08-10 01:36:24 +0000
committerGerrit Code Review <gerrit@ci3.zzzcomputing.com>2021-08-10 01:36:24 +0000
commit70a33dd32f2609f2de6421c3b28ef4cc4496fdae (patch)
tree108f7d59d828ebdd9c15dfb6a9b8050512496b5d /lib/sqlalchemy/orm
parentcb8906bab1776bafed48ef69ded0768461f7e7b8 (diff)
parent65d4f98b69328f734abb16aa62952ab6aae576f2 (diff)
downloadsqlalchemy-70a33dd32f2609f2de6421c3b28ef4cc4496fdae.tar.gz
Merge "create concise + deterministic cache key for unboundload.options"
Diffstat (limited to 'lib/sqlalchemy/orm')
-rw-r--r--lib/sqlalchemy/orm/strategy_options.py109
1 files changed, 95 insertions, 14 deletions
diff --git a/lib/sqlalchemy/orm/strategy_options.py b/lib/sqlalchemy/orm/strategy_options.py
index 399e33b89..ea1e5ea2a 100644
--- a/lib/sqlalchemy/orm/strategy_options.py
+++ b/lib/sqlalchemy/orm/strategy_options.py
@@ -28,6 +28,7 @@ from .. import util
from ..sql import and_
from ..sql import coercions
from ..sql import roles
+from ..sql import traversals
from ..sql import visitors
from ..sql.base import _generative
from ..sql.base import Generative
@@ -615,16 +616,88 @@ class _UnboundLoad(Load):
self.local_opts = {}
self._extra_criteria = ()
- _cache_key_traversal = [
- ("path", visitors.ExtendedInternalTraversal.dp_multi_list),
- ("strategy", visitors.ExtendedInternalTraversal.dp_plain_obj),
- ("_to_bind", visitors.ExtendedInternalTraversal.dp_has_cache_key_list),
- ("_extra_criteria", visitors.InternalTraversal.dp_clauseelement_list),
- (
- "local_opts",
- visitors.ExtendedInternalTraversal.dp_string_multi_dict,
- ),
- ]
+ def _gen_cache_key(self, anon_map, bindparams, _unbound_option_seen=None):
+ """Inlined gen_cache_key
+
+ Original traversal is::
+
+
+ _cache_key_traversal = [
+ ("path", visitors.ExtendedInternalTraversal.dp_multi_list),
+ ("strategy", visitors.ExtendedInternalTraversal.dp_plain_obj),
+ (
+ "_to_bind",
+ visitors.ExtendedInternalTraversal.dp_has_cache_key_list,
+ ),
+ (
+ "_extra_criteria",
+ visitors.InternalTraversal.dp_clauseelement_list),
+ (
+ "local_opts",
+ visitors.ExtendedInternalTraversal.dp_string_multi_dict,
+ ),
+ ]
+
+ The inlining is so that the "_to_bind" list can be flattened to not
+ repeat the same UnboundLoad options over and over again.
+
+ See #6869
+
+ """
+
+ idself = id(self)
+ cls = self.__class__
+
+ if idself in anon_map:
+ return (anon_map[idself], cls)
+ else:
+ id_ = anon_map[idself]
+
+ vis = traversals._cache_key_traversal_visitor
+
+ seen = _unbound_option_seen
+ if seen is None:
+ seen = set()
+
+ return (
+ (id_, cls)
+ + vis.visit_multi_list(
+ "path", self.path, self, anon_map, bindparams
+ )
+ + ("strategy", self.strategy)
+ + (
+ (
+ "_to_bind",
+ tuple(
+ elem._gen_cache_key(
+ anon_map, bindparams, _unbound_option_seen=seen
+ )
+ for elem in self._to_bind
+ if elem not in seen and not seen.add(elem)
+ ),
+ )
+ if self._to_bind
+ else ()
+ )
+ + (
+ (
+ "_extra_criteria",
+ tuple(
+ elem._gen_cache_key(anon_map, bindparams)
+ for elem in self._extra_criteria
+ ),
+ )
+ if self._extra_criteria
+ else ()
+ )
+ + (
+ vis.visit_string_multi_dict(
+ "local_opts", self.local_opts, self, anon_map, bindparams
+ )
+ if self.local_opts
+ else ()
+ )
+ )
_is_chain_link = False
@@ -663,12 +736,20 @@ class _UnboundLoad(Load):
assert cloned.is_class_strategy == self.is_class_strategy
assert cloned.is_opts_only == self.is_opts_only
- new_to_bind = {
+ uniq = set()
+
+ cloned._to_bind = parent._to_bind
+
+ cloned._to_bind[:] = [
+ elem
+ for elem in cloned._to_bind
+ if elem not in uniq and not uniq.add(elem)
+ ] + [
elem._apply_to_parent(parent, applied, bound, to_bind)
for elem in to_bind
- }
- cloned._to_bind = parent._to_bind
- cloned._to_bind.extend(new_to_bind)
+ if elem not in uniq and not uniq.add(elem)
+ ]
+
cloned.local_opts.update(self.local_opts)
return cloned