diff --git a/src/mavedb/lib/experiments.py b/src/mavedb/lib/experiments.py index d771f26b..1dff7090 100644 --- a/src/mavedb/lib/experiments.py +++ b/src/mavedb/lib/experiments.py @@ -1,7 +1,7 @@ import logging from typing import Optional -from sqlalchemy import func, or_ +from sqlalchemy import func, or_, not_ from sqlalchemy.orm import Session from mavedb.lib.logging.context import logging_context, save_to_logging_context @@ -99,6 +99,19 @@ def search_experiments( ) ) + if search.meta_analysis is not None: + if not search.meta_analysis: + query = query.filter( + or_( + # Keep experiments without any score sets + not_(Experiment.score_sets.any()), + # Keep experiments where score sets exist but have no meta_analyzes_score_sets + Experiment.score_sets.any(not_(ScoreSet.meta_analyzes_score_sets.any())) + ) + ) + else: + query = query.filter(Experiment.score_sets.any(ScoreSet.meta_analyzes_score_sets.any())) + items: list[Experiment] = query.order_by(Experiment.urn, Experiment.title).all() if not items: items = [] diff --git a/src/mavedb/routers/experiments.py b/src/mavedb/routers/experiments.py index cea7209e..ec0d65e0 100644 --- a/src/mavedb/routers/experiments.py +++ b/src/mavedb/routers/experiments.py @@ -7,6 +7,7 @@ from fastapi import APIRouter, Depends, HTTPException from fastapi.encoders import jsonable_encoder from sqlalchemy.orm import Session +from sqlalchemy import or_ from mavedb import deps from mavedb.lib.authentication import UserData, get_current_user @@ -43,7 +44,7 @@ ) -# TODO: Rewrite this function. +# None of any part calls this function. Feel free to modify it if we need it in the future. @router.get( "/experiments/", status_code=200, @@ -53,7 +54,6 @@ def list_experiments( *, editable: Optional[bool] = None, - q: Optional[str] = None, db: Session = Depends(deps.get_db), user_data: Optional[UserData] = Depends(get_current_user), ) -> list[Experiment]: @@ -61,22 +61,19 @@ def list_experiments( List experiments. """ query = db.query(Experiment) - if q is not None: - save_to_logging_context({"query_string": q}) + if editable: if user_data is None or user_data.user is None: logger.debug(msg="User is anonymous; Cannot list their experiments.", extra=logging_context()) return [] - if len(q) > 0: - logger.debug(msg="Listing experiments for the current user.", extra=logging_context()) - query = query.filter( - Experiment.created_by_id == user_data.user.id - ) # .filter(Experiment.published_date is None) - # else: - # query = query.filter(Experiment.created_by_id == user.id).filter(Experiment.published_date is None) - else: - logger.debug(msg="No query string was provided; Listing all experiments.", extra=logging_context()) + logger.debug(msg="Listing experiments for the current user.", extra=logging_context()) + query = query.filter( + or_( + Experiment.created_by_id == user_data.user.id, + Experiment.contributors.any(Contributor.orcid_id == user_data.user.username) + ) + ) items = query.order_by(Experiment.urn).all() return items diff --git a/src/mavedb/view_models/search.py b/src/mavedb/view_models/search.py index ed7f597c..307c1440 100644 --- a/src/mavedb/view_models/search.py +++ b/src/mavedb/view_models/search.py @@ -11,6 +11,7 @@ class ExperimentsSearch(BaseModel): publication_identifiers: Optional[list[str]] keywords: Optional[list[str]] text: Optional[str] + meta_analysis: Optional[bool] class ScoreSetsSearch(BaseModel): diff --git a/tests/routers/test_experiments.py b/tests/routers/test_experiments.py index 51dde99e..5b864e9c 100644 --- a/tests/routers/test_experiments.py +++ b/tests/routers/test_experiments.py @@ -973,6 +973,58 @@ def test_search_my_experiments(session, client, setup_router_db): assert response.json()[0]["title"] == experiment["title"] +def test_search_meta_analysis_experiment(session, data_provider, client, setup_router_db, data_files): + experiment = create_experiment(client) + score_set = create_seq_score_set_with_variants( + client, session, data_provider, experiment["urn"], data_files / "scores.csv" + ) + + score_set = (client.post(f"/api/v1/score-sets/{score_set['urn']}/publish")).json() + meta_score_set = create_seq_score_set_with_variants( + client, + session, + data_provider, + None, + data_files / "scores.csv", + update={"title": "Test Meta Analysis", "metaAnalyzesScoreSetUrns": [score_set["urn"]]}, + ) + + meta_score_set = (client.post(f"/api/v1/score-sets/{meta_score_set['urn']}/publish")).json() + score_set_refresh = (client.get(f"/api/v1/score-sets/{score_set['urn']}")).json() + search_payload = {"metaAnalysis": True} + response = client.post("/api/v1/me/experiments/search", json=search_payload) + assert response.status_code == 200 + response_data = response.json() + assert any(item["urn"] == meta_score_set["experiment"]["urn"] for item in response_data) + assert all(item["urn"] != score_set_refresh["experiment"]["urn"] for item in response_data) + + +def test_search_exclude_meta_analysis_experiment(session, data_provider, client, setup_router_db, data_files): + experiment = create_experiment(client) + score_set = create_seq_score_set_with_variants( + client, session, data_provider, experiment["urn"], data_files / "scores.csv" + ) + + score_set = (client.post(f"/api/v1/score-sets/{score_set['urn']}/publish")).json() + meta_score_set = create_seq_score_set_with_variants( + client, + session, + data_provider, + None, + data_files / "scores.csv", + update={"title": "Test Meta Analysis", "metaAnalyzesScoreSetUrns": [score_set["urn"]]}, + ) + + meta_score_set = (client.post(f"/api/v1/score-sets/{meta_score_set['urn']}/publish")).json() + score_set_refresh = (client.get(f"/api/v1/score-sets/{score_set['urn']}")).json() + search_payload = {"metaAnalysis": False} + response = client.post("/api/v1/me/experiments/search", json=search_payload) + assert response.status_code == 200 + response_data = response.json() + assert any(item["urn"] == score_set_refresh["experiment"]["urn"] for item in response_data) + assert all(item["urn"] != meta_score_set["experiment"]["urn"] for item in response_data) + + def test_search_score_sets_for_experiments(session, client, setup_router_db, data_files, data_provider): experiment = create_experiment(client) score_set_pub = create_seq_score_set_with_variants(