Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(iatlas): migrate iAtlas GraphQL API to the monorepo #2559

Closed
wants to merge 2 commits into from
Closed
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
6 changes: 6 additions & 0 deletions apps/iatlas/api/.dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
**/*.md
.gitignore
.git/
Dockerfile
no_commit/
scripts/
Empty file added apps/iatlas/api/.env.example
Empty file.
26 changes: 26 additions & 0 deletions apps/iatlas/api/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# git
# used by git-log to rewrite usernames
.mailmap
git-genui.config.json

# produced vignettes
vignettes/*.html
vignettes/*.pdf

# OAuth2 token, see https://github.com/hadley/httr/releases/tag/v0.3
.httr-oauth

# Generated files
.DS_Store

# Visual Studio Code
.vscode
*.code-workspace

# VIM
*.swp
*.swo

docker/
no_commit/
scripts/__pycache__
1 change: 1 addition & 0 deletions apps/iatlas/api/.python-version
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
3.10.13
8 changes: 8 additions & 0 deletions apps/iatlas/api/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# Start with a bare Alpine Linux to keep the container image small
FROM tiangolo/uwsgi-nginx-flask:python3.8

WORKDIR /app
COPY . /app

# Install the PyPI dependencies using pip
RUN pip3 install --no-cache-dir -r requirements.txt
55 changes: 55 additions & 0 deletions apps/iatlas/api/api/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import logging
from json import loads
from datetime import datetime as dt
from flask import Flask, request
from config import get_config
from .extensions import db, logs


def create_app(test=False):
config = get_config(test=test)
app = Flask(__name__)
app.config.from_object(config)

register_extensions(app)

# Blueprint registration here.
from .main import bp as main_bp
app.register_blueprint(main_bp)

@app.after_request
def after_request(response):
""" Logging after every POST request only if it isn't an introspection query. """
json_data = request.get_json()
is_introspection_query = bool(json_data and json_data.get(
'operationName', False) == 'IntrospectionQuery')
if request.method == 'POST' and not is_introspection_query:
logger = logging.getLogger('api.access')
logger.info(
'%s [%s] %s %s %s %s %s %s %s',
request.remote_addr,
dt.utcnow().strftime('%d/%b/%Y:%H:%M:%S.%f')[:-3],
request.method,
request.path,
request.scheme,
response.status,
response.content_length,
request.referrer,
request.user_agent,
)
return response

@ app.teardown_appcontext
def shutdown_session(exception=None):
db.session.remove()

return app


def register_extensions(app):
db.init_app(app)
logs.init_app(app)
return None


from api import db_models
27 changes: 27 additions & 0 deletions apps/iatlas/api/api/database/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
from .cohort_queries import *
from .cohort_to_feature_queries import *
from .cohort_to_gene_queries import *
from .cohort_to_mutation_queries import *
from .cohort_to_sample_queries import *
from .cohort_to_tag_queries import *
from .dataset_queries import *
from .dataset_to_sample_queries import *
from .dataset_to_tag_queries import *
from .edge_queries import *
from .feature_queries import *
from .feature_to_sample_queries import *
from .gene_queries import *
from .gene_to_sample_queries import *
from .gene_to_gene_set_queries import *
from .mutation_queries import *
from .node_queries import *
from .patient_queries import *
from .publication_queries import *
from .publication_to_gene_to_gene_set_queries import *
from .result_queries import *
from .sample_to_mutation_queries import *
from .sample_to_tag_queries import *
from .snp_queries import *
from .tag_queries import *
from .tag_to_publication_queries import *
from .tag_to_tag_queries import *
16 changes: 16 additions & 0 deletions apps/iatlas/api/api/database/cohort_queries.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
from sqlalchemy import orm
from api import db
from .database_helpers import build_general_query
from api.db_models import Cohort

cohort_related_fields = ['data_set', 'tag',
'samples', 'features', 'mutations', 'genes']

cohort_core_fields = ['id', 'name', 'dataset_id', 'tag_id']


def return_cohort_query(*args):
return build_general_query(
Cohort, args=args,
accepted_option_args=cohort_related_fields,
accepted_query_args=cohort_core_fields)
16 changes: 16 additions & 0 deletions apps/iatlas/api/api/database/cohort_to_feature_queries.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
from sqlalchemy import orm
from api import db
from api.db_models import CohortToFeature
from .database_helpers import build_general_query

accepted_cohort_to_feature_option_args = ['cohort', 'feature']

accepted_cohort_to_feature_query_args = [
'cohort_id', 'feature_id']


def return_cohort_to_feature_query(*args):
return build_general_query(
CohortToFeature, args=args,
accepted_option_args=accepted_cohort_to_feature_option_args,
accepted_query_args=accepted_cohort_to_feature_query_args)
16 changes: 16 additions & 0 deletions apps/iatlas/api/api/database/cohort_to_gene_queries.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
from sqlalchemy import orm
from api import db
from api.db_models import CohortToGene
from .database_helpers import build_general_query

accepted_cohort_to_gene_option_args = ['cohort', 'gene']

accepted_cohort_to_gene_query_args = [
'cohort_id', 'gene_id']


def return_cohort_to_gene_query(*args):
return build_general_query(
CohortToGene, args=args,
accepted_option_args=accepted_cohort_to_gene_option_args,
accepted_query_args=accepted_cohort_to_gene_query_args)
16 changes: 16 additions & 0 deletions apps/iatlas/api/api/database/cohort_to_mutation_queries.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
from sqlalchemy import orm
from api import db
from api.db_models import CohortToMutation
from .database_helpers import build_general_query

accepted_cohort_to_mutation_option_args = ['cohort', 'mutation']

accepted_cohort_to_mutation_query_args = [
'cohort_id', 'mutation_id']


def return_cohort_to_mutation_query(*args):
return build_general_query(
CohortToMutation, args=args,
accepted_option_args=accepted_cohort_to_mutation_option_args,
accepted_query_args=accepted_cohort_to_mutation_query_args)
16 changes: 16 additions & 0 deletions apps/iatlas/api/api/database/cohort_to_sample_queries.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
from sqlalchemy import orm
from api import db
from api.db_models import CohortToSample
from .database_helpers import build_general_query

accepted_cohort_to_sample_option_args = ['cohort', 'sample']

accepted_cohort_to_sample_query_args = [
'cohort_id', 'sample_id' 'tag_id']


def return_cohort_to_sample_query(*args):
return build_general_query(
CohortToSample, args=args,
accepted_option_args=accepted_cohort_to_sample_option_args,
accepted_query_args=accepted_cohort_to_sample_query_args)
16 changes: 16 additions & 0 deletions apps/iatlas/api/api/database/cohort_to_tag_queries.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
from sqlalchemy import orm
from api import db
from api.db_models import CohortToTag
from .database_helpers import build_general_query

accepted_cohort_to_tag_option_args = ['cohort', 'tag']

accepted_cohort_to_tag_query_args = [
'cohort_id', 'tag_id']


def return_cohort_to_tag_query(*args):
return build_general_query(
CohortToTag, args=args,
accepted_option_args=accepted_cohort_to_tag_option_args,
accepted_query_args=accepted_cohort_to_tag_query_args)
68 changes: 68 additions & 0 deletions apps/iatlas/api/api/database/database_helpers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
from sqlalchemy import orm
from sqlalchemy.ext.compiler import compiles
from sqlalchemy.sql.expression import ClauseElement, Executable
from sqlalchemy.sql import Select
from sqlalchemy.dialects import postgresql

from api import db

general_core_fields = ['id', 'name']


def build_general_query(model, args=[], accepted_option_args=[], accepted_query_args=[]):
option_args = build_option_args(*args, accepted_args=accepted_option_args)
query_args = build_query_args(
model, *args, accepted_args=accepted_query_args)
query = db.session.query(*query_args)
if option_args:
# If option args are found, the whole model must be queried.
return db.session.query(model).options(*option_args)
return db.session.query(*query_args)


def build_option_args(*args, accepted_args=[]):
option_args = []
for arg in args:
if arg in accepted_args:
option_args.append(orm.joinedload(arg))
return option_args


def build_query_args(model, *argv, accepted_args=[]):
query_args = []
for arg in argv:
if arg in accepted_args:
query_args.append(getattr(model, arg))
if not query_args:
return [model]
return query_args

def temp_table(name, query):
e = db.session.get_bind()
c = e.connect()
trans = c.begin()
c.execute(CreateTableAs(name, query))
trans.commit()
return c

class CreateTableAs(Select):
def __init__(self, name, query, *arg, **kw):
super(CreateTableAs, self).__init__(None, *arg, **kw)
self.name = name
self.query = query

@compiles(CreateTableAs)
def _create_table_as(element, compiler, **kw):
text = element.query.statement.compile(dialect=postgresql.dialect(), compile_kwargs={'literal_binds': True})
query = "CREATE TEMP TABLE %s AS %s" % (
element.name,
text
)
return query

def execute_sql(query, conn=None):
if conn:
return conn.execute(query)
engine = db.session.get_bind()
with engine.connect() as conn:
return conn.execute(query)
16 changes: 16 additions & 0 deletions apps/iatlas/api/api/database/dataset_queries.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
from sqlalchemy import orm
from api import db
from api.db_models import Dataset
from .database_helpers import general_core_fields, build_general_query

dataset_related_fields = [
'dataset_sample_assoc', 'dataset_tag_assoc', 'samples', 'tags']

dataset_core_fields = ['id', 'name', 'display', 'dataset_type']


def return_dataset_query(*args, model=Dataset):
return build_general_query(
model, args=args,
accepted_option_args=dataset_related_fields,
accepted_query_args=dataset_core_fields)
15 changes: 15 additions & 0 deletions apps/iatlas/api/api/database/dataset_to_sample_queries.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
from sqlalchemy import orm
from api import db
from api.db_models import DatasetToSample
from .database_helpers import build_general_query

related_fields = ['data_sets', 'samples']

core_fields = ['dataset_id', 'sample_id']


def return_dataset_to_sample_query(*args):
return build_general_query(
DatasetToSample, args=args,
accepted_option_args=related_fields,
accepted_query_args=core_fields)
15 changes: 15 additions & 0 deletions apps/iatlas/api/api/database/dataset_to_tag_queries.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
from sqlalchemy import orm
from api import db
from api.db_models import DatasetToTag
from .database_helpers import build_general_query

related_fields = ['data_sets', 'tags']

core_fields = ['dataset_id', 'tag_id']


def return_dataset_to_tag_query(*args):
return build_general_query(
DatasetToTag, args=args,
accepted_option_args=related_fields,
accepted_query_args=core_fields)
15 changes: 15 additions & 0 deletions apps/iatlas/api/api/database/edge_queries.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
from sqlalchemy import orm
from api import db
from api.db_models import Edge
from .database_helpers import build_general_query

accepted_option_args = ['node_1', 'node_2']

accepted_query_args = ['id', 'node_1_id',
'node_2_id', 'name', 'label', 'score']


def return_edge_query(*args):
return build_general_query(
Edge, args=args, accepted_option_args=accepted_option_args,
accepted_query_args=accepted_query_args)
17 changes: 17 additions & 0 deletions apps/iatlas/api/api/database/feature_queries.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
from sqlalchemy import orm
from api import db
from api.db_models import Feature
from .database_helpers import general_core_fields, build_general_query

feature_related_fields = [
'copy_number_results', 'driver_results',
'feature_sample_assoc', 'samples']

feature_core_fields = [
'id', 'name', 'display', 'order', 'unit', 'feature_class', 'method_tag', 'germline_category', 'germline_module']

def return_feature_query(*args):
return build_general_query(
Feature, args=args,
accepted_option_args=feature_related_fields,
accepted_query_args=feature_core_fields)
Loading
Loading