[3.1.x] Refs #12990 -- Added DatabaseFeatures.has_json_operators.

CockroachDB also has them.
Backport of f59a2b7306 from master
This commit is contained in:
Tim Graham 2020-05-18 02:12:20 -04:00 committed by Mariusz Felisiak
parent 16716551bd
commit 5480fab290
3 changed files with 8 additions and 3 deletions

View File

@ -309,6 +309,8 @@ class BaseDatabaseFeatures:
supports_primitives_in_json_field = True
# Is there a true datatype for JSON?
has_native_json_field = False
# Does the backend use PostgreSQL-style JSON operators like '->'?
has_json_operators = False
def __init__(self, connection):
self.connection = connection

View File

@ -58,6 +58,7 @@ class DatabaseFeatures(BaseDatabaseFeatures):
supported_explain_formats = {'JSON', 'TEXT', 'XML', 'YAML'}
validates_explain_options = False # A query will error on invalid options.
supports_deferrable_unique_constraints = True
has_json_operators = True
@cached_property
def is_postgresql_9_6(self):

View File

@ -17,7 +17,9 @@ from django.db.models.fields.json import (
KeyTransformTextLookupMixin,
)
from django.db.models.functions import Cast
from django.test import SimpleTestCase, TestCase, skipUnlessDBFeature
from django.test import (
SimpleTestCase, TestCase, skipIfDBFeature, skipUnlessDBFeature,
)
from django.test.utils import CaptureQueriesContext
from .models import CustomJSONDecoder, JSONModel, NullableJSONModel
@ -607,7 +609,7 @@ class TestQuerying(TestCase):
def test_key_iregex(self):
self.assertIs(NullableJSONModel.objects.filter(value__foo__iregex=r'^bAr$').exists(), True)
@skipUnless(connection.vendor == 'postgresql', 'kwargs are crafted for PostgreSQL.')
@skipUnlessDBFeature('has_json_operators')
def test_key_sql_injection(self):
with CaptureQueriesContext(connection) as queries:
self.assertIs(
@ -621,7 +623,7 @@ class TestQuerying(TestCase):
queries[0]['sql'],
)
@skipIf(connection.vendor == 'postgresql', 'PostgreSQL uses operators not functions.')
@skipIfDBFeature('has_json_operators')
def test_key_sql_injection_escape(self):
query = str(JSONModel.objects.filter(**{
"""value__test") = '"a"' OR 1 = 1 OR ("d""": 'x',