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
« prev ^ index » next coverage.py v6.4.4, created at 2023-07-17 14:22 -0600
1import math
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
13class Abs(Transform):
14 function = "ABS"
15 lookup_name = "abs"
18class ACos(NumericOutputFieldMixin, Transform):
19 function = "ACOS"
20 lookup_name = "acos"
23class ASin(NumericOutputFieldMixin, Transform):
24 function = "ASIN"
25 lookup_name = "asin"
28class ATan(NumericOutputFieldMixin, Transform):
29 function = "ATAN"
30 lookup_name = "atan"
33class ATan2(NumericOutputFieldMixin, Func):
34 function = "ATAN2"
35 arity = 2
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)
59class Ceil(Transform):
60 function = "CEILING"
61 lookup_name = "ceil"
63 def as_oracle(self, compiler, connection, **extra_context):
64 return super().as_sql(compiler, connection, function="CEIL", **extra_context)
67class Cos(NumericOutputFieldMixin, Transform):
68 function = "COS"
69 lookup_name = "cos"
72class Cot(NumericOutputFieldMixin, Transform):
73 function = "COT"
74 lookup_name = "cot"
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 )
82class Degrees(NumericOutputFieldMixin, Transform):
83 function = "DEGREES"
84 lookup_name = "degrees"
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 )
95class Exp(NumericOutputFieldMixin, Transform):
96 function = "EXP"
97 lookup_name = "exp"
100class Floor(Transform):
101 function = "FLOOR"
102 lookup_name = "floor"
105class Ln(NumericOutputFieldMixin, Transform):
106 function = "LN"
107 lookup_name = "ln"
110class Log(FixDecimalInputMixin, NumericOutputFieldMixin, Func):
111 function = "LOG"
112 arity = 2
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)
124class Mod(FixDecimalInputMixin, NumericOutputFieldMixin, Func):
125 function = "MOD"
126 arity = 2
129class Pi(NumericOutputFieldMixin, Func):
130 function = "PI"
131 arity = 0
133 def as_oracle(self, compiler, connection, **extra_context):
134 return super().as_sql(
135 compiler, connection, template=str(math.pi), **extra_context
136 )
139class Power(NumericOutputFieldMixin, Func):
140 function = "POWER"
141 arity = 2
144class Radians(NumericOutputFieldMixin, Transform):
145 function = "RADIANS"
146 lookup_name = "radians"
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 )
157class Random(NumericOutputFieldMixin, Func):
158 function = "RANDOM"
159 arity = 0
161 def as_mysql(self, compiler, connection, **extra_context):
162 return super().as_sql(compiler, connection, function="RAND", **extra_context)
164 def as_oracle(self, compiler, connection, **extra_context):
165 return super().as_sql(
166 compiler, connection, function="DBMS_RANDOM.VALUE", **extra_context
167 )
169 def as_sqlite(self, compiler, connection, **extra_context):
170 return super().as_sql(compiler, connection, function="RAND", **extra_context)
172 def get_group_by_cols(self, alias=None):
173 return []
176class Round(FixDecimalInputMixin, Transform):
177 function = "ROUND"
178 lookup_name = "round"
179 arity = None # Override Transform's arity=1 to enable passing precision.
181 def __init__(self, expression, precision=0, **extra):
182 super().__init__(expression, precision, **extra)
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)
190 def _resolve_output_field(self):
191 source = self.get_source_expressions()[0]
192 return source.output_field
195class Sign(Transform):
196 function = "SIGN"
197 lookup_name = "sign"
200class Sin(NumericOutputFieldMixin, Transform):
201 function = "SIN"
202 lookup_name = "sin"
205class Sqrt(NumericOutputFieldMixin, Transform):
206 function = "SQRT"
207 lookup_name = "sqrt"
210class Tan(NumericOutputFieldMixin, Transform):
211 function = "TAN"
212 lookup_name = "tan"