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

improve loading times of studies #3350

Merged
merged 5 commits into from
Jan 29, 2024
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
34 changes: 27 additions & 7 deletions qiita_db/study.py
Original file line number Diff line number Diff line change
Expand Up @@ -1175,17 +1175,37 @@ def has_access(self, user, no_public=False):
Whether user has access to study or not
"""
with qdb.sql_connection.TRN:
# if admin or superuser, just return true
# return True if the user is one of the admins
if user.level in {'superuser', 'admin'}:
return True

if no_public:
study_set = user.user_studies | user.shared_studies
else:
study_set = user.user_studies | user.shared_studies | \
self.get_by_status('public')
# if no_public is False then just check if the study is public
# and return True
if not no_public and self.status == 'public':
return True

# let's check if the study belongs to this user or has been
# shared with them
sql = """SELECT EXISTS (
SELECT study_id
FROM qiita.study
JOIN qiita.study_portal USING (study_id)
JOIN qiita.portal_type USING (portal_type_id)
WHERE email = %s AND portal = %s AND study_id = %s
UNION
SELECT study_id
FROM qiita.study_users
JOIN qiita.study_portal USING (study_id)
JOIN qiita.portal_type USING (portal_type_id)
WHERE email = %s AND portal = %s AND study_id = %s
)
"""
qdb.sql_connection.TRN.add(
sql, [user.email, qiita_config.portal, self.id,
user.email, qiita_config.portal, self.id])
result = qdb.sql_connection.TRN.execute_fetchlast()

return self in study_set
return result

def can_edit(self, user):
"""Returns whether the given user can edit the study
Expand Down
94 changes: 57 additions & 37 deletions qiita_pet/handlers/api_proxy/studies.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
from qiita_core.exceptions import IncompetentQiitaDeveloperError
from qiita_core.util import execute_as_transaction
from qiita_core.qiita_settings import r_client
from qiita_db.artifact import Artifact
from qiita_db.sql_connection import TRN
from qiita_db.user import User
from qiita_db.study import Study
from qiita_db.exceptions import QiitaDBColumnError, QiitaDBLookupError
Expand Down Expand Up @@ -114,8 +116,8 @@ def study_get_req(study_id, user_id):
study_info['has_access_to_raw_data'] = study.has_access(
User(user_id), True) or study.public_raw_download

study_info['show_biom_download_button'] = 'BIOM' in [
a.artifact_type for a in study.artifacts()]
study_info['show_biom_download_button'] = len(
study.artifacts(artifact_type='BIOM')) != 0
study_info['show_raw_download_button'] = any([
True for pt in study.prep_templates() if pt.artifact is not None])

Expand Down Expand Up @@ -201,53 +203,71 @@ def study_prep_get_req(study_id, user_id):
access_error = check_access(study_id, user_id)
if access_error:
return access_error
# Can only pass ids over API, so need to instantiate object

study = Study(int(study_id))
prep_info = defaultdict(list)
prep_info = {dtype: [] for dtype in study.data_types}
editable = study.can_edit(User(user_id))
for dtype in study.data_types:
dtype_infos = list()
for prep in study.prep_templates(dtype):
if prep.status != 'public' and not editable:
with TRN:
sql = """SELECT prep_template_id, pt.name as name, data_type,
artifact_id,
creation_timestamp, modification_timestamp, visibility,
(SELECT COUNT(sample_id)
FROM qiita.prep_template_sample
WHERE prep_template_id = spt.prep_template_id)
as total_samples,
(SELECT COUNT(sample_id)
FROM qiita.prep_template_sample
WHERE prep_template_id = spt.prep_template_id
AND ebi_experiment_accession != '')
as ebi_experiment
FROM qiita.study_prep_template spt
LEFT JOIN qiita.prep_template pt USING (prep_template_id)
LEFT JOIN qiita.data_type USING (data_type_id)
LEFT JOIN qiita.artifact USING (artifact_id)
LEFT JOIN qiita.visibility USING (visibility_id)
WHERE study_id = %s
GROUP BY prep_template_id, pt.name, data_type, artifact_id,
creation_timestamp, modification_timestamp,
visibility
ORDER BY creation_timestamp"""

TRN.add(sql, [study_id])
for row in TRN.execute_fetchindex():
row = dict(row)
if row['visibility'] != 'public' and not editable:
continue
start_artifact = prep.artifact
# for those preps that have no artifact
if row['visibility'] is None:
row['visibility'] = 'sandbox'

info = {
'name': prep.name,
'id': prep.id,
'status': prep.status,
'total_samples': len(prep),
'creation_timestamp': prep.creation_timestamp,
'modification_timestamp': prep.modification_timestamp
'name': row['name'],
'id': row['prep_template_id'],
'status': row['visibility'],
'total_samples': row['total_samples'],
'creation_timestamp': row['creation_timestamp'],
'modification_timestamp': row['modification_timestamp'],
'start_artifact': None,
'start_artifact_id': None,
'youngest_artifact': None,
'num_artifact_children': 0,
'youngest_artifact_name': None,
'youngest_artifact_type': None,
'ebi_experiment': row['ebi_experiment']
}
if start_artifact is not None:
youngest_artifact = prep.artifact.youngest_artifact
if row['artifact_id'] is not None:
start_artifact = Artifact(row['artifact_id'])
youngest_artifact = start_artifact.youngest_artifact
info['start_artifact'] = start_artifact.artifact_type
info['start_artifact_id'] = start_artifact.id
info['start_artifact_id'] = row['artifact_id']
info['num_artifact_children'] = len(start_artifact.children)
info['youngest_artifact_name'] = youngest_artifact.name
info['youngest_artifact_type'] = \
youngest_artifact.artifact_type
info['youngest_artifact'] = '%s - %s' % (
youngest_artifact.name, youngest_artifact.artifact_type)
info['ebi_experiment'] = len(
[v for _, v in prep.ebi_experiment_accessions.items()
if v is not None])
else:
info['start_artifact'] = None
info['start_artifact_id'] = None
info['youngest_artifact'] = None
info['num_artifact_children'] = 0
info['youngest_artifact_name'] = None
info['youngest_artifact_type'] = None
info['ebi_experiment'] = 0

dtype_infos.append(info)

# default sort is in ascending order of creation timestamp
sorted_info = sorted(dtype_infos,
key=lambda k: k['creation_timestamp'],
reverse=False)
prep_info[dtype] = sorted_info

prep_info[row['data_type']].append(info)

return {'status': 'success',
'message': '',
Expand Down
5 changes: 2 additions & 3 deletions qiita_pet/handlers/api_proxy/tests/test_studies.py
Original file line number Diff line number Diff line change
Expand Up @@ -229,8 +229,7 @@ def test_study_prep_get_req_failed_EBI(self):

# actual test
obs = study_prep_get_req(study.id, user_email)
temp_info = defaultdict(list)
temp_info['16S'] = [
temp_info = {'16S': [
{"status": 'sandbox',
'name': 'Prep information %d' % pt.id,
'start_artifact': None, 'youngest_artifact': None,
Expand All @@ -241,7 +240,7 @@ def test_study_prep_get_req_failed_EBI(self):
'num_artifact_children': 0,
'youngest_artifact_name': None,
'youngest_artifact_type': None,
'total_samples': 3}]
'total_samples': 3}]}

exp = {
'info': temp_info,
Expand Down
Loading