def fetchProjectsForDisplay(self): """See `ITranslationGroup`.""" # Avoid circular imports. from lp.registry.model.product import ( Product, ProductWithLicenses, ) using = [ Product, LeftJoin(LibraryFileAlias, LibraryFileAlias.id == Product.iconID), LeftJoin( LibraryFileContent, LibraryFileContent.id == LibraryFileAlias.contentID), ] columns = ( Product, ProductWithLicenses.composeLicensesColumn(), LibraryFileAlias, LibraryFileContent, ) product_data = ISlaveStore(Product).using(*using).find( columns, Product.translationgroupID == self.id, Product.active == True) product_data = product_data.order_by(Product.displayname) return [ ProductWithLicenses(product, tuple(licenses)) for product, licenses, icon_alias, icon_content in product_data]
def test_licenses_column_aggregates(self): # Adding a licensing column for a product with multiple licenses # still finds a single product, not one per licence. licenses = [License.AFFERO, License.GNU_GPL_V3] product = self.factory.makeProduct(licenses=licenses) column = ProductWithLicenses.composeLicensesColumn() store = Store.of(product) result = list(store.find((Product, column), Product.id == product.id)) self.assertEqual(1, len(result)) found_product, found_licenses = result[0] self.assertEqual(product, found_product) self.assertEqual(len(licenses), len(found_licenses))
def test_licenses_column_contains_licensing_info(self): # Feeding the licenses column into the ProductWithLicenses # constructor seeds it with the appropriate licenses. product = self.factory.makeProduct( licenses=[License.OTHER_PROPRIETARY]) column = ProductWithLicenses.composeLicensesColumn() store = Store.of(product) row = store.find((Product, column), Product.id == product.id).one() product_with_licenses = ProductWithLicenses(*row) licenses = product_with_licenses.licenses license_status = product_with_licenses.license_status self.assertEqual((License.OTHER_PROPRIETARY, ), licenses) self.assertEqual(LicenseStatus.PROPRIETARY, license_status)
def search(self, text, limit): """See `IPillarSet`.""" # Avoid circular import. from lp.registry.model.product import ProductWithLicenses if limit is None: limit = config.launchpad.default_batch_size # Pull out the licences as a subselect which is converted # into a PostgreSQL array so that multiple licences per product # can be retrieved in a single row for each product. extra_column = ProductWithLicenses.composeLicensesColumn() result = self.build_search_query(text, [extra_column]) # If the search text matches the name or title of the # Product, Project, or Distribution exactly, then this # row should get the highest search rank (9999999). # Each row in the PillarName table will join with only one # of either the Product, Project, or Distribution tables, # so the coalesce() is necessary to find the rank() which # is not null. result.order_by(SQL(''' (CASE WHEN PillarName.name = lower(%(text)s) OR lower(Product.title) = lower(%(text)s) OR lower(Project.title) = lower(%(text)s) OR lower(Distribution.title) = lower(%(text)s) THEN 9999999 ELSE coalesce(rank(Product.fti, ftq(%(text)s)), rank(Project.fti, ftq(%(text)s)), rank(Distribution.fti, ftq(%(text)s))) END) DESC, PillarName.name ''' % sqlvalues(text=text))) # People shouldn't be calling this method with too big limits longest_expected = 2 * config.launchpad.default_batch_size if limit > longest_expected: warnings.warn( "The search limit (%s) was greater " "than the longest expected size (%s)" % (limit, longest_expected), stacklevel=2) pillars = [] # Prefill pillar.product.licenses. for pillar_name, other, product, project, distro, licenses in ( result[:limit]): pillar = pillar_name.pillar if IProduct.providedBy(pillar): pillar = ProductWithLicenses(pillar, licenses) pillars.append(pillar) return pillars
def search(self, text, limit): """See `IPillarSet`.""" # Avoid circular import. from lp.registry.model.product import ProductWithLicenses if limit is None: limit = config.launchpad.default_batch_size # Pull out the licences as a subselect which is converted # into a PostgreSQL array so that multiple licences per product # can be retrieved in a single row for each product. extra_column = ProductWithLicenses.composeLicensesColumn() result = self.build_search_query(text, [extra_column]) # If the search text matches the name or title of the # Product, Project, or Distribution exactly, then this # row should get the highest search rank (9999999). # Each row in the PillarName table will join with only one # of either the Product, Project, or Distribution tables, # so the coalesce() is necessary to find the rank() which # is not null. result.order_by( SQL(''' (CASE WHEN PillarName.name = lower(%(text)s) OR lower(Product.title) = lower(%(text)s) OR lower(Project.title) = lower(%(text)s) OR lower(Distribution.title) = lower(%(text)s) THEN 9999999 ELSE coalesce(rank(Product.fti, ftq(%(text)s)), rank(Project.fti, ftq(%(text)s)), rank(Distribution.fti, ftq(%(text)s))) END) DESC, PillarName.name ''' % sqlvalues(text=text))) # People shouldn't be calling this method with too big limits longest_expected = 2 * config.launchpad.default_batch_size if limit > longest_expected: warnings.warn("The search limit (%s) was greater " "than the longest expected size (%s)" % (limit, longest_expected), stacklevel=2) pillars = [] # Prefill pillar.product.licenses. for pillar_name, other, product, project, distro, licenses in ( result[:limit]): pillar = pillar_name.pillar if IProduct.providedBy(pillar): pillar = ProductWithLicenses(pillar, licenses) pillars.append(pillar) return pillars