diff options
Diffstat (limited to 'lib/sqlalchemy/sql/elements.py')
-rw-r--r-- | lib/sqlalchemy/sql/elements.py | 41 |
1 files changed, 40 insertions, 1 deletions
diff --git a/lib/sqlalchemy/sql/elements.py b/lib/sqlalchemy/sql/elements.py index 00c2c37ba..52f46f295 100644 --- a/lib/sqlalchemy/sql/elements.py +++ b/lib/sqlalchemy/sql/elements.py @@ -3071,7 +3071,8 @@ class Over(ColumnElement): order_by = None partition_by = None - def __init__(self, element, partition_by=None, order_by=None): + def __init__( + self, element, partition_by=None, order_by=None, range=None, rows=None): """Produce an :class:`.Over` object against a function. Used against aggregate or so-called "window" functions, @@ -3115,6 +3116,44 @@ class Over(ColumnElement): *util.to_list(partition_by), _literal_as_text=_literal_as_label_reference) + if range is not None and rows is not None: + raise ValueError( + 'Must provide either RANGE specification or ' + 'ROWS specification, not both' + ) + + if range is None and rows is None: + range = {} + + self.frame_kind = 'ROWS' if rows is not None else 'RANGE' + frame = rows if rows is not None else range + + assert frame is not None + + if frozenset(frame) - frozenset(('preceding', 'following')): + raise ValueError( + 'Found additional keys in frame specification dict' + ) + self.preceding = Over._format_frame_clause( + frame, 'preceding', 'UNBOUNDED PRECEDING' + ) + self.following = Over._format_frame_clause( + frame, 'following', 'CURRENT ROW' + ) + + @staticmethod + def _format_frame_clause(frame, key, default): + value = frame.get(key, default) + + if value == default: + return default + elif value is None: + return 'UNBOUNDED %s' % key.upper() + elif value == 0: + return 'CURRENT ROW' + else: + return '%d %s' % (value, key.upper()) + @property def func(self): """the element referred to by this :class:`.Over` |