1
0
mirror of https://github.com/django/django.git synced 2024-12-22 17:16:24 +00:00

Used AND, OR, XOR constants instead of hard-coded values.

This commit is contained in:
Nick Pope 2022-07-23 13:31:35 +01:00 committed by Mariusz Felisiak
parent e20e5d1557
commit 769d7cce4a
6 changed files with 20 additions and 18 deletions

View File

@ -19,6 +19,7 @@ from django.db.models.sql.constants import (
SINGLE, SINGLE,
) )
from django.db.models.sql.query import Query, get_order_dir from django.db.models.sql.query import Query, get_order_dir
from django.db.models.sql.where import AND
from django.db.transaction import TransactionManagementError from django.db.transaction import TransactionManagementError
from django.utils.functional import cached_property from django.utils.functional import cached_property
from django.utils.hashable import make_hashable from django.utils.hashable import make_hashable
@ -1435,7 +1436,7 @@ class SQLCompiler:
for index, select_col in enumerate(self.query.select): for index, select_col in enumerate(self.query.select):
lhs_sql, lhs_params = self.compile(select_col) lhs_sql, lhs_params = self.compile(select_col)
rhs = "%s.%s" % (qn(alias), qn2(columns[index])) rhs = "%s.%s" % (qn(alias), qn2(columns[index]))
self.query.where.add(RawSQL("%s = %s" % (lhs_sql, rhs), lhs_params), "AND") self.query.where.add(RawSQL("%s = %s" % (lhs_sql, rhs), lhs_params), AND)
sql, params = self.as_sql() sql, params = self.as_sql()
return "EXISTS (%s)" % sql, params return "EXISTS (%s)" % sql, params

View File

@ -2658,7 +2658,7 @@ class JoinPromoter:
# to rel_a would remove a valid match from the query. So, we need # to rel_a would remove a valid match from the query. So, we need
# to promote any existing INNER to LOUTER (it is possible this # to promote any existing INNER to LOUTER (it is possible this
# promotion in turn will be demoted later on). # promotion in turn will be demoted later on).
if self.effective_connector == "OR" and votes < self.num_children: if self.effective_connector == OR and votes < self.num_children:
to_promote.add(table) to_promote.add(table)
# If connector is AND and there is a filter that can match only # If connector is AND and there is a filter that can match only
# when there is a joinable row, then use INNER. For example, in # when there is a joinable row, then use INNER. For example, in
@ -2670,8 +2670,8 @@ class JoinPromoter:
# (rel_a__col__icontains=Alex | rel_a__col__icontains=Russell) # (rel_a__col__icontains=Alex | rel_a__col__icontains=Russell)
# then if rel_a doesn't produce any rows, the whole condition # then if rel_a doesn't produce any rows, the whole condition
# can't match. Hence we can safely use INNER join. # can't match. Hence we can safely use INNER join.
if self.effective_connector == "AND" or ( if self.effective_connector == AND or (
self.effective_connector == "OR" and votes == self.num_children self.effective_connector == OR and votes == self.num_children
): ):
to_demote.add(table) to_demote.add(table)
# Finally, what happens in cases where we have: # Finally, what happens in cases where we have:

View File

@ -114,7 +114,7 @@ class QTests(SimpleTestCase):
("price", F("discounted_price")), ("price", F("discounted_price")),
), ),
) )
self.assertEqual(kwargs, {"_connector": "OR"}) self.assertEqual(kwargs, {"_connector": Q.OR})
def test_deconstruct_xor(self): def test_deconstruct_xor(self):
q1 = Q(price__gt=F("discounted_price")) q1 = Q(price__gt=F("discounted_price"))
@ -128,7 +128,7 @@ class QTests(SimpleTestCase):
("price", F("discounted_price")), ("price", F("discounted_price")),
), ),
) )
self.assertEqual(kwargs, {"_connector": "XOR"}) self.assertEqual(kwargs, {"_connector": Q.XOR})
def test_deconstruct_and(self): def test_deconstruct_and(self):
q1 = Q(price__gt=F("discounted_price")) q1 = Q(price__gt=F("discounted_price"))

View File

@ -16,7 +16,7 @@ from django.db.models.functions import Lower
from django.db.models.lookups import Exact, GreaterThan, IsNull, LessThan from django.db.models.lookups import Exact, GreaterThan, IsNull, LessThan
from django.db.models.sql.constants import SINGLE from django.db.models.sql.constants import SINGLE
from django.db.models.sql.query import JoinPromoter, Query, get_field_names_from_opts from django.db.models.sql.query import JoinPromoter, Query, get_field_names_from_opts
from django.db.models.sql.where import OR from django.db.models.sql.where import AND, OR
from django.test import SimpleTestCase, TestCase, skipUnlessDBFeature from django.test import SimpleTestCase, TestCase, skipUnlessDBFeature
from django.test.utils import register_lookup from django.test.utils import register_lookup
@ -214,6 +214,6 @@ class TestQueryNoModel(TestCase):
class JoinPromoterTest(SimpleTestCase): class JoinPromoterTest(SimpleTestCase):
def test_repr(self): def test_repr(self):
self.assertEqual( self.assertEqual(
repr(JoinPromoter("AND", 3, True)), repr(JoinPromoter(AND, 3, True)),
"JoinPromoter(connector='AND', num_children=3, negated=True)", "JoinPromoter(connector='AND', num_children=3, negated=True)",
) )

View File

@ -10,7 +10,7 @@ from django.db import DEFAULT_DB_ALIAS, connection
from django.db.models import Count, Exists, F, Max, OuterRef, Q from django.db.models import Count, Exists, F, Max, OuterRef, Q
from django.db.models.expressions import RawSQL from django.db.models.expressions import RawSQL
from django.db.models.sql.constants import LOUTER from django.db.models.sql.constants import LOUTER
from django.db.models.sql.where import NothingNode, WhereNode from django.db.models.sql.where import AND, OR, NothingNode, WhereNode
from django.test import SimpleTestCase, TestCase, skipUnlessDBFeature from django.test import SimpleTestCase, TestCase, skipUnlessDBFeature
from django.test.utils import CaptureQueriesContext, ignore_warnings from django.test.utils import CaptureQueriesContext, ignore_warnings
from django.utils.deprecation import RemovedInDjango50Warning from django.utils.deprecation import RemovedInDjango50Warning
@ -3559,16 +3559,16 @@ class WhereNodeTest(SimpleTestCase):
def test_empty_full_handling_disjunction(self): def test_empty_full_handling_disjunction(self):
compiler = WhereNodeTest.MockCompiler() compiler = WhereNodeTest.MockCompiler()
w = WhereNode(children=[NothingNode()], connector="OR") w = WhereNode(children=[NothingNode()], connector=OR)
with self.assertRaises(EmptyResultSet): with self.assertRaises(EmptyResultSet):
w.as_sql(compiler, connection) w.as_sql(compiler, connection)
w.negate() w.negate()
self.assertEqual(w.as_sql(compiler, connection), ("", [])) self.assertEqual(w.as_sql(compiler, connection), ("", []))
w = WhereNode(children=[self.DummyNode(), self.DummyNode()], connector="OR") w = WhereNode(children=[self.DummyNode(), self.DummyNode()], connector=OR)
self.assertEqual(w.as_sql(compiler, connection), ("(dummy OR dummy)", [])) self.assertEqual(w.as_sql(compiler, connection), ("(dummy OR dummy)", []))
w.negate() w.negate()
self.assertEqual(w.as_sql(compiler, connection), ("NOT (dummy OR dummy)", [])) self.assertEqual(w.as_sql(compiler, connection), ("NOT (dummy OR dummy)", []))
w = WhereNode(children=[NothingNode(), self.DummyNode()], connector="OR") w = WhereNode(children=[NothingNode(), self.DummyNode()], connector=OR)
self.assertEqual(w.as_sql(compiler, connection), ("dummy", [])) self.assertEqual(w.as_sql(compiler, connection), ("dummy", []))
w.negate() w.negate()
self.assertEqual(w.as_sql(compiler, connection), ("NOT (dummy)", [])) self.assertEqual(w.as_sql(compiler, connection), ("NOT (dummy)", []))
@ -3581,14 +3581,14 @@ class WhereNodeTest(SimpleTestCase):
w.negate() w.negate()
with self.assertRaises(EmptyResultSet): with self.assertRaises(EmptyResultSet):
w.as_sql(compiler, connection) w.as_sql(compiler, connection)
w.connector = "OR" w.connector = OR
with self.assertRaises(EmptyResultSet): with self.assertRaises(EmptyResultSet):
w.as_sql(compiler, connection) w.as_sql(compiler, connection)
w.negate() w.negate()
self.assertEqual(w.as_sql(compiler, connection), ("", [])) self.assertEqual(w.as_sql(compiler, connection), ("", []))
w = WhereNode(children=[empty_w, NothingNode()], connector="OR") w = WhereNode(children=[empty_w, NothingNode()], connector=OR)
self.assertEqual(w.as_sql(compiler, connection), ("", [])) self.assertEqual(w.as_sql(compiler, connection), ("", []))
w = WhereNode(children=[empty_w, NothingNode()], connector="AND") w = WhereNode(children=[empty_w, NothingNode()], connector=AND)
with self.assertRaises(EmptyResultSet): with self.assertRaises(EmptyResultSet):
w.as_sql(compiler, connection) w.as_sql(compiler, connection)

View File

@ -1,6 +1,7 @@
import copy import copy
import unittest import unittest
from django.db.models.sql import AND, OR
from django.utils.tree import Node from django.utils.tree import Node
@ -56,9 +57,9 @@ class NodeTests(unittest.TestCase):
self.assertEqual(str(node3), "(DEFAULT: ('a', 1), ('b', 2), ('c', 3))") self.assertEqual(str(node3), "(DEFAULT: ('a', 1), ('b', 2), ('c', 3))")
def test_add_eq_child_mixed_connector(self): def test_add_eq_child_mixed_connector(self):
node = Node(["a", "b"], "OR") node = Node(["a", "b"], OR)
self.assertEqual(node.add("a", "AND"), "a") self.assertEqual(node.add("a", AND), "a")
self.assertEqual(node, Node([Node(["a", "b"], "OR"), "a"], "AND")) self.assertEqual(node, Node([Node(["a", "b"], OR), "a"], AND))
def test_negate(self): def test_negate(self):
# negated is False by default # negated is False by default