Coverage for /var/srv/projects/api.amasfac.comuna18.com/tmp/venv/lib/python3.9/site-packages/django/db/models/functions/math.py: 80%

116 statements  

« prev     ^ index     » next       coverage.py v6.4.4, created at 2023-07-17 14:22 -0600

1import math 

2 

3from django.db.models.expressions import Func, Value 

4from django.db.models.fields import FloatField, IntegerField 

5from django.db.models.functions import Cast 

6from django.db.models.functions.mixins import ( 

7 FixDecimalInputMixin, 

8 NumericOutputFieldMixin, 

9) 

10from django.db.models.lookups import Transform 

11 

12 

13class Abs(Transform): 

14 function = "ABS" 

15 lookup_name = "abs" 

16 

17 

18class ACos(NumericOutputFieldMixin, Transform): 

19 function = "ACOS" 

20 lookup_name = "acos" 

21 

22 

23class ASin(NumericOutputFieldMixin, Transform): 

24 function = "ASIN" 

25 lookup_name = "asin" 

26 

27 

28class ATan(NumericOutputFieldMixin, Transform): 

29 function = "ATAN" 

30 lookup_name = "atan" 

31 

32 

33class ATan2(NumericOutputFieldMixin, Func): 

34 function = "ATAN2" 

35 arity = 2 

36 

37 def as_sqlite(self, compiler, connection, **extra_context): 

38 if not getattr( 

39 connection.ops, "spatialite", False 

40 ) or connection.ops.spatial_version >= (5, 0, 0): 

41 return self.as_sql(compiler, connection) 

42 # This function is usually ATan2(y, x), returning the inverse tangent 

43 # of y / x, but it's ATan2(x, y) on SpatiaLite < 5.0.0. 

44 # Cast integers to float to avoid inconsistent/buggy behavior if the 

45 # arguments are mixed between integer and float or decimal. 

46 # https://www.gaia-gis.it/fossil/libspatialite/tktview?name=0f72cca3a2 

47 clone = self.copy() 

48 clone.set_source_expressions( 

49 [ 

50 Cast(expression, FloatField()) 

51 if isinstance(expression.output_field, IntegerField) 

52 else expression 

53 for expression in self.get_source_expressions()[::-1] 

54 ] 

55 ) 

56 return clone.as_sql(compiler, connection, **extra_context) 

57 

58 

59class Ceil(Transform): 

60 function = "CEILING" 

61 lookup_name = "ceil" 

62 

63 def as_oracle(self, compiler, connection, **extra_context): 

64 return super().as_sql(compiler, connection, function="CEIL", **extra_context) 

65 

66 

67class Cos(NumericOutputFieldMixin, Transform): 

68 function = "COS" 

69 lookup_name = "cos" 

70 

71 

72class Cot(NumericOutputFieldMixin, Transform): 

73 function = "COT" 

74 lookup_name = "cot" 

75 

76 def as_oracle(self, compiler, connection, **extra_context): 

77 return super().as_sql( 

78 compiler, connection, template="(1 / TAN(%(expressions)s))", **extra_context 

79 ) 

80 

81 

82class Degrees(NumericOutputFieldMixin, Transform): 

83 function = "DEGREES" 

84 lookup_name = "degrees" 

85 

86 def as_oracle(self, compiler, connection, **extra_context): 

87 return super().as_sql( 

88 compiler, 

89 connection, 

90 template="((%%(expressions)s) * 180 / %s)" % math.pi, 

91 **extra_context, 

92 ) 

93 

94 

95class Exp(NumericOutputFieldMixin, Transform): 

96 function = "EXP" 

97 lookup_name = "exp" 

98 

99 

100class Floor(Transform): 

101 function = "FLOOR" 

102 lookup_name = "floor" 

103 

104 

105class Ln(NumericOutputFieldMixin, Transform): 

106 function = "LN" 

107 lookup_name = "ln" 

108 

109 

110class Log(FixDecimalInputMixin, NumericOutputFieldMixin, Func): 

111 function = "LOG" 

112 arity = 2 

113 

114 def as_sqlite(self, compiler, connection, **extra_context): 

115 if not getattr(connection.ops, "spatialite", False): 

116 return self.as_sql(compiler, connection) 

117 # This function is usually Log(b, x) returning the logarithm of x to 

118 # the base b, but on SpatiaLite it's Log(x, b). 

119 clone = self.copy() 

120 clone.set_source_expressions(self.get_source_expressions()[::-1]) 

121 return clone.as_sql(compiler, connection, **extra_context) 

122 

123 

124class Mod(FixDecimalInputMixin, NumericOutputFieldMixin, Func): 

125 function = "MOD" 

126 arity = 2 

127 

128 

129class Pi(NumericOutputFieldMixin, Func): 

130 function = "PI" 

131 arity = 0 

132 

133 def as_oracle(self, compiler, connection, **extra_context): 

134 return super().as_sql( 

135 compiler, connection, template=str(math.pi), **extra_context 

136 ) 

137 

138 

139class Power(NumericOutputFieldMixin, Func): 

140 function = "POWER" 

141 arity = 2 

142 

143 

144class Radians(NumericOutputFieldMixin, Transform): 

145 function = "RADIANS" 

146 lookup_name = "radians" 

147 

148 def as_oracle(self, compiler, connection, **extra_context): 

149 return super().as_sql( 

150 compiler, 

151 connection, 

152 template="((%%(expressions)s) * %s / 180)" % math.pi, 

153 **extra_context, 

154 ) 

155 

156 

157class Random(NumericOutputFieldMixin, Func): 

158 function = "RANDOM" 

159 arity = 0 

160 

161 def as_mysql(self, compiler, connection, **extra_context): 

162 return super().as_sql(compiler, connection, function="RAND", **extra_context) 

163 

164 def as_oracle(self, compiler, connection, **extra_context): 

165 return super().as_sql( 

166 compiler, connection, function="DBMS_RANDOM.VALUE", **extra_context 

167 ) 

168 

169 def as_sqlite(self, compiler, connection, **extra_context): 

170 return super().as_sql(compiler, connection, function="RAND", **extra_context) 

171 

172 def get_group_by_cols(self, alias=None): 

173 return [] 

174 

175 

176class Round(FixDecimalInputMixin, Transform): 

177 function = "ROUND" 

178 lookup_name = "round" 

179 arity = None # Override Transform's arity=1 to enable passing precision. 

180 

181 def __init__(self, expression, precision=0, **extra): 

182 super().__init__(expression, precision, **extra) 

183 

184 def as_sqlite(self, compiler, connection, **extra_context): 

185 precision = self.get_source_expressions()[1] 

186 if isinstance(precision, Value) and precision.value < 0: 

187 raise ValueError("SQLite does not support negative precision.") 

188 return super().as_sqlite(compiler, connection, **extra_context) 

189 

190 def _resolve_output_field(self): 

191 source = self.get_source_expressions()[0] 

192 return source.output_field 

193 

194 

195class Sign(Transform): 

196 function = "SIGN" 

197 lookup_name = "sign" 

198 

199 

200class Sin(NumericOutputFieldMixin, Transform): 

201 function = "SIN" 

202 lookup_name = "sin" 

203 

204 

205class Sqrt(NumericOutputFieldMixin, Transform): 

206 function = "SQRT" 

207 lookup_name = "sqrt" 

208 

209 

210class Tan(NumericOutputFieldMixin, Transform): 

211 function = "TAN" 

212 lookup_name = "tan"