diff options
author | Mike Bayer <mike_mp@zzzcomputing.com> | 2018-04-20 11:44:09 -0400 |
---|---|---|
committer | Mike Bayer <mike_mp@zzzcomputing.com> | 2018-04-20 14:36:00 -0400 |
commit | 43f278356d94b5342a1020a9a97feea0bb7cd88f (patch) | |
tree | ce38c527faf41b0e31b3a5e616cb75e9574e5ef5 /lib/sqlalchemy/ext/horizontal_shard.py | |
parent | 65ba2606be7f0eef2736270a099940ab2c218c4d (diff) | |
download | sqlalchemy-43f278356d94b5342a1020a9a97feea0bb7cd88f.tar.gz |
Refactor "get" to allow for pluggable identity token schemes
Fixed regression in 1.2 within sharded query feature where the
new "identity_token" element was not being correctly considered within
the scope of a lazy load operation, when searching the identity map
for a related many-to-one element. The new behavior will allow for
making use of the "id_chooser" in order to determine the best identity
key to retrieve from the identity map. In order to achieve this, some
refactoring of 1.2's "identity_token" approach has made some slight changes
to the implementation of ``ShardedQuery`` which should be noted for other
derivations of this class.
Change-Id: I04fa60535deec2d0cdec89f602935dfebeb9eb9d
Fixes: #4228
Diffstat (limited to 'lib/sqlalchemy/ext/horizontal_shard.py')
-rw-r--r-- | lib/sqlalchemy/ext/horizontal_shard.py | 59 |
1 files changed, 47 insertions, 12 deletions
diff --git a/lib/sqlalchemy/ext/horizontal_shard.py b/lib/sqlalchemy/ext/horizontal_shard.py index 039a4656b..266bd784e 100644 --- a/lib/sqlalchemy/ext/horizontal_shard.py +++ b/lib/sqlalchemy/ext/horizontal_shard.py @@ -62,30 +62,65 @@ class ShardedQuery(Query): # were done, this is where it would happen return iter(partial) - def _get_impl(self, ident, fallback_fn): - # TODO: the "ident" here should be getting the identity token - # which indicates that this area can likely be simplified, as the - # token will fall through into _execute_and_instances - def _fallback(query, ident): + @classmethod + def _identity_lookup( + cls, session, mapper, primary_key_identity, identity_token=None, + **kw): + """override the default Query._identity_lookup method so that we + search for a given non-token primary key identity across all + possible identity tokens (e.g. shard ids). + + """ + + if identity_token is not None: + return super(ShardedQuery, cls)._identity_lookup( + session, mapper, primary_key_identity, + identity_token=identity_token, + **kw + ) + else: + q = cls([mapper], session) + for shard_id in q.id_chooser(q, primary_key_identity): + obj = super(ShardedQuery, cls)._identity_lookup( + session, mapper, primary_key_identity, + identity_token=shard_id, + **kw + ) + if obj is not None: + return obj + + return None + + def _get_impl( + self, primary_key_identity, db_load_fn, identity_token=None): + """Override the default Query._get_impl() method so that we emit + a query to the DB for each possible identity token, if we don't + have one already. + + """ + def _db_load_fn(query, primary_key_identity): + # load from the database. The original db_load_fn will + # use the given Query object to load from the DB, so our + # shard_id is what will indicate the DB that we query from. if self._shard_id is not None: - return fallback_fn(self, ident) + return db_load_fn(self, primary_key_identity) else: - ident = util.to_list(ident) + ident = util.to_list(primary_key_identity) + # build a ShardedQuery for each shard identifier and + # try to load from the DB for shard_id in self.id_chooser(self, ident): q = self.set_shard(shard_id) - o = fallback_fn(q, ident) + o = db_load_fn(q, ident) if o is not None: return o else: return None - if self._shard_id is not None: + if identity_token is None and self._shard_id is not None: identity_token = self._shard_id - else: - identity_token = None return super(ShardedQuery, self)._get_impl( - ident, _fallback, identity_token=identity_token) + primary_key_identity, _db_load_fn, identity_token=identity_token) class ShardedSession(Session): |