aboutsummaryrefslogtreecommitdiff
path: root/qc_app/dbinsert.py
blob: 5381fb572284c1e5b572de6ac8b72dde181438df (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
"Handle inserting data into the database"
import os
import json
from functools import reduce

import requests
from redis import Redis
from MySQLdb.cursors import DictCursor
from flask import request, Blueprint, render_template, current_app as app

from . import jobs
from .db_utils import database_connection

dbinsertbp = Blueprint("dbinsert", __name__)

def render_error(error_msg):
    "Render the generic error page"
    return render_template("dbupdate_error.html", error_message=error_msg), 400

def make_menu_items_grouper(grouping_fn=lambda item: item):
    "Build function to be used to group menu items."
    def __grouper__(acc, row):
        grouping = grouping_fn(row[2])
        row_values = (row[0].strip(), row[1].strip())
        if acc.get(grouping) is None:
            return {**acc, grouping: (row_values,)}
        return {**acc, grouping: (acc[grouping] + (row_values,))}
    return __grouper__

def genechips():
    "Retrieve the genechip information from the database"
    def __organise_by_species__(acc, chip):
        species = chip["species_name"]
        if acc.get(species) is None:
            return {**acc, species: (chip,)}
        return {**acc, species: acc[species] + (chip,)}

    with database_connection() as conn:
        with conn.cursor(cursorclass=DictCursor) as cursor:
            cursor.execute(
                "SELECT GeneChip.*, LOWER(Species.Name) AS species_name "
                "FROM GeneChip INNER JOIN Species "
                "ON GeneChip.SpeciesId=Species.SpeciesId")
            return reduce(__organise_by_species__, cursor.fetchall(), {})

    return {}

@dbinsertbp.route("/select-dataset", methods=["POST"])
def select_dataset():
    "Select the dataset to add the file contents against"
    job_id = request.form["job_id"]
    with Redis.from_url(app.config["REDIS_URL"], decode_responses=True) as rconn:
        job = jobs.job(rconn, job_id)
        if job:
            filename = job["filename"]
            filepath = f"{app.config['UPLOAD_FOLDER']}/{filename}"
            if os.path.exists(filepath):
                req = requests.get(
                    "https://genenetwork.org/api3/api/menu/generate/json")
                menu_contents = req.json()
                default_species = "mouse"
                mouse_groups = reduce(
                    make_menu_items_grouper(
                        lambda item: item.strip()[7:].strip()),
                    menu_contents["groups"][default_species], {})
                default_group = "BXD"
                group_types = reduce(
                    make_menu_items_grouper(),
                    menu_contents["types"][default_species][default_group], {})
                default_type = group_types[tuple(group_types)[0]][0][0]
                datasets = menu_contents[
                    "datasets"][default_species][default_group][
                        default_type]

                gchips = genechips()

                return render_template(
                    "select_dataset.html", filename=filename,
                    species=menu_contents["species"],
                    default_species=default_species, groups=mouse_groups,
                    types=group_types, datasets=datasets,
                    menu_contents=json.dumps(menu_contents),
                    genechips_data=json.dumps(gchips),
                    genechips=gchips.get(default_species, []))
            return render_error(f"File '{filename}' no longer exists.")
        return render_error(f"Job '{job_id}' no longer exists.")
    return render_error("Unknown error")


@dbinsertbp.route("/insert_data", methods=["POST"])
def insert_data():
    "Preview the data before triggering entry into the database"
    form = request.form
    filename = form["filename"]
    filepath = f"{app.config['UPLOAD_FOLDER']}/{filename}"
    if os.path.exists(filepath):
        try:
            dataset_id = int(form["dataset"])
            return (f"Would insert data in file '{filepath}' "
                    "into the database with the dataset "
                    f"{dataset_id}")
        except ValueError as ve:
            msg = "::".join(ve.args)
            return render_error(f"Invalid value: {msg}")
    return render_error(f"File '{filename}' no longer exists.")