Skip to content

Commit

Permalink
Merge pull request #56 from TheJacksonLaboratory/G3-280-db-ontology-b…
Browse files Browse the repository at this point in the history
…y-geneset

G3-282 DB implementation ontology by geneset
  • Loading branch information
francastell authored Jul 8, 2024
2 parents e132aa3 + e48e2f2 commit fe35301
Show file tree
Hide file tree
Showing 8 changed files with 220 additions and 1 deletion.
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-db"
version = "0.5.0a8"
version = "0.5.0a9"
description = "Database Interaction Services for GeneWeaver"
authors = ["Jax Computational Sciences <[email protected]>"]
readme = "README.md"
Expand Down
32 changes: 32 additions & 0 deletions src/geneweaver/db/aio/ontology.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
"""Database code for interacting with ontologies."""

from typing import List, Optional

from geneweaver.db.query import ontology as ontology_query
from psycopg import AsyncCursor
from psycopg.rows import Row


async def by_geneset(
cursor: AsyncCursor,
geneset_id: int,
limit: Optional[int] = None,
offset: Optional[int] = None,
) -> List[Row]:
"""Get geneset ontologies from the database.
:param cursor: An async database cursor.
:param geneset_id: Show only results for this geneset identifier
:param limit: Limit the number of results.
:param offset: Offset the results.
@return:
"""
await cursor.execute(
*ontology_query.by_geneset(
geneset_id=geneset_id,
limit=limit,
offset=offset,
)
)

return await cursor.fetchall()
32 changes: 32 additions & 0 deletions src/geneweaver/db/ontology.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
"""Database code for interacting with ontologies."""

from typing import List, Optional

from geneweaver.db.query import ontology as ontology_query
from psycopg import Cursor
from psycopg.rows import Row


def by_geneset(
cursor: Cursor,
geneset_id: int,
limit: Optional[int] = None,
offset: Optional[int] = None,
) -> List[Row]:
"""Get geneset ontologies from the database.
:param cursor: A database cursor.
:param geneset_id: Show only results for this geneset identifier
:param limit: Limit the number of results.
:param offset: Offset the results.
@return:
"""
cursor.execute(
*ontology_query.by_geneset(
geneset_id=geneset_id,
limit=limit,
offset=offset,
)
)

return cursor.fetchall()
43 changes: 43 additions & 0 deletions src/geneweaver/db/query/ontology.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
"""Query generation functions for ontologies."""

from typing import Optional, Tuple

from geneweaver.db.utils import limit_and_offset
from psycopg.sql import SQL, Composed


def by_geneset(
geneset_id: int,
limit: Optional[int] = None,
offset: Optional[int] = None,
) -> Tuple[Composed, dict]:
"""Create a psycopg query to get genesets ontologies.
:param geneset_id: The geneset identifier to search for.
:param limit: The limit of results to return.
:param offset: The offset of results to return.
:return: A query (and params) that can be executed on a cursor.
"""
query = SQL("SELECT")
query_fields = (
SQL("geneset.gs_id AS geneset_id")
+ SQL(",ontology.ont_ref_id AS ontology_id")
+ SQL(",ontology.ont_name AS name")
+ SQL(",ontology.ont_description as description")
+ SQL(",ontologydb.ontdb_name as source_ontology")
)
query = (
query
+ query_fields
+ SQL("FROM geneset")
+ SQL("JOIN geneset_ontology ON geneset.gs_id = geneset_ontology.gs_id")
+ SQL("JOIN ontology ON geneset_ontology.ont_id = ontology.ont_id")
+ SQL("JOIN ontologydb ON ontology.ontdb_id = ontologydb.ontdb_id")
+ SQL("WHERE geneset.gs_id = %(gs_id)s")
).join(" ")
params = {"gs_id": geneset_id}

query = limit_and_offset(query, limit, offset).join(" ")

return query, params
1 change: 1 addition & 0 deletions tests/unit/ontology/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
"""Tests for the ontology db module."""
87 changes: 87 additions & 0 deletions tests/unit/ontology/test_by_geneset.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
"""Test the ontology.by_geneset db function."""

import pytest
from geneweaver.db.aio.ontology import (
by_geneset as async_get_ontology_by_gs_id,
)
from geneweaver.db.ontology import by_geneset

from tests.unit.testing_utils import (
async_create_execute_raises_error_test,
async_create_fetchall_raises_error_test,
create_execute_raises_error_test,
create_fetchall_raises_error_test,
)


@pytest.mark.parametrize("geneset_id", [12345])
@pytest.mark.parametrize("limit", [None, 1, 10])
@pytest.mark.parametrize("offset", [None, 1, 10])
@pytest.mark.parametrize(
"ontologies_resp",
[
["a", "b", "c"],
["d", "e", "f"],
["g", "h", "i"],
],
)
def test_get_ontology_by_gs_id(geneset_id, limit, offset, ontologies_resp, cursor):
"""Test the ontology.get_ontology_by_gs_id function."""
cursor.fetchall.return_value = ontologies_resp

result = by_geneset(
cursor=cursor,
geneset_id=geneset_id,
limit=limit,
offset=offset,
)
assert result == ontologies_resp
assert cursor.execute.call_count == 1
assert cursor.fetchone.call_count == 0
assert cursor.fetchall.call_count == 1


@pytest.mark.parametrize("geneset_id", [12345])
@pytest.mark.parametrize("limit", [None, 1, 10])
@pytest.mark.parametrize("offset", [None, 1, 10])
@pytest.mark.parametrize(
"ontologies_resp",
[
["a", "b", "c"],
["d", "e", "f"],
["g", "h", "i"],
],
)
async def test_async_get_ontology_by_gs_id(
geneset_id,
limit,
offset,
ontologies_resp,
async_cursor,
):
"""Test the async ontology.get_ontology_by_gs_id function."""
async_cursor.fetchall.return_value = ontologies_resp

result = await async_get_ontology_by_gs_id(
cursor=async_cursor,
geneset_id=geneset_id,
limit=limit,
offset=offset,
)
assert result == ontologies_resp
assert async_cursor.execute.call_count == 1
assert async_cursor.fetchone.call_count == 0
assert async_cursor.fetchall.call_count == 1


test_get_execute_raises_error = create_execute_raises_error_test(by_geneset, 1)

test_get_fetchall_raises_error = create_fetchall_raises_error_test(by_geneset, 1)

test_get_execute_raises_error = async_create_execute_raises_error_test(
async_get_ontology_by_gs_id, 1
)

test_async_get_fetchall_raises_error = async_create_fetchall_raises_error_test(
async_get_ontology_by_gs_id, 1
)
1 change: 1 addition & 0 deletions tests/unit/query/ontology/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
"""Test the sql generation code for ontologies."""
23 changes: 23 additions & 0 deletions tests/unit/query/ontology/test_by_geneset.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
"""Test the ontology.by_geneset query generation function."""

import pytest
from geneweaver.db.query.ontology import by_geneset


@pytest.mark.parametrize("geneset_id", [12345])
@pytest.mark.parametrize("limit", [None, 1, 10])
@pytest.mark.parametrize("offset", [None, 1, 10])
def test_all_kwargs(geneset_id, limit, offset):
"""Test all the kwarg combinations for query.ontology.by_geneset."""
query, params = by_geneset(
geneset_id=geneset_id,
limit=limit,
offset=offset,
)

assert "gs_id" in params

str_query = str(query)

for key in ["ontology_id", "name", "description", "source_ontology"]:
assert key in str_query

0 comments on commit fe35301

Please sign in to comment.