diff options
author | Márton Salomváry <marton@salomvary.com> | 2022-11-10 08:15:04 +0100 |
---|---|---|
committer | Mariusz Felisiak <felisiak.mariusz@gmail.com> | 2022-11-10 11:07:24 +0100 |
commit | d6cbf39a1ba2053c6211a16ed42d5410e5c5cdd0 (patch) | |
tree | 67afc0a74957af44d6dd3805ab25f87684141fb2 /tests/postgres_tests | |
parent | 0931d5b087a37545af0bef597deac03b5f0f7db0 (diff) | |
download | django-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.py | 43 |
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( |