-
Notifications
You must be signed in to change notification settings - Fork 80
DataTables load using AJAX, Search by metadata on studies page #1006
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
Changes from 15 commits
616300f
d595016
90313f7
fb5eef3
1ffd4bc
16257c4
9ccc098
abeb46f
259bec2
b8472a8
cf6ca77
cd4f66e
ce4d334
58b28cd
1872555
4b7ffcf
515f0f6
21b17d6
04f87f4
ee4c9e2
ef16d18
fbe7c74
e0f22d0
0df6666
5085c35
ea69fe8
3a12f87
25ae8f2
e01e224
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -98,12 +98,13 @@ | |
from __future__ import division | ||
from future.utils import viewitems | ||
from copy import deepcopy | ||
from itertools import chain | ||
|
||
from qiita_core.exceptions import IncompetentQiitaDeveloperError | ||
from .base import QiitaStatusObject, QiitaObject | ||
from .exceptions import (QiitaDBStatusError, QiitaDBColumnError, QiitaDBError) | ||
from .util import (check_required_columns, check_table_cols, convert_to_id, | ||
get_environmental_packages) | ||
get_environmental_packages, get_table_cols) | ||
from .sql_connection import SQLConnectionHandler | ||
|
||
|
||
|
@@ -143,6 +144,11 @@ class Study(QiitaStatusObject): | |
_table = "study" | ||
# The following columns are considered not part of the study info | ||
_non_info = {"email", "study_status_id", "study_title"} | ||
# The following tables are considered part of info | ||
_info_cols = frozenset(chain( | ||
get_table_cols('study'), get_table_cols('study_status'), | ||
get_table_cols('timeseries_type'), get_table_cols('portal_type'), | ||
get_table_cols('study_pmid'))) | ||
|
||
def _lock_non_sandbox(self, conn_handler): | ||
"""Raises QiitaDBStatusError if study is non-sandboxed""" | ||
|
@@ -175,6 +181,28 @@ def get_by_status(cls, status): | |
"ss.status = %s".format(cls._table)) | ||
return {x[0] for x in conn_handler.execute_fetchall(sql, (status, ))} | ||
|
||
@classmethod | ||
def get_info(cls, study_ids, info_cols=None): | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you add a docstring? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The name of this function is a bit confusing to me; I actually had to go and check how the instance method is called. Can we change it to something like |
||
if info_cols is None: | ||
info_cols = [s for s in cls._info_cols] | ||
else: | ||
info_cols = deepcopy(info_cols) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It doesn't seem like there's any need for this variable to be copied, am I missing something? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. remnant of old way of doing something, thanks for catching. |
||
|
||
search_cols = ",".join(sorted(cls._info_cols.intersection(info_cols))) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Might raise a warning if the user requests information columns that are not in |
||
|
||
sql = """SELECT {0} FROM ( | ||
qiita.study | ||
JOIN qiita.study_status USING (study_status_id) | ||
JOIN qiita.timeseries_type USING (timeseries_type_id) | ||
JOIN qiita.portal_type USING (portal_type_id) | ||
LEFT JOIN (SELECT study_id, array_agg(pmid ORDER BY study_id) as | ||
pmid FROM qiita.study_pmid GROUP BY study_id) sp USING (study_id) | ||
) WHERE study_id in ({1})""".format( | ||
search_cols, ','.join(str(s) for s in study_ids)) | ||
|
||
conn_handler = SQLConnectionHandler() | ||
return conn_handler.execute_fetchall(sql) | ||
|
||
@classmethod | ||
def exists(cls, study_title): | ||
"""Check if a study exists based on study_title, which is unique | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
-- March 19, 2015 | ||
-- Rename columns to be more descirptive and allow easier joins | ||
ALTER TABLE qiita.study_status RENAME COLUMN description TO status_description; | ||
ALTER TABLE qiita.portal_type RENAME COLUMN description TO portal_description; | ||
ALTER TABLE qiita.investigation RENAME COLUMN description TO investigation_description; | ||
ALTER TABLE qiita.investigation RENAME COLUMN name TO investigation_name; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm surprised that these changes don't affect more code, but I haven't had a chance to look closely There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. None of these columns are actually used anywhere, since investigations and portal types aren't implemented yet, and study_status description is never touched, only the status value itself. |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -177,6 +177,49 @@ def _make_sandbox(self): | |
# make studies private | ||
self.conn_handler.execute("UPDATE qiita.study SET study_status_id = 1") | ||
|
||
def test_get_info(self): | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you add another test in which there is more than 1 study? You can use the study create to add a new study (note that if the creation fails, we already have tests for the create function that will fail....) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's tested indirectly in the study handler tests, but if you want one here I can do it. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Something on qiita_db cannot be safely tested through something on qiita_pet... please add test here. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You added a new test but it is still testing 1 single study, could you test multiple? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. line 232 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Got it, I was reading how it works wrongly, thanks. |
||
obs = Study.get_info([1]) | ||
self.assertEqual(len(obs), 1) | ||
exp_keys = ['mixs_compliant', 'metadata_complete', 'reprocess', | ||
'timeseries_type', 'portal_description', 'emp_person_id', | ||
'number_samples_promised', 'funding', 'vamps_id', | ||
'first_contact', 'principal_investigator_id', | ||
'study_status_id', 'timeseries_type_id', 'study_abstract', | ||
'pmid', 'study_alias', 'status', 'spatial_series', | ||
'study_description', 'portal', 'status_description', | ||
'portal_type_id', 'intervention_type', 'email', 'study_id', | ||
'most_recent_contact', 'lab_person_id', 'study_title', | ||
'number_samples_collected'] | ||
exp_vals = [ | ||
['123456', '7891011'], 'test@foo.bar', 2, | ||
datetime(2014, 5, 19, 16, 10), None, 'None', 1, True, True, | ||
datetime(2014, 5, 19, 16, 11), 27, 27, 'EMP', 'EMP portal', 2, 3, | ||
False, False, 'private', | ||
'Only owner and shared users can see this study', | ||
'This is a preliminary study to examine the microbiota associated ' | ||
'with the Cannabis plant. Soils samples from the bulk soil, soil ' | ||
'associated with the roots, and the rhizosphere were extracted and' | ||
' the DNA sequenced. Roots from three independent plants of ' | ||
'different strains were examined. These roots were obtained ' | ||
'November 11, 2011 from plants that had been harvested in the ' | ||
'summer. Future studies will attempt to analyze the soils and ' | ||
'rhizospheres from the same location at different time points in ' | ||
'the plant lifecycle.', 'Cannabis Soils', 'Analysis of the ' | ||
'Cannabis Plant Microbiome', 1, 3, 'Identification of the ' | ||
'Microbiomes for Cannabis Soils', 'None', 1, None] | ||
self.assertItemsEqual(obs[0].keys(), exp_keys) | ||
self.assertItemsEqual(obs[0], exp_vals) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why not define your expected keys/values as an actual dict and use |
||
|
||
exp_keys = ['metadata_complete', 'reprocess', 'timeseries_type', | ||
'portal_description', 'pmid', 'study_title'] | ||
obs = Study.get_info([1], exp_keys) | ||
self.assertEqual(len(obs), 1) | ||
exp_vals = [ | ||
True, 'EMP portal', False, 'Identification of the Microbiomes for ' | ||
'Cannabis Soils', 'None', ['123456', '7891011']] | ||
self.assertItemsEqual(obs[0].keys(), exp_keys) | ||
self.assertItemsEqual(obs[0], exp_vals) | ||
|
||
def test_has_access_public(self): | ||
self.study.status = 'public' | ||
self.assertTrue(self.study.has_access(User("demo@microbio.me"))) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
None of this information will change at runtime, right? If so, I think this could be cached in
qiita_pet.__init__
and done onceThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ah! nevermind, it is at the static scope of the object. it is done once