| 6 | |
| 7 | |
| 8 | class JSONArray(Func): |
| 9 | function = "JSON_ARRAY" |
| 10 | output_field = JSONField() |
| 11 | |
| 12 | def as_sql(self, compiler, connection, **extra_context): |
| 13 | if not connection.features.supports_json_field: |
| 14 | raise NotSupportedError( |
| 15 | "JSONFields are not supported on this database backend." |
| 16 | ) |
| 17 | return super().as_sql(compiler, connection, **extra_context) |
| 18 | |
| 19 | def as_native(self, compiler, connection, *, returning, **extra_context): |
| 20 | # PostgreSQL 16+ and Oracle remove SQL NULL values from the array by |
| 21 | # default. Adds the NULL ON NULL clause to keep NULL values in the |
| 22 | # array, mapping them to JSON null values, which matches the behavior |
| 23 | # of SQLite. |
| 24 | null_on_null = "NULL ON NULL" if len(self.get_source_expressions()) > 0 else "" |
| 25 | |
| 26 | return self.as_sql( |
| 27 | compiler, |
| 28 | connection, |
| 29 | template=( |
| 30 | f"%(function)s(%(expressions)s {null_on_null} RETURNING {returning})" |
| 31 | ), |
| 32 | **extra_context, |
| 33 | ) |
| 34 | |
| 35 | def as_postgresql(self, compiler, connection, **extra_context): |
| 36 | # Casting source expressions is only required using JSONB_BUILD_ARRAY |
| 37 | # or when using JSON_ARRAY on PostgreSQL 16+ with server-side bindings. |
| 38 | # This is done in all cases for consistency. |
| 39 | casted_obj = self.copy() |
| 40 | casted_obj.set_source_expressions( |
| 41 | [ |
| 42 | ( |
| 43 | # Conditional Cast to avoid unnecessary wrapping. |
| 44 | expression |
| 45 | if isinstance(expression, Cast) |
| 46 | else Cast(expression, expression.output_field) |
| 47 | ) |
| 48 | for expression in casted_obj.get_source_expressions() |
| 49 | ] |
| 50 | ) |
| 51 | |
| 52 | if connection.features.is_postgresql_16: |
| 53 | return casted_obj.as_native( |
| 54 | compiler, connection, returning="JSONB", **extra_context |
| 55 | ) |
| 56 | |
| 57 | return casted_obj.as_sql( |
| 58 | compiler, |
| 59 | connection, |
| 60 | function="JSONB_BUILD_ARRAY", |
| 61 | **extra_context, |
| 62 | ) |
| 63 | |
| 64 | def as_oracle(self, compiler, connection, **extra_context): |
| 65 | return self.as_native(compiler, connection, returning="CLOB", **extra_context) |