Coverage for /Users/davegaeddert/Developer/dropseed/plain/plain-models/plain/models/functions/window.py: 71%

1 from plain.models.expressions import Func

2 from plain.models.fields import FloatField, IntegerField

3

4 __all__ = [

5 "CumeDist",

6 "DenseRank",

7 "FirstValue",

8 "Lag",

9 "LastValue",

10 "Lead",

11 "NthValue",

12 "Ntile",

13 "PercentRank",

14 "Rank",

15 "RowNumber",

16]

17

18

19 class CumeDist(Func):

20 function = "CUME_DIST"

21 output_field = FloatField()

22 window_compatible = True

23

24

25 class DenseRank(Func):

26 function = "DENSE_RANK"

27 output_field = IntegerField()

28 window_compatible = True

29

30

31 class FirstValue(Func):

32 arity = 1

33 function = "FIRST_VALUE"

34 window_compatible = True

35

36

37 class LagLeadFunction(Func):

38 window_compatible = True

39

40 def __init__(self, expression, offset=1, default=None, **extra):

41 if expression is None:

42 raise ValueError(

43 f"{self.__class__.__name__} requires a non-null source expression."

44 )

45 if offset is None or offset <= 0:

46 raise ValueError(

47 f"{self.__class__.__name__} requires a positive integer for the offset."

48 )

49 args = (expression, offset)

50 if default is not None:

51 args += (default,)

52 super().__init__(*args, **extra)

53

54 def _resolve_output_field(self):

55 sources = self.get_source_expressions()

56 return sources[0].output_field

57

58

59 class Lag(LagLeadFunction):

60 function = "LAG"

61

62

63 class LastValue(Func):

64 arity = 1

65 function = "LAST_VALUE"

66 window_compatible = True

67

68

69 class Lead(LagLeadFunction):

70 function = "LEAD"

71

72

73 class NthValue(Func):

74 function = "NTH_VALUE"

75 window_compatible = True

76

77 def __init__(self, expression, nth=1, **extra):

78 if expression is None:

79 raise ValueError(

80 f"{self.__class__.__name__} requires a non-null source expression."

81 )

82 if nth is None or nth <= 0:

83 raise ValueError(

84 f"{self.__class__.__name__} requires a positive integer as for nth."

85 )

86 super().__init__(expression, nth, **extra)

87

88 def _resolve_output_field(self):

89 sources = self.get_source_expressions()

90 return sources[0].output_field

91

92

93 class Ntile(Func):

94 function = "NTILE"

95 output_field = IntegerField()

96 window_compatible = True

97

98 def __init__(self, num_buckets=1, **extra):

99 if num_buckets <= 0:

100 raise ValueError("num_buckets must be greater than 0.")

101 super().__init__(num_buckets, **extra)

102

103

104 class PercentRank(Func):

105 function = "PERCENT_RANK"

106 output_field = FloatField()

107 window_compatible = True

108

109

110 class Rank(Func):

111 function = "RANK"

112 output_field = IntegerField()

113 window_compatible = True

114

115

116 class RowNumber(Func):

117 function = "ROW_NUMBER"

118 output_field = IntegerField()

119 window_compatible = True