Unverified Commit 59221e7d authored by Marius van den Beek's avatar Marius van den Beek Committed by GitHub
Browse files

Merge pull request #14127 from davelopez/case_insensitive_tag_search

[22.05] Fix: make tag filtering case insensitive
parents d96b389b d08aa077
Loading
Loading
Loading
Loading
+9 −5
Original line number Diff line number Diff line
@@ -7,7 +7,10 @@ Mixins for Taggable model managers and serializers.
import logging
from typing import Type

from sqlalchemy import sql
from sqlalchemy import (
    func,
    sql,
)

from galaxy import model
from galaxy.model.tags import GalaxyTagHandler
@@ -118,15 +121,16 @@ class TaggableFilterMixin:
            target_model = getattr(model, f"{class_name}TagAssociation")
            id_column = f"{target_model.table.name.rsplit('_tag_association')[0]}_id"
            column = target_model.table.c.user_tname + ":" + target_model.table.c.user_value
            lower_val = val.lower()  # Ignore case
            if op == "eq":
                if ":" not in val:
                if ":" not in lower_val:
                    # We require an exact match and the tag to look for has no user_value,
                    # so we can't just concatenate user_tname, ':' and user_vale
                    cond = target_model.table.c.user_tname == val
                    cond = func.lower(target_model.table.c.user_tname) == lower_val
                else:
                    cond = column == val
                    cond = func.lower(column) == lower_val
            else:
                cond = column.contains(val, autoescape=True)
                cond = func.lower(column).contains(lower_val, autoescape=True)
            return sql.expression.and_(model_class.table.c.id == getattr(target_model.table.c, id_column), cond)

        return _create_tag_filter
+37 −0
Original line number Diff line number Diff line
@@ -131,6 +131,43 @@ class DatasetsApiTestCase(ApiTestCase):
        index_response = self._get("datasets", payload).json()
        assert len(index_response) == 0

    def test_search_by_tag_case_insensitive(self):
        history_id = self.dataset_populator.new_history()
        hda_id = self.dataset_populator.new_dataset(history_id)["id"]
        update_payload = {
            "tags": ["name:new_TAG", "cool:another_TAG"],
        }
        updated_hda = self._put(f"histories/{history_id}/contents/{hda_id}", update_payload, json=True).json()
        assert "name:new_TAG" in updated_hda["tags"]
        assert "cool:another_TAG" in updated_hda["tags"]
        payload = {
            "limit": 10,
            "offset": 0,
            "q": ["history_content_type", "tag"],
            "qv": ["dataset", "name:new_tag"],
            "history_id": history_id,
        }
        index_response = self._get("datasets", payload).json()
        assert len(index_response) == 1
        payload = {
            "limit": 10,
            "offset": 0,
            "q": ["history_content_type", "tag-contains"],
            "qv": ["dataset", "new_tag"],
            "history_id": history_id,
        }
        index_response = self._get("datasets", payload).json()
        assert len(index_response) == 1
        payload = {
            "limit": 10,
            "offset": 0,
            "q": ["history_content_type", "tag-contains"],
            "qv": ["dataset", "notag"],
            "history_id": history_id,
        }
        index_response = self._get("datasets", payload).json()
        assert len(index_response) == 0

    def test_search_by_tool_id(self):
        self.dataset_populator.new_dataset(self.history_id)
        payload = {