From cc444ae07fadda50e7df3640efec61e4f6c7de6a Mon Sep 17 00:00:00 2001 From: Mark Gensler Date: Wed, 10 Jul 2024 14:45:30 +0100 Subject: [PATCH] Cache not invalidated for query using Case annotation for ManyToManyField --- cachalot/tests/test_case_annotation_bug.py | 42 ++++++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 cachalot/tests/test_case_annotation_bug.py diff --git a/cachalot/tests/test_case_annotation_bug.py b/cachalot/tests/test_case_annotation_bug.py new file mode 100644 index 000000000..5367f245a --- /dev/null +++ b/cachalot/tests/test_case_annotation_bug.py @@ -0,0 +1,42 @@ +from django.contrib.auth.models import Permission +from django.db.models import Case, When, BooleanField +from django.test import TransactionTestCase + +from cachalot.tests.models import TestChild +from cachalot.api import invalidate + + +class TestAnnotationFilteringBug(TransactionTestCase): + databases = ["default"] + def get_child_permissions(self, child): + # Dumb query which returns all Permission objects in a ManyToMany relationship + perms = child.permissions.all().values_list("pk", flat=True) + return Permission.objects.annotate( + is_related=Case(When(pk__in=perms, then=True), default=False, + output_field=BooleanField()) + ).filter(is_related=True) + + def test_result_is_incorrectly_cached(self): + child = TestChild.objects.create() + permission_A, permission_B = Permission.objects.all()[:2] + child.permissions.add(permission_A) + self.assertEqual(len(self.get_child_permissions(child)), 1) + self.assertSequenceEqual(self.get_child_permissions(child), [permission_A]) + child.permissions.add(permission_B) + self.assertEqual(len(self.get_child_permissions(child)), 2) # Fails + self.assertSequenceEqual( + self.get_child_permissions(child), [permission_A, permission_B] + ) + + def test_result_is_correct_if_cache_cleared(self): + child = TestChild.objects.create() + permission_A, permission_B = Permission.objects.all()[:2] + child.permissions.add(permission_A) + self.assertEqual(len(self.get_child_permissions(child)), 1) + self.assertSequenceEqual(self.get_child_permissions(child), [permission_A]) + child.permissions.add(permission_B) + invalidate(db_alias="default") + self.assertEqual(len(self.get_child_permissions(child)), 2) # Passes + self.assertSequenceEqual( + self.get_child_permissions(child), [permission_A, permission_B] + )