diff --git a/mistral/db/v2/sqlalchemy/api.py b/mistral/db/v2/sqlalchemy/api.py index 69486ebc5..219124795 100644 --- a/mistral/db/v2/sqlalchemy/api.py +++ b/mistral/db/v2/sqlalchemy/api.py @@ -144,16 +144,23 @@ def _paginate_query(model, limit=None, marker=None, sort_keys=None, if not query: query = _secure_query(model) + sort_keys = sort_keys if sort_keys else [] + sort_dirs = sort_dirs if sort_dirs else [] + + if 'id' not in sort_keys: + sort_keys.append('id') + sort_dirs.append('asc') + query = db_utils.paginate_query( query, model, limit, - sort_keys if sort_keys else {}, + sort_keys, marker=marker, sort_dirs=sort_dirs ) - return query.all() + return query def _delete_all(model, session=None, **kwargs): @@ -170,24 +177,27 @@ def _get_collection(model, insecure=False, limit=None, marker=None, if fields else () ) - tags = kwargs.pop('tags', None) - query = (b.model_query(model, *columns) if insecure else _secure_query(model, *columns)) query = query.filter_by(**kwargs) + tags = kwargs.pop('tags', None) + # To match the tag list, a resource must contain at least all of the # tags present in the filter parameter. if tags: tag_attr = getattr(model, 'tags') + if len(tags) == 1: expr = tag_attr.contains(tags) else: expr = sa.and_(*[tag_attr.contains(tag) for tag in tags]) + query = query.filter(expr) - try: - return _paginate_query( + if marker or limit: + # Paginate query only if query set is limited. + query = _paginate_query( model, limit, marker, @@ -195,10 +205,13 @@ def _get_collection(model, insecure=False, limit=None, marker=None, sort_dirs, query ) + + try: + return query.all() except Exception as e: raise exc.DBQueryEntryError( "Failed when querying database, error type: %s, " - "error message: %s" % (e.__class__.__name__, e.message) + "error message: %s" % (e.__class__.__name__, str(e)) ) diff --git a/mistral_tempest_tests/tests/api/v2/test_actions.py b/mistral_tempest_tests/tests/api/v2/test_actions.py index b095500ed..7aede1caa 100644 --- a/mistral_tempest_tests/tests/api/v2/test_actions.py +++ b/mistral_tempest_tests/tests/api/v2/test_actions.py @@ -65,10 +65,12 @@ class ActionTestsV2(base.TestCase): delimiter='&' ) + # NOTE: 'id' gets included into sort keys automatically with 'desc' + # sorting to avoid pagination looping. expected_sub_dict = { 'limit': 1, - 'sort_keys': 'name', - 'sort_dirs': 'desc' + 'sort_keys': 'name,id', + 'sort_dirs': 'desc,asc' } self.assertDictContainsSubset(expected_sub_dict, param_dict) diff --git a/mistral_tempest_tests/tests/api/v2/test_executions.py b/mistral_tempest_tests/tests/api/v2/test_executions.py index d7fc100b7..aa8b8d1c3 100644 --- a/mistral_tempest_tests/tests/api/v2/test_executions.py +++ b/mistral_tempest_tests/tests/api/v2/test_executions.py @@ -88,10 +88,12 @@ class ExecutionTestsV2(base.TestCase): delimiter='&' ) + # NOTE: 'id' gets included into sort keys automatically with 'desc' + # sorting to avoid pagination looping. expected_dict = { 'limit': 1, - 'sort_keys': 'workflow_name', - 'sort_dirs': 'asc', + 'sort_keys': 'workflow_name,id', + 'sort_dirs': 'asc,asc', } self.assertTrue( diff --git a/mistral_tempest_tests/tests/api/v2/test_workflows.py b/mistral_tempest_tests/tests/api/v2/test_workflows.py index a046f13b2..2b91e78b6 100644 --- a/mistral_tempest_tests/tests/api/v2/test_workflows.py +++ b/mistral_tempest_tests/tests/api/v2/test_workflows.py @@ -73,10 +73,12 @@ class WorkflowTestsV2(base.TestCase): delimiter='&' ) + # NOTE: 'id' gets included into sort keys automatically with 'desc' + # sorting to avoid pagination looping. expected_sub_dict = { 'limit': 1, - 'sort_keys': 'name', - 'sort_dirs': 'desc' + 'sort_keys': 'name,id', + 'sort_dirs': 'desc,asc' } self.assertDictContainsSubset(expected_sub_dict, param_dict)