Order the packages for parameter search

Previously, list packages with parameter 'search',
search content in any attributes, but packages are unordered
With this change, packages are  ordered.
Such as: list package with 'search=mysql'
the packages whose name like 'mysql' are ahead of others
whose afn like 'mysql',and so on

Change-Id: Iecc3038ac40e731788975cff0cdf7d42e7f97112
Closes-Bug:#1467487
This commit is contained in:
Huangsm 2016-01-28 01:00:19 -05:00 committed by huangsm
parent 3ef1d83c91
commit 82bd5858e3
4 changed files with 112 additions and 18 deletions

View File

@ -82,7 +82,7 @@ For an admin role all packages are available.
+----------------------+-------------+------------------------------------------------------------------------------------------------------------------------------+
| ``include_disabled`` | bool | Include disabled packages in a the result |
+----------------------+-------------+------------------------------------------------------------------------------------------------------------------------------+
| ``search`` | string | Gives opportunity to search specified data by all the package parameters |
| ``search`` | string | Gives opportunity to search specified data by all the package parameters and order packages |
+----------------------+-------------+------------------------------------------------------------------------------------------------------------------------------+
| ``class_name`` | string | Search only for packages, that use specified class |
+----------------------+-------------+------------------------------------------------------------------------------------------------------------------------------+

View File

@ -16,6 +16,7 @@ from oslo_db import api as oslo_db_api
from oslo_db import exception as db_exceptions
from oslo_db.sqlalchemy import utils
from oslo_log import log as logging
import re
import six
import sqlalchemy as sa
from sqlalchemy import or_
@ -340,26 +341,43 @@ def package_search(filters, context, manage_public=False,
fk_fields = {'categories': 'Category',
'tags': 'Tag',
'class_definitions': 'Class'}
conditions = []
# the default search order
fields = ['name',
'fully_qualified_name',
'description',
'categories',
'tags',
'class_definitions',
'author']
# split to searching words
key_words = re.split(';|,', filters['search'])
for attr in dir(pkg):
conditions = []
order_cases = []
sorted_fields = fields + list(set(dir(pkg)).difference(set(fields)))
for index in range(0, len(sorted_fields)):
attr = sorted_fields[index]
if attr.startswith('_'):
continue
if isinstance(getattr(pkg, attr),
attributes.InstrumentedAttribute):
search_str = filters['search']
for delim in ',;':
search_str = search_str.replace(delim, ' ')
for key_word in search_str.split():
_word = u'%{value}%'.format(value=key_word)
if attr in fk_fields.keys():
condition = getattr(pkg, attr).any(
getattr(models, fk_fields[attr]).name.like(_word))
conditions.append(condition)
elif isinstance(getattr(pkg, attr)
.property.columns[0].type, sa.String):
conditions.append(getattr(pkg, attr).like(_word))
query = query.filter(or_(*conditions))
if not isinstance(getattr(pkg, attr),
attributes.InstrumentedAttribute):
continue
priority = min(index, len(fields))
for key_word in key_words:
_word = u'%{value}%'.format(value=key_word)
if attr in fk_fields.keys():
condition = getattr(pkg, attr).any(
getattr(models, fk_fields[attr]).name.like(_word))
conditions.append(condition)
order_cases.append((condition, priority))
elif isinstance(getattr(pkg, attr)
.property.columns[0].type, sa.String):
condition = getattr(pkg, attr).like(_word)
conditions.append(condition)
order_cases.append((condition, priority))
order_expression = sa.case(order_cases).label("tmp_weight_uuid")
query = query.filter(or_(*conditions)).order_by(order_expression.asc())
sort_keys = [SEARCH_MAPPING[sort_key] for sort_key in
filters.get('order_by', ['name'])]

View File

@ -562,6 +562,57 @@ class TestCatalogApi(test_base.ControllerTest, test_base.MuranoApiTestCase):
self.assertIn("Search by parameter 'tag' caused an error",
warnings[0])
def test_packages_filter_by_search(self):
self._set_policy_rules(
{'get_package': '',
'manage_public_package': ''}
)
excepted_pkg1 = self._add_pkg("test_tenant",
type='Application',
name='awcloud',
description='some context')
excepted_pkg2 = self._add_pkg("test_tenant",
type='Application',
name='mysql',
description='awcloud product')
excepted_pkg3 = self._add_pkg("test_tenant",
type='Application',
name='package3',
author='mysql author')
# filter by search=awcloud can see 2 pkgs
req_awc = self._get('/catalog/packages',
params={'search': 'awcloud'})
# filter by search=mysql only see 2 pkgs
req_mysql = self._get('/catalog/packages',
params={'search': 'mysql'})
for dummy in range(2):
self.expect_policy_check('get_package')
self.expect_policy_check('manage_public_package')
res_awc = req_awc.get_response(self.api)
self.assertEqual(200, res_awc.status_code)
self.assertEqual(2, len(res_awc.json['packages']))
self.assertEqual(excepted_pkg1.name,
res_awc.json['packages'][0]['name'])
self.assertEqual(excepted_pkg2.name,
res_awc.json['packages'][1]['name'])
res_mysql = req_mysql.get_response(self.api)
self.assertEqual(200, res_mysql.status_code)
self.assertEqual(2, len(res_mysql.json['packages']))
self.assertEqual(excepted_pkg2.name,
res_mysql.json['packages'][0]['name'])
self.assertEqual(excepted_pkg3.name,
res_mysql.json['packages'][1]['name'])
def test_packages(self):
self._set_policy_rules(
{'get_package': '',

View File

@ -212,6 +212,31 @@ class CatalogDBTestCase(base.MuranoWithDBTestCase):
res = api.package_search({'marker': marker}, self.context, limit=4)
self.assertEqual(0, len(res))
def test_package_search_search_order(self):
pkg1 = api.package_upload(
self._stub_package(
fully_qualified_name=str(uuid.uuid4()),
name='mysql',
description='awcloud'),
self.tenant_id)
pkg2 = api.package_upload(
self._stub_package(
fully_qualified_name=str(uuid.uuid4()),
name='awcloud',
description='mysql'),
self.tenant_id)
api.package_upload(
self._stub_package(
tags=[],
fully_qualified_name=str(uuid.uuid4())),
self.tenant_id)
res = api.package_search(
{'search': 'mysql'}, self.context)
self.assertEqual(2, len(res))
self.assertEqual(pkg1.name, res[0].name)
self.assertEqual(pkg2.description, res[1].description)
def test_package_search_search(self):
pkg1 = api.package_upload(
self._stub_package(