Coerce an expression to a new field type.
| 5 | |
| 6 | |
| 7 | class Cast(Func): |
| 8 | """Coerce an expression to a new field type.""" |
| 9 | |
| 10 | function = "CAST" |
| 11 | template = "%(function)s(%(expressions)s AS %(db_type)s)" |
| 12 | |
| 13 | def __init__(self, expression, output_field): |
| 14 | super().__init__(expression, output_field=output_field) |
| 15 | |
| 16 | def as_sql(self, compiler, connection, **extra_context): |
| 17 | extra_context["db_type"] = self.output_field.cast_db_type(connection) |
| 18 | return super().as_sql(compiler, connection, **extra_context) |
| 19 | |
| 20 | def as_sqlite(self, compiler, connection, **extra_context): |
| 21 | db_type = self.output_field.db_type(connection) |
| 22 | if db_type in {"datetime", "time"}: |
| 23 | # Use strftime as datetime/time don't keep fractional seconds. |
| 24 | template = "strftime(%%s, %(expressions)s)" |
| 25 | sql, params = super().as_sql( |
| 26 | compiler, connection, template=template, **extra_context |
| 27 | ) |
| 28 | format_string = "%H:%M:%f" if db_type == "time" else "%Y-%m-%d %H:%M:%f" |
| 29 | params = (format_string, *params) |
| 30 | return sql, params |
| 31 | elif db_type == "date": |
| 32 | template = "date(%(expressions)s)" |
| 33 | return super().as_sql( |
| 34 | compiler, connection, template=template, **extra_context |
| 35 | ) |
| 36 | return self.as_sql(compiler, connection, **extra_context) |
| 37 | |
| 38 | def as_mysql(self, compiler, connection, **extra_context): |
| 39 | template = None |
| 40 | output_type = self.output_field.get_internal_type() |
| 41 | # MySQL doesn't support explicit cast to float. |
| 42 | if output_type == "FloatField": |
| 43 | template = "(%(expressions)s + 0.0)" |
| 44 | # MariaDB doesn't support explicit cast to JSON. |
| 45 | elif output_type == "JSONField" and connection.mysql_is_mariadb: |
| 46 | template = "JSON_EXTRACT(%(expressions)s, '$')" |
| 47 | return self.as_sql(compiler, connection, template=template, **extra_context) |
| 48 | |
| 49 | def as_postgresql(self, compiler, connection, **extra_context): |
| 50 | # CAST would be valid too, but the :: shortcut syntax is more readable. |
| 51 | # 'expressions' is wrapped in parentheses in case it's a complex |
| 52 | # expression. |
| 53 | return self.as_sql( |
| 54 | compiler, |
| 55 | connection, |
| 56 | template="(%(expressions)s)::%(db_type)s", |
| 57 | **extra_context, |
| 58 | ) |
| 59 | |
| 60 | def as_oracle(self, compiler, connection, **extra_context): |
| 61 | if self.output_field.get_internal_type() == "JSONField": |
| 62 | # Oracle doesn't support explicit cast to JSON. |
| 63 | template = "JSON_QUERY(%(expressions)s, '$')" |
| 64 | return super().as_sql( |
no outgoing calls