Skip to content
Merged
15 changes: 14 additions & 1 deletion src/mavedb/lib/experiments.py
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -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 = []
Expand Down
23 changes: 10 additions & 13 deletions src/mavedb/routers/experiments.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -43,7 +44,7 @@
)


# TODO: Rewrite this function.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lets retain this function-- I think it still has utility for just listing all experiments.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure. I'll modify it so that we don't need to send the weird q to it.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it is ok to just leave it as is for this PR so we can get it released. We can just handle it at some point later-- it isn't hurting anything right now.

# 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,
Expand All @@ -53,30 +54,26 @@
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]:
"""
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
Expand Down
1 change: 1 addition & 0 deletions src/mavedb/view_models/search.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Expand Down
52 changes: 52 additions & 0 deletions tests/routers/test_experiments.py
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down
Loading