Skip to content

Commit

Permalink
Merge pull request #336 from bento-platform/patch/leaner-queries
Browse files Browse the repository at this point in the history
Patch/leaner queries
  • Loading branch information
ppillot committed Sep 9, 2022
2 parents dc8193d + 612833b commit ff172dc
Show file tree
Hide file tree
Showing 4 changed files with 45 additions and 2 deletions.
5 changes: 5 additions & 0 deletions chord_metadata_service/chord/views_search.py
Original file line number Diff line number Diff line change
Expand Up @@ -276,6 +276,11 @@ def get_field_lookup(field):

def get_values_list(queryset, options):
field_lookup = get_field_lookup(options.get("field", []))

# Filter out null values because these values will be used to make joins,
# or fetch back some records.
queryset = queryset.filter(**{f"{field_lookup}__isnull": False})

if "add_field" in options:
# Return a list of the dict, with the additional field and the field
# used for the value. It will require further processing to get a list
Expand Down
7 changes: 5 additions & 2 deletions chord_metadata_service/patients/api_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
PhenopacketsRenderer,
IndividualCSVRenderer,
ARGORenderer,
IndividualBentoSearchRenderer,
)
from chord_metadata_service.restapi.pagination import LargeResultsSetPagination, BatchResultsSetPagination
from chord_metadata_service.restapi.utils import (
Expand All @@ -44,7 +45,8 @@ class IndividualViewSet(viewsets.ModelViewSet):
serializer_class = IndividualSerializer
pagination_class = LargeResultsSetPagination
renderer_classes = (*api_settings.DEFAULT_RENDERER_CLASSES, FHIRRenderer,
PhenopacketsRenderer, IndividualCSVRenderer, ARGORenderer)
PhenopacketsRenderer, IndividualCSVRenderer, ARGORenderer,
IndividualBentoSearchRenderer)
filter_backends = [DjangoFilterBackend, filters.OrderingFilter]
filter_class = IndividualFilter
ordering_fields = ["id"]
Expand All @@ -68,7 +70,8 @@ class IndividualBatchViewSet(BatchViewSet):
serializer_class = IndividualSerializer
pagination_class = BatchResultsSetPagination
renderer_classes = (*api_settings.DEFAULT_RENDERER_CLASSES, FHIRRenderer,
PhenopacketsRenderer, IndividualCSVRenderer, ARGORenderer)
PhenopacketsRenderer, IndividualCSVRenderer, ARGORenderer,
IndividualBentoSearchRenderer)
# Override to infer the renderer based on a `format` argument from the POST request body
content_negotiation_class = FormatInPostContentNegotiation

Expand Down
7 changes: 7 additions & 0 deletions chord_metadata_service/patients/tests/test_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,13 @@ def test_search(self):
response_obj_2 = get_resp_2.json()
self.assertEqual(len(response_obj_2['results']), 2)

def test_search_bento_search_format(self):
get_resp_1 = self.client.get('/api/individuals?search=P49Y&format=bento_search_result')
self.assertEqual(get_resp_1.status_code, status.HTTP_200_OK)
response_obj_1 = get_resp_1.json()
self.assertEqual(len(response_obj_1['results']), 1)
self.assertEqual(len(response_obj_1['results'][0]), 4) # 4 fields in the bento search response


# Note: the next five tests use the same setUp method. Initially they were
# all combined in the same class. But this caused bugs with regard to unavailable
Expand Down
28 changes: 28 additions & 0 deletions chord_metadata_service/restapi/api_renderers.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
from .jsonld_utils import dataset_to_jsonld
from .utils import parse_onset

OUTPUT_FORMAT_BENTO_SEARCH_RESULT = "bento_search_result"

register('json-ld', Serializer, 'rdflib_jsonld.serializer', 'JsonLDSerializer')

Expand Down Expand Up @@ -165,3 +166,30 @@ def render(self, data, media_type=None, renderer_context=None):
dict_writer.writerow(headers)
dict_writer.writerows(individuals)
return response


class IndividualBentoSearchRenderer(JSONRenderer):
media_type = 'application/json'
format = OUTPUT_FORMAT_BENTO_SEARCH_RESULT

def render(self, data, media_type=None, renderer_context=None):
individuals = []
for individual in data.get('results', []):
ind_obj = {
'subject_id': individual['id'],
'alternate_ids': individual.get('alternate_ids', []), # may be NULL
'biosamples': [],
'num_experiments': 0
}
if 'phenopackets' in individual:
ids = []
for p in individual['phenopackets']:
if 'biosamples' in p:
for biosample in p['biosamples']:
ids.append(biosample['id'])
if 'experiments' in biosample:
ind_obj['num_experiments'] += len(biosample['experiments'])
ind_obj['biosamples'] = ids
individuals.append(ind_obj)
data['results'] = individuals
return super(IndividualBentoSearchRenderer, self).render(data, self.media_type, renderer_context)

0 comments on commit ff172dc

Please sign in to comment.