Skip to content

Commit

Permalink
Merge pull request #48 from TheJacksonLaboratory/G3-210-geneset-db-ge…
Browse files Browse the repository at this point in the history
…t-call-refactoring

G3 210 geneset db get call refactoring
  • Loading branch information
francastell authored Apr 2, 2024
2 parents 19566b4 + 4007e82 commit 8b0680b
Show file tree
Hide file tree
Showing 11 changed files with 825 additions and 220 deletions.
10 changes: 5 additions & 5 deletions poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tool.poetry]
name = "geneweaver-api"
version = "0.4.0a7"
version = "0.4.0a9"
description = "The Geneweaver API"
authors = [
"Alexander Berger <[email protected]>",
Expand Down
93 changes: 88 additions & 5 deletions src/geneweaver/api/controller/genesets.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,13 @@
from tempfile import TemporaryDirectory
from typing import Optional

from fastapi import APIRouter, Depends, HTTPException, Path, Security
from fastapi import APIRouter, Depends, HTTPException, Path, Query, Security
from fastapi.responses import FileResponse
from geneweaver.api import dependencies as deps
from geneweaver.api.schemas.auth import UserInternal
from geneweaver.api.services import geneset as genset_service
from geneweaver.api.services import publications as publication_service
from geneweaver.core.enum import GeneIdentifier
from geneweaver.db import geneset as db_geneset
from geneweaver.core.enum import GeneIdentifier, GenesetTier, Species
from typing_extensions import Annotated

from . import message as api_message
Expand All @@ -25,10 +24,94 @@
def get_visible_genesets(
user: UserInternal = Security(deps.full_user),
cursor: Optional[deps.Cursor] = Depends(deps.cursor),
gs_id: Annotated[
Optional[int],
Query(
format="int64",
minimum=0,
maxiumum=9223372036854775807,
description=api_message.GENESET_ID,
),
] = None,
only_my_genesets: Annotated[
Optional[bool], Query(description=api_message.ONLY_MY_GS)
] = False,
curation_tier: Optional[GenesetTier] = None,
species: Optional[Species] = None,
name: Annotated[Optional[str], Query(description=api_message.NAME)] = None,
abbreviation: Annotated[
Optional[str], Query(description=api_message.ABBREVIATION)
] = None,
publication_id: Annotated[
Optional[int],
Query(
format="int64",
minimum=0,
maxiumum=9223372036854775807,
description=api_message.PUBLICATION_ID,
),
] = None,
pubmed_id: Annotated[
Optional[int],
Query(
format="int64",
minimum=0,
maxiumum=9223372036854775807,
description=api_message.PUBMED_ID,
),
] = None,
gene_id_type: Optional[GeneIdentifier] = None,
search_text: Annotated[
Optional[str], Query(description=api_message.SEARCH_TEXT)
] = None,
with_publication_info: Annotated[
bool, Query(description=api_message.ONLY_MY_GS)
] = True,
limit: Annotated[
Optional[int],
Query(
format="int64",
minimum=0,
maxiumum=1000,
description=api_message.LIMIT,
),
] = 10,
offset: Annotated[
Optional[int],
Query(
format="int64",
minimum=0,
maxiumum=9223372036854775807,
description=api_message.OFFSET,
),
] = None,
) -> dict:
"""Get all visible genesets."""
user_genesets = db_geneset.by_owner_id(cursor, user.id)
return {"genesets": user_genesets}
response = genset_service.get_visible_genesets(
cursor=cursor,
user=user,
gs_id=gs_id,
curation_tier=curation_tier,
species=species,
name=name,
abbreviation=abbreviation,
publication_id=publication_id,
pubmed_id=pubmed_id,
gene_id_type=gene_id_type,
search_text=search_text,
with_publication_info=with_publication_info,
only_my_genesets=only_my_genesets,
limit=limit,
offset=offset,
)

if "error" in response:
if response.get("message") == api_message.ACCESS_FORBIDDEN:
raise HTTPException(status_code=403, detail=api_message.ACCESS_FORBIDDEN)
else:
raise HTTPException(status_code=500, detail=api_message.UNEXPECTED_ERROR)

return response


@router.get("/{geneset_id}")
Expand Down
8 changes: 8 additions & 0 deletions src/geneweaver/api/controller/message.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,11 @@
GENE_PREFERRED = "Whether to search for preferred genes"
LIMIT = "The limit of results to return"
OFFSET = "The offset of results to return"
GENESET_ID = "Geneset ID"
ONLY_MY_GS = "Show only geneset results owned by this user ID"
NAME = "Show only results with this name"
ABBREVIATION = "Show only results with this abbreviation"
PUBLICATION_ID = "Show only results with this publication ID"
PUBMED_ID = "Show only results with this PubMed ID"
SEARCH_TEXT = "Return genesets that match this search text"
WITH_PUBLICATION = "Include publication info in the return"
120 changes: 92 additions & 28 deletions src/geneweaver/api/services/geneset.py
Original file line number Diff line number Diff line change
@@ -1,18 +1,83 @@
"""Service functions for dealing with genesets."""

from typing import Iterable
from typing import Iterable, Optional

from fastapi.logger import logger
from geneweaver.api.controller import message
from geneweaver.api.schemas.auth import User
from geneweaver.core.enum import GeneIdentifier
from geneweaver.core.enum import GeneIdentifier, GenesetTier, Species
from geneweaver.db import gene as db_gene
from geneweaver.db import geneset as db_geneset
from geneweaver.db import geneset_value as db_geneset_value
from geneweaver.db.geneset import is_readable as db_is_readable
from psycopg import Cursor


def get_visible_genesets(
cursor: Cursor,
user: User,
gs_id: Optional[int] = None,
only_my_genesets: Optional[bool] = None,
curation_tier: Optional[GenesetTier] = None,
species: Optional[Species] = None,
name: Optional[str] = None,
abbreviation: Optional[str] = None,
publication_id: Optional[int] = None,
pubmed_id: Optional[int] = None,
gene_id_type: Optional[GeneIdentifier] = None,
search_text: Optional[str] = None,
limit: Optional[int] = None,
offset: Optional[int] = None,
with_publication_info: bool = True,
) -> dict:
"""Get genesets from the database.
:param cursor: A database cursor.
:param gs_id: Show only results with this geneset ID.
:param curation_tier: Show only results of this curation tier.
:param species: Show only results associated with this species.
:param name: Show only results with this name.
:param abbreviation: Show only results with this abbreviation.
:param publication_id: Show only results with this publication ID (internal).
:param pubmed_id: Show only results with this PubMed ID.
:param gene_id_type: Show only results with this gene ID type.
:param search_text: Return genesets that match this search text (using PostgreSQL
full-text search).
:param limit: Limit the number of results.
:param offset: Offset the results.
:param with_publication_info: Include publication info in the return.
"""
try:
if user is None or user.id is None:
return {"error": True, "message": message.ACCESS_FORBIDDEN}

owner_id = None
if only_my_genesets:
owner_id = user.id

results = db_geneset.get(
cursor,
is_readable_by=user.id,
owner_id=owner_id,
gs_id=gs_id,
curation_tier=curation_tier,
species=species,
name=name,
abbreviation=abbreviation,
publication_id=publication_id,
pubmed_id=pubmed_id,
gene_id_type=gene_id_type,
search_text=search_text,
with_publication_info=with_publication_info,
limit=limit,
offset=offset,
)
return {"data": results}

except Exception as err:
logger.error(err)
raise err


def get_geneset_metadata(
cursor: Cursor, geneset_id: int, user: User, include_pub_info: bool = False
) -> dict:
Expand All @@ -25,11 +90,16 @@ def get_geneset_metadata(
@return: dictionary response (geneset).
"""
try:
if not is_geneset_readable_by_user(cursor, geneset_id, user):
if user is None or user.id is None:
return {"error": True, "message": message.ACCESS_FORBIDDEN}

geneset = db_geneset.by_id(cursor, geneset_id, include_pub_info)
return {"geneset": geneset}
results = db_geneset.get(
cursor,
is_readable_by=user.id,
gs_id=geneset_id,
with_publication_info=include_pub_info,
)
return {"geneset": results[0]}

except Exception as err:
logger.error(err)
Expand All @@ -45,10 +115,16 @@ def get_geneset(cursor: Cursor, geneset_id: int, user: User) -> dict:
@return: dictionary response (geneset and genset values).
"""
try:
if not is_geneset_readable_by_user(cursor, geneset_id, user):
if user is None or user.id is None:
return {"error": True, "message": message.ACCESS_FORBIDDEN}

geneset = db_geneset.by_id(cursor, geneset_id)
results = db_geneset.get(
cursor,
is_readable_by=user.id,
gs_id=geneset_id,
with_publication_info=False,
)
geneset = results[0]
geneset_values = db_geneset_value.by_geneset_id(cursor, geneset_id)
return {"geneset": geneset, "geneset_values": geneset_values}

Expand All @@ -69,10 +145,16 @@ def get_geneset_w_gene_id_type(
@return: Dictionary response (geneset identifier, geneset, and genset values).
"""
try:
if not is_geneset_readable_by_user(cursor, geneset_id, user):
if user is None or user.id is None:
return {"error": True, "message": message.ACCESS_FORBIDDEN}

geneset = db_geneset.by_id(cursor, geneset_id)
results = db_geneset.get(
cursor,
is_readable_by=user.id,
gs_id=geneset_id,
with_publication_info=False,
)
geneset = results[0]

mapping_across_species = False
original_gene_id_type = gene_id_type
Expand Down Expand Up @@ -132,21 +214,3 @@ def map_geneset_homology(
except Exception as err:
logger.error(err)
raise err


def is_geneset_readable_by_user(cursor: Cursor, geneset_id: int, user: User) -> bool:
"""Check if the user can read the geneset from DB.
@param cursor: DB cursor object
@param geneset_id: geneset identifier
@param user: GW user
@return: True if geneset is readable by user.
"""
readable: bool = False
try:
readable = db_is_readable(cursor, user.id, geneset_id)
except Exception as err:
logger.error(err)
raise err

return readable
Loading

0 comments on commit 8b0680b

Please sign in to comment.