summaryrefslogtreecommitdiff
path: root/lib/sqlalchemy/sql/coercions.py
diff options
context:
space:
mode:
authorMike Bayer <mike_mp@zzzcomputing.com>2020-08-05 16:42:26 -0400
committerMike Bayer <mike_mp@zzzcomputing.com>2020-08-05 16:42:26 -0400
commitcc57ea495f6460dd56daa6de57e40047ed999369 (patch)
tree837f5a84363c387d7f8fdeabc06928cd078028e1 /lib/sqlalchemy/sql/coercions.py
parent2a946254023135eddd222974cf300ffaa5583f02 (diff)
downloadsqlalchemy-cc57ea495f6460dd56daa6de57e40047ed999369.tar.gz
Robustness for lambdas, lambda statements
in order to accommodate relationship loaders with lambda caching, a lot more is needed. This is a full refactor of the lambda system such that it now has two levels of caching; the first level caches what can be known from the __code__ element, then the next level of caching is against the lambda itself and the contents of __closure__. This allows for the elements inside the lambdas, like columns and entities, to change and then be part of the cache key. Lazy/selectinloads' use of baked queries had to add distinct cache key elements, which was attempted here but overall things needed to be more robust than that. This commit is broken out from the very long and sprawling commit at Id6b5c03b1ce9ddb7b280f66792212a0ef0a1c541 . Change-Id: I29a513c98917b1d503abfdd61e6b6e8800851aa8
Diffstat (limited to 'lib/sqlalchemy/sql/coercions.py')
-rw-r--r--lib/sqlalchemy/sql/coercions.py41
1 files changed, 38 insertions, 3 deletions
diff --git a/lib/sqlalchemy/sql/coercions.py b/lib/sqlalchemy/sql/coercions.py
index 588c485ae..fa0f9c435 100644
--- a/lib/sqlalchemy/sql/coercions.py
+++ b/lib/sqlalchemy/sql/coercions.py
@@ -7,10 +7,13 @@
import numbers
import re
+import types
from . import operators
from . import roles
from . import visitors
+from .base import Options
+from .traversals import HasCacheKey
from .visitors import Visitable
from .. import exc
from .. import inspection
@@ -33,11 +36,36 @@ def _is_literal(element):
of a SQL expression construct.
"""
+
return not isinstance(
- element, (Visitable, schema.SchemaEventTarget)
+ element, (Visitable, schema.SchemaEventTarget),
) and not hasattr(element, "__clause_element__")
+def _deep_is_literal(element):
+ """Return whether or not the element is a "literal" in the context
+ of a SQL expression construct.
+
+ does a deeper more esoteric check than _is_literal. is used
+ for lambda elements that have to distinguish values that would
+ be bound vs. not without any context.
+
+ """
+
+ return (
+ not isinstance(
+ element,
+ (Visitable, schema.SchemaEventTarget, HasCacheKey, Options,),
+ )
+ and not hasattr(element, "__clause_element__")
+ and (
+ not isinstance(element, type)
+ or not issubclass(element, HasCacheKey)
+ )
+ and not isinstance(element, types.FunctionType)
+ )
+
+
def _document_text_coercion(paramname, meth_rst, param_rst):
return util.add_parameter_text(
paramname,
@@ -711,9 +739,16 @@ class StatementImpl(_NoTextCoercion, RoleImpl):
class CoerceTextStatementImpl(_CoerceLiterals, RoleImpl):
__slots__ = ()
- def _literal_coercion(self, element, **kw):
+ def _dont_literal_coercion(self, element, **kw):
if callable(element) and hasattr(element, "__code__"):
- return lambdas.StatementLambdaElement(element, self._role_class)
+ return lambdas.StatementLambdaElement(
+ element,
+ self._role_class,
+ additional_cache_criteria=kw.get(
+ "additional_cache_criteria", ()
+ ),
+ tracked=kw["tra"],
+ )
else:
return super(CoerceTextStatementImpl, self)._literal_coercion(
element, **kw