From 77c5495091667b858d9baefdca197eaa50c4e3bd Mon Sep 17 00:00:00 2001 From: Erwan Rouchet <rouchet@teklia.com> Date: Thu, 27 Jan 2022 11:03:13 +0100 Subject: [PATCH] Avoid any extra SQL query for top-level types --- arkindex/documents/api/elements.py | 10 ++++++++ arkindex/documents/tests/test_corpus.py | 32 +++++++++++++++++++++---- 2 files changed, 37 insertions(+), 5 deletions(-) diff --git a/arkindex/documents/api/elements.py b/arkindex/documents/api/elements.py index 729b0b0915..a3852e76c7 100644 --- a/arkindex/documents/api/elements.py +++ b/arkindex/documents/api/elements.py @@ -1149,6 +1149,16 @@ class CorpusList(ListCreateAPIView): for c in corpora: c.access_level = corpora_level[c.id] + # Avoid making any extra queries to retrieve the top_level_type. + # We already have prefetched the types, so we can use corpus.types.all() + # when a corpus has a top_level_type_id to retrieve it. + if c.top_level_type_id is not None: + c.top_level_type = next( + element_type + for element_type in c.types.all() + if element_type.id == c.top_level_type_id + ) + return corpora diff --git a/arkindex/documents/tests/test_corpus.py b/arkindex/documents/tests/test_corpus.py index 7308792ff5..273470120d 100644 --- a/arkindex/documents/tests/test_corpus.py +++ b/arkindex/documents/tests/test_corpus.py @@ -69,8 +69,9 @@ class TestCorpus(FixtureAPITestCase): def test_anon(self): # An anonymous user has only access to public - response = self.client.get(reverse('api:corpus')) - self.assertEqual(response.status_code, status.HTTP_200_OK) + with self.assertNumQueries(4): + response = self.client.get(reverse('api:corpus')) + self.assertEqual(response.status_code, status.HTTP_200_OK) data = response.json() self.assertEqual(len(data), 1) @@ -102,8 +103,9 @@ class TestCorpus(FixtureAPITestCase): def test_user(self): # A normal user has access to public + its private self.client.force_login(self.user) - response = self.client.get(reverse('api:corpus')) - self.assertEqual(response.status_code, status.HTTP_200_OK) + with self.assertNumQueries(7): + response = self.client.get(reverse('api:corpus')) + self.assertEqual(response.status_code, status.HTTP_200_OK) data = response.json() self.assertEqual(len(data), 2) @@ -150,7 +152,7 @@ class TestCorpus(FixtureAPITestCase): self.client.force_login(self.superuser) with self.assertNumQueries(5): response = self.client.get(reverse('api:corpus')) - self.assertEqual(response.status_code, status.HTTP_200_OK) + self.assertEqual(response.status_code, status.HTTP_200_OK) data = response.json() self.assertEqual(len(data), 3) @@ -206,6 +208,26 @@ class TestCorpus(FixtureAPITestCase): ] ) + def test_top_level_type_queries(self): + """ + Multiple corpora with top-level types should only cause one extra SQL query + """ + # Create a bunch of corpora with top-level types + for i in range(10): + corpus = Corpus.objects.create(name=str(i)) + element_type = corpus.types.create(slug='top_level') + corpus.top_level_type = element_type + corpus.save() + + self.client.force_login(self.superuser) + with self.assertNumQueries(6): + response = self.client.get(reverse('api:corpus')) + self.assertEqual(response.status_code, status.HTTP_200_OK) + data = response.json() + + self.assertEqual(len(data), 13) + self.assertSetEqual({corpus['top_level_type'] for corpus in data}, {None, 'top_level'}) + def test_mixin(self): vol1 = Element.objects.get(name="Volume 1") vol2 = Element.objects.get(name="Volume 2") -- GitLab