diff --git a/tests/_utils/local_test.sh b/tests/_utils/local_test.sh index 1a52aa1c88f7..fd8da6374c41 100755 --- a/tests/_utils/local_test.sh +++ b/tests/_utils/local_test.sh @@ -29,6 +29,10 @@ export DJANGO_SINGLESTORE_TABLE_STORAGE_TYPE_MANY_TO_MANY="ROWSTORE REFERENCE" # a number of models with unique keys, 13 many-to-many fields export DJANGO_SINGLESTORE_TABLE_STORAGE_TYPE_FIXTURES_REGRESS="ROWSTORE REFERENCE" +# a model with 3 many-to-many fields caused issues +export DJANGO_SINGLESTORE_TABLE_STORAGE_TYPE_DELETE="ROWSTORE REFERENCE" + + # queries app has a lot of models with OneToOne relationships export DJANGO_SINGLESTORE_NOT_ENFORCED_UNIQUE_QUERIES=1 diff --git a/tests/_utils/setup.sql b/tests/_utils/setup.sql index 94c797335d7f..8298a5b8a728 100644 --- a/tests/_utils/setup.sql +++ b/tests/_utils/setup.sql @@ -590,3 +590,13 @@ CREATE TABLE `backends_object_object` ( KEY (`from_object_id`), KEY (`to_object_id`) ); + +-- delete +CREATE TABLE `delete_player_game` ( + `player_id` BIGINT NOT NULL, + `game_id` BIGINT NOT NULL, + SHARD KEY (`player_id`), + UNIQUE KEY (`player_id`, `game_id`), + KEY (`player_id`), + KEY(`game_id`) +); diff --git a/tests/delete/models.py b/tests/delete/models.py index 4b627712bb65..9c49869825a9 100644 --- a/tests/delete/models.py +++ b/tests/delete/models.py @@ -2,6 +2,8 @@ from django.contrib.contenttypes.models import ContentType from django.db import models +from django_singlestore.schema import ModelStorageManager + class P(models.Model): pass @@ -241,3 +243,26 @@ class GenericDeleteBottomParent(models.Model): generic_delete_bottom = models.ForeignKey( GenericDeleteBottom, on_delete=models.CASCADE ) + + +class Game(models.Model): + home = models.CharField(max_length=100) + away = models.CharField(max_length=100) + + objects = ModelStorageManager("ROWSTORE") + + +class Player(models.Model): + name = models.CharField(max_length=100) + games = models.ManyToManyField(Game, related_name="players", through="PlayerGame") + + objects = ModelStorageManager("ROWSTORE") + + +class PlayerGame(models.Model): + player = models.ForeignKey(Player, on_delete=models.CASCADE) + game = models.ForeignKey(Game, on_delete=models.CASCADE) + + class Meta: + unique_together = (('player', 'game'),) + db_table = "delete_player_game" diff --git a/tests/delete/tests.py b/tests/delete/tests.py index 01228631f4ba..39f226d3270a 100644 --- a/tests/delete/tests.py +++ b/tests/delete/tests.py @@ -37,6 +37,8 @@ S, T, User, + Game, + Player, create_a, get_default_r, ) @@ -800,3 +802,17 @@ def test_fast_delete_full_match(self): with self.assertNumQueries(1): User.objects.filter(~Q(pk__in=[]) | Q(avatar__desc="foo")).delete() self.assertFalse(User.objects.exists()) + + def test_delete_with_custom_m2m(self): + """ + Test that deletion of a model with a custom through model + that doesn't have id field works correctly. + """ + g1 = Game.objects.create() + g2 = Game.objects.create() + + player = Player.objects.create() + player.games.add(g1, g2) + g1.delete() + g2.delete() + self.assertFalse(Game.objects.exists())