summaryrefslogtreecommitdiff
path: root/django/db/models/functions/window.py
diff options
context:
space:
mode:
Diffstat (limited to 'django/db/models/functions/window.py')
-rw-r--r--django/db/models/functions/window.py118
1 files changed, 118 insertions, 0 deletions
diff --git a/django/db/models/functions/window.py b/django/db/models/functions/window.py
new file mode 100644
index 0000000000..3719dfca88
--- /dev/null
+++ b/django/db/models/functions/window.py
@@ -0,0 +1,118 @@
+from django.db.models import FloatField, Func, IntegerField
+
+__all__ = [
+ 'CumeDist', 'DenseRank', 'FirstValue', 'Lag', 'LastValue', 'Lead',
+ 'NthValue', 'Ntile', 'PercentRank', 'Rank', 'RowNumber',
+]
+
+
+class CumeDist(Func):
+ function = 'CUME_DIST'
+ name = 'CumeDist'
+ output_field = FloatField()
+ window_compatible = True
+
+
+class DenseRank(Func):
+ function = 'DENSE_RANK'
+ name = 'DenseRank'
+ output_field = IntegerField()
+ window_compatible = True
+
+
+class FirstValue(Func):
+ arity = 1
+ function = 'FIRST_VALUE'
+ name = 'FirstValue'
+ window_compatible = True
+
+
+class LagLeadFunction(Func):
+ window_compatible = True
+
+ def __init__(self, expression, offset=1, default=None, **extra):
+ if expression is None:
+ raise ValueError(
+ '%s requires a non-null source expression.' %
+ self.__class__.__name__
+ )
+ if offset is None or offset <= 0:
+ raise ValueError(
+ '%s requires a positive integer for the offset.' %
+ self.__class__.__name__
+ )
+ args = (expression, offset)
+ if default is not None:
+ args += (default,)
+ super().__init__(*args, **extra)
+
+ def _resolve_output_field(self):
+ sources = self.get_source_expressions()
+ return sources[0].output_field
+
+
+class Lag(LagLeadFunction):
+ function = 'LAG'
+ name = 'Lag'
+
+
+class LastValue(Func):
+ arity = 1
+ function = 'LAST_VALUE'
+ name = 'LastValue'
+ window_compatible = True
+
+
+class Lead(LagLeadFunction):
+ function = 'LEAD'
+ name = 'Lead'
+
+
+class NthValue(Func):
+ function = 'NTH_VALUE'
+ name = 'NthValue'
+ window_compatible = True
+
+ def __init__(self, expression, nth=1, **extra):
+ if expression is None:
+ raise ValueError('%s requires a non-null source expression.' % self.__class__.__name__)
+ if nth is None or nth <= 0:
+ raise ValueError('%s requires a positive integer as for nth.' % self.__class__.__name__)
+ super().__init__(expression, nth, **extra)
+
+ def _resolve_output_field(self):
+ sources = self.get_source_expressions()
+ return sources[0].output_field
+
+
+class Ntile(Func):
+ function = 'NTILE'
+ name = 'Ntile'
+ output_field = IntegerField()
+ window_compatible = True
+
+ def __init__(self, num_buckets=1, **extra):
+ if num_buckets <= 0:
+ raise ValueError('num_buckets must be greater than 0.')
+ super().__init__(num_buckets, **extra)
+
+
+class PercentRank(Func):
+ function = 'PERCENT_RANK'
+ name = 'PercentRank'
+ output_field = FloatField()
+ window_compatible = True
+
+
+class Rank(Func):
+ function = 'RANK'
+ name = 'Rank'
+ output_field = IntegerField()
+ window_compatible = True
+
+
+class RowNumber(Func):
+ function = 'ROW_NUMBER'
+ name = 'RowNumber'
+ output_field = IntegerField()
+ window_compatible = True