mirror of
https://github.com/galaxyproject/galaxy.git
synced 2026-09-24 16:30:27 +08:00
Merge pull request #15786 from ahmedhamidawan/related_filter_refactor
Add API test and refactor code for related:hid history filter
This commit is contained in:
@@ -531,34 +531,23 @@ class HistoryContentsFilters(
|
||||
|
||||
def parse_query_filters_with_relations(self, query_filters: ValueFilterQueryParams, history_id):
|
||||
"""Parse query filters but consider case where related filter is included."""
|
||||
if query_filters.q and query_filters.qv and "related-eq" in query_filters.q:
|
||||
qv_index = query_filters.q.index("related-eq")
|
||||
has_related_q = [q for q in ("related-eq", "related") if query_filters.q and q in query_filters.q]
|
||||
if query_filters.q and query_filters.qv and has_related_q:
|
||||
qv_index = query_filters.q.index(has_related_q[0])
|
||||
qv_hid = query_filters.qv[qv_index]
|
||||
|
||||
# Type check whether hid is int
|
||||
if not qv_hid.isdigit():
|
||||
raise glx_exceptions.RequestParameterInvalidException(
|
||||
"unparsable value for filter",
|
||||
"unparsable value for related filter",
|
||||
column="related",
|
||||
operation="eq",
|
||||
value=qv_hid,
|
||||
ValueError="invalid type in filter",
|
||||
)
|
||||
|
||||
# Make new q and qv excluding related filter
|
||||
new_q = [x for i, x in enumerate(query_filters.q) if i != qv_index]
|
||||
new_qv = [x for i, x in enumerate(query_filters.qv) if i != qv_index]
|
||||
|
||||
# Get list of related item hids from job_connections manager
|
||||
job_connections_manager = JobConnectionsManager(self.app.model.session)
|
||||
related = job_connections_manager.get_related_hids(history_id, qv_hid)
|
||||
|
||||
# Make new query_filters with updated list of related hids for given hid
|
||||
new_q.append("related-eq")
|
||||
new_qv.append(json.dumps(related))
|
||||
query_filters_with_relations = ValueFilterQueryParams(
|
||||
q=new_q,
|
||||
qv=new_qv,
|
||||
query_filters_with_relations = self.get_query_filters_with_relations(
|
||||
query_filters=query_filters, related_q=has_related_q[0], history_id=history_id
|
||||
)
|
||||
return super().parse_query_filters(query_filters_with_relations)
|
||||
return super().parse_query_filters(query_filters)
|
||||
@@ -617,6 +606,30 @@ class HistoryContentsFilters(
|
||||
return self.parsed_filter(filter_type="orm", filter=column_filter)
|
||||
return super()._parse_orm_filter(attr, op, val)
|
||||
|
||||
def get_query_filters_with_relations(self, query_filters: ValueFilterQueryParams, related_q: str, history_id):
|
||||
"""Return `query_filters_with_relations` changing `related:hid` to `related:[hid1, hid2, ...]`."""
|
||||
if query_filters.q and query_filters.qv:
|
||||
qv_index = query_filters.q.index(related_q)
|
||||
qv_hid = query_filters.qv[qv_index]
|
||||
|
||||
# Make new q and qv excluding related filter
|
||||
new_q = [x for i, x in enumerate(query_filters.q) if i != qv_index]
|
||||
new_qv = [x for i, x in enumerate(query_filters.qv) if i != qv_index]
|
||||
|
||||
# Get list of related item hids from job_connections manager
|
||||
job_connections_manager = JobConnectionsManager(self.app.model.session)
|
||||
related = job_connections_manager.get_related_hids(history_id, int(qv_hid))
|
||||
|
||||
# Make new query_filters with updated list of related hids for given hid
|
||||
new_q.append("related-eq")
|
||||
new_qv.append(json.dumps(related))
|
||||
query_filters_with_relations = ValueFilterQueryParams(
|
||||
q=new_q,
|
||||
qv=new_qv,
|
||||
)
|
||||
return query_filters_with_relations
|
||||
return query_filters
|
||||
|
||||
def decode_type_id(self, type_id):
|
||||
TYPE_ID_SEP = "-"
|
||||
split = type_id.split(TYPE_ID_SEP, 1)
|
||||
@@ -638,8 +651,6 @@ class HistoryContentsFilters(
|
||||
self.orm_filter_parsers.update(
|
||||
{
|
||||
"history_content_type": {"op": ("eq")},
|
||||
# maybe remove related from here, as there's no corresponding field?
|
||||
"related": {"op": ("eq")},
|
||||
"type_id": {"op": ("eq", "in"), "val": self.parse_type_id_list},
|
||||
"hid": {"op": ("eq", "ge", "le", "gt", "lt"), "val": int},
|
||||
# TODO: needs a different val parser - but no way to add to the above
|
||||
|
||||
@@ -18,7 +18,7 @@ class JobConnectionsManager:
|
||||
def __init__(self, sa_session: galaxy_scoped_session):
|
||||
self.sa_session = sa_session
|
||||
|
||||
def get_connections_graph(self, id, src):
|
||||
def get_connections_graph(self, id: int, src: str):
|
||||
"""Get connections graph of inputs and outputs for given item id"""
|
||||
if src == "HistoryDatasetAssociation":
|
||||
output_selects = self.outputs_derived_from_input_hda(id)
|
||||
@@ -34,7 +34,7 @@ class JobConnectionsManager:
|
||||
result["inputs"] = self._get_union_results(*input_selects)
|
||||
return result
|
||||
|
||||
def get_related_hids(self, history_id, hid):
|
||||
def get_related_hids(self, history_id, hid: int):
|
||||
"""Get connections graph of inputs and outputs for given item hid from the given history_id"""
|
||||
# Get id(s) and src(s) for the given hid
|
||||
items_by_hid = self.sa_session.execute(
|
||||
@@ -63,7 +63,7 @@ class JobConnectionsManager:
|
||||
result.append({"src": row.src, "id": row.id})
|
||||
return result
|
||||
|
||||
def outputs_derived_from_input_hda(self, input_hda_id):
|
||||
def outputs_derived_from_input_hda(self, input_hda_id: int):
|
||||
hda_select = (
|
||||
select(
|
||||
[
|
||||
@@ -94,7 +94,7 @@ class JobConnectionsManager:
|
||||
)
|
||||
return hda_select, hdca_select
|
||||
|
||||
def outputs_derived_from_input_hdca(self, input_hdca_id):
|
||||
def outputs_derived_from_input_hdca(self, input_hdca_id: int):
|
||||
hda_select = (
|
||||
select(
|
||||
[
|
||||
@@ -126,7 +126,7 @@ class JobConnectionsManager:
|
||||
)
|
||||
return hda_select, hdca_select
|
||||
|
||||
def inputs_for_hda(self, input_hda_id):
|
||||
def inputs_for_hda(self, input_hda_id: int):
|
||||
input_hdas = (
|
||||
select(
|
||||
[
|
||||
@@ -157,7 +157,7 @@ class JobConnectionsManager:
|
||||
)
|
||||
return input_hdas, input_hdcas
|
||||
|
||||
def inputs_for_hdca(self, input_hdca_id):
|
||||
def inputs_for_hdca(self, input_hdca_id: int):
|
||||
input_hdas = (
|
||||
select(
|
||||
[
|
||||
|
||||
@@ -737,6 +737,38 @@ class TestHistoryContentsApi(ApiTestCase):
|
||||
).json()
|
||||
assert len(contents_response) == 0
|
||||
|
||||
@skip_without_tool("cat_data_and_sleep")
|
||||
def test_index_filter_by_related_items(self, history_id):
|
||||
# initialise history with 2 datasets
|
||||
input_hda_id = self.dataset_populator.new_dataset(history_id)["id"]
|
||||
unrelated_hid = self.dataset_populator.new_dataset(history_id)["hid"]
|
||||
|
||||
# Run tool on first dataset to get 3rd, related dataset
|
||||
inputs = {
|
||||
"input1": {"src": "hda", "id": input_hda_id},
|
||||
"sleep_time": 0,
|
||||
}
|
||||
run_response = self.dataset_populator.run_tool_raw(
|
||||
"cat_data_and_sleep",
|
||||
inputs,
|
||||
history_id,
|
||||
)
|
||||
related_hid = run_response.json()["outputs"][0]["hid"]
|
||||
|
||||
# Test q = related-eq, for related items
|
||||
contents_response = self._get(f"histories/{history_id}/contents?v=dev&q=related-eq&qv={related_hid}").json()
|
||||
assert len(contents_response) == 2
|
||||
|
||||
# Test q = related, for unrelated item
|
||||
contents_response = self._get(f"histories/{history_id}/contents?v=dev&q=related&qv={unrelated_hid}").json()
|
||||
assert len(contents_response) == 1
|
||||
|
||||
# Test error case: qv is string
|
||||
related_qv = "one"
|
||||
contents_response = self._get(f"histories/{history_id}/contents?v=dev&q=related-eq&qv={related_qv}")
|
||||
assert contents_response.status_code == 400
|
||||
assert contents_response.json()["err_msg"] == "unparsable value for related filter"
|
||||
|
||||
def test_elements_datatypes_field(self, history_id):
|
||||
collection_name = "homogeneous"
|
||||
expected_datatypes = ["txt"]
|
||||
|
||||
Reference in New Issue
Block a user