Skip to content

Commit 3990409

Browse files
committed
GAIA publications collection initial commit.
1 parent 13da704 commit 3990409

File tree

3 files changed

+135
-18
lines changed

3 files changed

+135
-18
lines changed

api/models/gaia.py

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,3 +22,41 @@ class Aliases(db.Model):
2222
id: db.Mapped[int] = db.mapped_column(db.Integer, nullable=False, primary_key=True)
2323
genes_id: db.Mapped[int] = db.mapped_column(ForeignKey("genes.id", ondelete="CASCADE"), nullable=False)
2424
alias: db.Mapped[str] = db.mapped_column(db.String(256), nullable=False)
25+
26+
27+
class PublicationFigures(db.Model):
28+
__bind_key__ = "gaia"
29+
__tablename__ = "publication_figures"
30+
31+
id: db.Mapped[int] = db.mapped_column(db.Integer, nullable=False, primary_key=True)
32+
title: db.Mapped[str] = db.mapped_column(db.String(512), nullable=True)
33+
abstract: db.Mapped[str] = db.mapped_column(db.Text, nullable=True)
34+
children: db.Mapped[List["PubIds"]] = relationship()
35+
children: db.Mapped[List["Figures"]] = relationship()
36+
37+
38+
class PubIds(db.Model):
39+
__bind_key__ = "gaia"
40+
__tablename__ = "pub_ids"
41+
42+
id: db.Mapped[int] = db.mapped_column(db.Integer, nullable=False, primary_key=True)
43+
publication_figures_id: db.Mapped[int] = db.mapped_column(db.Integer, nullable=False)
44+
publication_figures_id: db.Mapped[int] = db.mapped_column(
45+
ForeignKey("publication_figures.id", ondelete="CASCADE"), nullable=False
46+
)
47+
pubmed: db.Mapped[str] = db.mapped_column(db.String(16), nullable=True)
48+
pmc: db.Mapped[str] = db.mapped_column(db.String(16), nullable=True)
49+
50+
51+
class Figures(db.Model):
52+
__bind_key__ = "gaia"
53+
__tablename__ = "figures"
54+
55+
id: db.Mapped[int] = db.mapped_column(db.Integer, nullable=False, primary_key=True)
56+
publication_figures_id: db.Mapped[int] = db.mapped_column(db.Integer, nullable=False)
57+
publication_figures_id: db.Mapped[int] = db.mapped_column(
58+
ForeignKey("publication_figures.id", ondelete="CASCADE"), nullable=False
59+
)
60+
img_name: db.Mapped[str] = db.mapped_column(db.String(64), nullable=False)
61+
caption: db.Mapped[str] = db.mapped_column(db.Text, nullable=True)
62+
img_url: db.Mapped[str] = db.mapped_column(db.String(256), nullable=True)

api/resources/gaia.py

Lines changed: 81 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,41 @@
1-
from flask_restx import Namespace, Resource
1+
from flask import request
2+
from flask_restx import Namespace, Resource, fields
23
from markupsafe import escape
34
from api import db
45
from api.utils.bar_utils import BARUtils
5-
from api.models.gaia import Genes, Aliases
6+
from api.models.gaia import Genes, Aliases, PubIds, Figures
67
from sqlalchemy import func, or_
8+
from marshmallow import Schema, ValidationError, fields as marshmallow_fields
79
import json
810

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

13+
parser = gaia.parser()
14+
parser.add_argument(
15+
"terms",
16+
type=list,
17+
action="append",
18+
required=True,
19+
help="Publication IDs",
20+
default=["32492426", "32550561"],
21+
)
22+
23+
publication_request_fields = gaia.model(
24+
"Publications",
25+
{
26+
"pubmeds": fields.List(
27+
required=True,
28+
example=["32492426", "32550561"],
29+
cls_or_instance=fields.String,
30+
),
31+
},
32+
)
33+
34+
35+
# Validation is done in a different way to keep things simple
36+
class PublicationSchema(Schema):
37+
pubmeds = marshmallow_fields.List(cls_or_instance=marshmallow_fields.String)
38+
1139

1240
@gaia.route("/aliases/<string:identifier>")
1341
class GaiaAliases(Resource):
@@ -78,3 +106,54 @@ def get(self, identifier=""):
78106

79107
else:
80108
return BARUtils.error_exit("Invalid identifier"), 400
109+
110+
111+
@gaia.route("/publication_figures")
112+
class GaiaPublicationFigures(Resource):
113+
@gaia.expect(publication_request_fields)
114+
def post(self):
115+
json_data = request.get_json()
116+
data = {}
117+
118+
# Validate json
119+
try:
120+
json_data = PublicationSchema().load(json_data)
121+
except ValidationError as err:
122+
return BARUtils.error_exit(err.messages), 400
123+
124+
pubmeds = json_data["pubmeds"]
125+
126+
# Check if pubmed ids are valide
127+
for pubmed in pubmeds:
128+
if not BARUtils.is_integer(pubmed):
129+
return BARUtils.error_exit("Invalid Pubmed ID"), 400
130+
131+
# It is valid. Continue
132+
data = []
133+
134+
# Left join is important in case aliases do not exist for the given locus / geneid
135+
query = (
136+
db.select(Figures.img_name, Figures.caption, Figures.img_url, PubIds.pubmed, PubIds.pmc)
137+
.select_from(Figures)
138+
.join(PubIds, PubIds.publication_figures_id == Figures.publication_figures_id)
139+
.filter(PubIds.pubmed.in_(pubmeds))
140+
)
141+
142+
rows = db.session.execute(query).fetchall()
143+
144+
# Just output the rows for now, we will format later
145+
if rows and len(rows) > 0:
146+
for row in rows:
147+
record = {
148+
"img_name": row.img_name,
149+
"caption": row.caption,
150+
"img_url": row.img_url,
151+
"pubmed": row.pubmed,
152+
"pmc": row.pmc,
153+
}
154+
155+
# Add the record to data
156+
data.append(record)
157+
158+
# Return final data
159+
return BARUtils.success_exit(data)

requirements.txt

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,23 @@
11
aniso8601==10.0.1
22
async-timeout==5.0.1
33
attrs==25.4.0
4-
black==25.9.0
4+
black==25.12.0
55
blinker==1.9.0
66
cachelib==0.13.0
7-
certifi==2025.10.5
7+
certifi==2025.11.12
88
charset-normalizer==3.4.4
9-
click==8.3.0
10-
coverage==7.11.0
11-
Deprecated==1.2.18
9+
click==8.3.1
10+
coverage==7.13.0
11+
Deprecated==1.3.1
1212
flake8==7.3.0
1313
Flask==3.1.2
1414
Flask-Caching==2.3.1
1515
flask-cors==6.0.1
16-
Flask-Limiter==4.0.0
16+
Flask-Limiter==4.1.1
1717
flask-marshmallow==1.3.0
1818
flask-restx==1.3.2
1919
Flask-SQLAlchemy==3.1.1
20-
greenlet==3.2.4
20+
greenlet==3.3.0
2121
idna==3.11
2222
importlib_resources==6.5.2
2323
iniconfig==2.3.0
@@ -28,34 +28,34 @@ jsonschema-specifications==2025.9.1
2828
limits==5.6.0
2929
markdown-it-py==4.0.0
3030
MarkupSafe==3.0.3
31-
marshmallow==4.0.1
31+
marshmallow==4.1.1
3232
mccabe==0.7.0
3333
mdurl==0.1.2
3434
mypy_extensions==1.1.0
3535
mysqlclient==2.2.7
3636
ordered-set==4.1.0
3737
packaging==25.0
3838
pathspec==0.12.1
39-
platformdirs==4.5.0
39+
platformdirs==4.5.1
4040
pluggy==1.6.0
4141
pycodestyle==2.14.0
4242
pyflakes==3.4.0
4343
Pygments==2.19.2
4444
pyrsistent==0.20.0
45-
pytest==8.4.2
45+
pytest==9.0.2
4646
python-dateutil==2.9.0.post0
47-
pytokens==0.2.0
47+
pytokens==0.3.0
4848
pytz==2025.2
49-
redis==7.0.1
49+
redis==7.1.0
5050
referencing==0.37.0
5151
requests==2.32.5
5252
rich==14.2.0
53-
rpds-py==0.28.0
53+
rpds-py==0.30.0
5454
setuptools==80.9.0
5555
six==1.17.0
5656
SQLAlchemy==2.0.44
5757
typing_extensions==4.15.0
58-
urllib3==2.5.0
59-
Werkzeug==3.1.3
58+
urllib3==2.6.1
59+
Werkzeug==3.1.4
6060
wheel==0.45.1
61-
wrapt==1.17.3
61+
wrapt==2.0.1

0 commit comments

Comments
 (0)