Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 38 additions & 0 deletions api/models/gaia.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,41 @@ class Aliases(db.Model):
id: db.Mapped[int] = db.mapped_column(db.Integer, nullable=False, primary_key=True)
genes_id: db.Mapped[int] = db.mapped_column(ForeignKey("genes.id", ondelete="CASCADE"), nullable=False)
alias: db.Mapped[str] = db.mapped_column(db.String(256), nullable=False)


class PublicationFigures(db.Model):
__bind_key__ = "gaia"
__tablename__ = "publication_figures"

id: db.Mapped[int] = db.mapped_column(db.Integer, nullable=False, primary_key=True)
title: db.Mapped[str] = db.mapped_column(db.String(512), nullable=True)
abstract: db.Mapped[str] = db.mapped_column(db.Text, nullable=True)
children: db.Mapped[List["PubIds"]] = relationship()
children: db.Mapped[List["Figures"]] = relationship()


class PubIds(db.Model):
__bind_key__ = "gaia"
__tablename__ = "pub_ids"

id: db.Mapped[int] = db.mapped_column(db.Integer, nullable=False, primary_key=True)
publication_figures_id: db.Mapped[int] = db.mapped_column(db.Integer, nullable=False)
publication_figures_id: db.Mapped[int] = db.mapped_column(
ForeignKey("publication_figures.id", ondelete="CASCADE"), nullable=False
)
pubmed: db.Mapped[str] = db.mapped_column(db.String(16), nullable=True)
pmc: db.Mapped[str] = db.mapped_column(db.String(16), nullable=True)


class Figures(db.Model):
__bind_key__ = "gaia"
__tablename__ = "figures"

id: db.Mapped[int] = db.mapped_column(db.Integer, nullable=False, primary_key=True)
publication_figures_id: db.Mapped[int] = db.mapped_column(db.Integer, nullable=False)
publication_figures_id: db.Mapped[int] = db.mapped_column(
ForeignKey("publication_figures.id", ondelete="CASCADE"), nullable=False
)
img_name: db.Mapped[str] = db.mapped_column(db.String(64), nullable=False)
caption: db.Mapped[str] = db.mapped_column(db.Text, nullable=True)
img_url: db.Mapped[str] = db.mapped_column(db.String(256), nullable=True)
100 changes: 98 additions & 2 deletions api/resources/gaia.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,41 @@
from flask_restx import Namespace, Resource
from flask import request
from flask_restx import Namespace, Resource, fields
from markupsafe import escape
from api import db
from api.utils.bar_utils import BARUtils
from api.models.gaia import Genes, Aliases
from api.models.gaia import Genes, Aliases, PubIds, Figures
from sqlalchemy import func, or_
from marshmallow import Schema, ValidationError, fields as marshmallow_fields
import json

gaia = Namespace("Gaia", description="Gaia", path="/gaia")

parser = gaia.parser()
parser.add_argument(
"terms",
type=list,
action="append",
required=True,
help="Publication IDs",
default=["32492426", "32550561"],
)

publication_request_fields = gaia.model(
"Publications",
{
"pubmeds": fields.List(
required=True,
example=["32492426", "32550561"],
cls_or_instance=fields.String,
),
},
)


# Validation is done in a different way to keep things simple
class PublicationSchema(Schema):
pubmeds = marshmallow_fields.List(cls_or_instance=marshmallow_fields.String)


@gaia.route("/aliases/<string:identifier>")
class GaiaAliases(Resource):
Expand Down Expand Up @@ -78,3 +106,71 @@ def get(self, identifier=""):

else:
return BARUtils.error_exit("Invalid identifier"), 400


@gaia.route("/publication_figures")
class GaiaPublicationFigures(Resource):
@gaia.expect(publication_request_fields)
def post(self):
json_data = request.get_json()

# Validate json
try:
json_data = PublicationSchema().load(json_data)
except ValidationError as err:
return BARUtils.error_exit(err.messages), 400

pubmeds = json_data["pubmeds"]

# Check if pubmed ids are valid
for pubmed in pubmeds:
if not BARUtils.is_integer(pubmed):
return BARUtils.error_exit("Invalid Pubmed ID"), 400

# It is valid. Continue
data = []

# Left join is important in case aliases do not exist for the given locus / geneid
query = (
db.select(Figures.img_name, Figures.caption, Figures.img_url, PubIds.pubmed, PubIds.pmc)
.select_from(Figures)
.join(PubIds, PubIds.publication_figures_id == Figures.publication_figures_id)
.filter(PubIds.pubmed.in_(pubmeds))
.order_by(PubIds.pubmed.desc())
)

rows = db.session.execute(query).fetchall()

record = {}

if rows and len(rows) > 0:
for row in rows:

# Check if record has an id. If it doesn't, this is first row.
if "id" in record:
# Check if this is a new pubmed id
if record["id"]["pubmed"] != row.pubmed:
# new record. Add old now to data and create a new record
data.append(record)
record = {}

# Check if figures exists, if not add it.
if record.get("figures") is None:
# Create a new figures record
record["figures"] = []

# Now append figure to the record
figure = {"img_name": row.img_name, "caption": row.caption, "img_url": row.img_url}
record["figures"].append(figure)

# Now add the id. If it exists don't add
if record.get("id") is None:
record["id"] = {}
record["id"]["pubmed"] = row.pubmed
record["id"]["pmc"] = row.pmc

# The last record
data.append(record)

# Return final data
return BARUtils.success_exit(data)
32 changes: 16 additions & 16 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,23 +1,23 @@
aniso8601==10.0.1
async-timeout==5.0.1
attrs==25.4.0
black==25.9.0
black==25.12.0
blinker==1.9.0
cachelib==0.13.0
certifi==2025.10.5
certifi==2025.11.12
charset-normalizer==3.4.4
click==8.3.0
coverage==7.11.0
Deprecated==1.2.18
click==8.3.1
coverage==7.13.0
Deprecated==1.3.1
flake8==7.3.0
Flask==3.1.2
Flask-Caching==2.3.1
flask-cors==6.0.1
Flask-Limiter==4.0.0
Flask-Limiter==4.1.1
flask-marshmallow==1.3.0
flask-restx==1.3.2
Flask-SQLAlchemy==3.1.1
greenlet==3.2.4
greenlet==3.3.0
idna==3.11
importlib_resources==6.5.2
iniconfig==2.3.0
Expand All @@ -28,34 +28,34 @@ jsonschema-specifications==2025.9.1
limits==5.6.0
markdown-it-py==4.0.0
MarkupSafe==3.0.3
marshmallow==4.0.1
marshmallow==4.1.1
mccabe==0.7.0
mdurl==0.1.2
mypy_extensions==1.1.0
mysqlclient==2.2.7
ordered-set==4.1.0
packaging==25.0
pathspec==0.12.1
platformdirs==4.5.0
platformdirs==4.5.1
pluggy==1.6.0
pycodestyle==2.14.0
pyflakes==3.4.0
Pygments==2.19.2
pyrsistent==0.20.0
pytest==8.4.2
pytest==9.0.2
python-dateutil==2.9.0.post0
pytokens==0.2.0
pytokens==0.3.0
pytz==2025.2
redis==7.0.1
redis==7.1.0
referencing==0.37.0
requests==2.32.5
rich==14.2.0
rpds-py==0.28.0
rpds-py==0.30.0
setuptools==80.9.0
six==1.17.0
SQLAlchemy==2.0.44
typing_extensions==4.15.0
urllib3==2.5.0
Werkzeug==3.1.3
urllib3==2.6.1
Werkzeug==3.1.4
wheel==0.45.1
wrapt==1.17.3
wrapt==2.0.1
Loading