← Back to team overview

launchpad-reviewers team mailing list archive

[Merge] ~lgp171188/launchpad:optimize-distribution-has-published-sources-queries into launchpad:master

 

Guruprasad has proposed merging ~lgp171188/launchpad:optimize-distribution-has-published-sources-queries into launchpad:master.

Commit message:
Optimize the queries issued by IDistribution.has_published_sources

Requested reviews:
  Launchpad code reviewers (launchpad-reviewers)

For more details, see:
https://code.launchpad.net/~lgp171188/launchpad/+git/launchpad/+merge/431724
-- 
Your team Launchpad code reviewers is requested to review the proposed merge of ~lgp171188/launchpad:optimize-distribution-has-published-sources-queries into launchpad:master.
diff --git a/lib/lp/registry/model/distribution.py b/lib/lp/registry/model/distribution.py
index 354353b..378ec86 100644
--- a/lib/lp/registry/model/distribution.py
+++ b/lib/lp/registry/model/distribution.py
@@ -196,6 +196,7 @@ from lp.soyuz.model.publishing import (
     SourcePackagePublishingHistory,
     get_current_source_releases,
 )
+from lp.soyuz.model.sourcepackagerelease import SourcePackageRelease
 from lp.translations.enums import TranslationPermission
 from lp.translations.model.hastranslationimports import (
     HasTranslationImportsMixin,
@@ -2144,12 +2145,25 @@ class Distribution(
 
         return weight_function
 
-    @property
+    @cachedproperty
     def has_published_sources(self):
-        for archive in self.all_distro_archives:
-            if not archive.getPublishedSources().order_by().is_empty():
-                return True
-        return False
+        if not self.all_distro_archives:
+            return False
+
+        store = Store.of(self)
+        clauses = [
+            SourcePackagePublishingHistory.archiveID.is_in(
+                archive.id for archive in self.all_distro_archives
+            ),
+            SourcePackagePublishingHistory.sourcepackagenameID
+            == SourcePackageName.id,
+            SourcePackagePublishingHistory.sourcepackagereleaseID
+            == SourcePackageRelease.id,
+        ]
+
+        if store.find(SourcePackagePublishingHistory, *clauses).is_empty():
+            return False
+        return True
 
     def newOCIProject(self, registrant, name, description=None):
         """Create an `IOCIProject` for this distro."""
diff --git a/lib/lp/registry/tests/test_distribution.py b/lib/lp/registry/tests/test_distribution.py
index b50fa90..7f2b6cf 100644
--- a/lib/lp/registry/tests/test_distribution.py
+++ b/lib/lp/registry/tests/test_distribution.py
@@ -74,11 +74,11 @@ from lp.registry.interfaces.series import SeriesStatus
 from lp.registry.model.distribution import Distribution
 from lp.registry.tests.test_distroseries import CurrentSourceReleasesMixin
 from lp.services.librarianserver.testing.fake import FakeLibrarian
-from lp.services.propertycache import get_property_cache
+from lp.services.propertycache import clear_property_cache, get_property_cache
 from lp.services.webapp import canonical_url
 from lp.services.webapp.interfaces import OAuthPermission
 from lp.services.worlddata.interfaces.country import ICountrySet
-from lp.soyuz.enums import PackagePublishingStatus
+from lp.soyuz.enums import ArchivePurpose, PackagePublishingStatus
 from lp.soyuz.interfaces.distributionsourcepackagerelease import (
     IDistributionSourcePackageRelease,
 )
@@ -99,7 +99,7 @@ from lp.testing.layers import (
     LaunchpadFunctionalLayer,
     ZopelessDatabaseLayer,
 )
-from lp.testing.matchers import Provides
+from lp.testing.matchers import HasQueryCount, Provides
 from lp.testing.pages import webservice_for_person
 from lp.testing.views import create_initialized_view
 from lp.translations.enums import TranslationPermission
@@ -2709,3 +2709,33 @@ class TestDistributionVulnerabilitiesWebService(TestCaseWithFactory):
                 }
             ),
         )
+
+
+class TestDistributionPublishedSources(TestCaseWithFactory):
+
+    layer = DatabaseFunctionalLayer
+
+    def test_has_published_sources_no_sources(self):
+        distribution = self.factory.makeDistribution()
+        self.assertFalse(distribution.has_published_sources)
+
+    def test_has_published_sources(self):
+        ubuntu = getUtility(IDistributionSet).getByName("ubuntu")
+        self.assertTrue(ubuntu.all_distro_archives.count() > 0)
+        self.assertTrue(ubuntu.has_published_sources)
+
+    def test_has_published_sources_query_count(self):
+        distribution = self.factory.makeDistribution()
+        self.assertEqual(1, distribution.all_distro_archives.count())
+        with StormStatementRecorder() as recorder1:
+            distribution.has_published_sources
+        clear_property_cache(distribution)
+        self.factory.makeArchive(
+            distribution=distribution,
+            purpose=ArchivePurpose.PARTNER,
+        )
+        self.assertEqual(2, distribution.all_distro_archives.count())
+        with StormStatementRecorder() as recorder2:
+            distribution.has_published_sources
+
+        self.assertThat(recorder2, HasQueryCount.byEquality(recorder1))

Follow ups