summaryrefslogtreecommitdiff
path: root/tests/postgres_tests
diff options
context:
space:
mode:
authorMárton Salomváry <marton@salomvary.com>2022-11-10 08:15:04 +0100
committerMariusz Felisiak <felisiak.mariusz@gmail.com>2022-11-10 11:07:24 +0100
commitd6cbf39a1ba2053c6211a16ed42d5410e5c5cdd0 (patch)
tree67afc0a74957af44d6dd3805ab25f87684141fb2 /tests/postgres_tests
parent0931d5b087a37545af0bef597deac03b5f0f7db0 (diff)
downloaddjango-d6cbf39a1ba2053c6211a16ed42d5410e5c5cdd0.tar.gz
Fixed #34149 -- Allowed adding deferrable conditional exclusion constraints on PostgreSQL.
Diffstat (limited to 'tests/postgres_tests')
-rw-r--r--tests/postgres_tests/test_constraints.py43
1 files changed, 33 insertions, 10 deletions
diff --git a/tests/postgres_tests/test_constraints.py b/tests/postgres_tests/test_constraints.py
index 844c04cd6d..5084f116ab 100644
--- a/tests/postgres_tests/test_constraints.py
+++ b/tests/postgres_tests/test_constraints.py
@@ -312,16 +312,6 @@ class ExclusionConstraintTests(PostgreSQLTestCase):
deferrable="invalid",
)
- def test_deferrable_with_condition(self):
- msg = "ExclusionConstraint with conditions cannot be deferred."
- with self.assertRaisesMessage(ValueError, msg):
- ExclusionConstraint(
- name="exclude_invalid_condition",
- expressions=[(F("datespan"), RangeOperators.OVERLAPS)],
- condition=Q(cancelled=False),
- deferrable=Deferrable.DEFERRED,
- )
-
def test_invalid_include_type(self):
msg = "ExclusionConstraint.include must be a list or tuple."
with self.assertRaisesMessage(ValueError, msg):
@@ -912,6 +902,39 @@ class ExclusionConstraintTests(PostgreSQLTestCase):
RangesModel.objects.create(ints=(10, 19))
RangesModel.objects.create(ints=(51, 60))
+ def test_range_adjacent_initially_deferred_with_condition(self):
+ constraint_name = "ints_adjacent_deferred_with_condition"
+ self.assertNotIn(
+ constraint_name, self.get_constraints(RangesModel._meta.db_table)
+ )
+ constraint = ExclusionConstraint(
+ name=constraint_name,
+ expressions=[("ints", RangeOperators.ADJACENT_TO)],
+ condition=Q(ints__lt=(100, 200)),
+ deferrable=Deferrable.DEFERRED,
+ )
+ with connection.schema_editor() as editor:
+ editor.add_constraint(RangesModel, constraint)
+ self.assertIn(constraint_name, self.get_constraints(RangesModel._meta.db_table))
+ RangesModel.objects.create(ints=(20, 50))
+ adjacent_range = RangesModel.objects.create(ints=(10, 20))
+ # Constraint behavior can be changed with SET CONSTRAINTS.
+ with self.assertRaises(IntegrityError):
+ with transaction.atomic(), connection.cursor() as cursor:
+ quoted_name = connection.ops.quote_name(constraint_name)
+ cursor.execute(f"SET CONSTRAINTS {quoted_name} IMMEDIATE")
+ # Remove adjacent range before the end of transaction.
+ adjacent_range.delete()
+ RangesModel.objects.create(ints=(10, 19))
+ RangesModel.objects.create(ints=(51, 60))
+ # Add adjacent range that doesn't match the condition.
+ RangesModel.objects.create(ints=(200, 500))
+ adjacent_range = RangesModel.objects.create(ints=(100, 200))
+ # Constraint behavior can be changed with SET CONSTRAINTS.
+ with transaction.atomic(), connection.cursor() as cursor:
+ quoted_name = connection.ops.quote_name(constraint_name)
+ cursor.execute(f"SET CONSTRAINTS {quoted_name} IMMEDIATE")
+
def test_range_adjacent_gist_include(self):
constraint_name = "ints_adjacent_gist_include"
self.assertNotIn(