Exemple #1
0
 def test_eq(self):
     constraint_1 = ExclusionConstraint(
         name='exclude_overlapping',
         expressions=[
             (F('datespan'), RangeOperators.OVERLAPS),
             (F('room'), RangeOperators.EQUAL),
         ],
         condition=Q(cancelled=False),
     )
     constraint_2 = ExclusionConstraint(
         name='exclude_overlapping',
         expressions=[
             ('datespan', RangeOperators.OVERLAPS),
             ('room', RangeOperators.EQUAL),
         ],
     )
     constraint_3 = ExclusionConstraint(
         name='exclude_overlapping',
         expressions=[('datespan', RangeOperators.OVERLAPS)],
         condition=Q(cancelled=False),
     )
     self.assertEqual(constraint_1, constraint_1)
     self.assertEqual(constraint_1, mock.ANY)
     self.assertNotEqual(constraint_1, constraint_2)
     self.assertNotEqual(constraint_1, constraint_3)
     self.assertNotEqual(constraint_2, constraint_3)
     self.assertNotEqual(constraint_1, object())
Exemple #2
0
 def test_repr(self):
     constraint = ExclusionConstraint(
         name="exclude_overlapping",
         expressions=[
             (F("datespan"), RangeOperators.OVERLAPS),
             (F("room"), RangeOperators.EQUAL),
         ],
     )
     self.assertEqual(
         repr(constraint),
         "<ExclusionConstraint: index_type='GIST' expressions=["
         "(F(datespan), '&&'), (F(room), '=')] name='exclude_overlapping'>",
     )
     constraint = ExclusionConstraint(
         name="exclude_overlapping",
         expressions=[(F("datespan"), RangeOperators.ADJACENT_TO)],
         condition=Q(cancelled=False),
         index_type="SPGiST",
     )
     self.assertEqual(
         repr(constraint),
         "<ExclusionConstraint: index_type='SPGiST' expressions=["
         "(F(datespan), '-|-')] name='exclude_overlapping' "
         "condition=(AND: ('cancelled', False))>",
     )
     constraint = ExclusionConstraint(
         name="exclude_overlapping",
         expressions=[(F("datespan"), RangeOperators.ADJACENT_TO)],
         deferrable=Deferrable.IMMEDIATE,
     )
     self.assertEqual(
         repr(constraint),
         "<ExclusionConstraint: index_type='GIST' expressions=["
         "(F(datespan), '-|-')] name='exclude_overlapping' "
         "deferrable=Deferrable.IMMEDIATE>",
     )
     constraint = ExclusionConstraint(
         name="exclude_overlapping",
         expressions=[(F("datespan"), RangeOperators.ADJACENT_TO)],
         include=["cancelled", "room"],
     )
     self.assertEqual(
         repr(constraint),
         "<ExclusionConstraint: index_type='GIST' expressions=["
         "(F(datespan), '-|-')] name='exclude_overlapping' "
         "include=('cancelled', 'room')>",
     )
     constraint = ExclusionConstraint(
         name="exclude_overlapping",
         expressions=[
             (OpClass("datespan",
                      name="range_ops"), RangeOperators.ADJACENT_TO),
         ],
     )
     self.assertEqual(
         repr(constraint),
         "<ExclusionConstraint: index_type='GIST' expressions=["
         "(OpClass(F(datespan), name=range_ops), '-|-')] "
         "name='exclude_overlapping'>",
     )
Exemple #3
0
 def test_repr(self):
     constraint = ExclusionConstraint(
         name='exclude_overlapping',
         expressions=[
             (F('datespan'), RangeOperators.OVERLAPS),
             (F('room'), RangeOperators.EQUAL),
         ],
     )
     self.assertEqual(
         repr(constraint),
         "<ExclusionConstraint: index_type=GIST, expressions=["
         "(F(datespan), '&&'), (F(room), '=')]>",
     )
     constraint = ExclusionConstraint(
         name='exclude_overlapping',
         expressions=[(F('datespan'), RangeOperators.ADJACENT_TO)],
         condition=Q(cancelled=False),
         index_type='SPGiST',
     )
     self.assertEqual(
         repr(constraint),
         "<ExclusionConstraint: index_type=SPGiST, expressions=["
         "(F(datespan), '-|-')], condition=(AND: ('cancelled', False))>",
     )
     constraint = ExclusionConstraint(
         name='exclude_overlapping',
         expressions=[(F('datespan'), RangeOperators.ADJACENT_TO)],
         deferrable=Deferrable.IMMEDIATE,
     )
     self.assertEqual(
         repr(constraint),
         "<ExclusionConstraint: index_type=GIST, expressions=["
         "(F(datespan), '-|-')], deferrable=Deferrable.IMMEDIATE>",
     )
Exemple #4
0
 def test_deconstruct_condition(self):
     constraint = ExclusionConstraint(
         name="exclude_overlapping",
         expressions=[
             ("datespan", RangeOperators.OVERLAPS),
             ("room", RangeOperators.EQUAL),
         ],
         condition=Q(cancelled=False),
     )
     path, args, kwargs = constraint.deconstruct()
     self.assertEqual(
         path, "django.contrib.postgres.constraints.ExclusionConstraint")
     self.assertEqual(args, ())
     self.assertEqual(
         kwargs,
         {
             "name":
             "exclude_overlapping",
             "expressions": [
                 ("datespan", RangeOperators.OVERLAPS),
                 ("room", RangeOperators.EQUAL),
             ],
             "condition":
             Q(cancelled=False),
         },
     )
Exemple #5
0
 def test_range_adjacent_opclass(self):
     constraint_name = "ints_adjacent_opclass"
     self.assertNotIn(constraint_name,
                      self.get_constraints(RangesModel._meta.db_table))
     constraint = ExclusionConstraint(
         name=constraint_name,
         expressions=[
             (OpClass("ints",
                      name="range_ops"), RangeOperators.ADJACENT_TO),
         ],
     )
     with connection.schema_editor() as editor:
         editor.add_constraint(RangesModel, constraint)
     constraints = self.get_constraints(RangesModel._meta.db_table)
     self.assertIn(constraint_name, constraints)
     with editor.connection.cursor() as cursor:
         cursor.execute(SchemaTests.get_opclass_query, [constraint_name])
         self.assertEqual(
             cursor.fetchall(),
             [("range_ops", constraint_name)],
         )
     RangesModel.objects.create(ints=(20, 50))
     with self.assertRaises(IntegrityError), transaction.atomic():
         RangesModel.objects.create(ints=(10, 20))
     RangesModel.objects.create(ints=(10, 19))
     RangesModel.objects.create(ints=(51, 60))
     # Drop the constraint.
     with connection.schema_editor() as editor:
         editor.remove_constraint(RangesModel, constraint)
     self.assertNotIn(constraint_name,
                      self.get_constraints(RangesModel._meta.db_table))
Exemple #6
0
 def test_deconstruct_index_type(self):
     constraint = ExclusionConstraint(
         name="exclude_overlapping",
         index_type="SPGIST",
         expressions=[
             ("datespan", RangeOperators.OVERLAPS),
             ("room", RangeOperators.EQUAL),
         ],
     )
     path, args, kwargs = constraint.deconstruct()
     self.assertEqual(
         path, "django.contrib.postgres.constraints.ExclusionConstraint")
     self.assertEqual(args, ())
     self.assertEqual(
         kwargs,
         {
             "name":
             "exclude_overlapping",
             "index_type":
             "SPGIST",
             "expressions": [
                 ("datespan", RangeOperators.OVERLAPS),
                 ("room", RangeOperators.EQUAL),
             ],
         },
     )
Exemple #7
0
 def test_invalid_index_type(self):
     msg = 'Exclusion constraints only support GiST or SP-GiST indexes.'
     with self.assertRaisesMessage(ValueError, msg):
         ExclusionConstraint(
             index_type='gin',
             name='exclude_invalid_index_type',
             expressions=[(F('datespan'), RangeOperators.OVERLAPS)],
         )
Exemple #8
0
 def test_range_overlaps(self):
     constraint = ExclusionConstraint(
         name='exclude_overlapping_reservations',
         expressions=[(F('datespan'), RangeOperators.OVERLAPS),
                      ('room', RangeOperators.EQUAL)],
         condition=Q(cancelled=False),
     )
     self._test_range_overlaps(constraint)
Exemple #9
0
 def test_invalid_opclasses_type(self):
     msg = "ExclusionConstraint.opclasses must be a list or tuple."
     with self.assertRaisesMessage(ValueError, msg):
         ExclusionConstraint(
             name="exclude_invalid_opclasses",
             expressions=[(F("datespan"), RangeOperators.OVERLAPS)],
             opclasses="invalid",
         )
Exemple #10
0
 def test_invalid_deferrable(self):
     msg = "ExclusionConstraint.deferrable must be a Deferrable instance."
     with self.assertRaisesMessage(ValueError, msg):
         ExclusionConstraint(
             name="exclude_invalid_deferrable",
             expressions=[(F("datespan"), RangeOperators.OVERLAPS)],
             deferrable="invalid",
         )
Exemple #11
0
 def test_invalid_deferrable(self):
     msg = 'ExclusionConstraint.deferrable must be a Deferrable instance.'
     with self.assertRaisesMessage(ValueError, msg):
         ExclusionConstraint(
             name='exclude_invalid_deferrable',
             expressions=[(F('datespan'), RangeOperators.OVERLAPS)],
             deferrable='invalid',
         )
Exemple #12
0
 def test_invalid_index_type(self):
     msg = "Exclusion constraints only support GiST or SP-GiST indexes."
     with self.assertRaisesMessage(ValueError, msg):
         ExclusionConstraint(
             index_type="gin",
             name="exclude_invalid_index_type",
             expressions=[(F("datespan"), RangeOperators.OVERLAPS)],
         )
Exemple #13
0
 def test_invalid_opclasses_type(self):
     msg = 'ExclusionConstraint.opclasses must be a list or tuple.'
     with self.assertRaisesMessage(ValueError, msg):
         ExclusionConstraint(
             name='exclude_invalid_opclasses',
             expressions=[(F('datespan'), RangeOperators.OVERLAPS)],
             opclasses='invalid',
         )
Exemple #14
0
 def test_invalid_condition(self):
     msg = "ExclusionConstraint.condition must be a Q instance."
     with self.assertRaisesMessage(ValueError, msg):
         ExclusionConstraint(
             index_type="GIST",
             name="exclude_invalid_condition",
             expressions=[(F("datespan"), RangeOperators.OVERLAPS)],
             condition=F("invalid"),
         )
Exemple #15
0
 def test_invalid_include_index_type(self):
     msg = 'Covering exclusion constraints only support GiST indexes.'
     with self.assertRaisesMessage(ValueError, msg):
         ExclusionConstraint(
             name='exclude_invalid_index_type',
             expressions=[(F('datespan'), RangeOperators.OVERLAPS)],
             include=['cancelled'],
             index_type='spgist',
         )
Exemple #16
0
 def test_invalid_expressions(self):
     msg = 'The expressions must be a list of 2-tuples.'
     for expressions in (['foo'], [('foo')], [('foo_1', 'foo_2', 'foo_3')]):
         with self.subTest(expressions), self.assertRaisesMessage(ValueError, msg):
             ExclusionConstraint(
                 index_type='GIST',
                 name='exclude_invalid_expressions',
                 expressions=expressions,
             )
Exemple #17
0
 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,
         )
Exemple #18
0
 def test_empty_expressions(self):
     msg = 'At least one expression is required to define an exclusion constraint.'
     for empty_expressions in (None, []):
         with self.subTest(empty_expressions), self.assertRaisesMessage(ValueError, msg):
             ExclusionConstraint(
                 index_type='GIST',
                 name='exclude_empty_expressions',
                 expressions=empty_expressions,
             )
Exemple #19
0
 def test_invalid_condition(self):
     msg = 'ExclusionConstraint.condition must be a Q instance.'
     with self.assertRaisesMessage(ValueError, msg):
         ExclusionConstraint(
             index_type='GIST',
             name='exclude_invalid_condition',
             expressions=[(F('datespan'), RangeOperators.OVERLAPS)],
             condition=F('invalid'),
         )
Exemple #20
0
 def test_range_equal_cast(self):
     constraint_name = 'exclusion_equal_room_cast'
     self.assertNotIn(constraint_name, self.get_constraints(Room._meta.db_table))
     constraint = ExclusionConstraint(
         name=constraint_name,
         expressions=[(Cast('number', IntegerField()), RangeOperators.EQUAL)],
     )
     with connection.schema_editor() as editor:
         editor.add_constraint(Room, constraint)
     self.assertIn(constraint_name, self.get_constraints(Room._meta.db_table))
Exemple #21
0
 def test_invalid_expressions(self):
     msg = "The expressions must be a list of 2-tuples."
     for expressions in (["foo"], [("foo")], [("foo_1", "foo_2", "foo_3")]):
         with self.subTest(expressions), self.assertRaisesMessage(
                 ValueError, msg):
             ExclusionConstraint(
                 index_type="GIST",
                 name="exclude_invalid_expressions",
                 expressions=expressions,
             )
Exemple #22
0
 def test_opclasses_and_expressions_same_length(self):
     msg = ("ExclusionConstraint.expressions and "
            "ExclusionConstraint.opclasses must have the same number of "
            "elements.")
     with self.assertRaisesMessage(ValueError, msg):
         ExclusionConstraint(
             name="exclude_invalid_expressions_opclasses_length",
             expressions=[(F("datespan"), RangeOperators.OVERLAPS)],
             opclasses=["foo", "bar"],
         )
Exemple #23
0
 def test_warning(self):
     msg = ("The opclasses argument is deprecated in favor of using "
            "django.contrib.postgres.indexes.OpClass in "
            "ExclusionConstraint.expressions.")
     with self.assertWarnsMessage(RemovedInDjango50Warning, msg):
         ExclusionConstraint(
             name="exclude_overlapping",
             expressions=[(F("datespan"), RangeOperators.ADJACENT_TO)],
             opclasses=["range_ops"],
         )
 def test_opclasses_and_expressions_same_length(self):
     msg = ('ExclusionConstraint.expressions and '
            'ExclusionConstraint.opclasses must have the same number of '
            'elements.')
     with self.assertRaisesMessage(ValueError, msg):
         ExclusionConstraint(
             name='exclude_invalid_expressions_opclasses_length',
             expressions=[(F('datespan'), RangeOperators.OVERLAPS)],
             opclasses=['foo', 'bar'],
         )
Exemple #25
0
 def test_expressions_with_params(self):
     constraint_name = 'scene_left_equal'
     self.assertNotIn(constraint_name, self.get_constraints(Scene._meta.db_table))
     constraint = ExclusionConstraint(
         name=constraint_name,
         expressions=[(Left('scene', 4), RangeOperators.EQUAL)],
     )
     with connection.schema_editor() as editor:
         editor.add_constraint(Scene, constraint)
     self.assertIn(constraint_name, self.get_constraints(Scene._meta.db_table))
 def test_warning(self):
     msg = ('The opclasses argument is deprecated in favor of using '
            'django.contrib.postgres.indexes.OpClass in '
            'ExclusionConstraint.expressions.')
     with self.assertWarnsMessage(RemovedInDjango50Warning, msg):
         ExclusionConstraint(
             name='exclude_overlapping',
             expressions=[(F('datespan'), RangeOperators.ADJACENT_TO)],
             opclasses=['range_ops'],
         )
Exemple #27
0
 def test_range_overlaps(self):
     constraint = ExclusionConstraint(
         name="exclude_overlapping_reservations",
         expressions=[
             (F("datespan"), RangeOperators.OVERLAPS),
             ("room", RangeOperators.EQUAL),
         ],
         condition=Q(cancelled=False),
     )
     self._test_range_overlaps(constraint)
 class Meta:
     constraints = [
         ExclusionConstraint(
             name='exclude_overlapping_reservations',
             expressions=[
                 ('dates_range', RangeOperators.OVERLAPS),
                 ('place', RangeOperators.EQUAL),
             ],
         )
     ]
 class Meta:
     constraints = [
         ExclusionConstraint(
             name='hotel_room_excl_constraint',
             expressions=[
                 ("time", RangeOperators.OVERLAPS),
                 ("room", RangeOperators.EQUAL),
             ],
             index_type="GIST",
         )
     ]
Exemple #30
0
 def test_range_adjacent_opclasses_include(self):
     constraint_name = 'ints_adjacent_opclasses_include'
     self.assertNotIn(constraint_name, self.get_constraints(RangesModel._meta.db_table))
     constraint = ExclusionConstraint(
         name=constraint_name,
         expressions=[('ints', RangeOperators.ADJACENT_TO)],
         opclasses=['range_ops'],
         include=['decimals'],
     )
     with connection.schema_editor() as editor:
         editor.add_constraint(RangesModel, constraint)
     self.assertIn(constraint_name, self.get_constraints(RangesModel._meta.db_table))