From 40d57e0893985d448153fb93aa147bd5680fc7b0 Mon Sep 17 00:00:00 2001 From: Kushal Agrawal Date: Sun, 29 Apr 2018 20:33:52 +0530 Subject: [PATCH] Search based on tags condition with or condition combiner In case of more than one tags values in request query with other condition it was not using separate alias name for artifact_tag table to join with glare_artifacts table. To rectify this we have created aliases beforehand and using it updating the tag search condition. Change-Id: Ic7afe47fcf8f23a694f2c3d99dbdbd7797d506dd closes-bug: #1765338 --- glare/db/sqlalchemy/api.py | 8 +++++++- glare/tests/functional/test_sample_artifact.py | 15 +++++++++++++++ glare/tests/unit/api/test_list.py | 12 +++++++++--- 3 files changed, 31 insertions(+), 4 deletions(-) diff --git a/glare/db/sqlalchemy/api.py b/glare/db/sqlalchemy/api.py index c5aab88..9fff052 100644 --- a/glare/db/sqlalchemy/api.py +++ b/glare/db/sqlalchemy/api.py @@ -265,8 +265,14 @@ def _apply_user_filters(query, basic_conds, tag_conds, prop_conds): for tag_condition in tag_conds['and']: query = query.join(models.ArtifactTag, aliased=True).filter( and_(*tag_condition)) + tag_or_queries = [] for tag_condition in tag_conds['or']: - or_queries.append(*tag_condition) + artifact_tag_alias = aliased(models.ArtifactTag) + query = query.join(artifact_tag_alias) + for tag_cond in tag_condition: + tag_cond.left = artifact_tag_alias.value + tag_or_queries.append(and_(*tag_condition)) + or_queries.append(and_(*tag_or_queries)) if prop_conds: for prop_condition in prop_conds['and']: diff --git a/glare/tests/functional/test_sample_artifact.py b/glare/tests/functional/test_sample_artifact.py index 7526b48..15650be 100644 --- a/glare/tests/functional/test_sample_artifact.py +++ b/glare/tests/functional/test_sample_artifact.py @@ -715,6 +715,21 @@ class TestList(base.TestArtifact): result = self.get(url=url)['artifacts'] self.assertEqual([], result) + url = '/sample_artifact?name=or:eq:name2&tags-any=or:tag1,tag4' \ + '&sort=name:asc' + result = self.get(url=url)['artifacts'] + self.assertEqual(4, len(result)) + for i in (1, 2, 4): + self.assertIn(art_list[i], result) + self.assertEqual(public_art, result[3]) + + url = '/sample_artifact?name=or:eq:name2&&tags=or:tag4,tag5' \ + '&sort=name:asc' + result = self.get(url=url)['artifacts'] + self.assertEqual(2, len(result)) + self.assertEqual(art_list[2], result[0]) + self.assertEqual(public_art, result[1]) + class TestBlobs(base.TestArtifact): def test_blob_dicts(self): diff --git a/glare/tests/unit/api/test_list.py b/glare/tests/unit/api/test_list.py index 5b72286..98f41ba 100644 --- a/glare/tests/unit/api/test_list.py +++ b/glare/tests/unit/api/test_list.py @@ -539,10 +539,16 @@ class TestArtifactList(base.BaseTestArtifactAPI): for i in (3, 0): self.assertIn(arts[i], res['artifacts']) - filters = [('name', 'or:in:name4,name1'), ('tags-any', 'or:tag4')] + filters = [('name', 'or:in:name2,name1'), ('tags-any', 'or:tag2,tag5')] res = self.controller.list(self.req, 'sample_artifact', filters) - self.assertEqual(6, len(res['artifacts'])) - for i in (5, 4, 3, 0): + self.assertEqual(4, len(res['artifacts'])) + for i in (5, 3, 1, 0): + self.assertIn(arts[i], res['artifacts']) + + filters = [('name', 'or:in:name4,name1'), ('tags', 'or:tag1,tag3')] + res = self.controller.list(self.req, 'sample_artifact', filters) + self.assertEqual(3, len(res['artifacts'])) + for i in (3, 1, 0): self.assertIn(arts[i], res['artifacts']) # Filtering by tags with operators leads to BadRequest