diff options
author | mike bayer <mike_mp@zzzcomputing.com> | 2021-02-03 21:26:19 +0000 |
---|---|---|
committer | Gerrit Code Review <gerrit@bbpush.zzzcomputing.com> | 2021-02-03 21:26:19 +0000 |
commit | 496efe51262be77d73ed514c4de16cdc2da2d435 (patch) | |
tree | 6555470ba68316d7977748474e709665b190fb8e /lib/sqlalchemy/sql/elements.py | |
parent | 08fd52156459b26f54b22f9014e2ed197730cc37 (diff) | |
parent | afcab5edf6a3a6e9e83d1940d0be079e92c53e79 (diff) | |
download | sqlalchemy-496efe51262be77d73ed514c4de16cdc2da2d435.tar.gz |
Merge "Implement support for functions as FROM with columns clause support"
Diffstat (limited to 'lib/sqlalchemy/sql/elements.py')
-rw-r--r-- | lib/sqlalchemy/sql/elements.py | 175 |
1 files changed, 123 insertions, 52 deletions
diff --git a/lib/sqlalchemy/sql/elements.py b/lib/sqlalchemy/sql/elements.py index 3d6643503..c6eae739d 100644 --- a/lib/sqlalchemy/sql/elements.py +++ b/lib/sqlalchemy/sql/elements.py @@ -3856,6 +3856,8 @@ class Over(ColumnElement): .. seealso:: + :ref:`tutorial_window_functions` - in the :ref:`unified_tutorial` + :data:`.expression.func` :func:`_expression.within_group` @@ -4007,6 +4009,9 @@ class WithinGroup(ColumnElement): .. seealso:: + :ref:`tutorial_functions_within_group` - in the + :ref:`unified_tutorial` + :data:`.expression.func` :func:`_expression.over` @@ -4104,8 +4109,10 @@ class FunctionFilter(ColumnElement): .. seealso:: - :meth:`.FunctionElement.filter` + :ref:`tutorial_functions_within_group` - in the + :ref:`unified_tutorial` + :meth:`.FunctionElement.filter` """ self.func = func @@ -4317,11 +4324,82 @@ class Label(roles.LabeledColumnExprRole, ColumnElement): return self.key, e +class NamedColumn(ColumnElement): + is_literal = False + table = None + + def _compare_name_for_result(self, other): + return (hasattr(other, "name") and self.name == other.name) or ( + hasattr(other, "_label") and self._label == other._label + ) + + @util.memoized_property + def description(self): + if util.py3k: + return self.name + else: + return self.name.encode("ascii", "backslashreplace") + + @HasMemoized.memoized_attribute + def _key_label(self): + if self.key != self.name: + return self._gen_label(self.key) + else: + return self._label + + @HasMemoized.memoized_attribute + def _label(self): + return self._gen_label(self.name) + + @HasMemoized.memoized_attribute + def _render_label_in_columns_clause(self): + return True + + def _gen_label(self, name, dedupe_on_key=True): + return name + + def _bind_param(self, operator, obj, type_=None, expanding=False): + return BindParameter( + self.key, + obj, + _compared_to_operator=operator, + _compared_to_type=self.type, + type_=type_, + unique=True, + expanding=expanding, + ) + + def _make_proxy( + self, + selectable, + name=None, + name_is_truncatable=False, + disallow_is_literal=False, + **kw + ): + c = ColumnClause( + coercions.expect(roles.TruncatedLabelRole, name or self.name) + if name_is_truncatable + else (name or self.name), + type_=self.type, + _selectable=selectable, + is_literal=False, + ) + c._propagate_attrs = selectable._propagate_attrs + if name is None: + c.key = self.key + c._proxies = [self] + if selectable._is_clone_of is not None: + c._is_clone_of = selectable._is_clone_of.columns.get(c.key) + return c.key, c + + class ColumnClause( roles.DDLReferredColumnRole, roles.LabeledColumnExprRole, + roles.StrAsPlainColumnRole, Immutable, - ColumnElement, + NamedColumn, ): """Represents a column expression from any textual string. @@ -4360,6 +4438,9 @@ class ColumnClause( """ + table = None + is_literal = False + __visit_name__ = "column" _traverse_internals = [ @@ -4470,27 +4551,6 @@ class ColumnClause( self.type = type_api.to_instance(type_) self.is_literal = is_literal - def _compare_name_for_result(self, other): - if ( - self.is_literal - or self.table is None - or self.table._is_textual - or not hasattr(other, "proxy_set") - or ( - isinstance(other, ColumnClause) - and ( - other.is_literal - or other.table is None - or other.table._is_textual - ) - ) - ): - return (hasattr(other, "name") and self.name == other.name) or ( - hasattr(other, "_label") and self._label == other._label - ) - else: - return other.proxy_set.intersection(self.proxy_set) - def get_children(self, column_tables=False, **kw): # override base get_children() to not return the Table # or selectable that is parent to this column. Traversals @@ -4505,24 +4565,6 @@ class ColumnClause( else: return [] - @util.memoized_property - def description(self): - if util.py3k: - return self.name - else: - return self.name.encode("ascii", "backslashreplace") - - @HasMemoized.memoized_attribute - def _key_label(self): - if self.key != self.name: - return self._gen_label(self.key) - else: - return self._label - - @HasMemoized.memoized_attribute - def _label(self): - return self._gen_label(self.name) - @HasMemoized.memoized_attribute def _render_label_in_columns_clause(self): return self.table is not None @@ -4531,6 +4573,27 @@ class ColumnClause( def _ddl_label(self): return self._gen_label(self.name, dedupe_on_key=False) + def _compare_name_for_result(self, other): + if ( + self.is_literal + or self.table is None + or self.table._is_textual + or not hasattr(other, "proxy_set") + or ( + isinstance(other, ColumnClause) + and ( + other.is_literal + or other.table is None + or other.table._is_textual + ) + ) + ): + return (hasattr(other, "name") and self.name == other.name) or ( + hasattr(other, "_label") and self._label == other._label + ) + else: + return other.proxy_set.intersection(self.proxy_set) + def _gen_label(self, name, dedupe_on_key=True): t = self.table if self.is_literal: @@ -4575,17 +4638,6 @@ class ColumnClause( else: return name - def _bind_param(self, operator, obj, type_=None, expanding=False): - return BindParameter( - self.key, - obj, - _compared_to_operator=operator, - _compared_to_type=self.type, - type_=type_, - unique=True, - expanding=expanding, - ) - def _make_proxy( self, selectable, @@ -4627,6 +4679,25 @@ class ColumnClause( return c.key, c +class TableValuedColumn(NamedColumn): + __visit_name__ = "table_valued_column" + + _traverse_internals = [ + ("name", InternalTraversal.dp_anon_name), + ("type", InternalTraversal.dp_type), + ("scalar_alias", InternalTraversal.dp_clauseelement), + ] + + def __init__(self, scalar_alias, type_): + self.scalar_alias = scalar_alias + self.key = self.name = scalar_alias.name + self.type = type_ + + @property + def _from_objects(self): + return [self.scalar_alias] + + class CollationClause(ColumnElement): __visit_name__ = "collation" |