Skip to content

Commit

Permalink
#60 - Add biosample endpoint
Browse files Browse the repository at this point in the history
- add functions to handle biosample endpoint
- add additional biospecimen filter
  • Loading branch information
vabishaa committed Aug 2, 2024
1 parent 3cc6736 commit 4726ce6
Show file tree
Hide file tree
Showing 13 changed files with 325 additions and 13 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -219,9 +219,9 @@ private List<Resource> transformToResourceListLevelTwo (List<Resource> resourceL
case "https://w3id.org/ejp-rd/vocabulary#VPBeacon2_catalog":
queryTypeList.add(QueryType.BEACON_CATALOG);
break;
/*case "https://w3id.org/ejp-rd/vocabulary#VPBeacon2_biosamples":
queryTypeList.add(QueryType.BEACON_CATALOG)
break;*/
case "https://w3id.org/ejp-rd/vocabulary#VPBeacon2_biosamples":
queryTypeList.add(QueryType.BEACON_BIOSAMPLE);
break;
default:
continue;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,6 @@

public enum QueryType {
BEACON_INDIVIDUALS,
BEACON_CATALOG;
BEACON_BIOSAMPLE,
BEACON_CATALOG
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import org.ejprarediseases.vpdpbackend.resource_monitoring.v1.model.Period;
import org.ejprarediseases.vpdpbackend.resource_monitoring.v1.model.ResourceMonitoringSummary;
import org.ejprarediseases.vpdpbackend.resource_monitoring.v1.model.enums.HttpStatusCategory;
import org.ejprarediseases.vpdpbackend.search.v1.handler.BeaconBiosampleQueryHandler;
import org.ejprarediseases.vpdpbackend.search.v1.handler.BeaconCatalogQueryHandler;
import org.ejprarediseases.vpdpbackend.search.v1.handler.BeaconIndividualsQueryHandler;
import org.ejprarediseases.vpdpbackend.search.v1.model.beacon.request_body.BeaconRequestBody;
Expand All @@ -30,8 +31,7 @@
import java.util.List;
import java.util.concurrent.TimeUnit;

import static org.ejprarediseases.vpdpbackend.resource.v1.model.QueryType.BEACON_CATALOG;
import static org.ejprarediseases.vpdpbackend.resource.v1.model.QueryType.BEACON_INDIVIDUALS;
import static org.ejprarediseases.vpdpbackend.resource.v1.model.QueryType.*;
import static org.ejprarediseases.vpdpbackend.resource_monitoring.v1.model.enums.HttpStatusCategory.*;

@Service
Expand Down Expand Up @@ -76,6 +76,8 @@ void monitorBeaconResource(Resource resource) {
defaultRequestBody = BeaconIndividualsQueryHandler.getDefaultRequestBody();
} else if (resource.getQueryType().contains(BEACON_CATALOG)) {
defaultRequestBody = BeaconCatalogQueryHandler.getDefaultRequestBody();
} else if (resource.getQueryType().contains(BEACON_BIOSAMPLE)) {
defaultRequestBody = BeaconBiosampleQueryHandler.getDefaultRequestBody();
}
long startTime = System.currentTimeMillis();
Monitor monitor = new Monitor();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,14 @@
import org.ejprarediseases.vpdpbackend.resource.v1.ResourceService;
import org.ejprarediseases.vpdpbackend.resource.v1.model.Resource;
import org.ejprarediseases.vpdpbackend.resource.v1.model.ResourceType;
import org.ejprarediseases.vpdpbackend.search.v1.handler.BeaconBiosampleQueryHandler;
import org.ejprarediseases.vpdpbackend.search.v1.handler.BeaconCatalogQueryHandler;
import org.ejprarediseases.vpdpbackend.search.v1.handler.BeaconIndividualsQueryHandler;
import org.ejprarediseases.vpdpbackend.search.v1.model.SearchRequest;
import org.ejprarediseases.vpdpbackend.search.v1.model.SearchResponse;
import org.ejprarediseases.vpdpbackend.search.v1.model.beacon.request_body.BeaconRequestBody;
import org.ejprarediseases.vpdpbackend.search.v1.model.beacon.response_body.BeaconResponseBody;
import org.ejprarediseases.vpdpbackend.search.v1.model.beacon.response_body.BiosampleResponseBody;
import org.ejprarediseases.vpdpbackend.search.v1.model.beacon.response_body.CatalogResponseBody;
import org.ejprarediseases.vpdpbackend.search.v1.model.beacon.response_body.IndividualsResponseBody;
import org.ejprarediseases.vpdpbackend.utils.ObjectIOHandler;
Expand All @@ -19,8 +21,7 @@
import java.io.IOException;
import java.util.NoSuchElementException;

import static org.ejprarediseases.vpdpbackend.resource.v1.model.QueryType.BEACON_CATALOG;
import static org.ejprarediseases.vpdpbackend.resource.v1.model.QueryType.BEACON_INDIVIDUALS;
import static org.ejprarediseases.vpdpbackend.resource.v1.model.QueryType.*;

@Service
@RequiredArgsConstructor
Expand Down Expand Up @@ -48,6 +49,8 @@ public SearchResponse searchForDiseasesByOrphaCode(SearchRequest searchRequest)
}
} else if (resource.getQueryType().contains(BEACON_CATALOG)) {
return handleBeaconCatalogQuery(searchRequest, resource);
} else if (resource.getQueryType().contains(BEACON_BIOSAMPLE)) {
return handleBeaconBiosampleQuery(searchRequest, resource);
}
return new SearchResponse();
}
Expand Down Expand Up @@ -94,6 +97,27 @@ private SearchResponse handleBeaconCatalogQuery(
return new SearchResponse();
}

/**
* Handles the search request for Beacon Individuals query and returns the corresponding search response.
*
* @param searchRequest The search request containing filter criteria.
* @param resource The Beacon resource to query.
* @return The search response containing the retrieved information.
* @throws JsonProcessingException If there is an error during JSON processing.
*/
private SearchResponse handleBeaconBiosampleQuery(
SearchRequest searchRequest, Resource resource) throws JsonProcessingException {
BeaconRequestBody requestBody =
BeaconBiosampleQueryHandler.convertToBeaconRequestBody(searchRequest);
String beaconResponseAsString = BeaconBiosampleQueryHandler.getResponse(resource, requestBody);
if (beaconResponseAsString != null) {
BeaconResponseBody response =
ObjectIOHandler.deserialize(beaconResponseAsString, BiosampleResponseBody.class);
return beaconToSearchResponse(resource, response);
}
return null;
}

/**
* Converts the Beacon query response to a SearchResponse.
*
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@

package org.ejprarediseases.vpdpbackend.search.v1.handler;

import org.ejprarediseases.vpdpbackend.resource.v1.model.Resource;
import org.ejprarediseases.vpdpbackend.search.v1.model.SearchRequest;
import org.ejprarediseases.vpdpbackend.search.v1.model.beacon.enums.BiospecimenType;
import org.ejprarediseases.vpdpbackend.search.v1.model.beacon.request_body.BeaconRequestBody;
import org.ejprarediseases.vpdpbackend.search.v1.model.beacon.request_body.filters.BeaconRequestBodyFilter;
import org.ejprarediseases.vpdpbackend.search.v1.model.beacon.request_body.filters.ontology_filter.BeaconRequestBodyOntologyFilter;
import org.ejprarediseases.vpdpbackend.search.v1.model.beacon.request_body.sections.BeaconRequestBodyMetaSection;
import org.ejprarediseases.vpdpbackend.search.v1.model.beacon.request_body.sections.BeaconRequestBodyQuerySection;
import org.ejprarediseases.vpdpbackend.utils.UserHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.MediaType;
import org.springframework.web.reactive.function.client.WebClient;
import reactor.core.publisher.Mono;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import static org.ejprarediseases.vpdpbackend.search.v1.handler.BeaconFilterHandler.*;

public class BeaconBiosampleQueryHandler {

static Logger logger = LoggerFactory.getLogger(BeaconBiosampleQueryHandler.class);


/**
* Retrieves a response from the specified beacon resource using the provided request body and authorization key.
*
* @param resource The resource to query.
* @param requestBody The request body for the query.
* @return The response string from the resource.
*/

public static String getResponse(Resource resource, BeaconRequestBody requestBody) {
String response;
try {
WebClient client = WebClient.create();
response = client.post()
.uri( resource.getResourceAddress())
.bodyValue(requestBody)
.accept(MediaType.APPLICATION_JSON)
.header("Authorization", UserHandler.getBearerToken())
.retrieve()
.onStatus(httpStatus -> httpStatus.value() == 403,
error -> Mono.error(new RuntimeException("error Body")))
.bodyToMono(String.class)
.block();
} catch (Exception e) {
logger.error("authKey for resource: " + resource.getResourceName() + " is not defined." + e);
return null;
}
return response;
}


/**
* Builds and returns the meta section of a Beacon query request body.
*
* @return The constructed BeaconRequestBodyMetaSection.
*/

public static BeaconRequestBodyMetaSection buildMetaSection() {
BeaconRequestBodyMetaSection metaSection = new BeaconRequestBodyMetaSection();
metaSection.setApiVersion("v0.2");
return metaSection;
}


/**
* Builds and returns the query section of a Beacon query request body.
*
* @param searchRequest The search request containing filter criteria.
* @return The constructed BeaconRequestBodyQuerySection.
*/

private static BeaconRequestBodyQuerySection buildQuerySection(SearchRequest searchRequest) {
BeaconRequestBodyQuerySection querySection = new BeaconRequestBodyQuerySection();
List<BeaconRequestBodyFilter> filters = new ArrayList<>();
filters.add(buildDiseaseFilter(searchRequest.getDiseases()));
if (searchRequest.getSexes() != null && !searchRequest.getSexes().isEmpty()) {
filters.add(buildSexFilter(searchRequest.getSexes()));
}
if (searchRequest.getAgeThisYear() != null && searchRequest.getAgeThisYear().size() == 2) {
filters.add(buildMinAgeFilter(searchRequest.getAgeThisYear().get(0)));
filters.add(buildMaxAgeFilter(searchRequest.getAgeThisYear().get(1)));
}
if (searchRequest.getSymptomOnset() != null && searchRequest.getSymptomOnset().size() == 2) {
filters.add(buildMinSymptomOnsetFilter(searchRequest.getSymptomOnset().get(0)));
filters.add(buildMaxSymptomOnsetFilter(searchRequest.getSymptomOnset().get(1)));
}
if (searchRequest.getAgeAtDiagnosis() != null && searchRequest.getAgeAtDiagnosis().size() == 2) {
filters.add(buildMinAgeAtDiagnosisFilter(searchRequest.getAgeAtDiagnosis().get(0)));
filters.add(buildMaxAgeAtDiagnosisFilter(searchRequest.getAgeAtDiagnosis().get(1)));
}
if (searchRequest.getBiospecimenTypes() != null && !searchRequest.getBiospecimenTypes().isEmpty()) {
filters.add(buildBiospecimenTypeFilter(searchRequest.getBiospecimenTypes()));
}
querySection.setFilters(filters);
return querySection;
}


/**
* Converts a SearchRequest into a BeaconRequestBody.
*
* @param searchRequest The search request containing filter criteria.
* @return The constructed BeaconRequestBody.
*/

public static BeaconRequestBody convertToBeaconRequestBody(SearchRequest searchRequest) {
BeaconRequestBody requestBody = new BeaconRequestBody();
requestBody.setMeta(buildMetaSection());
requestBody.setQuery(buildQuerySection(searchRequest));
return requestBody;
}


/**
* Builds and returns a default query section for Beacon query request body.
*
* @return The constructed BeaconRequestBodyQuerySection.
*/

private static BeaconRequestBodyQuerySection getDefaultQuerySection() {
BeaconRequestBodyQuerySection querySection = new BeaconRequestBodyQuerySection();
List<BeaconRequestBodyFilter> filters = new ArrayList<>();
BeaconRequestBodyOntologyFilter filter = new BeaconRequestBodyOntologyFilter();
List<String> ids = new ArrayList<>();
ids.add("ordo:Orphanet_730");
ids.add("ordo:Orphanet_635");
filter.setId(ids);
filters.add(filter);
//filters.add(buildSexFilter(Arrays.asList(Sex.values())));
filters.add(buildMinAgeFilter(0));
filters.add(buildMaxAgeFilter(100));
filters.add(buildMinSymptomOnsetFilter(0));
filters.add(buildMaxSymptomOnsetFilter(100));
filters.add(buildMinAgeAtDiagnosisFilter(0));
filters.add(buildMaxAgeAtDiagnosisFilter(100));
filters.add(buildBiospecimenTypeFilter(Arrays.asList(BiospecimenType.BLOOD_SPECIMEN)));
querySection.setFilters(filters);
return querySection;
}


/**
* Builds and returns a default request body for Beacon query.
*
* @return The constructed BeaconRequestBody.
*/

public static BeaconRequestBody getDefaultRequestBody() {
BeaconRequestBody requestBody = new BeaconRequestBody();
requestBody.setMeta(buildMetaSection());
requestBody.setQuery(getDefaultQuerySection());
return requestBody;
}


}

Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
package org.ejprarediseases.vpdpbackend.search.v1.handler;

import org.ejprarediseases.vpdpbackend.resource.v1.model.ResourceType;
import org.ejprarediseases.vpdpbackend.search.v1.model.beacon.enums.BeaconFilterOperator;
import org.ejprarediseases.vpdpbackend.search.v1.model.beacon.enums.BeaconFilterType;
import org.ejprarediseases.vpdpbackend.search.v1.model.beacon.enums.Country;
import org.ejprarediseases.vpdpbackend.search.v1.model.beacon.enums.Sex;
import org.ejprarediseases.vpdpbackend.search.v1.model.beacon.enums.*;
import org.ejprarediseases.vpdpbackend.search.v1.model.beacon.request_body.filters.numerical_alphanumerical_filter.BeaconRequestBodyANDFilter;
import org.ejprarediseases.vpdpbackend.search.v1.model.beacon.request_body.filters.numerical_alphanumerical_filter.BeaconRequestBodyORFilter;
import org.ejprarediseases.vpdpbackend.search.v1.model.beacon.request_body.filters.ontology_filter.BeaconRequestBodyOntologyFilter;
Expand Down Expand Up @@ -145,6 +142,18 @@ public static BeaconRequestBodyANDFilter buildMaxAgeAtDiagnosisFilter(int maxAge
return createANDFilter(AGE_AT_DIAGNOSIS, LESS_OR_EQUAL, String.valueOf(maxAgeAtDiagnosis));
}

/**
* Builds an OR filter for the biospecimen type.
*
* @param biospecimenTypes The txpe of biospecimen.
* @return The constructed BeaconRequestBodyANDFilter.
*/
public static BeaconRequestBodyORFilter buildBiospecimenTypeFilter(List<BiospecimenType> biospecimenTypes) {
List<String> biospecimenIds =
biospecimenTypes.stream().map(BeaconFilterHandler::getBiospecimenTypeIdBasedOnApiSpec).toList();
return createORFilter(BIOSPECIMEN_TYPE, EQUAL, biospecimenIds);
}

/**
* Builds an OR filter for the specified list of resource types.
*
Expand Down Expand Up @@ -197,4 +206,34 @@ private static String getResourceTypeIdBasedOnApiSpec(ResourceType type) {
case CATALOG -> "Catalog";
};
}

/**
* Maps a Biospecimen enumeration value to its corresponding API-specific ID.
*
* @param biospecimen The Biospecimen type enumeration value.
* @return The API-specific ID for the given sex.
*/
private static String getBiospecimenTypeIdBasedOnApiSpec(BiospecimenType biospecimen) {
return switch (biospecimen) {
case BLOOD_SPECIMEN -> "OBI_0000655";
case BONE_MARROW -> "OBI_0002512";
case BUFFY_COAT -> "OBIB_0000036";
case PERIPHERAL_BLOOD_MONONUCLEAR_CELL -> "CL_2000001";
case BLOOD_PLASMA_SPECIMEN -> "OBI_0100016";
case BLOOD_SERUM -> "OBI_0100017";
case ASCITES_FLUID -> "UBERON_0007795";
case CEREBROSSPINAL_FLUID -> "OBI_0002502";
case SALVIA -> "OBI_0002507";
case FECES -> "OBI_0002503";
case URINE -> "OBI_0000651";
case SWAB -> "OBI_0002599";
case BODILY_FLUID_SPECIMEN -> "OBI_2000009";
case FFPE_SPECIMEN -> "OBI_1200000";
case FROZEN_SPECIMEN -> "OBI_0000922";
case SPECIMEN_WITH_KNOWN_STORAGE_STATE -> "OBI_0001472";
case DNA_EXTRACT -> "OBI_0001051";
case RNA_EXTRACT -> "OBI_0000880";
case SPECIMEN_FROM_ORGANISM -> "OBI_0001479";
};
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import jakarta.validation.constraints.Size;
import lombok.Data;
import org.ejprarediseases.vpdpbackend.resource.v1.model.ResourceType;
import org.ejprarediseases.vpdpbackend.search.v1.model.beacon.enums.BiospecimenType;
import org.ejprarediseases.vpdpbackend.search.v1.model.beacon.enums.Country;
import org.ejprarediseases.vpdpbackend.search.v1.model.beacon.enums.Sex;

Expand All @@ -22,4 +23,5 @@ public class SearchRequest {
private List<Integer> symptomOnset;
private List<Country> countries;
private List<ResourceType> resourceTypes;
private List<BiospecimenType> biospecimenTypes;
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ public enum BeaconFilterType {
ORGANISATION("organisation"),
RESOURCE_TYPES("resourceTypes"),
COUNTRY("country"),
AGE_AT_DIAGNOSIS("obo:NCIT_C156420");
AGE_AT_DIAGNOSIS("obo:NCIT_C156420"),
BIOSPECIMEN_TYPE("obo:NCIT_C70713");

private final String value;

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package org.ejprarediseases.vpdpbackend.search.v1.model.beacon.enums;

public enum BiospecimenType {
BLOOD_SPECIMEN,
BONE_MARROW,
BUFFY_COAT,
PERIPHERAL_BLOOD_MONONUCLEAR_CELL,
BLOOD_PLASMA_SPECIMEN,
BLOOD_SERUM,
ASCITES_FLUID,
CEREBROSSPINAL_FLUID,
SALVIA,
FECES,
URINE,
SWAB,
BODILY_FLUID_SPECIMEN,
FFPE_SPECIMEN,
FROZEN_SPECIMEN,
SPECIMEN_WITH_KNOWN_STORAGE_STATE,
DNA_EXTRACT,
RNA_EXTRACT,
SPECIMEN_FROM_ORGANISM
}
Loading

0 comments on commit 4726ce6

Please sign in to comment.