Skip to content

Commit 4d0d8bf

Browse files
authored
improve loading times of studies (qiita-spots#3350)
* improve loading times of studies * self.status == 'public' * prep_info * add extra case for not no_public * improving study_prep_get_req
1 parent 379caa5 commit 4d0d8bf

File tree

3 files changed

+86
-47
lines changed

3 files changed

+86
-47
lines changed

qiita_db/study.py

Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1175,17 +1175,37 @@ def has_access(self, user, no_public=False):
11751175
Whether user has access to study or not
11761176
"""
11771177
with qdb.sql_connection.TRN:
1178-
# if admin or superuser, just return true
1178+
# return True if the user is one of the admins
11791179
if user.level in {'superuser', 'admin'}:
11801180
return True
11811181

1182-
if no_public:
1183-
study_set = user.user_studies | user.shared_studies
1184-
else:
1185-
study_set = user.user_studies | user.shared_studies | \
1186-
self.get_by_status('public')
1182+
# if no_public is False then just check if the study is public
1183+
# and return True
1184+
if not no_public and self.status == 'public':
1185+
return True
1186+
1187+
# let's check if the study belongs to this user or has been
1188+
# shared with them
1189+
sql = """SELECT EXISTS (
1190+
SELECT study_id
1191+
FROM qiita.study
1192+
JOIN qiita.study_portal USING (study_id)
1193+
JOIN qiita.portal_type USING (portal_type_id)
1194+
WHERE email = %s AND portal = %s AND study_id = %s
1195+
UNION
1196+
SELECT study_id
1197+
FROM qiita.study_users
1198+
JOIN qiita.study_portal USING (study_id)
1199+
JOIN qiita.portal_type USING (portal_type_id)
1200+
WHERE email = %s AND portal = %s AND study_id = %s
1201+
)
1202+
"""
1203+
qdb.sql_connection.TRN.add(
1204+
sql, [user.email, qiita_config.portal, self.id,
1205+
user.email, qiita_config.portal, self.id])
1206+
result = qdb.sql_connection.TRN.execute_fetchlast()
11871207

1188-
return self in study_set
1208+
return result
11891209

11901210
def can_edit(self, user):
11911211
"""Returns whether the given user can edit the study

qiita_pet/handlers/api_proxy/studies.py

Lines changed: 57 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111
from qiita_core.exceptions import IncompetentQiitaDeveloperError
1212
from qiita_core.util import execute_as_transaction
1313
from qiita_core.qiita_settings import r_client
14+
from qiita_db.artifact import Artifact
15+
from qiita_db.sql_connection import TRN
1416
from qiita_db.user import User
1517
from qiita_db.study import Study
1618
from qiita_db.exceptions import QiitaDBColumnError, QiitaDBLookupError
@@ -114,8 +116,8 @@ def study_get_req(study_id, user_id):
114116
study_info['has_access_to_raw_data'] = study.has_access(
115117
User(user_id), True) or study.public_raw_download
116118

117-
study_info['show_biom_download_button'] = 'BIOM' in [
118-
a.artifact_type for a in study.artifacts()]
119+
study_info['show_biom_download_button'] = len(
120+
study.artifacts(artifact_type='BIOM')) != 0
119121
study_info['show_raw_download_button'] = any([
120122
True for pt in study.prep_templates() if pt.artifact is not None])
121123

@@ -201,53 +203,71 @@ def study_prep_get_req(study_id, user_id):
201203
access_error = check_access(study_id, user_id)
202204
if access_error:
203205
return access_error
204-
# Can only pass ids over API, so need to instantiate object
206+
205207
study = Study(int(study_id))
206-
prep_info = defaultdict(list)
208+
prep_info = {dtype: [] for dtype in study.data_types}
207209
editable = study.can_edit(User(user_id))
208-
for dtype in study.data_types:
209-
dtype_infos = list()
210-
for prep in study.prep_templates(dtype):
211-
if prep.status != 'public' and not editable:
210+
with TRN:
211+
sql = """SELECT prep_template_id, pt.name as name, data_type,
212+
artifact_id,
213+
creation_timestamp, modification_timestamp, visibility,
214+
(SELECT COUNT(sample_id)
215+
FROM qiita.prep_template_sample
216+
WHERE prep_template_id = spt.prep_template_id)
217+
as total_samples,
218+
(SELECT COUNT(sample_id)
219+
FROM qiita.prep_template_sample
220+
WHERE prep_template_id = spt.prep_template_id
221+
AND ebi_experiment_accession != '')
222+
as ebi_experiment
223+
FROM qiita.study_prep_template spt
224+
LEFT JOIN qiita.prep_template pt USING (prep_template_id)
225+
LEFT JOIN qiita.data_type USING (data_type_id)
226+
LEFT JOIN qiita.artifact USING (artifact_id)
227+
LEFT JOIN qiita.visibility USING (visibility_id)
228+
WHERE study_id = %s
229+
GROUP BY prep_template_id, pt.name, data_type, artifact_id,
230+
creation_timestamp, modification_timestamp,
231+
visibility
232+
ORDER BY creation_timestamp"""
233+
234+
TRN.add(sql, [study_id])
235+
for row in TRN.execute_fetchindex():
236+
row = dict(row)
237+
if row['visibility'] != 'public' and not editable:
212238
continue
213-
start_artifact = prep.artifact
239+
# for those preps that have no artifact
240+
if row['visibility'] is None:
241+
row['visibility'] = 'sandbox'
242+
214243
info = {
215-
'name': prep.name,
216-
'id': prep.id,
217-
'status': prep.status,
218-
'total_samples': len(prep),
219-
'creation_timestamp': prep.creation_timestamp,
220-
'modification_timestamp': prep.modification_timestamp
244+
'name': row['name'],
245+
'id': row['prep_template_id'],
246+
'status': row['visibility'],
247+
'total_samples': row['total_samples'],
248+
'creation_timestamp': row['creation_timestamp'],
249+
'modification_timestamp': row['modification_timestamp'],
250+
'start_artifact': None,
251+
'start_artifact_id': None,
252+
'youngest_artifact': None,
253+
'num_artifact_children': 0,
254+
'youngest_artifact_name': None,
255+
'youngest_artifact_type': None,
256+
'ebi_experiment': row['ebi_experiment']
221257
}
222-
if start_artifact is not None:
223-
youngest_artifact = prep.artifact.youngest_artifact
258+
if row['artifact_id'] is not None:
259+
start_artifact = Artifact(row['artifact_id'])
260+
youngest_artifact = start_artifact.youngest_artifact
224261
info['start_artifact'] = start_artifact.artifact_type
225-
info['start_artifact_id'] = start_artifact.id
262+
info['start_artifact_id'] = row['artifact_id']
226263
info['num_artifact_children'] = len(start_artifact.children)
227264
info['youngest_artifact_name'] = youngest_artifact.name
228265
info['youngest_artifact_type'] = \
229266
youngest_artifact.artifact_type
230267
info['youngest_artifact'] = '%s - %s' % (
231268
youngest_artifact.name, youngest_artifact.artifact_type)
232-
info['ebi_experiment'] = len(
233-
[v for _, v in prep.ebi_experiment_accessions.items()
234-
if v is not None])
235-
else:
236-
info['start_artifact'] = None
237-
info['start_artifact_id'] = None
238-
info['youngest_artifact'] = None
239-
info['num_artifact_children'] = 0
240-
info['youngest_artifact_name'] = None
241-
info['youngest_artifact_type'] = None
242-
info['ebi_experiment'] = 0
243-
244-
dtype_infos.append(info)
245-
246-
# default sort is in ascending order of creation timestamp
247-
sorted_info = sorted(dtype_infos,
248-
key=lambda k: k['creation_timestamp'],
249-
reverse=False)
250-
prep_info[dtype] = sorted_info
269+
270+
prep_info[row['data_type']].append(info)
251271

252272
return {'status': 'success',
253273
'message': '',

qiita_pet/handlers/api_proxy/tests/test_studies.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -229,8 +229,7 @@ def test_study_prep_get_req_failed_EBI(self):
229229

230230
# actual test
231231
obs = study_prep_get_req(study.id, user_email)
232-
temp_info = defaultdict(list)
233-
temp_info['16S'] = [
232+
temp_info = {'16S': [
234233
{"status": 'sandbox',
235234
'name': 'Prep information %d' % pt.id,
236235
'start_artifact': None, 'youngest_artifact': None,
@@ -241,7 +240,7 @@ def test_study_prep_get_req_failed_EBI(self):
241240
'num_artifact_children': 0,
242241
'youngest_artifact_name': None,
243242
'youngest_artifact_type': None,
244-
'total_samples': 3}]
243+
'total_samples': 3}]}
245244

246245
exp = {
247246
'info': temp_info,

0 commit comments

Comments
 (0)