summaryrefslogtreecommitdiff
path: root/lib/sqlalchemy/sql/coercions.py
diff options
context:
space:
mode:
Diffstat (limited to 'lib/sqlalchemy/sql/coercions.py')
-rw-r--r--lib/sqlalchemy/sql/coercions.py82
1 files changed, 77 insertions, 5 deletions
diff --git a/lib/sqlalchemy/sql/coercions.py b/lib/sqlalchemy/sql/coercions.py
index c7b85c415..2fc63b82f 100644
--- a/lib/sqlalchemy/sql/coercions.py
+++ b/lib/sqlalchemy/sql/coercions.py
@@ -57,7 +57,7 @@ def expect(role, element, **kw):
if not isinstance(
element,
- (elements.ClauseElement, schema.SchemaItem, schema.FetchedValue),
+ (elements.ClauseElement, schema.SchemaItem, schema.FetchedValue,),
):
resolved = impl._resolve_for_clause_element(element, **kw)
else:
@@ -106,7 +106,9 @@ class RoleImpl(object):
self.name = role_class._role_name
self._use_inspection = issubclass(role_class, roles.UsesInspection)
- def _resolve_for_clause_element(self, element, argname=None, **kw):
+ def _resolve_for_clause_element(
+ self, element, argname=None, apply_plugins=None, **kw
+ ):
original_element = element
is_clause_element = False
@@ -115,18 +117,39 @@ class RoleImpl(object):
if not getattr(element, "is_clause_element", False):
element = element.__clause_element__()
else:
- return element
+ break
+
+ should_apply_plugins = (
+ apply_plugins is not None
+ and apply_plugins._compile_state_plugin is None
+ )
if is_clause_element:
+ if (
+ should_apply_plugins
+ and "compile_state_plugin" in element._annotations
+ ):
+ apply_plugins._compile_state_plugin = element._annotations[
+ "compile_state_plugin"
+ ]
return element
if self._use_inspection:
insp = inspection.inspect(element, raiseerr=False)
if insp is not None:
+ insp._post_inspect
try:
- return insp.__clause_element__()
+ element = insp.__clause_element__()
except AttributeError:
self._raise_for_expected(original_element, argname)
+ else:
+ if (
+ should_apply_plugins
+ and "compile_state_plugin" in element._annotations
+ ):
+ plugin = element._annotations["compile_state_plugin"]
+ apply_plugins._compile_state_plugin = plugin
+ return element
return self._literal_coercion(element, argname=argname, **kw)
@@ -287,7 +310,7 @@ class _SelectIsNotFrom(object):
advice = (
"To create a "
"FROM clause from a %s object, use the .subquery() method."
- % (element.__class__)
+ % (element.__class__,)
)
code = "89ve"
else:
@@ -453,6 +476,18 @@ class OrderByImpl(ByOfImpl, RoleImpl):
return resolved
+class GroupByImpl(ByOfImpl, RoleImpl):
+ __slots__ = ()
+
+ def _implicit_coercions(
+ self, original_element, resolved, argname=None, **kw
+ ):
+ if isinstance(resolved, roles.StrictFromClauseRole):
+ return elements.ClauseList(*resolved.c)
+ else:
+ return resolved
+
+
class DMLColumnImpl(_ReturnsStringKey, RoleImpl):
__slots__ = ()
@@ -618,6 +653,37 @@ class HasCTEImpl(ReturnsRowsImpl, roles.HasCTERole):
pass
+class JoinTargetImpl(RoleImpl):
+ __slots__ = ()
+
+ def _literal_coercion(self, element, legacy=False, **kw):
+ if isinstance(element, str):
+ return element
+
+ def _implicit_coercions(
+ self, original_element, resolved, argname=None, legacy=False, **kw
+ ):
+ if isinstance(original_element, roles.JoinTargetRole):
+ return original_element
+ elif legacy and isinstance(resolved, (str, roles.WhereHavingRole)):
+ return resolved
+ elif legacy and resolved._is_select_statement:
+ util.warn_deprecated(
+ "Implicit coercion of SELECT and textual SELECT "
+ "constructs into FROM clauses is deprecated; please call "
+ ".subquery() on any Core select or ORM Query object in "
+ "order to produce a subquery object.",
+ version="1.4",
+ )
+ # TODO: doing _implicit_subquery here causes tests to fail,
+ # how was this working before? probably that ORM
+ # join logic treated it as a select and subquery would happen
+ # in _ORMJoin->Join
+ return resolved
+ else:
+ self._raise_for_expected(original_element, argname, resolved)
+
+
class FromClauseImpl(_SelectIsNotFrom, _NoTextCoercion, RoleImpl):
__slots__ = ()
@@ -647,6 +713,12 @@ class FromClauseImpl(_SelectIsNotFrom, _NoTextCoercion, RoleImpl):
else:
self._raise_for_expected(original_element, argname, resolved)
+ def _post_coercion(self, element, deannotate=False, **kw):
+ if deannotate:
+ return element._deannotate()
+ else:
+ return element
+
class StrictFromClauseImpl(FromClauseImpl):
__slots__ = ()