diff options
| author | mike bayer <mike_mp@zzzcomputing.com> | 2020-03-22 16:47:04 +0000 |
|---|---|---|
| committer | Gerrit Code Review <gerrit@bbpush.zzzcomputing.com> | 2020-03-22 16:47:04 +0000 |
| commit | fd74bd8eea3f3696c43ca0336ed4e437036c43c5 (patch) | |
| tree | a3fb9cd1194ed83e0721c886e2b8ccafc47d50ee /lib/sqlalchemy | |
| parent | 7ff3e3f2e73e7f17c0a352dacf5c0ccfa2ef7be9 (diff) | |
| parent | becab22dcbe9d68b0671a9246e022c9810f7e319 (diff) | |
| download | sqlalchemy-fd74bd8eea3f3696c43ca0336ed4e437036c43c5.tar.gz | |
Merge "Test instance for matching class hierarchy on get_from_identity"
Diffstat (limited to 'lib/sqlalchemy')
| -rw-r--r-- | lib/sqlalchemy/orm/attributes.py | 1 | ||||
| -rw-r--r-- | lib/sqlalchemy/orm/base.py | 7 | ||||
| -rw-r--r-- | lib/sqlalchemy/orm/loading.py | 5 | ||||
| -rw-r--r-- | lib/sqlalchemy/orm/query.py | 2 | ||||
| -rw-r--r-- | lib/sqlalchemy/orm/session.py | 2 | ||||
| -rw-r--r-- | lib/sqlalchemy/orm/strategies.py | 5 |
6 files changed, 19 insertions, 3 deletions
diff --git a/lib/sqlalchemy/orm/attributes.py b/lib/sqlalchemy/orm/attributes.py index a959b0a40..5ca2858e9 100644 --- a/lib/sqlalchemy/orm/attributes.py +++ b/lib/sqlalchemy/orm/attributes.py @@ -34,6 +34,7 @@ from .base import NO_CHANGE # noqa from .base import NO_RAISE from .base import NO_VALUE from .base import NON_PERSISTENT_OK # noqa +from .base import PASSIVE_CLASS_MISMATCH # noqa from .base import PASSIVE_NO_FETCH from .base import PASSIVE_NO_FETCH_RELATED # noqa from .base import PASSIVE_NO_INITIALIZE diff --git a/lib/sqlalchemy/orm/base.py b/lib/sqlalchemy/orm/base.py index a31745aec..6df8acf1e 100644 --- a/lib/sqlalchemy/orm/base.py +++ b/lib/sqlalchemy/orm/base.py @@ -25,6 +25,13 @@ PASSIVE_NO_RESULT = util.symbol( """, ) +PASSIVE_CLASS_MISMATCH = util.symbol( + "PASSIVE_CLASS_MISMATCH", + """Symbol indicating that an object is locally present for a given + primary key identity but it is not of the requested class. The + return value is therefore None and no SQL should be emitted.""", +) + ATTR_WAS_SET = util.symbol( "ATTR_WAS_SET", """Symbol returned by a loader callable to indicate the diff --git a/lib/sqlalchemy/orm/loading.py b/lib/sqlalchemy/orm/loading.py index c3d4773cd..49c71e5b2 100644 --- a/lib/sqlalchemy/orm/loading.py +++ b/lib/sqlalchemy/orm/loading.py @@ -161,7 +161,7 @@ def merge_result(query, iterator, load=True): session.autoflush = autoflush -def get_from_identity(session, key, passive): +def get_from_identity(session, mapper, key, passive): """Look up the given key in the given session's identity map, check the object for expired state if found. @@ -171,6 +171,9 @@ def get_from_identity(session, key, passive): state = attributes.instance_state(instance) + if mapper.inherits and not state.mapper.isa(mapper): + return attributes.PASSIVE_CLASS_MISMATCH + # expired - ensure it still exists if state.expired: if not passive & attributes.SQL_OK: diff --git a/lib/sqlalchemy/orm/query.py b/lib/sqlalchemy/orm/query.py index fe1ea9bfc..0da7d08a4 100644 --- a/lib/sqlalchemy/orm/query.py +++ b/lib/sqlalchemy/orm/query.py @@ -1048,6 +1048,8 @@ class Query(Generative): if not issubclass(instance.__class__, mapper.class_): return None return instance + elif instance is attributes.PASSIVE_CLASS_MISMATCH: + return None return db_load_fn(self, primary_key_identity) diff --git a/lib/sqlalchemy/orm/session.py b/lib/sqlalchemy/orm/session.py index f172649ba..fefdd4ef1 100644 --- a/lib/sqlalchemy/orm/session.py +++ b/lib/sqlalchemy/orm/session.py @@ -1617,7 +1617,7 @@ class Session(_SessionClassMethods): key = mapper.identity_key_from_primary_key( primary_key_identity, identity_token=identity_token ) - return loading.get_from_identity(self, key, passive) + return loading.get_from_identity(self, mapper, key, passive) @property @util.contextmanager diff --git a/lib/sqlalchemy/orm/strategies.py b/lib/sqlalchemy/orm/strategies.py index 7d05a37f5..094637082 100644 --- a/lib/sqlalchemy/orm/strategies.py +++ b/lib/sqlalchemy/orm/strategies.py @@ -774,7 +774,10 @@ class LazyLoader(AbstractRelationshipLoader, util.MemoizedSlots): ) if instance is not None: - return instance + if instance is attributes.PASSIVE_CLASS_MISMATCH: + return None + else: + return instance elif ( not passive & attributes.SQL_OK or not passive & attributes.RELATED_OBJECT_OK |
