summaryrefslogtreecommitdiff
path: root/lib/sqlalchemy/orm/strategies.py
diff options
context:
space:
mode:
Diffstat (limited to 'lib/sqlalchemy/orm/strategies.py')
-rw-r--r--lib/sqlalchemy/orm/strategies.py89
1 files changed, 55 insertions, 34 deletions
diff --git a/lib/sqlalchemy/orm/strategies.py b/lib/sqlalchemy/orm/strategies.py
index 0ba22e7a7..5dc80e4f2 100644
--- a/lib/sqlalchemy/orm/strategies.py
+++ b/lib/sqlalchemy/orm/strategies.py
@@ -14,6 +14,10 @@ from __future__ import annotations
import collections
import itertools
+from typing import Any
+from typing import Dict
+from typing import Tuple
+from typing import TYPE_CHECKING
from . import attributes
from . import exc as orm_exc
@@ -28,7 +32,9 @@ from . import util as orm_util
from .base import _DEFER_FOR_STATE
from .base import _RAISE_FOR_STATE
from .base import _SET_DEFERRED_EXPIRED
+from .base import LoaderCallableStatus
from .base import PASSIVE_OFF
+from .base import PassiveFlag
from .context import _column_descriptions
from .context import ORMCompileState
from .context import ORMSelectCompileState
@@ -50,6 +56,10 @@ from ..sql import visitors
from ..sql.selectable import LABEL_STYLE_TABLENAME_PLUS_COL
from ..sql.selectable import Select
+if TYPE_CHECKING:
+ from .relationships import Relationship
+ from ..sql.elements import ColumnElement
+
def _register_attribute(
prop,
@@ -486,10 +496,10 @@ class DeferredColumnLoader(LoaderStrategy):
def _load_for_state(self, state, passive):
if not state.key:
- return attributes.ATTR_EMPTY
+ return LoaderCallableStatus.ATTR_EMPTY
- if not passive & attributes.SQL_OK:
- return attributes.PASSIVE_NO_RESULT
+ if not passive & PassiveFlag.SQL_OK:
+ return LoaderCallableStatus.PASSIVE_NO_RESULT
localparent = state.manager.mapper
@@ -522,7 +532,7 @@ class DeferredColumnLoader(LoaderStrategy):
state.mapper, state, set(group), PASSIVE_OFF
)
- return attributes.ATTR_WAS_SET
+ return LoaderCallableStatus.ATTR_WAS_SET
def _invoke_raise_load(self, state, passive, lazy):
raise sa_exc.InvalidRequestError(
@@ -626,7 +636,9 @@ class NoLoader(AbstractRelationshipLoader):
@relationships.Relationship.strategy_for(lazy="raise")
@relationships.Relationship.strategy_for(lazy="raise_on_sql")
@relationships.Relationship.strategy_for(lazy="baked_select")
-class LazyLoader(AbstractRelationshipLoader, util.MemoizedSlots):
+class LazyLoader(
+ AbstractRelationshipLoader, util.MemoizedSlots, log.Identified
+):
"""Provide loading behavior for a :class:`.Relationship`
with "lazy=True", that is loads when first accessed.
@@ -648,7 +660,16 @@ class LazyLoader(AbstractRelationshipLoader, util.MemoizedSlots):
"_raise_on_sql",
)
- def __init__(self, parent, strategy_key):
+ _lazywhere: ColumnElement[bool]
+ _bind_to_col: Dict[str, ColumnElement[Any]]
+ _rev_lazywhere: ColumnElement[bool]
+ _rev_bind_to_col: Dict[str, ColumnElement[Any]]
+
+ parent_property: Relationship[Any]
+
+ def __init__(
+ self, parent: Relationship[Any], strategy_key: Tuple[Any, ...]
+ ):
super(LazyLoader, self).__init__(parent, strategy_key)
self._raise_always = self.strategy_opts["lazy"] == "raise"
self._raise_on_sql = self.strategy_opts["lazy"] == "raise_on_sql"
@@ -786,13 +807,13 @@ class LazyLoader(AbstractRelationshipLoader, util.MemoizedSlots):
o = state.obj() # strong ref
dict_ = attributes.instance_dict(o)
- if passive & attributes.INIT_OK:
- passive ^= attributes.INIT_OK
+ if passive & PassiveFlag.INIT_OK:
+ passive ^= PassiveFlag.INIT_OK
params = {}
for key, ident, value in param_keys:
if ident is not None:
- if passive and passive & attributes.LOAD_AGAINST_COMMITTED:
+ if passive and passive & PassiveFlag.LOAD_AGAINST_COMMITTED:
value = mapper._get_committed_state_attr_by_column(
state, dict_, ident, passive
)
@@ -818,23 +839,23 @@ class LazyLoader(AbstractRelationshipLoader, util.MemoizedSlots):
)
or not state.session_id
):
- return attributes.ATTR_EMPTY
+ return LoaderCallableStatus.ATTR_EMPTY
pending = not state.key
primary_key_identity = None
use_get = self.use_get and (not loadopt or not loadopt._extra_criteria)
- if (not passive & attributes.SQL_OK and not use_get) or (
+ if (not passive & PassiveFlag.SQL_OK and not use_get) or (
not passive & attributes.NON_PERSISTENT_OK and pending
):
- return attributes.PASSIVE_NO_RESULT
+ return LoaderCallableStatus.PASSIVE_NO_RESULT
if (
# we were given lazy="raise"
self._raise_always
# the no_raise history-related flag was not passed
- and not passive & attributes.NO_RAISE
+ and not passive & PassiveFlag.NO_RAISE
and (
# if we are use_get and related_object_ok is disabled,
# which means we are at most looking in the identity map
@@ -842,7 +863,7 @@ class LazyLoader(AbstractRelationshipLoader, util.MemoizedSlots):
# PASSIVE_NO_RESULT, don't raise. This is also a
# history-related flag
not use_get
- or passive & attributes.RELATED_OBJECT_OK
+ or passive & PassiveFlag.RELATED_OBJECT_OK
)
):
@@ -850,8 +871,8 @@ class LazyLoader(AbstractRelationshipLoader, util.MemoizedSlots):
session = _state_session(state)
if not session:
- if passive & attributes.NO_RAISE:
- return attributes.PASSIVE_NO_RESULT
+ if passive & PassiveFlag.NO_RAISE:
+ return LoaderCallableStatus.PASSIVE_NO_RESULT
raise orm_exc.DetachedInstanceError(
"Parent instance %s is not bound to a Session; "
@@ -865,19 +886,19 @@ class LazyLoader(AbstractRelationshipLoader, util.MemoizedSlots):
primary_key_identity = self._get_ident_for_use_get(
session, state, passive
)
- if attributes.PASSIVE_NO_RESULT in primary_key_identity:
- return attributes.PASSIVE_NO_RESULT
- elif attributes.NEVER_SET in primary_key_identity:
- return attributes.NEVER_SET
+ if LoaderCallableStatus.PASSIVE_NO_RESULT in primary_key_identity:
+ return LoaderCallableStatus.PASSIVE_NO_RESULT
+ elif LoaderCallableStatus.NEVER_SET in primary_key_identity:
+ return LoaderCallableStatus.NEVER_SET
if _none_set.issuperset(primary_key_identity):
return None
if (
self.key in state.dict
- and not passive & attributes.DEFERRED_HISTORY_LOAD
+ and not passive & PassiveFlag.DEFERRED_HISTORY_LOAD
):
- return attributes.ATTR_WAS_SET
+ return LoaderCallableStatus.ATTR_WAS_SET
# look for this identity in the identity map. Delegate to the
# Query class in use, as it may have special rules for how it
@@ -892,15 +913,15 @@ class LazyLoader(AbstractRelationshipLoader, util.MemoizedSlots):
)
if instance is not None:
- if instance is attributes.PASSIVE_CLASS_MISMATCH:
+ if instance is LoaderCallableStatus.PASSIVE_CLASS_MISMATCH:
return None
else:
return instance
elif (
- not passive & attributes.SQL_OK
- or not passive & attributes.RELATED_OBJECT_OK
+ not passive & PassiveFlag.SQL_OK
+ or not passive & PassiveFlag.RELATED_OBJECT_OK
):
- return attributes.PASSIVE_NO_RESULT
+ return LoaderCallableStatus.PASSIVE_NO_RESULT
return self._emit_lazyload(
session,
@@ -914,7 +935,7 @@ class LazyLoader(AbstractRelationshipLoader, util.MemoizedSlots):
def _get_ident_for_use_get(self, session, state, passive):
instance_mapper = state.manager.mapper
- if passive & attributes.LOAD_AGAINST_COMMITTED:
+ if passive & PassiveFlag.LOAD_AGAINST_COMMITTED:
get_attr = instance_mapper._get_committed_state_attr_by_column
else:
get_attr = instance_mapper._get_state_attr_by_column
@@ -985,7 +1006,7 @@ class LazyLoader(AbstractRelationshipLoader, util.MemoizedSlots):
stmt._compile_options += {"_current_path": effective_path}
if use_get:
- if self._raise_on_sql and not passive & attributes.NO_RAISE:
+ if self._raise_on_sql and not passive & PassiveFlag.NO_RAISE:
self._invoke_raise_load(state, passive, "raise_on_sql")
return loading.load_on_pk_identity(
@@ -1022,9 +1043,9 @@ class LazyLoader(AbstractRelationshipLoader, util.MemoizedSlots):
if (
self.key in state.dict
- and not passive & attributes.DEFERRED_HISTORY_LOAD
+ and not passive & PassiveFlag.DEFERRED_HISTORY_LOAD
):
- return attributes.ATTR_WAS_SET
+ return LoaderCallableStatus.ATTR_WAS_SET
if pending:
if util.has_intersection(orm_util._none_set, params.values()):
@@ -1033,7 +1054,7 @@ class LazyLoader(AbstractRelationshipLoader, util.MemoizedSlots):
elif util.has_intersection(orm_util._never_set, params.values()):
return None
- if self._raise_on_sql and not passive & attributes.NO_RAISE:
+ if self._raise_on_sql and not passive & PassiveFlag.NO_RAISE:
self._invoke_raise_load(state, passive, "raise_on_sql")
stmt._where_criteria = (lazy_clause,)
@@ -1246,9 +1267,9 @@ class ImmediateLoader(PostLoader):
# "use get" load. the "_RELATED" part means it may return
# instance even if its expired, since this is a mutually-recursive
# load operation.
- flags = attributes.PASSIVE_NO_FETCH_RELATED | attributes.NO_RAISE
+ flags = attributes.PASSIVE_NO_FETCH_RELATED | PassiveFlag.NO_RAISE
else:
- flags = attributes.PASSIVE_OFF | attributes.NO_RAISE
+ flags = attributes.PASSIVE_OFF | PassiveFlag.NO_RAISE
populators["delayed"].append((self.key, load_immediate))
@@ -2840,7 +2861,7 @@ class SelectInLoader(PostLoader, util.MemoizedSlots):
# if the loaded parent objects do not have the foreign key
# to the related item loaded, then degrade into the joined
# version of selectinload
- if attributes.PASSIVE_NO_RESULT in related_ident:
+ if LoaderCallableStatus.PASSIVE_NO_RESULT in related_ident:
query_info = self._fallback_query_info
break