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))
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'], )
class Meta: constraints = [ ExclusionConstraint( name='exclude_overlapping_reservations', expressions=[ ('dates_range', RangeOperators.OVERLAPS), ('place', RangeOperators.EQUAL), ], ) ]
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, )
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"], )
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)
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, )
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_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, )
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)
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_repr(self): constraint = ExclusionConstraint( name="exclude_overlapping", expressions=[(F("datespan"), RangeOperators.ADJACENT_TO)], opclasses=["range_ops"], ) self.assertEqual( repr(constraint), "<ExclusionConstraint: index_type='GIST' expressions=[" "(F(datespan), '-|-')] name='exclude_overlapping' " "opclasses=['range_ops']>", )
class Meta: ordering = ["when"] constraints = [ # we do not want overlapping hours for the same Facility ExclusionConstraint( name="prevent_facility_opening_hours_overlaps", expressions=[ ("when", RangeOperators.OVERLAPS), ("facility", RangeOperators.EQUAL), ], ), ]
class Meta: constraints = [ ExclusionConstraint( name='cname_exclusivity', expressions=[ ('domain', RangeOperators.EQUAL), ('subname', RangeOperators.EQUAL), (RawSQL("int4(type = 'CNAME')", ()), RangeOperators.NOT_EQUAL), ], ), ] unique_together = (("domain", "subname", "type"), )
def test_deconstruct(self): constraint = ExclusionConstraint( name="exclude_overlapping", 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", "expressions": [ ("datespan", RangeOperators.OVERLAPS), ("room", RangeOperators.EQUAL), ], }, )
def test_range_adjacent_opclasses_deferrable(self): constraint_name = "ints_adjacent_opclasses_deferrable" self.assertNotIn(constraint_name, self.get_constraints(RangesModel._meta.db_table)) constraint = ExclusionConstraint( name=constraint_name, expressions=[("ints", RangeOperators.ADJACENT_TO)], opclasses=["range_ops"], 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))
def test_range_adjacent_spgist_opclasses_include(self): constraint_name = "ints_adjacent_spgist_opclasses_include" self.assertNotIn(constraint_name, self.get_constraints(RangesModel._meta.db_table)) constraint = ExclusionConstraint( name=constraint_name, expressions=[("ints", RangeOperators.ADJACENT_TO)], index_type="spgist", 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))
def test_range_adjacent_opclass_condition(self): constraint_name = "ints_adjacent_opclass_condition" 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), ], condition=Q(id__gte=100), ) with connection.schema_editor() as editor: editor.add_constraint(RangesModel, constraint) self.assertIn(constraint_name, self.get_constraints(RangesModel._meta.db_table))