diff --git a/src/main/java/org/cbioportal/application/rest/mapper/CancerStudyMetadataMapper.java b/src/main/java/org/cbioportal/application/rest/mapper/CancerStudyMetadataMapper.java index cbf1467d815..fac977590ab 100644 --- a/src/main/java/org/cbioportal/application/rest/mapper/CancerStudyMetadataMapper.java +++ b/src/main/java/org/cbioportal/application/rest/mapper/CancerStudyMetadataMapper.java @@ -1,7 +1,7 @@ package org.cbioportal.application.rest.mapper; import org.cbioportal.application.rest.response.CancerStudyMetadataDTO; -import org.cbioportal.cancerstudy.CancerStudyMetadata; +import org.cbioportal.domain.cancerstudy.CancerStudyMetadata; import org.mapstruct.Mapper; import org.mapstruct.Mapping; import org.mapstruct.factory.Mappers; diff --git a/src/main/java/org/cbioportal/application/rest/mapper/SampleMapper.java b/src/main/java/org/cbioportal/application/rest/mapper/SampleMapper.java new file mode 100644 index 00000000000..786ea9e13c1 --- /dev/null +++ b/src/main/java/org/cbioportal/application/rest/mapper/SampleMapper.java @@ -0,0 +1,25 @@ +package org.cbioportal.application.rest.mapper; + +import org.cbioportal.application.rest.response.SampleDTO; +import org.cbioportal.legacy.utils.Encoder; +import org.cbioportal.domain.sample.Sample; +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; +import org.mapstruct.factory.Mappers; + +import java.util.List; + +@Mapper( imports = Encoder.class) +public interface SampleMapper { + SampleMapper INSTANCE = Mappers.getMapper(SampleMapper.class); + + @Mapping(target = "patientId", source = "patientStableId") + @Mapping(target = "sampleId", source = "stableId") + @Mapping(target = "studyId", source = "cancerStudyIdentifier") + @Mapping(target = "uniqueSampleKey", expression = "java( Encoder.calculateBase64(sample.stableId()," + + "sample.cancerStudyIdentifier()) )") + @Mapping(target = "uniquePatientKey", expression = "java( Encoder.calculateBase64(sample.patientStableId(), " + + "sample.cancerStudyIdentifier()) )") + SampleDTO toSampleDTO(Sample sample); + List toDtos(List samples); +} diff --git a/src/main/java/org/cbioportal/application/rest/request/StudyViewFilterDTO.java b/src/main/java/org/cbioportal/application/rest/request/StudyViewFilterDTO.java new file mode 100644 index 00000000000..623d8cd4deb --- /dev/null +++ b/src/main/java/org/cbioportal/application/rest/request/StudyViewFilterDTO.java @@ -0,0 +1,239 @@ +package org.cbioportal.application.rest.request; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonInclude.Include; +import jakarta.validation.Valid; +import jakarta.validation.constraints.AssertTrue; +import jakarta.validation.constraints.Size; +import org.cbioportal.legacy.model.AlterationFilter; +import org.cbioportal.legacy.model.GeneFilter; +import org.cbioportal.legacy.model.StudyViewStructuralVariantFilter; +import org.cbioportal.legacy.web.parameter.ClinicalDataFilter; +import org.cbioportal.legacy.web.parameter.DataFilter; +import org.cbioportal.legacy.web.parameter.GenericAssayDataFilter; +import org.cbioportal.legacy.web.parameter.GenomicDataFilter; +import org.cbioportal.legacy.web.parameter.MutationDataFilter; +import org.cbioportal.legacy.web.parameter.SampleIdentifier; +import org.cbioportal.legacy.web.parameter.filter.AndedPatientTreatmentFilters; +import org.cbioportal.legacy.web.parameter.filter.AndedSampleTreatmentFilters; + +import java.util.List; +import java.util.Objects; + +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonInclude(Include.NON_NULL) +public class StudyViewFilterDTO { + + @Size(min = 1) + private List sampleIdentifiers; + @Size(min = 1) + private List studyIds; + private List clinicalDataFilters; + private List geneFilters; + @Valid + private List structuralVariantFilters; + private AndedSampleTreatmentFilters sampleTreatmentFilters; + private AndedSampleTreatmentFilters sampleTreatmentGroupFilters; + private AndedSampleTreatmentFilters sampleTreatmentTargetFilters; + private AndedPatientTreatmentFilters patientTreatmentFilters; + private AndedPatientTreatmentFilters patientTreatmentGroupFilters; + private AndedPatientTreatmentFilters patientTreatmentTargetFilters; + private List> genomicProfiles; + private List genomicDataFilters; + private List genericAssayDataFilters; + private List> caseLists; + private List customDataFilters; + private AlterationFilter alterationFilter; + private List clinicalEventFilters; + private List mutationDataFilters; + + @AssertTrue + private boolean isEitherSampleIdentifiersOrStudyIdsPresent() { + return sampleIdentifiers != null ^ studyIds != null; + } + + @AssertTrue + private boolean isEitherValueOrRangePresentInClinicalDataIntervalFilters() { + return validateDataFilters(clinicalDataFilters); + } + + @AssertTrue + private boolean isEitherValueOrRangePresentInGenomicDataIntervalFilters() { + return validateDataFilters(genomicDataFilters); + } + + @AssertTrue + private boolean isEitherValueOrRangePresentInGenericAssayDataIntervalFilters() { + return validateDataFilters(genericAssayDataFilters); + } + + @AssertTrue + private boolean isEitherValueOrRangePresentInCustomDataFilters() { + return validateDataFilters(customDataFilters); + } + + private boolean validateDataFilters(List dataFilters) { + long invalidCount = 0; + + if (dataFilters != null) { + invalidCount = dataFilters.stream() + .flatMap(f -> f.getValues().stream()) + .filter(Objects::nonNull) + .filter(v -> v.getValue() != null == (v.getStart() != null || v.getEnd() != null)) + .count(); + } + + return invalidCount == 0; + } + + public List getSampleIdentifiers() { + return sampleIdentifiers; + } + + public void setSampleIdentifiers(List sampleIdentifiers) { + this.sampleIdentifiers = sampleIdentifiers; + } + + public List getStudyIds() { + return studyIds; + } + + public void setStudyIds(List studyIds) { + this.studyIds = studyIds; + } + + public List getClinicalDataFilters() { + return clinicalDataFilters; + } + + public void setClinicalDataFilters(List clinicalDataFilters) { + this.clinicalDataFilters = clinicalDataFilters; + } + + public List getGeneFilters() { + return geneFilters; + } + + public void setGeneFilters(List geneFilters) { + this.geneFilters = geneFilters; + } + + public List getStructuralVariantFilters() { + return structuralVariantFilters; + } + + public void setStructuralVariantFilters(List structuralVariantFilters) { + this.structuralVariantFilters = (structuralVariantFilters != null) ? structuralVariantFilters : List.of(); + } + + public List> getGenomicProfiles() { + return genomicProfiles; + } + + public void setGenomicProfiles(List> genomicProfiles) { + this.genomicProfiles = genomicProfiles; + } + + public List getGenomicDataFilters() { + return genomicDataFilters; + } + + public void setGenomicDataFilters(List genomicDataFilters) { + this.genomicDataFilters = genomicDataFilters; + } + + public AndedSampleTreatmentFilters getSampleTreatmentFilters() { + return sampleTreatmentFilters; + } + + public void setSampleTreatmentFilters(AndedSampleTreatmentFilters sampleTreatmentFilters) { + this.sampleTreatmentFilters = sampleTreatmentFilters; + } + + public AndedPatientTreatmentFilters getPatientTreatmentFilters() { + return patientTreatmentFilters; + } + + public void setPatientTreatmentFilters(AndedPatientTreatmentFilters patientTreatmentFilters) { + this.patientTreatmentFilters = patientTreatmentFilters; + } + + public List> getCaseLists() { + return caseLists; + } + + public void setCaseLists(List> caseLists) { + this.caseLists = caseLists; + } + + public List getGenericAssayDataFilters() { + return genericAssayDataFilters; + } + + public void setGenericAssayDataFilters(List genericAssayDataFilters) { + this.genericAssayDataFilters = genericAssayDataFilters; + } + + public List getCustomDataFilters() { + return customDataFilters; + } + + public void setCustomDataFilters(List customDataFilters) { + this.customDataFilters = customDataFilters; + } + + public AlterationFilter getAlterationFilter() { + return alterationFilter; + } + + public void setAlterationFilter(AlterationFilter alterationFilter) { + this.alterationFilter = (alterationFilter != null) ? alterationFilter : new AlterationFilter(); + } + + public AndedSampleTreatmentFilters getSampleTreatmentGroupFilters() { + return sampleTreatmentGroupFilters; + } + + public void setSampleTreatmentGroupFilters(AndedSampleTreatmentFilters sampleTreatmentGroupFilters) { + this.sampleTreatmentGroupFilters = sampleTreatmentGroupFilters; + } + + public AndedPatientTreatmentFilters getPatientTreatmentGroupFilters() { + return patientTreatmentGroupFilters; + } + + public void setPatientTreatmentGroupFilters(AndedPatientTreatmentFilters patientTreatmentGroupFilters) { + this.patientTreatmentGroupFilters = patientTreatmentGroupFilters; + } + + public AndedSampleTreatmentFilters getSampleTreatmentTargetFilters() { + return sampleTreatmentTargetFilters; + } + + public void setSampleTreatmentTargetFilters(AndedSampleTreatmentFilters sampleTreatmentTargetFilters) { + this.sampleTreatmentTargetFilters = sampleTreatmentTargetFilters; + } + + public AndedPatientTreatmentFilters getPatientTreatmentTargetFilters() { + return patientTreatmentTargetFilters; + } + + public void setPatientTreatmentTargetFilters(AndedPatientTreatmentFilters patientTreatmentTagetFilters) { + this.patientTreatmentTargetFilters = patientTreatmentTagetFilters; + } + + public List getClinicalEventFilters() { + return clinicalEventFilters; + } + + public void setClinicalEventFilters(List clinicalEventFilters) { + this.clinicalEventFilters = clinicalEventFilters; + } + + public List getMutationDataFilters() { return mutationDataFilters; } + + public void setMutationDataFilters(List mutationDataFilters) { + this.mutationDataFilters = mutationDataFilters; + } +} diff --git a/src/main/java/org/cbioportal/application/rest/response/CancerStudyMetadataDTO.java b/src/main/java/org/cbioportal/application/rest/response/CancerStudyMetadataDTO.java index 448de69ca28..a5a9b6e1fd9 100644 --- a/src/main/java/org/cbioportal/application/rest/response/CancerStudyMetadataDTO.java +++ b/src/main/java/org/cbioportal/application/rest/response/CancerStudyMetadataDTO.java @@ -1,7 +1,7 @@ package org.cbioportal.application.rest.response; import io.swagger.v3.oas.annotations.media.Schema; -import org.cbioportal.cancerstudy.TypeOfCancer; +import org.cbioportal.domain.cancerstudy.TypeOfCancer; @Schema(name = "CancerStudyMetadata", description = "Represents a cancer study") public record CancerStudyMetadataDTO(String cancerStudyIdentifier, String typeOfCancerId, diff --git a/src/main/java/org/cbioportal/application/rest/response/SampleDTO.java b/src/main/java/org/cbioportal/application/rest/response/SampleDTO.java new file mode 100644 index 00000000000..b0940a656b1 --- /dev/null +++ b/src/main/java/org/cbioportal/application/rest/response/SampleDTO.java @@ -0,0 +1,7 @@ +package org.cbioportal.application.rest.response; + +import org.cbioportal.domain.sample.SampleType; + +public record SampleDTO(String sampleId, SampleType sampleType, String patientId, String studyId, Boolean sequenced, + Boolean copyNumberSegmentPresent, String uniqueSampleKey, String uniquePatientKey) { +} diff --git a/src/main/java/org/cbioportal/application/rest/vcolumnstore/ColumnStoreStudyController.java b/src/main/java/org/cbioportal/application/rest/vcolumnstore/ColumnStoreStudyController.java index c8bcb5c28b6..2586f69e15a 100644 --- a/src/main/java/org/cbioportal/application/rest/vcolumnstore/ColumnStoreStudyController.java +++ b/src/main/java/org/cbioportal/application/rest/vcolumnstore/ColumnStoreStudyController.java @@ -4,7 +4,7 @@ import io.swagger.v3.oas.annotations.Parameter; import org.cbioportal.application.rest.mapper.CancerStudyMetadataMapper; import org.cbioportal.application.rest.response.CancerStudyMetadataDTO; -import org.cbioportal.cancerstudy.usecase.GetCancerStudyMetadataUseCase; +import org.cbioportal.domain.cancerstudy.usecase.GetCancerStudyMetadataUseCase; import org.cbioportal.legacy.web.parameter.Direction; import org.cbioportal.legacy.web.parameter.sort.StudySortBy; import org.cbioportal.shared.SortAndSearchCriteria; diff --git a/src/main/java/org/cbioportal/application/rest/vcolumnstore/ColumnarStoreStudyViewController.java b/src/main/java/org/cbioportal/application/rest/vcolumnstore/ColumnarStoreStudyViewController.java new file mode 100644 index 00000000000..e6bcbed4afd --- /dev/null +++ b/src/main/java/org/cbioportal/application/rest/vcolumnstore/ColumnarStoreStudyViewController.java @@ -0,0 +1,568 @@ +package org.cbioportal.application.rest.vcolumnstore; + +import io.swagger.v3.oas.annotations.Hidden; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.media.ArraySchema; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import jakarta.validation.Valid; +import org.cbioportal.application.rest.mapper.SampleMapper; +import org.cbioportal.application.rest.response.SampleDTO; +import org.cbioportal.infrastructure.service.BasicDataBinner; +import org.cbioportal.infrastructure.service.ClinicalDataBinner; +import org.cbioportal.legacy.model.AlterationCountByGene; +import org.cbioportal.legacy.model.CaseListDataCount; +import org.cbioportal.legacy.model.ClinicalData; +import org.cbioportal.legacy.model.ClinicalDataBin; +import org.cbioportal.legacy.model.ClinicalDataCountItem; +import org.cbioportal.legacy.model.ClinicalEventKeyCode; +import org.cbioportal.legacy.model.ClinicalEventTypeCount; +import org.cbioportal.legacy.model.ClinicalViolinPlotData; +import org.cbioportal.legacy.model.CopyNumberCountByGene; +import org.cbioportal.legacy.model.DensityPlotData; +import org.cbioportal.legacy.model.GenericAssayDataBin; +import org.cbioportal.legacy.model.GenericAssayDataCountItem; +import org.cbioportal.legacy.model.GenomicDataBin; +import org.cbioportal.legacy.model.GenomicDataCount; +import org.cbioportal.legacy.model.GenomicDataCountItem; +import org.cbioportal.legacy.model.PatientTreatmentReport; +import org.cbioportal.legacy.model.SampleTreatmentReport; +import org.cbioportal.legacy.service.ClinicalDataDensityPlotService; +import org.cbioportal.legacy.service.CustomDataService; +import org.cbioportal.legacy.service.ViolinPlotService; +import org.cbioportal.legacy.service.exception.StudyNotFoundException; +import org.cbioportal.legacy.service.util.CustomDataSession; +import org.cbioportal.legacy.web.columnar.util.CustomDataFilterUtil; +import org.cbioportal.legacy.web.columnar.util.NewStudyViewFilterUtil; +import org.cbioportal.legacy.web.parameter.ClinicalDataBinCountFilter; +import org.cbioportal.legacy.web.parameter.ClinicalDataCountFilter; +import org.cbioportal.legacy.web.parameter.ClinicalDataFilter; +import org.cbioportal.legacy.web.parameter.DataBinMethod; +import org.cbioportal.legacy.web.parameter.GenericAssayDataBinCountFilter; +import org.cbioportal.legacy.web.parameter.GenericAssayDataCountFilter; +import org.cbioportal.legacy.web.parameter.GenericAssayDataFilter; +import org.cbioportal.legacy.web.parameter.GenomicDataBinCountFilter; +import org.cbioportal.legacy.web.parameter.GenomicDataCountFilter; +import org.cbioportal.legacy.web.parameter.GenomicDataFilter; +import org.cbioportal.legacy.web.parameter.MutationOption; +import org.cbioportal.legacy.web.parameter.Projection; +import org.cbioportal.legacy.web.parameter.SampleIdentifier; +import org.cbioportal.legacy.web.parameter.StudyViewFilter; +import org.cbioportal.legacy.web.util.DensityPlotParameters; +import org.cbioportal.domain.sample.Sample; +import org.cbioportal.domain.studyview.StudyViewService; +import org.springframework.context.annotation.Profile; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import static java.util.stream.Collectors.toSet; + +@RestController +@RequestMapping("/api/column-store") +@Profile("clickhouse") +public class ColumnarStoreStudyViewController { + + private final StudyViewService studyViewService; + private final BasicDataBinner basicDataBinner; + private final ClinicalDataBinner clinicalDataBinner; + private final ClinicalDataDensityPlotService clinicalDataDensityPlotService; + private final ViolinPlotService violinPlotService; + private final CustomDataService customDataService; + private final CustomDataFilterUtil customDataFilterUtil; + + + public ColumnarStoreStudyViewController(StudyViewService studyViewService, BasicDataBinner basicDataBinner, ClinicalDataBinner clinicalDataBinner, ClinicalDataDensityPlotService clinicalDataDensityPlotService, ViolinPlotService violinPlotService, CustomDataService customDataService, CustomDataFilterUtil customDataFilterUtil) { + this.studyViewService = studyViewService; + this.basicDataBinner = basicDataBinner; + this.clinicalDataBinner = clinicalDataBinner; + this.clinicalDataDensityPlotService = clinicalDataDensityPlotService; + this.violinPlotService = violinPlotService; + this.customDataService = customDataService; + this.customDataFilterUtil = customDataFilterUtil; + } + + @Hidden + @PostMapping(value = "/filtered-samples/fetch", + consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE) + @PreAuthorize("hasPermission(#studyViewFilter, 'StudyViewFilter', T(org.cbioportal.legacy.utils.security.AccessLevel).READ)") + public ResponseEntity> fetchFilteredSamples( + @RequestParam(defaultValue = "false") Boolean negateFilters, + @RequestBody(required = false) StudyViewFilter studyViewFilter) { + return ResponseEntity.ok(SampleMapper.INSTANCE.toDtos(studyViewService.getFilteredSamples(studyViewFilter)) + ); + } + + @Hidden // should unhide when we remove legacy controller + @PostMapping(value = "/mutated-genes/fetch", + consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE) + @PreAuthorize("hasPermission(#studyViewFilter, 'StudyViewFilter', T(org.cbioportal.legacy.utils.security.AccessLevel).READ)") + public ResponseEntity> fetchMutatedGenes( + @RequestBody(required = false) StudyViewFilter studyViewFilter + ) throws StudyNotFoundException { + return ResponseEntity.ok(studyViewService.getMutatedGenes(studyViewFilter) + ); + } + + @Hidden // should unhide when we remove legacy controller + @PostMapping(value = "/molecular-profile-sample-counts/fetch", + consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE) + @Operation(description = "Fetch sample counts by study view filter") + @PreAuthorize("hasPermission(#studyViewFilter, 'StudyViewFilter', T(org.cbioportal.legacy.utils.security.AccessLevel).READ)") + @ApiResponse(responseCode = "200", description = "OK", + content = @Content(array = @ArraySchema(schema = @Schema(implementation = GenomicDataCount.class)))) + public ResponseEntity> fetchMolecularProfileSampleCounts( + @Parameter(required = true, description = "Study view filter") + @Valid @RequestBody(required = false) StudyViewFilter studyViewFilter + ) throws StudyNotFoundException { + return ResponseEntity.ok( + studyViewService.getMolecularProfileSampleCounts(studyViewFilter)); + } + + @Hidden // should unhide when we remove legacy controller + @PostMapping(value = "/cna-genes/fetch", + consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE) + @PreAuthorize("hasPermission(#studyViewFilter, 'StudyViewFilter', T(org.cbioportal.legacy.utils.security.AccessLevel).READ)") + public ResponseEntity> fetchCnaGenes( + @RequestBody(required = false) StudyViewFilter studyViewFilter + ) throws StudyNotFoundException { + return ResponseEntity.ok(studyViewService.getCnaGenes(studyViewFilter)); + } + + @Hidden // should unhide when we remove legacy controller + @PostMapping(value = "/structuralvariant-genes/fetch", + consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE) + @Operation(description = "Fetch structural variant genes by study view filter") + @ApiResponse(responseCode = "200", description = "OK", + content = @Content(array = @ArraySchema(schema = @Schema(implementation = AlterationCountByGene.class)))) + @PreAuthorize("hasPermission(#studyViewFilter, 'StudyViewFilter', T(org.cbioportal.legacy.utils.security.AccessLevel).READ)") + public ResponseEntity> fetchStructuralVariantGenes( + @Parameter(required = true, description = "Study view filter") + @Valid @RequestBody(required = false) StudyViewFilter studyViewFilter + ) throws StudyNotFoundException { + return ResponseEntity.ok(studyViewService.getStructuralVariantGenes(studyViewFilter)); + } + + @Hidden // should unhide when we remove legacy controller + @PostMapping(value = "/clinical-data-counts/fetch", + consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE) + @PreAuthorize("hasPermission(#clinicalDataCountFilter, 'ClinicalDataCountFilter', T(org.cbioportal.legacy.utils.security.AccessLevel).READ)") + public ResponseEntity> fetchClinicalDataCounts( + @RequestBody(required = false) ClinicalDataCountFilter clinicalDataCountFilter) + { + + List attributes = clinicalDataCountFilter.getAttributes(); + StudyViewFilter studyViewFilter = clinicalDataCountFilter.getStudyViewFilter(); + + if (attributes.size() == 1) { + NewStudyViewFilterUtil.removeClinicalDataFilter(attributes.getFirst().getAttributeId(), studyViewFilter.getClinicalDataFilters()); + } + List result = studyViewService.getClinicalDataCounts( + studyViewFilter, + attributes.stream().map(ClinicalDataFilter::getAttributeId).toList()); + return ResponseEntity.ok(result); + } + + @Hidden // should unhide when we remove legacy controller + @PostMapping(value = "/sample-lists-counts/fetch", + consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE) + @Operation(description = "Fetch case list sample counts by study view filter") + @PreAuthorize("hasPermission(#studyViewFilter, 'StudyViewFilter', T(org.cbioportal.legacy.utils.security.AccessLevel).READ)") + public List fetchCaseListCounts( + @Parameter(required = true, description = "Study view filter") + @Valid @RequestBody(required = false) StudyViewFilter studyViewFilter) { + + return studyViewService.getCaseListDataCounts(studyViewFilter); + } + + @Hidden // should unhide when we remove legacy controller + @PostMapping(value = "/clinical-data-bin-counts/fetch", + consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE) + @PreAuthorize("hasPermission(#clinicalDataBinCountFilter, 'DataBinCountFilter', T(org.cbioportal.legacy.utils.security.AccessLevel).READ)") + public ResponseEntity> fetchClinicalDataBinCounts( + @RequestParam(defaultValue = "DYNAMIC") DataBinMethod dataBinMethod, + @RequestBody(required = false) ClinicalDataBinCountFilter clinicalDataBinCountFilter) { + List clinicalDataBins = clinicalDataBinner.fetchClinicalDataBinCounts( + dataBinMethod, + clinicalDataBinCountFilter, + true + ); + return new ResponseEntity<>(clinicalDataBins, HttpStatus.OK); + } + + @Hidden // should unhide when we remove legacy controller + @PostMapping(value = "/clinical-data-density-plot/fetch", + consumes = MediaType.APPLICATION_JSON_VALUE, + produces = MediaType.APPLICATION_JSON_VALUE) + @Operation(description = "Fetch clinical data density plot bins by study view filter") + @ApiResponse(responseCode = "200", description = "OK", + content = @Content(schema = @Schema(implementation = DensityPlotData.class))) + @Validated + @PreAuthorize("hasPermission(#studyViewFilter, 'StudyViewFilter', T(org.cbioportal.legacy.utils.security.AccessLevel).READ)") + public ResponseEntity fetchClinicalDataDensityPlot( + @Parameter(required = true, description = "Clinical Attribute ID of the X axis") + @RequestParam String xAxisAttributeId, + @Parameter(description = "Number of the bins in X axis") + @RequestParam(defaultValue = "50") Integer xAxisBinCount, + @Parameter(description = "Starting point of the X axis, if different than smallest value") + @RequestParam(required = false) BigDecimal xAxisStart, + @Parameter(description = "Starting point of the X axis, if different than largest value") + @RequestParam(required = false) BigDecimal xAxisEnd, + @Parameter(required = true, description = "Clinical Attribute ID of the Y axis") + @RequestParam String yAxisAttributeId, + @Parameter(description = "Number of the bins in Y axis") + @RequestParam(defaultValue = "50") Integer yAxisBinCount, + @Parameter(description = "Starting point of the Y axis, if different than smallest value") + @RequestParam(required = false) BigDecimal yAxisStart, + @Parameter(description = "Starting point of the Y axis, if different than largest value") + @RequestParam(required = false) BigDecimal yAxisEnd, + @Parameter(description="Use log scale for X axis") + @RequestParam(required = false, defaultValue = "false") Boolean xAxisLogScale, + @Schema(defaultValue = "false") + @Parameter(description="Use log scale for Y axis") + @RequestParam(required = false, defaultValue = "false") Boolean yAxisLogScale, + @Parameter(required = true, description = "Study view filter") + @RequestBody(required = false) StudyViewFilter studyViewFilter + ) { + DensityPlotParameters densityPlotParameters = + new DensityPlotParameters.Builder() + .xAxisAttributeId(xAxisAttributeId) + .yAxisAttributeId(yAxisAttributeId) + .xAxisBinCount(xAxisBinCount) + .yAxisBinCount(yAxisBinCount) + .xAxisStart(xAxisStart) + .yAxisStart(yAxisStart) + .xAxisEnd(xAxisEnd) + .yAxisEnd(yAxisEnd) + .xAxisLogScale(xAxisLogScale) + .yAxisLogScale(yAxisLogScale) + .build(); + + List combinedClinicalDataList = studyViewService.getClinicalDataForXyPlot( + studyViewFilter, + List.of(xAxisAttributeId, yAxisAttributeId), + false + ); + + DensityPlotData result = clinicalDataDensityPlotService.getDensityPlotData( + combinedClinicalDataList, + densityPlotParameters, + studyViewFilter + ); + + return new ResponseEntity<>(result, HttpStatus.OK); + } + + @Hidden // should unhide when we remove legacy controller + @PreAuthorize("hasPermission(#studyViewFilter, 'StudyViewFilter', T(org.cbioportal.legacy.utils.security.AccessLevel).READ)") + @PostMapping(value = "/clinical-data-violin-plots/fetch", + consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE) + @Operation(description = "Fetch violin plot curves per categorical clinical data value, filtered by study view filter") + @ApiResponse(responseCode = "200", description = "OK", + content = @Content(schema = @Schema(implementation = ClinicalViolinPlotData.class))) + public ResponseEntity fetchClinicalDataViolinPlots( + @Parameter(required = true, description = "Clinical Attribute ID of the categorical attribute") + @RequestParam String categoricalAttributeId, + @Parameter(required = true, description = "Clinical Attribute ID of the numerical attribute") + @RequestParam String numericalAttributeId, + @Parameter(description = "Starting point of the violin plot axis, if different than smallest value") + @RequestParam(required = false) BigDecimal axisStart, + @Parameter(description = "Ending point of the violin plot axis, if different than largest value") + @RequestParam(required = false) BigDecimal axisEnd, + @Parameter(description = "Number of points in the curve") + @RequestParam(required = false, defaultValue = "100") BigDecimal numCurvePoints, + @Parameter(description="Use log scale for the numerical attribute") + @RequestParam(required = false, defaultValue = "false") Boolean logScale, + @Parameter(description="Sigma stepsize multiplier") + @RequestParam(required = false, defaultValue = "1") BigDecimal sigmaMultiplier, + @Parameter(required = true, description = "Study view filter") + @Valid @RequestBody(required = false) StudyViewFilter studyViewFilter + ) { + // fetch the samples by using the provided study view filter + List filteredSamples = studyViewService.getFilteredSamples(studyViewFilter); + + // remove the numerical clinical data filter from the study view filter. + // this new modified filter is used to fetch sample and patient clinical data. + // this is required to get the complete violin plot data. + // filteredSamples reflects only the original unmodified study view filter. + // we will need to fetch samples again to get the samples corresponding to this modified filter, + // otherwise patient to sample mapping may be incomplete. + if (studyViewFilter.getClinicalDataFilters() != null) { + studyViewFilter.getClinicalDataFilters().stream() + .filter(f->f.getAttributeId().equals(numericalAttributeId)) + .findAny() + .ifPresent(f->studyViewFilter.getClinicalDataFilters().remove(f)); + } + + List combinedClinicalDataList = studyViewService.getClinicalDataForXyPlot( + studyViewFilter, + List.of(numericalAttributeId, categoricalAttributeId), + true // filter out clinical data with empty attribute values due to Clickhouse migration + ); + + // Only mutation count can use log scale + boolean useLogScale = logScale && numericalAttributeId.equals("MUTATION_COUNT"); + + Set sampleIdsSet = filteredSamples + .stream() + .map(Sample::internalId) + .collect(toSet()); + + ClinicalViolinPlotData result = violinPlotService.getClinicalViolinPlotData( + combinedClinicalDataList, + sampleIdsSet, + axisStart, + axisEnd, + numCurvePoints, + useLogScale, + sigmaMultiplier, + studyViewFilter + ); + + return new ResponseEntity<>(result, HttpStatus.OK); + } + + @Hidden // should unhide when we remove legacy controller + @PostMapping(value = "/genomic-data-counts/fetch", + consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE) + @Operation(description = "Fetch genomic data counts by GenomicDataCountFilter") + @ApiResponse(responseCode = "200", description = "OK", + content = @Content(array = @ArraySchema(schema = @Schema(implementation = GenomicDataCountItem.class)))) + @PreAuthorize("hasPermission(#genomicDataCountFilter, 'GenomicDataCountFilter', T(org.cbioportal.legacy.utils.security.AccessLevel).READ)") + public ResponseEntity> fetchGenomicDataCounts( + @Parameter(required = true, description = "Genomic data count filter") + @Valid @RequestBody(required = false) + GenomicDataCountFilter genomicDataCountFilter) throws StudyNotFoundException { + List genomicDataFilters = genomicDataCountFilter.getGenomicDataFilters(); + StudyViewFilter studyViewFilter = genomicDataCountFilter.getStudyViewFilter(); + // when there is only one filter, it means study view is doing a single chart filter operation + // remove filter from studyViewFilter to return all data counts + // the reason we do this is to make sure after chart get filtered, user can still see unselected portion of the chart + if (genomicDataFilters.size() == 1) { + NewStudyViewFilterUtil.removeSelfFromGenomicDataFilter( + genomicDataFilters.get(0).getHugoGeneSymbol(), + genomicDataFilters.get(0).getProfileType(), + studyViewFilter); + } + + // This endpoint is CNA specific. The name choice of "genomic data" does not imply it support other genomic data types + List result = studyViewService.getCNACountsByGeneSpecific(studyViewFilter, genomicDataFilters); + + return new ResponseEntity<>(result, HttpStatus.OK); + } + + @Hidden // should unhide when we remove legacy controller + @PostMapping(value = "/generic-assay-data-counts/fetch", + consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE) + @Operation(description = "Fetch generic assay data counts by study view filter") + @ApiResponse(responseCode = "200", description = "OK", + content = @Content(array = @ArraySchema(schema = @Schema(implementation = GenericAssayDataCountItem.class)))) + @PreAuthorize("hasPermission(#genericAssayDataCountFilter, 'GenericAssayDataCountFilter', T(org.cbioportal.legacy.utils.security.AccessLevel).READ)") + public ResponseEntity> fetchGenericAssayDataCounts( + @Parameter(required = true, description = "Generic assay data count filter") + @Valid @RequestBody(required = false) + GenericAssayDataCountFilter genericAssayDataCountFilter) { + + List gaFilters = genericAssayDataCountFilter.getGenericAssayDataFilters(); + StudyViewFilter studyViewFilter = genericAssayDataCountFilter.getStudyViewFilter(); + // when there is only one filter, it means study view is doing a single chart filter operation + // remove filter from studyViewFilter to return all data counts + // the reason we do this is to make sure after chart get filtered, user can still see unselected portion of the chart + + if (gaFilters.size() == 1) { + NewStudyViewFilterUtil.removeSelfFromGenericAssayFilter(gaFilters.getFirst().getStableId(), studyViewFilter); + } + + return ResponseEntity.ok(studyViewService.getGenericAssayDataCounts(studyViewFilter, gaFilters)); + } + + @Hidden // should unhide when we remove legacy controller + @PostMapping(value = "/mutation-data-counts/fetch", + consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE) + @Operation(description = "Fetch mutation data counts by GenomicDataCountFilter") + @PreAuthorize("hasPermission(#genomicDataCountFilter, 'GenomicDataCountFilter', T(org.cbioportal.legacy.utils.security.AccessLevel).READ)") + public ResponseEntity> fetchMutationDataCounts( + @Parameter(description = "Level of detail of the response") + @RequestParam(defaultValue = "SUMMARY") Projection projection, + @Parameter(required = true, description = "Genomic data count filter") + @Valid @RequestBody(required = false) GenomicDataCountFilter genomicDataCountFilter + ) { + List genomicDataFilters = genomicDataCountFilter.getGenomicDataFilters(); + StudyViewFilter studyViewFilter = genomicDataCountFilter.getStudyViewFilter(); + // when there is only one filter, it means study view is doing a single chart filter operation + // remove filter from studyViewFilter to return all data counts + // the reason we do this is to make sure after chart get filtered, user can still see unselected portion of the chart + if (genomicDataFilters.size() == 1 && projection == Projection.SUMMARY) { + NewStudyViewFilterUtil.removeSelfFromMutationDataFilter( + genomicDataFilters.get(0).getHugoGeneSymbol(), + genomicDataFilters.get(0).getProfileType(), + MutationOption.MUTATED, + studyViewFilter); + } + + List result = projection == Projection.SUMMARY ? + studyViewService.getMutationCountsByGeneSpecific(studyViewFilter, genomicDataFilters) : + studyViewService.getMutationTypeCountsByGeneSpecific(studyViewFilter, genomicDataFilters); + + return ResponseEntity.ok(result); + } + + @Hidden // should unhide when we remove legacy controller + @PostMapping(value = "/clinical-event-type-counts/fetch", + + consumes = MediaType.APPLICATION_JSON_VALUE, + produces = MediaType.APPLICATION_JSON_VALUE) + @Operation(description = "Get Counts of Clinical Event Types by Study View Filter") + @ApiResponse(responseCode = "200", description = "OK", + content = @Content(array = @ArraySchema(schema = @Schema(implementation = ClinicalEventTypeCount.class)))) + @PreAuthorize("hasPermission(#studyViewFilter, 'StudyViewFilter', T(org.cbioportal.legacy.utils.security.AccessLevel).READ)") + public ResponseEntity> getClinicalEventTypeCounts( + @Parameter(required = true, description = "Study view filter") + @Valid + @RequestBody(required = false) + StudyViewFilter studyViewFilter) { + return ResponseEntity.ok(studyViewService.getClinicalEventTypeCounts(studyViewFilter)); + } + + @PostMapping(value = "/treatments/patient-counts/fetch", + + produces = MediaType.APPLICATION_JSON_VALUE) + @Operation(description = "Get all patient level treatments") + @ApiResponse(responseCode = "200", description = "OK", + content = @Content(schema = @Schema(implementation = PatientTreatmentReport.class))) + @PreAuthorize("hasPermission(#studyViewFilter, 'StudyViewFilter', T(org.cbioportal.legacy.utils.security.AccessLevel).READ)") + public ResponseEntity fetchPatientTreatmentCounts( + @Parameter(required = false ) + @RequestParam(name = "tier", required = false, defaultValue = "Agent") + ClinicalEventKeyCode tier, + + @Parameter(required = true, description = "Study view filter") + @Valid + @RequestBody(required = false) + StudyViewFilter studyViewFilter) { + return ResponseEntity.ok(studyViewService.getPatientTreatmentReport(studyViewFilter)); + } + + @PostMapping(value = "/treatments/sample-counts/fetch", + + produces = MediaType.APPLICATION_JSON_VALUE) + @ApiResponse(responseCode = "200", description = "OK", + content = @Content(schema = @Schema(implementation = SampleTreatmentReport.class))) + @PreAuthorize("hasPermission(#studyViewFilter, 'StudyViewFilter', T(org.cbioportal.legacy.utils.security.AccessLevel).READ)") + public ResponseEntity fetchSampleTreatmentCounts( + @Parameter(required = false ) + @RequestParam(name = "tier", required = false, defaultValue = "Agent") + ClinicalEventKeyCode tier, + + @Parameter(required = true, description = "Study view filter") + @Valid + @RequestBody(required = false) + StudyViewFilter studyViewFilter) { + return ResponseEntity.ok(studyViewService.getSampleTreatmentReport(studyViewFilter)); + } + + @Hidden // should unhide when we remove legacy controller + @PostMapping(value = "/custom-data-counts/fetch", + consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE) + @Operation(description = "Fetch custom data counts by study view filter") + @ApiResponse(responseCode = "200", description = "OK", + content = @Content(array = @ArraySchema(schema = @Schema(implementation = ClinicalDataCountItem.class)))) + @PreAuthorize("hasPermission(#clinicalDataCountFilter, 'DataCountFilter', T(org.cbioportal.legacy.utils.security.AccessLevel).READ)") + public ResponseEntity> fetchCustomDataCounts( + @Parameter(required = true, description = "Custom data count filter") @Valid @RequestBody(required = + false) ClinicalDataCountFilter clinicalDataCountFilter){ + + List attributes = clinicalDataCountFilter.getAttributes(); + StudyViewFilter studyViewFilter = clinicalDataCountFilter.getStudyViewFilter(); + if (attributes.size() == 1) { + NewStudyViewFilterUtil.removeClinicalDataFilter(attributes.getFirst().getAttributeId(), studyViewFilter.getCustomDataFilters()); + } + + List filteredSampleIdentifiers = + studyViewService.getFilteredSamples(studyViewFilter) + .stream() + .map(sample -> NewStudyViewFilterUtil.buildSampleIdentifier(sample.cancerStudyIdentifier(), sample.stableId())) + .toList(); + + if (filteredSampleIdentifiers.isEmpty()) { + return new ResponseEntity<>(new ArrayList<>(), HttpStatus.OK); + } + + final List attributeIds = attributes.stream().map(ClinicalDataFilter::getAttributeId).toList(); + Map customDataSessionsMap = customDataService.getCustomDataSessions(attributeIds); + + List result = customDataFilterUtil.getCustomDataCounts(filteredSampleIdentifiers, customDataSessionsMap); + + return new ResponseEntity<>(result, HttpStatus.OK); + } + + @Hidden // should unhide when we remove legacy controller + @PostMapping(value = "/custom-data-bin-counts/fetch", + consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE) + @Operation(description = "Fetch custom data bin counts by study view filter") + @ApiResponse(responseCode = "200", description = "OK", + content = @Content(array = @ArraySchema(schema = @Schema(implementation = ClinicalDataBin.class)))) + @PreAuthorize("hasPermission(#clinicalDataBinCountFilter, 'DataBinCountFilter', T(org.cbioportal.legacy.utils.security.AccessLevel).READ)") + public ResponseEntity> fetchCustomDataBinCounts( + @Parameter(description = "Method for data binning") + @RequestParam(defaultValue = "DYNAMIC") DataBinMethod dataBinMethod, + @Parameter(required = true, description = "Clinical data bin count filter") + @Valid @RequestBody(required = false) ClinicalDataBinCountFilter clinicalDataBinCountFilter) { + List customDataBins = basicDataBinner.getDataBins( + dataBinMethod, + clinicalDataBinCountFilter, + true + ); + return ResponseEntity.ok(customDataBins); + } + + @Hidden // should unhide when we remove legacy controller + @PostMapping(value = "/genomic-data-bin-counts/fetch", + consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE) + @ApiResponse(responseCode = "200", description = "OK", + content = @Content(array = @ArraySchema(schema = @Schema(implementation = GenomicDataBin.class)))) + @PreAuthorize("hasPermission(#genomicDataBinCountFilter, 'DataBinCountFilter', T(org.cbioportal.legacy.utils.security.AccessLevel).READ)") + public ResponseEntity> fetchGenomicDataBinCounts( + @RequestParam(defaultValue = "DYNAMIC") DataBinMethod dataBinMethod, + @RequestBody(required = false) GenomicDataBinCountFilter genomicDataBinCountFilter) { + List genomicDataBins = basicDataBinner.getDataBins( + dataBinMethod, + genomicDataBinCountFilter, + true + ); + return ResponseEntity.ok(genomicDataBins); + } + + @Hidden // should unhide when we remove legacy controller + @PostMapping(value = "/generic-assay-data-bin-counts/fetch", + consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE) + @ApiResponse(responseCode = "200", description = "OK", + content = @Content(array = @ArraySchema(schema = @Schema(implementation = GenericAssayDataBin.class)))) + @PreAuthorize("hasPermission(#genericAssayDataBinCountFilter, 'DataBinCountFilter', T(org.cbioportal.legacy.utils.security.AccessLevel).READ)") + public ResponseEntity> fetchGenericAssayDataBinCounts( + @RequestParam(defaultValue = "DYNAMIC") DataBinMethod dataBinMethod, + @RequestBody(required = false) GenericAssayDataBinCountFilter genericAssayDataBinCountFilter) { + List genericAssayDataBins = basicDataBinner.getDataBins( + dataBinMethod, + genericAssayDataBinCountFilter, + true + ); + return ResponseEntity.ok(genericAssayDataBins); + } +} diff --git a/src/main/java/org/cbioportal/application/security/CancerStudyPermissionEvaluator.java b/src/main/java/org/cbioportal/application/security/CancerStudyPermissionEvaluator.java index d92ecd70a5d..d49b8a2f9a5 100644 --- a/src/main/java/org/cbioportal/application/security/CancerStudyPermissionEvaluator.java +++ b/src/main/java/org/cbioportal/application/security/CancerStudyPermissionEvaluator.java @@ -42,6 +42,11 @@ import org.cbioportal.legacy.model.SampleList; import org.cbioportal.legacy.persistence.cachemaputil.CacheMapUtil; import org.cbioportal.legacy.utils.security.AccessLevel; +import org.cbioportal.legacy.web.parameter.ClinicalDataCountFilter; +import org.cbioportal.legacy.web.parameter.DataBinCountFilter; +import org.cbioportal.legacy.web.parameter.GenericAssayDataCountFilter; +import org.cbioportal.legacy.web.parameter.GenomicDataCountFilter; +import org.cbioportal.legacy.web.parameter.StudyViewFilter; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.security.access.PermissionEvaluator; @@ -185,6 +190,43 @@ public boolean hasPermission(Authentication authentication, Serializable targetI return hasAccessToMolecularProfiles(authentication, (Collection)targetId, permission); } else if (TARGET_TYPE_COLLECTION_OF_SAMPLE_LIST_IDS.equals(targetType)) { return hasAccessToSampleLists(authentication, (Collection) targetId, permission); + } else if (targetType.contains("Filter")) { + switch (targetId) { + case StudyViewFilter studyViewFilter -> { + return hasAccessToCancerStudies(authentication, studyViewFilter.getUniqueStudyIds(), permission); + } + case ClinicalDataCountFilter clinicalDataCountFilter -> { + Set studyIds = new HashSet<>(); + if (clinicalDataCountFilter.getStudyViewFilter() != null) { + studyIds = clinicalDataCountFilter.getStudyViewFilter().getUniqueStudyIds(); + } + return hasAccessToCancerStudies(authentication, studyIds, permission); + } + case DataBinCountFilter dataBinCountFilter -> { + Set studyIds = new HashSet<>(); + if (dataBinCountFilter.getStudyViewFilter() != null) { + studyIds = dataBinCountFilter.getStudyViewFilter().getUniqueStudyIds(); + } + return hasAccessToCancerStudies(authentication,studyIds, permission); + } + case GenomicDataCountFilter genomicDataCountFilter -> { + Set studyIds = new HashSet<>(); + if (genomicDataCountFilter.getStudyViewFilter() != null) { + studyIds = genomicDataCountFilter.getStudyViewFilter().getUniqueStudyIds(); + } + return hasAccessToCancerStudies(authentication, studyIds, permission); + } + + case GenericAssayDataCountFilter genericAssayDataCountFilter -> { + Set studyIds = new HashSet<>(); + if (genericAssayDataCountFilter.getStudyViewFilter() != null) { + studyIds = genericAssayDataCountFilter.getStudyViewFilter().getUniqueStudyIds(); + } + return hasAccessToCancerStudies(authentication, studyIds, permission); + } + + default -> log.debug("hasPermission(), unknown targetType '" + targetType + "'"); + } } else { if (log.isDebugEnabled()) { log.debug("hasPermission(), unknown targetType '" + targetType + "'"); diff --git a/src/main/java/org/cbioportal/domain/alteration/repository/AlterationRepository.java b/src/main/java/org/cbioportal/domain/alteration/repository/AlterationRepository.java new file mode 100644 index 00000000000..1ffd5be7d5f --- /dev/null +++ b/src/main/java/org/cbioportal/domain/alteration/repository/AlterationRepository.java @@ -0,0 +1,77 @@ +package org.cbioportal.domain.alteration.repository; + +import org.cbioportal.legacy.model.AlterationCountByGene; +import org.cbioportal.legacy.model.CopyNumberCountByGene; +import org.cbioportal.legacy.model.MolecularProfile; +import org.cbioportal.domain.studyview.StudyViewFilterContext; + +import java.util.List; +import java.util.Map; +import java.util.Set; + +public interface AlterationRepository { + + /** + * Retrieves a list of mutated genes along with their alteration counts based on the given study view filter context. + * + * @param studyViewFilterContext The filter criteria for the study view. + * @return A list of {@link AlterationCountByGene} representing mutated genes and their counts. + */ + List getMutatedGenes(StudyViewFilterContext studyViewFilterContext); + + /** + * Retrieves a list of structural variant genes along with their alteration counts based on the given study view filter context. + * + * @param studyViewFilterContext The filter criteria for the study view. + * @return A list of {@link AlterationCountByGene} representing structural variant genes and their counts. + */ + List getStructuralVariantGenes(StudyViewFilterContext studyViewFilterContext); + + /** + * Retrieves a list of copy number alteration (CNA) genes along with their alteration counts based on the given study view filter context. + * + * @param studyViewFilterContext The filter criteria for the study view. + * @return A list of {@link CopyNumberCountByGene} representing CNA genes and their counts. + */ + List getCnaGenes(StudyViewFilterContext studyViewFilterContext); + + /** + * Retrieves the total number of profiled samples for a specific alteration type based on the given study view filter context. + * + * @param studyViewFilterContext The filter criteria for the study view. + * @param alterationType The type of alteration (e.g., MUTATION, CNA, SV). + * @return The total number of profiled samples for the specified alteration type. + */ + int getTotalProfiledCountsByAlterationType(StudyViewFilterContext studyViewFilterContext, String alterationType); + + /** + * Retrieves the total number of profiled samples categorized by molecular profile and alteration type. + * + * @param studyViewFilterContext The filter criteria for the study view. + * @param alterationType The type of alteration (e.g., MUTATION, CNA, SV). + * @param molecularProfiles A list of molecular profiles to consider. + * @return A map where the key is the molecular profile ID and the value is the total count of profiled samples. + */ + Map getTotalProfiledCounts(StudyViewFilterContext studyViewFilterContext, + String alterationType, List molecularProfiles); + + /** + * Retrieves a mapping of alteration types to the corresponding gene panel IDs that match the given study view filter context. + * + * @param studyViewFilterContext The filter criteria for the study view. + * @param alterationType The type of alteration (e.g., MUTATION, CNA, SV). + * @return A map where the key is the alteration type and the value is a set of matching gene panel IDs. + */ + Map> getMatchingGenePanelIds(StudyViewFilterContext studyViewFilterContext, + String alterationType); + + /** + * Retrieves the count of sample profiles that do not have associated gene panel data for a given alteration type. + * + * @param studyViewFilterContext The filter criteria for the study view. + * @param alterationType The type of alteration (e.g., MUTATION, CNA, SV). + * @return The number of sample profiles without gene panel data for the specified alteration type. + */ + int getSampleProfileCountWithoutPanelData(StudyViewFilterContext studyViewFilterContext, String alterationType); +} + diff --git a/src/main/java/org/cbioportal/domain/alteration/usecase/AbstractAlterationCountByGeneUseCase.java b/src/main/java/org/cbioportal/domain/alteration/usecase/AbstractAlterationCountByGeneUseCase.java new file mode 100644 index 00000000000..89431068834 --- /dev/null +++ b/src/main/java/org/cbioportal/domain/alteration/usecase/AbstractAlterationCountByGeneUseCase.java @@ -0,0 +1,108 @@ +package org.cbioportal.domain.alteration.usecase; + +import org.cbioportal.domain.alteration.repository.AlterationRepository; +import org.cbioportal.domain.generic_assay.usecase.GetFilteredMolecularProfilesByAlterationType; +import org.cbioportal.domain.studyview.StudyViewFilterContext; +import org.cbioportal.legacy.model.AlterationCountByGene; +import org.cbioportal.legacy.model.AlterationType; +import org.cbioportal.legacy.model.MolecularProfile; +import org.springframework.lang.NonNull; + +import java.util.Collections; +import java.util.List; +import java.util.Set; +import java.util.function.Function; +import java.util.stream.Collectors; + +abstract class AbstractAlterationCountByGeneUseCase { + + private static final String WHOLE_EXOME_SEQUENCING = "WES"; + + private final AlterationRepository alterationRepository; + private final GetFilteredMolecularProfilesByAlterationType getFilteredMolecularProfilesByAlterationType; + + AbstractAlterationCountByGeneUseCase(AlterationRepository alterationRepository, GetFilteredMolecularProfilesByAlterationType getFilteredMolecularProfilesByAlterationType){ + this.alterationRepository = alterationRepository; + this.getFilteredMolecularProfilesByAlterationType = getFilteredMolecularProfilesByAlterationType; + } + + /** + * Populates alteration counts with profile data, including the total profiled count and matching gene panel IDs. + * + * @param alterationCounts List of alteration counts to enrich. + * @param studyViewFilterContext Context containing filter criteria. + * @param alterationType Type of alteration (e.g., mutation, CNA, structural variant). + * @param The type of alteration count. + * @return List of enriched alteration counts. + */ + List populateAlterationCounts(@NonNull List alterationCounts, + @NonNull StudyViewFilterContext studyViewFilterContext, + @NonNull AlterationType alterationType) { + final var firstMolecularProfileForEachStudy = getFirstMolecularProfileGroupedByStudy(studyViewFilterContext, + alterationType); + final int totalProfiledCount = alterationRepository.getTotalProfiledCountsByAlterationType(studyViewFilterContext, + alterationType.toString()); + var profiledCountsMap = alterationRepository.getTotalProfiledCounts(studyViewFilterContext, alterationType.toString(), + firstMolecularProfileForEachStudy); + final var matchingGenePanelIdsMap = alterationRepository.getMatchingGenePanelIds(studyViewFilterContext, + alterationType.toString()); + final int sampleProfileCountWithoutGenePanelData = + alterationRepository.getSampleProfileCountWithoutPanelData(studyViewFilterContext, alterationType.toString()); + + alterationCounts.parallelStream() + .forEach(alterationCountByGene -> { + String hugoGeneSymbol = alterationCountByGene.getHugoGeneSymbol(); + Set matchingGenePanelIds = matchingGenePanelIdsMap.get(hugoGeneSymbol) != null ? + matchingGenePanelIdsMap.get(hugoGeneSymbol) : Collections.emptySet(); + + int alterationTotalProfiledCount = computeTotalProfiledCount(hasGenePanelData(matchingGenePanelIds), + profiledCountsMap.getOrDefault(hugoGeneSymbol, 0), + sampleProfileCountWithoutGenePanelData, totalProfiledCount); + + alterationCountByGene.setNumberOfProfiledCases(alterationTotalProfiledCount); + + alterationCountByGene.setMatchingGenePanelIds(matchingGenePanelIds); + + }); + return alterationCounts; + } + + + private boolean hasGenePanelData(@NonNull Set matchingGenePanelIds) { + return matchingGenePanelIds.contains(WHOLE_EXOME_SEQUENCING) + && matchingGenePanelIds.size() > 1 || !matchingGenePanelIds.contains(WHOLE_EXOME_SEQUENCING) && !matchingGenePanelIds.isEmpty(); + } + + private int computeTotalProfiledCount(boolean hasGenePanelData, int alterationsProfiledCount, + int sampleProfileCountWithoutGenePanelData, int totalProfiledCount) { + int profiledCount = hasGenePanelData ? alterationsProfiledCount + sampleProfileCountWithoutGenePanelData + : sampleProfileCountWithoutGenePanelData; + return profiledCount == 0 ? totalProfiledCount : profiledCount; + } + + /** + * Retrieves the first molecular profile for each study based on the alteration type. + * + * @param studyViewFilterContext Context containing filter criteria. + * @param alterationType Type of alteration (e.g., mutation, CNA, structural variant). + * @return List of MolecularProfile objects representing the first profile for each study. + */ + private List getFirstMolecularProfileGroupedByStudy(StudyViewFilterContext studyViewFilterContext, AlterationType alterationType) { + final var molecularProfiles = + getFilteredMolecularProfilesByAlterationType.execute(studyViewFilterContext, alterationType.toString()); + return getFirstMolecularProfileGroupedByStudy(molecularProfiles); + } + + private List getFirstMolecularProfileGroupedByStudy(List molecularProfiles) { + return molecularProfiles.stream() + .collect(Collectors.toMap( + MolecularProfile::getCancerStudyIdentifier, + Function.identity(), + (existing, replacement) -> existing // Keep the first occurrence + )) + .values() + .stream() + .toList(); + } + +} diff --git a/src/main/java/org/cbioportal/domain/alteration/usecase/AlterationCountByGeneUseCases.java b/src/main/java/org/cbioportal/domain/alteration/usecase/AlterationCountByGeneUseCases.java new file mode 100644 index 00000000000..a865aebbd6c --- /dev/null +++ b/src/main/java/org/cbioportal/domain/alteration/usecase/AlterationCountByGeneUseCases.java @@ -0,0 +1,13 @@ +package org.cbioportal.domain.alteration.usecase; + +import org.springframework.context.annotation.Profile; +import org.springframework.stereotype.Service; + +@Service +@Profile("clickhouse") +public record AlterationCountByGeneUseCases( + GetAlterationCountByGeneUseCase getAlterationCountByGeneUseCase, + GetCnaAlterationCountByGeneUseCase getCnaAlterationCountByGeneUseCase) { + + +} diff --git a/src/main/java/org/cbioportal/domain/alteration/usecase/GetAlterationCountByGeneUseCase.java b/src/main/java/org/cbioportal/domain/alteration/usecase/GetAlterationCountByGeneUseCase.java new file mode 100644 index 00000000000..526ca2452df --- /dev/null +++ b/src/main/java/org/cbioportal/domain/alteration/usecase/GetAlterationCountByGeneUseCase.java @@ -0,0 +1,144 @@ +package org.cbioportal.domain.alteration.usecase; + +import org.cbioportal.domain.alteration.repository.AlterationRepository; +import org.cbioportal.domain.cancerstudy.usecase.GetFilteredStudyIdsUseCase; +import org.cbioportal.domain.generic_assay.usecase.GetFilteredMolecularProfilesByAlterationType; +import org.cbioportal.domain.studyview.StudyViewFilterContext; +import org.cbioportal.legacy.model.AlterationCountByGene; +import org.cbioportal.legacy.model.AlterationType; +import org.cbioportal.legacy.model.MutSig; +import org.cbioportal.legacy.service.SignificantlyMutatedGeneService; +import org.cbioportal.legacy.service.exception.StudyNotFoundException; +import org.cbioportal.legacy.web.parameter.Projection; +import org.springframework.context.annotation.Profile; +import org.springframework.stereotype.Service; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.function.Function; +import java.util.stream.Collectors; + +@Service +@Profile("clickhouse") +public class GetAlterationCountByGeneUseCase extends AbstractAlterationCountByGeneUseCase { + private final AlterationRepository alterationRepository; + private final GetFilteredStudyIdsUseCase getFilteredStudyIdsUseCase; + private final SignificantlyMutatedGeneService significantlyMutatedGeneService; + public GetAlterationCountByGeneUseCase(AlterationRepository alterationRepository, GetFilteredMolecularProfilesByAlterationType getFilteredMolecularProfilesByAlterationType, GetFilteredStudyIdsUseCase getFilteredStudyIdsUseCase, SignificantlyMutatedGeneService significantlyMutatedGeneService) { + super(alterationRepository, getFilteredMolecularProfilesByAlterationType); + + this.alterationRepository = alterationRepository; + this.getFilteredStudyIdsUseCase = getFilteredStudyIdsUseCase; + this.significantlyMutatedGeneService = significantlyMutatedGeneService; + } + + /** + * Retrieves alteration counts by gene based on the given {@link AlterationType} and study filter context. + * Supports {@code MUTATION_EXTENDED} and {@code STRUCTURAL_VARIANT} alteration types. + * + * @param studyViewFilterContext the context containing study view filters + * @param alterationType the type of alteration to retrieve (must be either {@code MUTATION_EXTENDED} or {@code STRUCTURAL_VARIANT}) + * @return a list of {@link AlterationCountByGene} objects containing alteration counts + * @throws StudyNotFoundException if the study is not found + * @throws UnsupportedOperationException if the given {@code alterationType} is not supported + */ + public List execute(StudyViewFilterContext studyViewFilterContext, + AlterationType alterationType) throws StudyNotFoundException { + + final List alterationCountByGenes = switch (alterationType) { + case MUTATION_EXTENDED -> alterationRepository.getMutatedGenes(studyViewFilterContext); + case STRUCTURAL_VARIANT -> alterationRepository.getStructuralVariantGenes(studyViewFilterContext); + default -> throw new UnsupportedOperationException("AlterationType " + alterationType + " not supported.." + + ". For cna... use GetCnaAlterationCountByGeneUseCase"); + }; + + var combinedAlterationCountByGenes = + combineAlterationCountsWithConflictingHugoSymbols(alterationCountByGenes); + + return populateAlterationCountsWithMutSigQValue( + populateAlterationCounts( + combinedAlterationCountByGenes, + studyViewFilterContext, alterationType), + studyViewFilterContext); + } + + /** + * Combines alteration counts by Hugo gene symbols. If multiple entries exist for the same + * gene symbol, their number of altered cases and total counts are summed up. Returns a + * list of unique AlterationCountByGene objects where each gene symbol is represented only once. + * + * This appears in the Data where Genes have similar Hugo Gene Symbols but different Entrez Ids + * + * @param alterationCounts List of AlterationCountByGene objects, potentially with duplicate gene symbols + * @return List of AlterationCountByGene objects with unique gene symbols and combined counts + */ + private List combineAlterationCountsWithConflictingHugoSymbols(List alterationCounts) { + Map alterationCountByGeneMap = new HashMap<>(); + for (var alterationCount : alterationCounts) { + if (alterationCountByGeneMap.containsKey(alterationCount.getHugoGeneSymbol())){ + AlterationCountByGene toUpdate = alterationCountByGeneMap.get(alterationCount.getHugoGeneSymbol()); + toUpdate.setNumberOfAlteredCases(toUpdate.getNumberOfAlteredCases() + alterationCount.getNumberOfAlteredCases()); + toUpdate.setTotalCount(toUpdate.getTotalCount() + alterationCount.getTotalCount()); + } else { + alterationCountByGeneMap.put(alterationCount.getHugoGeneSymbol(), alterationCount); + } + } + return alterationCountByGeneMap.values().stream().toList(); + } + + /** + * Updates alteration counts with MutSig Q-value data for significance. + * + * @param alterationCountByGenes List of alteration counts to update. + * @param studyViewFilterContext Context containing filter criteria. + * @return List of alteration counts updated with MutSig Q-value. + * @throws StudyNotFoundException if the specified study is not found. + */ + private List populateAlterationCountsWithMutSigQValue(List alterationCountByGenes, StudyViewFilterContext studyViewFilterContext) throws StudyNotFoundException { + final var mutSigs = getMutSigs(studyViewFilterContext); + // If MutSig is not empty update Mutated Genes + return updateAlterationCountsWithMutSigQValue(alterationCountByGenes, mutSigs); + } + + /** + * Retrieves MutSig data for significantly mutated genes in the specified studies. + * + * @param studyViewFilterContext Context containing filter criteria. + * @return Map of MutSig objects keyed by Hugo gene symbol. + * @throws StudyNotFoundException if the specified study is not found. + */ + private Map getMutSigs(StudyViewFilterContext studyViewFilterContext) throws StudyNotFoundException { + var distinctStudyIds = getFilteredStudyIdsUseCase.execute(studyViewFilterContext); + Map mutSigs = new HashMap<>(); + if (distinctStudyIds.size() == 1) { + var studyId = distinctStudyIds.getFirst(); + mutSigs = significantlyMutatedGeneService.getSignificantlyMutatedGenes( + studyId, + Projection.SUMMARY.name(), + null, + null, + null, + null) + .stream() + .collect(Collectors.toMap(MutSig::getHugoGeneSymbol, Function.identity())); + } + return mutSigs; + } + + private List updateAlterationCountsWithMutSigQValue( + List alterationCountByGenes, + Map mutSigs) { + + if (!mutSigs.isEmpty()) { + alterationCountByGenes.parallelStream() + .filter(alterationCount -> mutSigs.containsKey(alterationCount.getHugoGeneSymbol())) + .forEach(alterationCount -> + alterationCount.setqValue(mutSigs.get(alterationCount.getHugoGeneSymbol()).getqValue()) + ); + } + return alterationCountByGenes; + } + + +} diff --git a/src/main/java/org/cbioportal/domain/alteration/usecase/GetCnaAlterationCountByGeneUseCase.java b/src/main/java/org/cbioportal/domain/alteration/usecase/GetCnaAlterationCountByGeneUseCase.java new file mode 100644 index 00000000000..318a50c90d0 --- /dev/null +++ b/src/main/java/org/cbioportal/domain/alteration/usecase/GetCnaAlterationCountByGeneUseCase.java @@ -0,0 +1,131 @@ +package org.cbioportal.domain.alteration.usecase; + +import org.apache.commons.math3.util.Pair; +import org.cbioportal.domain.alteration.repository.AlterationRepository; +import org.cbioportal.domain.cancerstudy.usecase.GetFilteredStudyIdsUseCase; +import org.cbioportal.domain.generic_assay.usecase.GetFilteredMolecularProfilesByAlterationType; +import org.cbioportal.domain.studyview.StudyViewFilterContext; +import org.cbioportal.legacy.model.AlterationType; +import org.cbioportal.legacy.model.CopyNumberCountByGene; +import org.cbioportal.legacy.model.Gistic; +import org.cbioportal.legacy.service.SignificantCopyNumberRegionService; +import org.cbioportal.legacy.service.exception.StudyNotFoundException; +import org.cbioportal.legacy.service.util.AlterationCountServiceUtil; +import org.cbioportal.legacy.web.parameter.Projection; +import org.springframework.context.annotation.Profile; +import org.springframework.stereotype.Service; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +@Service +@Profile("clickhouse") +public class GetCnaAlterationCountByGeneUseCase extends AbstractAlterationCountByGeneUseCase{ + + private final AlterationRepository alterationRepository; + private final GetFilteredStudyIdsUseCase getFilteredStudyIdsUseCase; + private final SignificantCopyNumberRegionService significantCopyNumberRegionService; + + public GetCnaAlterationCountByGeneUseCase(AlterationRepository alterationRepository, + GetFilteredMolecularProfilesByAlterationType getFilteredMolecularProfilesByAlterationType, GetFilteredStudyIdsUseCase getFilteredStudyIdsUseCase, SignificantCopyNumberRegionService significantCopyNumberRegionService){ + super(alterationRepository,getFilteredMolecularProfilesByAlterationType); + + this.alterationRepository = alterationRepository; + this.getFilteredStudyIdsUseCase = getFilteredStudyIdsUseCase; + this.significantCopyNumberRegionService = significantCopyNumberRegionService; + } + + /** + * Retrieves a list of genes with copy number alterations (CNA) and their alteration counts for a given filter context. + * + * @param studyViewFilterContext Context containing filter criteria. + * @return List of CopyNumberCountByGene objects representing genes with CNAs. + * @throws StudyNotFoundException if the specified study is not found. + */ + public List execute(StudyViewFilterContext studyViewFilterContext) throws StudyNotFoundException { + var combinedCopyNumberCountByGene = + combineCopyNumberCountsWithConflictingHugoSymbols(alterationRepository.getCnaGenes(studyViewFilterContext)); + return populateAlterationCountsWithCNASigQValue( + populateAlterationCounts(combinedCopyNumberCountByGene,studyViewFilterContext, + AlterationType.COPY_NUMBER_ALTERATION), + studyViewFilterContext); + } + + /** + * Combines alteration counts by Hugo gene symbols. If multiple entries exist for the same + * gene symbol, their number of altered cases and total counts are summed up. Returns a + * list of unique AlterationCountByGene objects where each gene symbol is represented only once. + * + * This appears in the Data where Genes have similar Hugo Gene Symbols but different Entrez Ids. + * This is a special case to handle Copy Number Mutations where the Alteration type should be a part of the key + * + * @param alterationCounts List of CopyNumberCountByGene objects, potentially with duplicate gene symbols + * @return List of AlterationCountByGene objects with unique gene symbols and combined counts + */ + private List combineCopyNumberCountsWithConflictingHugoSymbols(List alterationCounts) { + Map, CopyNumberCountByGene> alterationCountByGeneMap = new HashMap<>(); + for (var alterationCount : alterationCounts) { + var copyNumberKey = Pair.create(alterationCount.getHugoGeneSymbol(), alterationCount.getAlteration()); + if (alterationCountByGeneMap.containsKey(copyNumberKey)) { + CopyNumberCountByGene toUpdate = alterationCountByGeneMap.get(copyNumberKey); + toUpdate.setNumberOfAlteredCases(toUpdate.getNumberOfAlteredCases() + alterationCount.getNumberOfAlteredCases()); + toUpdate.setTotalCount(toUpdate.getTotalCount() + alterationCount.getTotalCount()); + } else { + alterationCountByGeneMap.put(copyNumberKey, alterationCount); + } + } + return alterationCountByGeneMap.values().stream().toList(); + } + + /** + * Updates copy number alteration counts with GISTIC significance data. + * + * @param alterationCountByGenes List of alteration counts to update. + * @param studyViewFilterContext Context containing filter criteria. + * @return List of alteration counts updated with GISTIC significance data. + * @throws StudyNotFoundException if the specified study is not found. + */ + private List populateAlterationCountsWithCNASigQValue(List alterationCountByGenes, StudyViewFilterContext studyViewFilterContext) throws StudyNotFoundException { + final var gisticMap = getGisticMap(studyViewFilterContext); + return updateAlterationCountsWithCNASigQValue(alterationCountByGenes, gisticMap); + } + + /** + * Retrieves GISTIC data for significant copy number alterations in the specified studies. + * + * @param studyViewFilterContext Context containing filter criteria. + * @return Map of GISTIC objects keyed by gene and G-score rank. + * @throws StudyNotFoundException if the specified study is not found. + */ + private Map, Gistic> getGisticMap(StudyViewFilterContext studyViewFilterContext) throws StudyNotFoundException { + var distinctStudyIds = getFilteredStudyIdsUseCase.execute(studyViewFilterContext); + Map, Gistic> gisticMap = new HashMap<>(); + if (distinctStudyIds.size() == 1) { + var studyId = distinctStudyIds.getFirst(); + List gisticList = significantCopyNumberRegionService.getSignificantCopyNumberRegions( + studyId, + Projection.SUMMARY.name(), + null, + null, + null, + null); + AlterationCountServiceUtil.setupGisticMap(gisticList, gisticMap); + } + return gisticMap; + } + + private List updateAlterationCountsWithCNASigQValue( + List alterationCountByGenes, + Map, Gistic> gisticMap) { + + if (!gisticMap.isEmpty()) { + alterationCountByGenes.parallelStream() + .filter(alterationCount -> gisticMap.containsKey(Pair.create(alterationCount.getHugoGeneSymbol(), alterationCount.getAlteration()))) + .forEach(alterationCount -> + alterationCount.setqValue(gisticMap.get(Pair.create(alterationCount.getHugoGeneSymbol(), alterationCount.getAlteration())).getqValue()) + ); + } + return alterationCountByGenes; + } +} diff --git a/src/main/java/org/cbioportal/cancerstudy/CancerStudyMetadata.java b/src/main/java/org/cbioportal/domain/cancerstudy/CancerStudyMetadata.java similarity index 97% rename from src/main/java/org/cbioportal/cancerstudy/CancerStudyMetadata.java rename to src/main/java/org/cbioportal/domain/cancerstudy/CancerStudyMetadata.java index 4631e559084..3114be6fc3c 100644 --- a/src/main/java/org/cbioportal/cancerstudy/CancerStudyMetadata.java +++ b/src/main/java/org/cbioportal/domain/cancerstudy/CancerStudyMetadata.java @@ -1,4 +1,4 @@ -package org.cbioportal.cancerstudy; +package org.cbioportal.domain.cancerstudy; import java.util.Date; diff --git a/src/main/java/org/cbioportal/cancerstudy/TypeOfCancer.java b/src/main/java/org/cbioportal/domain/cancerstudy/TypeOfCancer.java similarity index 72% rename from src/main/java/org/cbioportal/cancerstudy/TypeOfCancer.java rename to src/main/java/org/cbioportal/domain/cancerstudy/TypeOfCancer.java index a1265421641..91ae9342812 100644 --- a/src/main/java/org/cbioportal/cancerstudy/TypeOfCancer.java +++ b/src/main/java/org/cbioportal/domain/cancerstudy/TypeOfCancer.java @@ -1,4 +1,4 @@ -package org.cbioportal.cancerstudy; +package org.cbioportal.domain.cancerstudy; public record TypeOfCancer(String id, String name, String dedicatedColor, String shortName, String parent) { } diff --git a/src/main/java/org/cbioportal/cancerstudy/repository/CancerStudyRepository.java b/src/main/java/org/cbioportal/domain/cancerstudy/repository/CancerStudyRepository.java similarity index 91% rename from src/main/java/org/cbioportal/cancerstudy/repository/CancerStudyRepository.java rename to src/main/java/org/cbioportal/domain/cancerstudy/repository/CancerStudyRepository.java index fe9856e7c9c..e729b408827 100644 --- a/src/main/java/org/cbioportal/cancerstudy/repository/CancerStudyRepository.java +++ b/src/main/java/org/cbioportal/domain/cancerstudy/repository/CancerStudyRepository.java @@ -1,7 +1,8 @@ -package org.cbioportal.cancerstudy.repository; +package org.cbioportal.domain.cancerstudy.repository; -import org.cbioportal.cancerstudy.CancerStudyMetadata; +import org.cbioportal.domain.cancerstudy.CancerStudyMetadata; import org.cbioportal.shared.SortAndSearchCriteria; +import org.cbioportal.domain.studyview.StudyViewFilterContext; import java.util.List; @@ -74,4 +75,6 @@ public interface CancerStudyRepository { * are found. */ List getCancerStudiesMetadataSummary(SortAndSearchCriteria sortAndSearchCriteria); + + List getFilteredStudyIds(StudyViewFilterContext studyViewFilterContext); } diff --git a/src/main/java/org/cbioportal/cancerstudy/usecase/GetCancerStudyMetadataUseCase.java b/src/main/java/org/cbioportal/domain/cancerstudy/usecase/GetCancerStudyMetadataUseCase.java similarity index 94% rename from src/main/java/org/cbioportal/cancerstudy/usecase/GetCancerStudyMetadataUseCase.java rename to src/main/java/org/cbioportal/domain/cancerstudy/usecase/GetCancerStudyMetadataUseCase.java index 47241038b1e..983465e747b 100644 --- a/src/main/java/org/cbioportal/cancerstudy/usecase/GetCancerStudyMetadataUseCase.java +++ b/src/main/java/org/cbioportal/domain/cancerstudy/usecase/GetCancerStudyMetadataUseCase.java @@ -1,7 +1,7 @@ -package org.cbioportal.cancerstudy.usecase; +package org.cbioportal.domain.cancerstudy.usecase; -import org.cbioportal.cancerstudy.CancerStudyMetadata; -import org.cbioportal.cancerstudy.repository.CancerStudyRepository; +import org.cbioportal.domain.cancerstudy.CancerStudyMetadata; +import org.cbioportal.domain.cancerstudy.repository.CancerStudyRepository; import org.cbioportal.shared.SortAndSearchCriteria; import org.cbioportal.shared.enums.ProjectionType; import org.springframework.context.annotation.Profile; diff --git a/src/main/java/org/cbioportal/domain/cancerstudy/usecase/GetFilteredStudyIdsUseCase.java b/src/main/java/org/cbioportal/domain/cancerstudy/usecase/GetFilteredStudyIdsUseCase.java new file mode 100644 index 00000000000..d691f7135f0 --- /dev/null +++ b/src/main/java/org/cbioportal/domain/cancerstudy/usecase/GetFilteredStudyIdsUseCase.java @@ -0,0 +1,23 @@ +package org.cbioportal.domain.cancerstudy.usecase; + +import org.cbioportal.domain.cancerstudy.repository.CancerStudyRepository; +import org.cbioportal.domain.studyview.StudyViewFilterContext; +import org.springframework.context.annotation.Profile; +import org.springframework.stereotype.Service; + +import java.util.List; + +@Service +@Profile("clickhouse") +public class GetFilteredStudyIdsUseCase { + + private final CancerStudyRepository studyRepository; + + public GetFilteredStudyIdsUseCase(CancerStudyRepository studyRepository) { + this.studyRepository = studyRepository; + } + + public List execute(StudyViewFilterContext studyViewFilterContext) { + return this.studyRepository.getFilteredStudyIds(studyViewFilterContext); + } +} diff --git a/src/main/java/org/cbioportal/domain/clinical_attributes/repository/ClinicalAttributesRepository.java b/src/main/java/org/cbioportal/domain/clinical_attributes/repository/ClinicalAttributesRepository.java new file mode 100644 index 00000000000..c0e3c8a99f4 --- /dev/null +++ b/src/main/java/org/cbioportal/domain/clinical_attributes/repository/ClinicalAttributesRepository.java @@ -0,0 +1,25 @@ +package org.cbioportal.domain.clinical_attributes.repository; + +import org.cbioportal.legacy.model.ClinicalAttribute; +import org.cbioportal.legacy.web.parameter.ClinicalDataType; + +import java.util.List; +import java.util.Map; + +public interface ClinicalAttributesRepository { + + /** + * Retrieves a list of clinical attributes for the specified studies. + * + * @param studyIds A list of study IDs. + * @return A list of {@link ClinicalAttribute} representing the clinical attributes for the given studies. + */ + List getClinicalAttributesForStudies(List studyIds); + + /** + * Retrieves a mapping of clinical attribute names to their corresponding data types. + * + * @return A map where the key is the clinical attribute name and the value is the corresponding {@link ClinicalDataType}. + */ + Map getClinicalAttributeDatatypeMap(); +} \ No newline at end of file diff --git a/src/main/java/org/cbioportal/domain/clinical_attributes/usecase/GetClinicalAttributesDataTypeMapUseCase.java b/src/main/java/org/cbioportal/domain/clinical_attributes/usecase/GetClinicalAttributesDataTypeMapUseCase.java new file mode 100644 index 00000000000..e9fc3070be9 --- /dev/null +++ b/src/main/java/org/cbioportal/domain/clinical_attributes/usecase/GetClinicalAttributesDataTypeMapUseCase.java @@ -0,0 +1,39 @@ +package org.cbioportal.domain.clinical_attributes.usecase; + +import org.cbioportal.domain.clinical_attributes.repository.ClinicalAttributesRepository; +import org.cbioportal.legacy.web.parameter.ClinicalDataType; +import org.springframework.context.annotation.Profile; +import org.springframework.stereotype.Service; + +import java.util.Map; + +@Service +@Profile("clickhouse") +/** + * Use case for retrieving a mapping of clinical attribute names to their corresponding data types. + * This class interacts with the {@link ClinicalAttributesRepository} to fetch the required data. + */ +public class GetClinicalAttributesDataTypeMapUseCase { + + private final ClinicalAttributesRepository clinicalAttributesRepository; + + + /** + * Constructs a use case for retrieving the clinical attribute data type map. + * + * @param clinicalAttributesRepository The repository used to fetch clinical attribute data types. + */ + public GetClinicalAttributesDataTypeMapUseCase(ClinicalAttributesRepository clinicalAttributesRepository) { + this.clinicalAttributesRepository = clinicalAttributesRepository; + } + + + /** + * Executes the use case to retrieve a mapping of clinical attribute names to their corresponding data types. + * + * @return A map where the key is the clinical attribute name and the value is the corresponding {@link ClinicalDataType}. + */ + public Map execute() { + return clinicalAttributesRepository.getClinicalAttributeDatatypeMap(); + } +} diff --git a/src/main/java/org/cbioportal/domain/clinical_attributes/usecase/GetClinicalAttributesForStudiesUseCase.java b/src/main/java/org/cbioportal/domain/clinical_attributes/usecase/GetClinicalAttributesForStudiesUseCase.java new file mode 100644 index 00000000000..3b0fbff7339 --- /dev/null +++ b/src/main/java/org/cbioportal/domain/clinical_attributes/usecase/GetClinicalAttributesForStudiesUseCase.java @@ -0,0 +1,39 @@ +package org.cbioportal.domain.clinical_attributes.usecase; + +import org.cbioportal.domain.clinical_attributes.repository.ClinicalAttributesRepository; +import org.cbioportal.legacy.model.ClinicalAttribute; +import org.springframework.context.annotation.Profile; +import org.springframework.stereotype.Service; + +import java.util.List; + +@Service +@Profile("clickhouse") +/** + * Use case for retrieving clinical attributes for specified studies. + * This class interacts with the {@link ClinicalAttributesRepository} to fetch the required data. + */ +public class GetClinicalAttributesForStudiesUseCase { + + private final ClinicalAttributesRepository clinicalAttributesRepository; + + /** + * Constructs a use case for retrieving clinical attributes for studies. + * + * @param clinicalAttributesRepository The repository used to fetch clinical attributes. + */ + public GetClinicalAttributesForStudiesUseCase(ClinicalAttributesRepository clinicalAttributesRepository) { + this.clinicalAttributesRepository = clinicalAttributesRepository; + } + + /** + * Executes the use case to retrieve clinical attributes for the given list of study IDs. + * + * @param studyIds A list of study IDs. + * @return A list of {@link ClinicalAttribute} representing the clinical attributes for the given studies. + */ + public List execute(List studyIds){ + return clinicalAttributesRepository.getClinicalAttributesForStudies(studyIds); + } +} + diff --git a/src/main/java/org/cbioportal/domain/clinical_data/repository/ClinicalDataRepository.java b/src/main/java/org/cbioportal/domain/clinical_data/repository/ClinicalDataRepository.java new file mode 100644 index 00000000000..7b3a5c969e3 --- /dev/null +++ b/src/main/java/org/cbioportal/domain/clinical_data/repository/ClinicalDataRepository.java @@ -0,0 +1,41 @@ +package org.cbioportal.domain.clinical_data.repository; + +import org.cbioportal.legacy.model.ClinicalData; +import org.cbioportal.legacy.model.ClinicalDataCountItem; +import org.cbioportal.domain.studyview.StudyViewFilterContext; + +import java.util.List; + +/** + * Repository interface for retrieving clinical data related to patients and samples. + */ +public interface ClinicalDataRepository { + + /** + * Retrieves clinical data for patients based on the given study view filter context and filtered attributes. + * + * @param studyViewFilterContext The filter criteria for the study view. + * @param filteredAttributes A list of attributes to filter the clinical data. + * @return A list of {@link ClinicalData} representing patient clinical data. + */ + List getPatientClinicalData(StudyViewFilterContext studyViewFilterContext, List filteredAttributes); + + /** + * Retrieves clinical data for samples based on the given study view filter context and filtered attributes. + * + * @param studyViewFilterContext The filter criteria for the study view. + * @param filteredAttributes A list of attributes to filter the clinical data. + * @return A list of {@link ClinicalData} representing sample clinical data. + */ + List getSampleClinicalData(StudyViewFilterContext studyViewFilterContext, List filteredAttributes); + + /** + * Retrieves counts of clinical data records based on the given study view filter context and filtered attributes. + * + * @param studyViewFilterContext The filter criteria for the study view. + * @param filteredAttributes A list of attributes to filter the clinical data. + * @return A list of {@link ClinicalDataCountItem} representing clinical data counts. + */ + List getClinicalDataCounts(StudyViewFilterContext studyViewFilterContext, + List filteredAttributes); +} diff --git a/src/main/java/org/cbioportal/domain/clinical_data/usecase/ClinicalDataUseCases.java b/src/main/java/org/cbioportal/domain/clinical_data/usecase/ClinicalDataUseCases.java new file mode 100644 index 00000000000..d698168e57a --- /dev/null +++ b/src/main/java/org/cbioportal/domain/clinical_data/usecase/ClinicalDataUseCases.java @@ -0,0 +1,24 @@ +package org.cbioportal.domain.clinical_data.usecase; + +import org.springframework.context.annotation.Profile; +import org.springframework.stereotype.Service; + +@Service +@Profile("clickhouse") +/** + * A record representing a collection of use cases related to clinical data operations. + * This record encapsulates instances of various use case classes, providing a centralized + * way to access and manage clinical data-related operations. + * + * @param getClinicalDataCountsUseCase the use case for retrieving and processing clinical data counts + * @param getClinicalDataForXyPlotUseCase the use case for retrieving clinical data for XY plots + * @param getPatientClinicalDataUseCase the use case for retrieving clinical data for patients + * @param getSampleClinicalDataUseCase the use case for retrieving clinical data for samples + */ +public record ClinicalDataUseCases( + GetClinicalDataCountsUseCase getClinicalDataCountsUseCase, + GetClinicalDataForXyPlotUseCase getClinicalDataForXyPlotUseCase, + GetPatientClinicalDataUseCase getPatientClinicalDataUseCase, + GetSampleClinicalDataUseCase getSampleClinicalDataUseCase +) { +} diff --git a/src/main/java/org/cbioportal/domain/clinical_data/usecase/GetClinicalDataCountsUseCase.java b/src/main/java/org/cbioportal/domain/clinical_data/usecase/GetClinicalDataCountsUseCase.java new file mode 100644 index 00000000000..b18020d4e5a --- /dev/null +++ b/src/main/java/org/cbioportal/domain/clinical_data/usecase/GetClinicalDataCountsUseCase.java @@ -0,0 +1,90 @@ +package org.cbioportal.domain.clinical_data.usecase; + +import org.cbioportal.domain.clinical_attributes.usecase.GetClinicalAttributesForStudiesUseCase; +import org.cbioportal.domain.clinical_data.repository.ClinicalDataRepository; +import org.cbioportal.legacy.model.ClinicalDataCountItem; +import org.cbioportal.legacy.service.util.StudyViewColumnarServiceUtil; +import org.cbioportal.domain.patient.usecase.GetFilteredPatientCountUseCase; +import org.cbioportal.domain.sample.usecase.GetFilteredSamplesCountUseCase; +import org.cbioportal.domain.studyview.StudyViewFilterContext; +import org.springframework.context.annotation.Profile; +import org.springframework.stereotype.Service; + +import java.util.List; + +@Service +@Profile("clickhouse") +/** + * Use case for retrieving and processing clinical data counts. + * This class orchestrates the retrieval of clinical data counts from the repository, + * normalizes the data, and ensures that missing attributes are accounted for in the result. + */ +public class GetClinicalDataCountsUseCase { + + private final ClinicalDataRepository clinicalDataRepository; + private final GetClinicalAttributesForStudiesUseCase getClinicalAttributesForStudiesUseCase; + private final GetFilteredSamplesCountUseCase getFilteredSamplesCountUseCase; + private final GetFilteredPatientCountUseCase getFilteredPatientCountUseCase; + + /** + * Constructs a {@code GetClinicalDataCountsUseCase} with the provided use cases and repository. + * + * @param clinicalDataRepository the repository to be used for retrieving clinical data counts + * @param getClinicalAttributesForStudiesUseCase the use case for retrieving clinical attributes for studies + * @param getFilteredSamplesCountUseCase the use case for retrieving filtered sample counts + * @param getFilteredPatientCountUseCase the use case for retrieving filtered patient counts + */ + public GetClinicalDataCountsUseCase( + ClinicalDataRepository clinicalDataRepository, + GetClinicalAttributesForStudiesUseCase getClinicalAttributesForStudiesUseCase, + GetFilteredSamplesCountUseCase getFilteredSamplesCountUseCase, + GetFilteredPatientCountUseCase getFilteredPatientCountUseCase) { + this.clinicalDataRepository = clinicalDataRepository; + this.getClinicalAttributesForStudiesUseCase = getClinicalAttributesForStudiesUseCase; + this.getFilteredSamplesCountUseCase = getFilteredSamplesCountUseCase; + this.getFilteredPatientCountUseCase = getFilteredPatientCountUseCase; + } + + /** + * Executes the use case to retrieve and process clinical data counts. + * It normalizes the data counts and ensures that missing attributes are restored. + * + * @param studyViewFilterContext the context of the study view filter to apply + * @param filteredAttributes a list of filtered clinical attribute IDs + * @return a list of {@link ClinicalDataCountItem} containing the normalized and complete clinical data counts + */ + public List execute(StudyViewFilterContext studyViewFilterContext, + List filteredAttributes) { + + List involvedCancerStudies = studyViewFilterContext.customDataFilterCancerStudies(); + + var result = clinicalDataRepository.getClinicalDataCounts(studyViewFilterContext, filteredAttributes); + + // Normalize data counts so that values like TRUE, True, and true are all merged in one count + result.forEach(item -> item.setCounts(StudyViewColumnarServiceUtil.normalizeDataCounts(item.getCounts()))); + + // attributes may be missing in result set because they have been filtered out + // e.g. if the filtered samples happen to have no SEX data, they will not appear in the list + // even though the inferred value of those attributes is NA + // the following code restores these counts for missing attributes + if (result.size() != filteredAttributes.size()) { + var attributes = getClinicalAttributesForStudiesUseCase.execute(involvedCancerStudies) + .stream() + .filter(attribute -> filteredAttributes.contains(attribute.getAttrId())) + .toList(); + + Integer filteredSampleCount = getFilteredSamplesCountUseCase.execute(studyViewFilterContext); + Integer filteredPatientCount = getFilteredPatientCountUseCase.execute(studyViewFilterContext); + + result = StudyViewColumnarServiceUtil.addClinicalDataCountsForMissingAttributes( + result, + attributes, + filteredSampleCount, + filteredPatientCount + ); + } + + return StudyViewColumnarServiceUtil.mergeClinicalDataCounts(result); + } +} + diff --git a/src/main/java/org/cbioportal/domain/clinical_data/usecase/GetClinicalDataForXyPlotUseCase.java b/src/main/java/org/cbioportal/domain/clinical_data/usecase/GetClinicalDataForXyPlotUseCase.java new file mode 100644 index 00000000000..83905cb1713 --- /dev/null +++ b/src/main/java/org/cbioportal/domain/clinical_data/usecase/GetClinicalDataForXyPlotUseCase.java @@ -0,0 +1,163 @@ +package org.cbioportal.domain.clinical_data.usecase; + +import org.cbioportal.legacy.model.ClinicalData; +import org.cbioportal.domain.sample.Sample; +import org.cbioportal.domain.sample.usecase.GetFilteredSamplesUseCase; +import org.cbioportal.domain.studyview.StudyViewFilterContext; +import org.springframework.context.annotation.Profile; +import org.springframework.stereotype.Service; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +@Service +@Profile("clickhouse") +/** + * Use case for retrieving and combining clinical data for an XY plot. + * This class orchestrates the fetching of clinical data for both patients and samples, + * then combines them based on the provided context and filter options, preparing them for XY plot visualization. + */ +public class GetClinicalDataForXyPlotUseCase { + + private final GetPatientClinicalDataUseCase getPatientClinicalDataUseCase; + private final GetSampleClinicalDataUseCase getSampleClinicalDataUseCase; + private final GetFilteredSamplesUseCase getFilteredSamplesUseCase; + + /** + * Constructs a {@code GetClinicalDataForXyPlotUseCase} with the provided use cases. + * + * @param getPatientClinicalDataUseCase the use case for retrieving patient clinical data + * @param getSampleClinicalDataUseCase the use case for retrieving sample clinical data + * @param getFilteredSamplesUseCase the use case for filtering samples + */ + public GetClinicalDataForXyPlotUseCase( + GetPatientClinicalDataUseCase getPatientClinicalDataUseCase, + GetSampleClinicalDataUseCase getSampleClinicalDataUseCase, + GetFilteredSamplesUseCase getFilteredSamplesUseCase) { + this.getPatientClinicalDataUseCase = getPatientClinicalDataUseCase; + this.getSampleClinicalDataUseCase = getSampleClinicalDataUseCase; + this.getFilteredSamplesUseCase = getFilteredSamplesUseCase; + } + + /** + * Executes the use case to retrieve and combine clinical data for an XY plot. + * + * @param studyViewFilterContext the context of the study view filter to apply + * @param attributeIds a list of attribute IDs to filter the clinical data + * @param shouldFilterNonEmptyClinicalData flag indicating whether to filter out clinical data with empty values + * @return a list of {@link ClinicalData} ready for XY plot visualization + */ + public List execute(StudyViewFilterContext studyViewFilterContext, List attributeIds, + boolean shouldFilterNonEmptyClinicalData) { + + List sampleClinicalDataList = getSampleClinicalDataUseCase.execute(studyViewFilterContext, attributeIds); + List patientClinicalDataList = getPatientClinicalDataUseCase.execute(studyViewFilterContext, attributeIds); + + List samples = List.of(); + + if (!patientClinicalDataList.isEmpty()) { + // fetch samples for the given study view filter. + // we need this to construct the complete patient to sample map. + samples = getFilteredSamplesUseCase.execute(studyViewFilterContext); + } + + return combineClinicalDataForXyPlot(sampleClinicalDataList, patientClinicalDataList, samples, shouldFilterNonEmptyClinicalData); + } + + /** + * Combines the clinical data for samples and patients into a single list, optionally filtering non-empty data. + * + * @param sampleClinicalDataList a list of clinical data for samples + * @param patientClinicalDataList a list of clinical data for patients + * @param samples a list of samples to map patient data to + * @param shouldFilterNonEmptyClinicalData flag indicating whether to filter out clinical data with empty values + * @return a list of combined {@link ClinicalData} for XY plot visualization + */ + private List combineClinicalDataForXyPlot( + List sampleClinicalDataList, + List patientClinicalDataList, + List samples, + boolean shouldFilterNonEmptyClinicalData) { + + List combinedClinicalDataList; + + if (shouldFilterNonEmptyClinicalData) { + sampleClinicalDataList = filterNonEmptyClinicalData(sampleClinicalDataList); + patientClinicalDataList = filterNonEmptyClinicalData(patientClinicalDataList); + } + + if (patientClinicalDataList.isEmpty()) { + combinedClinicalDataList = sampleClinicalDataList; + } else { + combinedClinicalDataList = Stream.concat( + sampleClinicalDataList.stream(), + convertPatientClinicalDataToSampleClinicalData(patientClinicalDataList, samples).stream() + ).toList(); + } + + return combinedClinicalDataList; + } + + /** + * Filters out clinical data items with empty attribute values. + * + * @param clinicalData the list of clinical data to filter + * @return a filtered list of {@link ClinicalData} containing only non-empty attribute values + */ + private List filterNonEmptyClinicalData(List clinicalData) { + return clinicalData + .stream() + .filter(data -> !data.getAttrValue().isEmpty()) + .toList(); + } + + /** + * Converts patient clinical data into sample clinical data, mapping each patient to their corresponding samples. + * + * @param patientClinicalDataList a list of clinical data for patients + * @param samplesWithoutNumericalFilter a list of samples to map patient data to + * @return a list of {@link ClinicalData} representing the patient's clinical data in sample form + */ + private List convertPatientClinicalDataToSampleClinicalData( + List patientClinicalDataList, + List samplesWithoutNumericalFilter) { + + List sampleClinicalDataList = new ArrayList<>(); + + Map>> patientToSamples = samplesWithoutNumericalFilter + .stream() + .collect(Collectors.groupingBy( + Sample::patientStableId, + Collectors.groupingBy(Sample::cancerStudyIdentifier) + )); + + // Put all clinical data into sample form + for (ClinicalData d : patientClinicalDataList) { + List samplesForPatient = patientToSamples.get(d.getPatientId()).get(d.getStudyId()); + if (samplesForPatient != null) { + for (Sample s : samplesForPatient) { + ClinicalData newData = new ClinicalData(); + + newData.setInternalId(s.internalId()); + newData.setAttrId(d.getAttrId()); + newData.setPatientId(d.getPatientId()); + newData.setStudyId(d.getStudyId()); + newData.setAttrValue(d.getAttrValue()); + newData.setSampleId(s.stableId()); + + sampleClinicalDataList.add(newData); + } + } else { + // TODO: Ignoring for now rather than throwing an error + // patient has no samples - this shouldn't happen and could affect the integrity + // of the data analysis + // return new ResponseEntity<>(null, HttpStatus.INTERNAL_SERVER_ERROR); + } + } + + return sampleClinicalDataList; + } +} \ No newline at end of file diff --git a/src/main/java/org/cbioportal/domain/clinical_data/usecase/GetPatientClinicalDataUseCase.java b/src/main/java/org/cbioportal/domain/clinical_data/usecase/GetPatientClinicalDataUseCase.java new file mode 100644 index 00000000000..dc22bb67005 --- /dev/null +++ b/src/main/java/org/cbioportal/domain/clinical_data/usecase/GetPatientClinicalDataUseCase.java @@ -0,0 +1,42 @@ +package org.cbioportal.domain.clinical_data.usecase; + +import org.cbioportal.domain.clinical_data.repository.ClinicalDataRepository; +import org.cbioportal.legacy.model.ClinicalData; +import org.cbioportal.domain.studyview.StudyViewFilterContext; +import org.springframework.context.annotation.Profile; +import org.springframework.stereotype.Service; + +import java.util.List; + +@Service +@Profile("clickhouse") +/** + * Use case for retrieving clinical data for a patient from the repository. + * This class encapsulates the business logic for fetching clinical data based on + * the provided study view filter context and filtered attributes. + */ +public class GetPatientClinicalDataUseCase { + + private final ClinicalDataRepository clinicalDataRepository; + + /** + * Constructs a {@code GetPatientClinicalDataUseCase} with the provided repository. + * + * @param clinicalDataRepository the repository to be used for fetching patient clinical data + */ + public GetPatientClinicalDataUseCase(ClinicalDataRepository clinicalDataRepository) { + this.clinicalDataRepository = clinicalDataRepository; + } + + /** + * Executes the use case to retrieve clinical data for a patient. + * + * @param studyViewFilterContext the context of the study view filter to apply + * @param filteredAttributes a list of attributes to filter the clinical data + * @return a list of {@link ClinicalData} representing the patient's clinical data + */ + public List execute(StudyViewFilterContext studyViewFilterContext, List filteredAttributes) { + return clinicalDataRepository.getPatientClinicalData(studyViewFilterContext, filteredAttributes); + } +} + diff --git a/src/main/java/org/cbioportal/domain/clinical_data/usecase/GetSampleClinicalDataUseCase.java b/src/main/java/org/cbioportal/domain/clinical_data/usecase/GetSampleClinicalDataUseCase.java new file mode 100644 index 00000000000..540aebd0d8e --- /dev/null +++ b/src/main/java/org/cbioportal/domain/clinical_data/usecase/GetSampleClinicalDataUseCase.java @@ -0,0 +1,42 @@ +package org.cbioportal.domain.clinical_data.usecase; + +import org.cbioportal.domain.clinical_data.repository.ClinicalDataRepository; +import org.cbioportal.legacy.model.ClinicalData; +import org.cbioportal.domain.studyview.StudyViewFilterContext; +import org.springframework.context.annotation.Profile; +import org.springframework.stereotype.Service; + +import java.util.List; + +@Service +@Profile("clickhouse") +/** + * Use case for retrieving clinical data for a sample from the repository. + * This class encapsulates the business logic for fetching clinical data based on + * the provided study view filter context and filtered attributes. + */ +public class GetSampleClinicalDataUseCase { + + private final ClinicalDataRepository clinicalDataRepository; + + /** + * Constructs a {@code GetSampleClinicalDataUseCase} with the provided repository. + * + * @param clinicalDataRepository the repository to be used for fetching sample clinical data + */ + public GetSampleClinicalDataUseCase(ClinicalDataRepository clinicalDataRepository) { + this.clinicalDataRepository = clinicalDataRepository; + } + + /** + * Executes the use case to retrieve clinical data for a sample. + * + * @param studyViewFilterContext the context of the study view filter to apply + * @param filteredAttributes a list of attributes to filter the clinical data + * @return a list of {@link ClinicalData} representing the sample's clinical data + */ + public List execute(StudyViewFilterContext studyViewFilterContext, List filteredAttributes) { + return clinicalDataRepository.getSampleClinicalData(studyViewFilterContext, filteredAttributes); + } +} + diff --git a/src/main/java/org/cbioportal/domain/clinical_event/repository/ClinicalEventRepository.java b/src/main/java/org/cbioportal/domain/clinical_event/repository/ClinicalEventRepository.java new file mode 100644 index 00000000000..c2770eacd90 --- /dev/null +++ b/src/main/java/org/cbioportal/domain/clinical_event/repository/ClinicalEventRepository.java @@ -0,0 +1,20 @@ +package org.cbioportal.domain.clinical_event.repository; + +import org.cbioportal.legacy.model.ClinicalEventTypeCount; +import org.cbioportal.domain.studyview.StudyViewFilterContext; + +import java.util.List; + +/** + * Repository interface for retrieving clinical events and related data. + */ +public interface ClinicalEventRepository { + + /** + * Retrieves counts of different clinical event types based on the given study view filter context. + * + * @param studyViewFilterContext The filter criteria for the study view. + * @return A list of {@link ClinicalEventTypeCount} representing the counts of clinical event types. + */ + List getClinicalEventTypeCounts(StudyViewFilterContext studyViewFilterContext); +} diff --git a/src/main/java/org/cbioportal/domain/clinical_event/usecase/GetClinicalEventTypeCountsUseCase.java b/src/main/java/org/cbioportal/domain/clinical_event/usecase/GetClinicalEventTypeCountsUseCase.java new file mode 100644 index 00000000000..192b13cfdb1 --- /dev/null +++ b/src/main/java/org/cbioportal/domain/clinical_event/usecase/GetClinicalEventTypeCountsUseCase.java @@ -0,0 +1,39 @@ +package org.cbioportal.domain.clinical_event.usecase; + +import org.cbioportal.domain.clinical_event.repository.ClinicalEventRepository; +import org.cbioportal.legacy.model.ClinicalEventTypeCount; +import org.cbioportal.domain.studyview.StudyViewFilterContext; +import org.springframework.context.annotation.Profile; +import org.springframework.stereotype.Service; + +import java.util.List; + +@Service +@Profile("clickhouse") +/** + * Use case for retrieving counts of different clinical event types. + * This class interacts with the {@link ClinicalEventRepository} to fetch the required data. + */ +public class GetClinicalEventTypeCountsUseCase { + + private final ClinicalEventRepository clinicalEventRepository; + + /** + * Constructs a use case for retrieving clinical event type counts. + * + * @param clinicalEventRepository The repository used to fetch clinical event type counts. + */ + public GetClinicalEventTypeCountsUseCase(ClinicalEventRepository clinicalEventRepository) { + this.clinicalEventRepository = clinicalEventRepository; + } + + /** + * Executes the use case to retrieve counts of different clinical event types based on the study view filter context. + * + * @param studyViewFilterContext The filter criteria for the study view. + * @return A list of {@link ClinicalEventTypeCount} representing the counts of clinical event types. + */ + public List execute(StudyViewFilterContext studyViewFilterContext){ + return this.clinicalEventRepository.getClinicalEventTypeCounts(studyViewFilterContext); + } +} \ No newline at end of file diff --git a/src/main/java/org/cbioportal/domain/generic_assay/repository/GenericAssayRepository.java b/src/main/java/org/cbioportal/domain/generic_assay/repository/GenericAssayRepository.java new file mode 100644 index 00000000000..45de74c77cb --- /dev/null +++ b/src/main/java/org/cbioportal/domain/generic_assay/repository/GenericAssayRepository.java @@ -0,0 +1,53 @@ +package org.cbioportal.domain.generic_assay.repository; + +import org.cbioportal.legacy.model.ClinicalDataCount; +import org.cbioportal.legacy.model.GenericAssayDataCountItem; +import org.cbioportal.legacy.model.MolecularProfile; +import org.cbioportal.legacy.web.parameter.GenericAssayDataBinFilter; +import org.cbioportal.legacy.web.parameter.GenericAssayDataFilter; +import org.cbioportal.domain.studyview.StudyViewFilterContext; + +import java.util.List; + +/** + * Repository interface for retrieving molecular profiles and assay-related data. + */ +public interface GenericAssayRepository { + + /** + * Retrieves all generic assay molecular profiles. + * + * @return A list of {@link MolecularProfile} representing generic assay profiles. + */ + List getGenericAssayProfiles(); + + /** + * Retrieves molecular profiles filtered by alteration type based on the study view filter context. + * + * @param studyViewFilterContext The filter criteria for the study view. + * @param alterationType The type of alteration to filter the molecular profiles. + * @return A list of {@link MolecularProfile} matching the criteria. + */ + List getFilteredMolecularProfilesByAlterationType(StudyViewFilterContext studyViewFilterContext, + String alterationType); + + /** + * Retrieves bin counts for generic assay data based on the study view filter context and specified bin filters. + * + * @param studyViewFilterContext The filter criteria for the study view. + * @param genericAssayDataBinFilters A list of bin filters to apply to the assay data. + * @return A list of {@link ClinicalDataCount} representing bin counts for the generic assay data. + */ + List getGenericAssayDataBinCounts(StudyViewFilterContext studyViewFilterContext, + List genericAssayDataBinFilters); + + /** + * Retrieves counts for generic assay data based on the study view filter context and specified data filters. + * + * @param studyViewFilterContext The filter criteria for the study view. + * @param genericAssayDataFilters A list of data filters to apply to the assay data. + * @return A list of {@link GenericAssayDataCountItem} representing assay data counts. + */ + List getGenericAssayDataCounts(StudyViewFilterContext studyViewFilterContext, + List genericAssayDataFilters); +} diff --git a/src/main/java/org/cbioportal/domain/generic_assay/usecase/GenericAssayUseCases.java b/src/main/java/org/cbioportal/domain/generic_assay/usecase/GenericAssayUseCases.java new file mode 100644 index 00000000000..226db8ba47c --- /dev/null +++ b/src/main/java/org/cbioportal/domain/generic_assay/usecase/GenericAssayUseCases.java @@ -0,0 +1,25 @@ +package org.cbioportal.domain.generic_assay.usecase; + +import org.springframework.context.annotation.Profile; +import org.springframework.stereotype.Service; + +@Service +@Profile("clickhouse") +/** + * A record representing a collection of use cases related to generic assay data operations. + * This record encapsulates instances of various use case classes, providing a centralized + * way to access and manage them. + * + * @param getFilteredMolecularProfilesByAlterationType the use case for retrieving molecular profiles + * filtered by alteration type. + * @param getGenericAssayDataBinCounts the use case for retrieving binned counts of generic assay data. + * @param getGenericAssayDataCountsUseCase the use case for retrieving counts of generic assay data. + * @param getGenericAssayProfilesUseCase the use case for retrieving generic assay profiles. + */ +public record GenericAssayUseCases( + GetFilteredMolecularProfilesByAlterationType getFilteredMolecularProfilesByAlterationType, + GetGenericAssayDataBinCounts getGenericAssayDataBinCounts, + GetGenericAssayDataCountsUseCase getGenericAssayDataCountsUseCase, + GetGenericAssayProfilesUseCase getGenericAssayProfilesUseCase +) { +} diff --git a/src/main/java/org/cbioportal/domain/generic_assay/usecase/GetFilteredMolecularProfilesByAlterationType.java b/src/main/java/org/cbioportal/domain/generic_assay/usecase/GetFilteredMolecularProfilesByAlterationType.java new file mode 100644 index 00000000000..9d286d6e4c2 --- /dev/null +++ b/src/main/java/org/cbioportal/domain/generic_assay/usecase/GetFilteredMolecularProfilesByAlterationType.java @@ -0,0 +1,45 @@ +package org.cbioportal.domain.generic_assay.usecase; + +import org.cbioportal.domain.generic_assay.repository.GenericAssayRepository; +import org.cbioportal.legacy.model.MolecularProfile; +import org.cbioportal.domain.studyview.StudyViewFilterContext; +import org.springframework.context.annotation.Profile; +import org.springframework.stereotype.Service; + +import java.util.List; + +@Service +@Profile("clickhouse") +/** + * A use case class responsible for retrieving molecular profiles filtered by a specific alteration type. + * This class acts as an intermediary between the application logic and the data repository, + * delegating the data retrieval to the {@link GenericAssayRepository}. + */ +public class GetFilteredMolecularProfilesByAlterationType { + private final GenericAssayRepository genericAssayRepository; + + /** + * Constructs a new instance of {@link GetFilteredMolecularProfilesByAlterationType}. + * + * @param genericAssayRepository the repository used to access molecular profile data. + * Must not be {@code null}. + */ + public GetFilteredMolecularProfilesByAlterationType(GenericAssayRepository genericAssayRepository) { + this.genericAssayRepository = genericAssayRepository; + } + + /** + * Executes the use case to retrieve molecular profiles filtered by a specific alteration type. + * + * @param studyViewFilterContext the context containing study view filter criteria. + * Must not be {@code null}. + * @param alterationType the type of alteration used to filter molecular profiles. + * Must not be {@code null}. + * @return a list of {@link MolecularProfile} objects representing the molecular profiles + * that match the provided alteration type. The list may be empty if no profiles match the criteria. + */ + public List execute(StudyViewFilterContext studyViewFilterContext, + String alterationType) { + return genericAssayRepository.getFilteredMolecularProfilesByAlterationType(studyViewFilterContext, alterationType); + } +} diff --git a/src/main/java/org/cbioportal/domain/generic_assay/usecase/GetGenericAssayDataBinCounts.java b/src/main/java/org/cbioportal/domain/generic_assay/usecase/GetGenericAssayDataBinCounts.java new file mode 100644 index 00000000000..ab89fae7b70 --- /dev/null +++ b/src/main/java/org/cbioportal/domain/generic_assay/usecase/GetGenericAssayDataBinCounts.java @@ -0,0 +1,46 @@ +package org.cbioportal.domain.generic_assay.usecase; + +import org.cbioportal.domain.generic_assay.repository.GenericAssayRepository; +import org.cbioportal.legacy.model.ClinicalDataCount; +import org.cbioportal.legacy.web.parameter.GenericAssayDataBinFilter; +import org.cbioportal.domain.studyview.StudyViewFilterContext; +import org.springframework.context.annotation.Profile; +import org.springframework.stereotype.Service; + +import java.util.List; + +@Service +@Profile("clickhouse") +/** + * A use case class responsible for retrieving binned counts of generic assay data based on the provided filters. + * This class acts as an intermediary between the application logic and the data repository, + * delegating the data retrieval to the {@link GenericAssayRepository}. + */ +public class GetGenericAssayDataBinCounts { + private final GenericAssayRepository genericAssayRepository; + + /** + * Constructs a new instance of {@link GetGenericAssayDataBinCounts}. + * + * @param genericAssayRepository the repository used to access generic assay data. + * Must not be {@code null}. + */ + public GetGenericAssayDataBinCounts(GenericAssayRepository genericAssayRepository) { + this.genericAssayRepository = genericAssayRepository; + } + + /** + * Executes the use case to retrieve binned counts of generic assay data based on the provided filters. + * + * @param studyViewFilterContext the context containing study view filter criteria. + * Must not be {@code null}. + * @param genericAssayDataBinFilters a list of filters to apply to the generic assay data for binning. + * Must not be {@code null}. + * @return a list of {@link ClinicalDataCount} objects representing the binned counts of generic assay data + * that match the provided filters. The list may be empty if no data matches the filters. + */ + public List execute(StudyViewFilterContext studyViewFilterContext, + List genericAssayDataBinFilters) { + return genericAssayRepository.getGenericAssayDataBinCounts(studyViewFilterContext, genericAssayDataBinFilters); + } +} \ No newline at end of file diff --git a/src/main/java/org/cbioportal/domain/generic_assay/usecase/GetGenericAssayDataCountsUseCase.java b/src/main/java/org/cbioportal/domain/generic_assay/usecase/GetGenericAssayDataCountsUseCase.java new file mode 100644 index 00000000000..7f77a4e9691 --- /dev/null +++ b/src/main/java/org/cbioportal/domain/generic_assay/usecase/GetGenericAssayDataCountsUseCase.java @@ -0,0 +1,46 @@ +package org.cbioportal.domain.generic_assay.usecase; + +import org.cbioportal.domain.generic_assay.repository.GenericAssayRepository; +import org.cbioportal.legacy.model.GenericAssayDataCountItem; +import org.cbioportal.legacy.web.parameter.GenericAssayDataFilter; +import org.cbioportal.domain.studyview.StudyViewFilterContext; +import org.springframework.context.annotation.Profile; +import org.springframework.stereotype.Service; + +import java.util.List; + +@Service +@Profile("clickhouse") +/** + * A use case class responsible for retrieving counts of generic assay data based on the provided filters. + * This class acts as an intermediary between the application logic and the data repository, + * delegating the data retrieval to the {@link GenericAssayRepository}. + */ +public class GetGenericAssayDataCountsUseCase { + private final GenericAssayRepository genericAssayRepository; + + /** + * Constructs a new instance of {@link GetGenericAssayDataCountsUseCase}. + * + * @param genericAssayRepository the repository used to access generic assay data. + * Must not be {@code null}. + */ + public GetGenericAssayDataCountsUseCase(GenericAssayRepository genericAssayRepository) { + this.genericAssayRepository = genericAssayRepository; + } + + /** + * Executes the use case to retrieve counts of generic assay data based on the provided filters. + * + * @param studyViewFilterContext the context containing study view filter criteria. + * Must not be {@code null}. + * @param genericAssayDataFilters a list of filters to apply to the generic assay data. + * Must not be {@code null}. + * @return a list of {@link GenericAssayDataCountItem} objects representing the counts of generic assay data + * that match the provided filters. The list may be empty if no data matches the filters. + */ + public List execute(StudyViewFilterContext studyViewFilterContext, + List genericAssayDataFilters) { + return genericAssayRepository.getGenericAssayDataCounts(studyViewFilterContext, genericAssayDataFilters); + } +} diff --git a/src/main/java/org/cbioportal/domain/generic_assay/usecase/GetGenericAssayProfilesUseCase.java b/src/main/java/org/cbioportal/domain/generic_assay/usecase/GetGenericAssayProfilesUseCase.java new file mode 100644 index 00000000000..08c4a9f6de8 --- /dev/null +++ b/src/main/java/org/cbioportal/domain/generic_assay/usecase/GetGenericAssayProfilesUseCase.java @@ -0,0 +1,37 @@ +package org.cbioportal.domain.generic_assay.usecase; + +import org.cbioportal.domain.generic_assay.repository.GenericAssayRepository; +import org.cbioportal.legacy.model.MolecularProfile; +import org.springframework.context.annotation.Profile; +import org.springframework.stereotype.Service; + +import java.util.List; + +@Service +@Profile("clickhouse") +/** + * Use case for retrieving generic assay molecular profiles. + * This class interacts with the {@link GenericAssayRepository} to fetch the required data. + */ +public class GetGenericAssayProfilesUseCase { + + private final GenericAssayRepository repository; + + /** + * Constructs a use case for retrieving generic assay profiles. + * + * @param repository The repository used to fetch generic assay profiles. + */ + public GetGenericAssayProfilesUseCase(GenericAssayRepository repository) { + this.repository = repository; + } + + /** + * Executes the use case to retrieve all generic assay profiles. + * + * @return A list of {@link MolecularProfile} representing generic assay profiles. + */ + public List execute() { + return repository.getGenericAssayProfiles(); + } +} diff --git a/src/main/java/org/cbioportal/domain/genomic_data/repository/GenomicDataRepository.java b/src/main/java/org/cbioportal/domain/genomic_data/repository/GenomicDataRepository.java new file mode 100644 index 00000000000..7f34397a511 --- /dev/null +++ b/src/main/java/org/cbioportal/domain/genomic_data/repository/GenomicDataRepository.java @@ -0,0 +1,73 @@ +package org.cbioportal.domain.genomic_data.repository; + +import org.cbioportal.legacy.model.ClinicalDataCount; +import org.cbioportal.legacy.model.GenomicDataCount; +import org.cbioportal.legacy.model.GenomicDataCountItem; +import org.cbioportal.legacy.web.parameter.GenomicDataBinFilter; +import org.cbioportal.legacy.web.parameter.GenomicDataFilter; +import org.cbioportal.domain.studyview.StudyViewFilterContext; + +import java.util.List; +import java.util.Map; + +/** + * An interface defining the contract for a repository that provides access to genomic data. + * This repository is responsible for retrieving various types of genomic data counts and statistics. + */ +public interface GenomicDataRepository { + + /** + * Retrieves the sample counts for molecular profiles based on the provided study view filter context. + * + * @param studyViewFilterContext the context containing study view filter criteria. + * Must not be {@code null}. + * @return a list of {@link GenomicDataCount} objects representing the sample counts for molecular profiles. + */ + List getMolecularProfileSampleCounts(StudyViewFilterContext studyViewFilterContext); + + /** + * Retrieves binned genomic data counts based on the provided study view filter context and bin filters. + * + * @param studyViewFilterContext the context containing study view filter criteria. + * Must not be {@code null}. + * @param genomicDataBinFilters a list of filters to apply to the genomic data for binning. + * Must not be {@code null}. + * @return a list of {@link ClinicalDataCount} objects representing the binned genomic data counts. + */ + List getGenomicDataBinCounts(StudyViewFilterContext studyViewFilterContext, + List genomicDataBinFilters); + + /** + * Retrieves copy number alteration (CNA) counts based on the provided study view filter context and genomic data filters. + * + * @param studyViewFilterContext the context containing study view filter criteria. + * Must not be {@code null}. + * @param genomicDataFilters a list of filters to apply to the genomic data. + * Must not be {@code null}. + * @return a list of {@link GenomicDataCountItem} objects representing the CNA counts. + */ + List getCNACounts(StudyViewFilterContext studyViewFilterContext, List genomicDataFilters); + + /** + * Retrieves mutation counts based on the provided study view filter context and mutation filters. + * + * @param studyViewFilterContext the context containing study view filter criteria. + * Must not be {@code null}. + * @param mutationFilters the filter to apply to the mutation data. + * Must not be {@code null}. + * @return a map where the key is a string representing a mutation type and the value is the count of mutations. + */ + Map getMutationCounts(StudyViewFilterContext studyViewFilterContext, GenomicDataFilter mutationFilters); + + /** + * Retrieves mutation counts grouped by mutation type based on the provided study view filter context and genomic data filters. + * + * @param studyViewFilterContext the context containing study view filter criteria. + * Must not be {@code null}. + * @param genomicDataFilters a list of filters to apply to the genomic data. + * Must not be {@code null}. + * @return a list of {@link GenomicDataCountItem} objects representing the mutation counts by type. + */ + List getMutationCountsByType(StudyViewFilterContext studyViewFilterContext, + List genomicDataFilters); +} diff --git a/src/main/java/org/cbioportal/domain/genomic_data/usecase/GenomicDataUseCases.java b/src/main/java/org/cbioportal/domain/genomic_data/usecase/GenomicDataUseCases.java new file mode 100644 index 00000000000..a822f85ce4a --- /dev/null +++ b/src/main/java/org/cbioportal/domain/genomic_data/usecase/GenomicDataUseCases.java @@ -0,0 +1,26 @@ +package org.cbioportal.domain.genomic_data.usecase; + +import org.springframework.context.annotation.Profile; +import org.springframework.stereotype.Service; + +@Service +@Profile("clickhouse") +/** + * A record representing a collection of use cases related to genomic data operations. + * This record encapsulates instances of various genomic data use cases, providing a centralized + * way to access and manage them. + * + * @param getCNACountsByGeneSpecificUseCase the use case for retrieving CNA counts by gene-specific data. + * @param getGenomicDataBinCountsUseCase the use case for retrieving genomic data bin counts. + * @param getMolecularProfileSampleCountsUseCase the use case for retrieving molecular profile sample counts. + * @param getMutationCountsByTypeUseCase the use case for retrieving mutation counts by type. + * @param getMutationCountsUseCase the use case for retrieving mutation counts. + */ +public record GenomicDataUseCases( + GetCNACountsByGeneSpecificUseCase getCNACountsByGeneSpecificUseCase, + GetGenomicDataBinCountsUseCase getGenomicDataBinCountsUseCase, + GetMolecularProfileSampleCountsUseCase getMolecularProfileSampleCountsUseCase, + GetMutationCountsByTypeUseCase getMutationCountsByTypeUseCase, + GetMutationCountsUseCase getMutationCountsUseCase +) { +} diff --git a/src/main/java/org/cbioportal/domain/genomic_data/usecase/GetCNACountsByGeneSpecificUseCase.java b/src/main/java/org/cbioportal/domain/genomic_data/usecase/GetCNACountsByGeneSpecificUseCase.java new file mode 100644 index 00000000000..1942c7f5dbd --- /dev/null +++ b/src/main/java/org/cbioportal/domain/genomic_data/usecase/GetCNACountsByGeneSpecificUseCase.java @@ -0,0 +1,44 @@ +package org.cbioportal.domain.genomic_data.usecase; + +import org.cbioportal.domain.genomic_data.repository.GenomicDataRepository; +import org.cbioportal.legacy.model.GenomicDataCountItem; +import org.cbioportal.legacy.web.parameter.GenomicDataFilter; +import org.cbioportal.domain.studyview.StudyViewFilterContext; +import org.springframework.context.annotation.Profile; +import org.springframework.stereotype.Service; + +import java.util.List; + +@Service +@Profile("clickhouse") +/** + * Use case for retrieving CNA counts by gene-specific data from the repository. + * This class encapsulates the business logic for fetching CNA counts based on + * the provided study view filter context and genomic data filters. + */ +public class GetCNACountsByGeneSpecificUseCase { + + private final GenomicDataRepository repository; + + /** + * Constructs a {@code GetCNACountsByGeneSpecificUseCase} with the provided repository. + * + * @param repository the repository to be used for fetching CNA counts by gene-specific data + */ + public GetCNACountsByGeneSpecificUseCase(GenomicDataRepository repository) { + this.repository = repository; + } + + /** + * Executes the use case to retrieve CNA counts by gene-specific data. + * + * @param studyViewFilterContext the context of the study view filter to apply + * @param genomicDataFilters a list of genomic data filters to apply + * @return a list of {@link GenomicDataCountItem} representing the CNA counts by gene + */ + public List execute(StudyViewFilterContext studyViewFilterContext, + List genomicDataFilters) { + return repository.getCNACounts(studyViewFilterContext, genomicDataFilters); + } +} + diff --git a/src/main/java/org/cbioportal/domain/genomic_data/usecase/GetGenomicDataBinCountsUseCase.java b/src/main/java/org/cbioportal/domain/genomic_data/usecase/GetGenomicDataBinCountsUseCase.java new file mode 100644 index 00000000000..70844ee95af --- /dev/null +++ b/src/main/java/org/cbioportal/domain/genomic_data/usecase/GetGenomicDataBinCountsUseCase.java @@ -0,0 +1,43 @@ +package org.cbioportal.domain.genomic_data.usecase; + +import org.cbioportal.domain.genomic_data.repository.GenomicDataRepository; +import org.cbioportal.legacy.model.ClinicalDataCount; +import org.cbioportal.legacy.web.parameter.GenomicDataBinFilter; +import org.cbioportal.domain.studyview.StudyViewFilterContext; +import org.springframework.context.annotation.Profile; +import org.springframework.stereotype.Service; + +import java.util.List; + +@Service +@Profile("clickhouse") +/** + * Use case for retrieving genomic data bin counts from the repository. + * This class encapsulates the business logic for fetching genomic data + * bin counts based on the provided study view filter context and genomic data filters. + */ +public class GetGenomicDataBinCountsUseCase { + + private final GenomicDataRepository genomicDataRepository; + + /** + * Constructs a {@code GetGenomicDataBinCountsUseCase} with the provided repository. + * + * @param genomicDataRepository the repository to be used for fetching genomic data bin counts + */ + public GetGenomicDataBinCountsUseCase(GenomicDataRepository genomicDataRepository) { + this.genomicDataRepository = genomicDataRepository; + } + + /** + * Executes the use case to retrieve genomic data bin counts. + * + * @param studyViewFilterContext the context of the study view filter to apply + * @param genomicDataFilters a list of genomic data bin filters to apply + * @return a list of {@link ClinicalDataCount} representing the genomic data bin counts + */ + public List execute(StudyViewFilterContext studyViewFilterContext, + List genomicDataFilters) { + return genomicDataRepository.getGenomicDataBinCounts(studyViewFilterContext, genomicDataFilters); + } +} diff --git a/src/main/java/org/cbioportal/domain/genomic_data/usecase/GetMolecularProfileSampleCountsUseCase.java b/src/main/java/org/cbioportal/domain/genomic_data/usecase/GetMolecularProfileSampleCountsUseCase.java new file mode 100644 index 00000000000..e2b2d810dcb --- /dev/null +++ b/src/main/java/org/cbioportal/domain/genomic_data/usecase/GetMolecularProfileSampleCountsUseCase.java @@ -0,0 +1,41 @@ +package org.cbioportal.domain.genomic_data.usecase; + +import org.cbioportal.domain.genomic_data.repository.GenomicDataRepository; +import org.cbioportal.legacy.model.GenomicDataCount; +import org.cbioportal.legacy.service.util.StudyViewColumnarServiceUtil; +import org.cbioportal.domain.studyview.StudyViewFilterContext; +import org.springframework.context.annotation.Profile; +import org.springframework.stereotype.Service; + +import java.util.List; + +@Service +@Profile("clickhouse") +/** + * Use case for retrieving molecular profile sample counts from the repository. + * This class encapsulates the business logic for fetching molecular profile + * sample counts and merging them into a final result. + */ +public class GetMolecularProfileSampleCountsUseCase { + + private final GenomicDataRepository genomicDataRepository; + + /** + * Constructs a {@code GetMolecularProfileSampleCountsUseCase} with the provided repository. + * + * @param genomicDataRepository the repository to be used for fetching molecular profile sample counts + */ + public GetMolecularProfileSampleCountsUseCase(GenomicDataRepository genomicDataRepository) { + this.genomicDataRepository = genomicDataRepository; + } + + /** + * Executes the use case to retrieve and merge molecular profile sample counts. + * + * @param studyViewFilterContext the context of the study view filter to apply + * @return a list of {@link GenomicDataCount} representing the molecular profile sample counts + */ + public List execute(StudyViewFilterContext studyViewFilterContext) { + return StudyViewColumnarServiceUtil.mergeGenomicDataCounts(genomicDataRepository.getMolecularProfileSampleCounts(studyViewFilterContext)); + } +} diff --git a/src/main/java/org/cbioportal/domain/genomic_data/usecase/GetMutationCountsByTypeUseCase.java b/src/main/java/org/cbioportal/domain/genomic_data/usecase/GetMutationCountsByTypeUseCase.java new file mode 100644 index 00000000000..909362e8154 --- /dev/null +++ b/src/main/java/org/cbioportal/domain/genomic_data/usecase/GetMutationCountsByTypeUseCase.java @@ -0,0 +1,44 @@ +package org.cbioportal.domain.genomic_data.usecase; + +import org.cbioportal.domain.genomic_data.repository.GenomicDataRepository; +import org.cbioportal.legacy.model.GenomicDataCountItem; +import org.cbioportal.legacy.web.parameter.GenomicDataFilter; +import org.cbioportal.domain.studyview.StudyViewFilterContext; +import org.springframework.context.annotation.Profile; +import org.springframework.stereotype.Service; + +import java.util.List; + +@Service +@Profile("clickhouse") +/** + * Use case for retrieving mutation counts by type from the repository. + * This class encapsulates the business logic for fetching mutation counts + * based on the provided study view filter context and genomic data filters. + */ +public class GetMutationCountsByTypeUseCase { + + private final GenomicDataRepository repository; + + /** + * Constructs a {@code GetMutationCountsByTypeUseCase} with the provided repository. + * + * @param repository the repository to be used for fetching mutation counts + */ + public GetMutationCountsByTypeUseCase(GenomicDataRepository repository) { + this.repository = repository; + } + + /** + * Executes the use case to retrieve mutation counts by type. + * + * @param studyViewFilterContext the context of the study view filter to apply + * @param genomicDataFilters a list of genomic data filters to apply + * @return a list of {@link GenomicDataCountItem} representing the mutation counts by type + */ + public List execute(StudyViewFilterContext studyViewFilterContext, + List genomicDataFilters) { + return repository.getMutationCountsByType(studyViewFilterContext, genomicDataFilters); + } +} + diff --git a/src/main/java/org/cbioportal/domain/genomic_data/usecase/GetMutationCountsUseCase.java b/src/main/java/org/cbioportal/domain/genomic_data/usecase/GetMutationCountsUseCase.java new file mode 100644 index 00000000000..4621e347237 --- /dev/null +++ b/src/main/java/org/cbioportal/domain/genomic_data/usecase/GetMutationCountsUseCase.java @@ -0,0 +1,45 @@ +package org.cbioportal.domain.genomic_data.usecase; + +import org.cbioportal.domain.genomic_data.repository.GenomicDataRepository; +import org.cbioportal.legacy.web.parameter.GenomicDataFilter; +import org.cbioportal.domain.studyview.StudyViewFilterContext; +import org.springframework.context.annotation.Profile; +import org.springframework.stereotype.Service; + +import java.util.Map; + +@Service +@Profile("clickhouse") +/** + * A use case class responsible for retrieving mutation counts based on the provided study view filter context + * and genomic data filter. This class acts as an intermediary between the application logic and the data repository, + * delegating the data retrieval to the {@link GenomicDataRepository}. + */ +public class GetMutationCountsUseCase { + private final GenomicDataRepository repository; + + /** + * Constructs a new instance of {@link GetMutationCountsUseCase}. + * + * @param repository the repository used to access genomic data. + * Must not be {@code null}. + */ + public GetMutationCountsUseCase(GenomicDataRepository repository) { + this.repository = repository; + } + + /** + * Executes the use case to retrieve mutation counts based on the provided study view filter context + * and genomic data filter. + * + * @param studyViewFilterContext the context containing study view filter criteria. + * Must not be {@code null}. + * @param genomicDataFilter the filter to apply to the genomic data for retrieving mutation counts. + * Must not be {@code null}. + * @return a map where the key is a string representing a mutation type and the value is the count of mutations. + */ + public Map execute(StudyViewFilterContext studyViewFilterContext, + GenomicDataFilter genomicDataFilter) { + return repository.getMutationCounts(studyViewFilterContext, genomicDataFilter); + } +} diff --git a/src/main/java/org/cbioportal/domain/patient/repository/PatientRepository.java b/src/main/java/org/cbioportal/domain/patient/repository/PatientRepository.java new file mode 100644 index 00000000000..8c0bdb14c2b --- /dev/null +++ b/src/main/java/org/cbioportal/domain/patient/repository/PatientRepository.java @@ -0,0 +1,30 @@ +package org.cbioportal.domain.patient.repository; + +import org.cbioportal.legacy.model.CaseListDataCount; +import org.cbioportal.domain.studyview.StudyViewFilterContext; + +import java.util.List; + +/** + * Repository interface for performing operations related to patient data. + * This interface defines methods for retrieving filtered patient counts and case list data counts. + */ +public interface PatientRepository { + + /** + * Retrieves the count of filtered patients based on the provided study view filter context. + * + * @param studyViewFilterContext the context containing the filter criteria for the study view + * @return the count of patients that match the filter criteria + */ + int getFilteredPatientCount(StudyViewFilterContext studyViewFilterContext); + + /** + * Retrieves the case list data counts based on the provided study view filter context. + * + * @param studyViewFilterContext the context containing the filter criteria for the study view + * @return a list of {@link CaseListDataCount} representing the counts of case list data + */ + List getCaseListDataCounts(StudyViewFilterContext studyViewFilterContext); +} + diff --git a/src/main/java/org/cbioportal/domain/patient/usecase/GetCaseListDataCountsUseCase.java b/src/main/java/org/cbioportal/domain/patient/usecase/GetCaseListDataCountsUseCase.java new file mode 100644 index 00000000000..b68b621a825 --- /dev/null +++ b/src/main/java/org/cbioportal/domain/patient/usecase/GetCaseListDataCountsUseCase.java @@ -0,0 +1,41 @@ +package org.cbioportal.domain.patient.usecase; + +import org.cbioportal.legacy.model.CaseListDataCount; +import org.cbioportal.domain.patient.repository.PatientRepository; +import org.cbioportal.domain.studyview.StudyViewFilterContext; +import org.springframework.context.annotation.Profile; +import org.springframework.stereotype.Service; + +import java.util.List; + +@Service +@Profile("clickhouse") +/** + * Use case for retrieving case list data counts. + * This class interacts with the {@link PatientRepository} to fetch the case list data counts + * based on the filter criteria specified in the study view filter context. + */ +public class GetCaseListDataCountsUseCase { + + private final PatientRepository patientRepository; + + /** + * Constructs a {@code GetCaseListDataCountsUseCase} with the provided {@link PatientRepository}. + * + * @param patientRepository the repository to be used for retrieving the case list data counts + */ + public GetCaseListDataCountsUseCase(PatientRepository patientRepository) { + this.patientRepository = patientRepository; + } + + /** + * Executes the use case to retrieve the case list data counts based on the given study view filter context. + * + * @param studyViewFilterContext the context of the study view filter to apply + * @return a list of {@link CaseListDataCount} representing the counts of case list data + */ + public List execute(StudyViewFilterContext studyViewFilterContext) { + return patientRepository.getCaseListDataCounts(studyViewFilterContext); + } +} + diff --git a/src/main/java/org/cbioportal/domain/patient/usecase/GetFilteredPatientCountUseCase.java b/src/main/java/org/cbioportal/domain/patient/usecase/GetFilteredPatientCountUseCase.java new file mode 100644 index 00000000000..b41ab7eb6f8 --- /dev/null +++ b/src/main/java/org/cbioportal/domain/patient/usecase/GetFilteredPatientCountUseCase.java @@ -0,0 +1,38 @@ +package org.cbioportal.domain.patient.usecase; + +import org.cbioportal.domain.patient.repository.PatientRepository; +import org.cbioportal.domain.studyview.StudyViewFilterContext; +import org.springframework.context.annotation.Profile; +import org.springframework.stereotype.Service; + +@Service +@Profile("clickhouse") +/** + * Use case for retrieving the count of filtered patients. + * This class interacts with the {@link PatientRepository} to fetch the number of patients + * that match the given filter criteria specified in the study view filter context. + */ +public class GetFilteredPatientCountUseCase { + + private final PatientRepository patientRepository; + + /** + * Constructs a {@code GetFilteredPatientCountUseCase} with the provided {@link PatientRepository}. + * + * @param patientRepository the repository to be used for retrieving the filtered patient count + */ + public GetFilteredPatientCountUseCase(PatientRepository patientRepository) { + this.patientRepository = patientRepository; + } + + /** + * Executes the use case to retrieve the count of filtered patients based on the given study view filter context. + * + * @param studyViewFilterContext the context of the study view filter to apply + * @return the count of filtered patients + */ + public int execute(StudyViewFilterContext studyViewFilterContext) { + return patientRepository.getFilteredPatientCount(studyViewFilterContext); + } +} + diff --git a/src/main/java/org/cbioportal/domain/sample/Sample.java b/src/main/java/org/cbioportal/domain/sample/Sample.java new file mode 100644 index 00000000000..a878086ba7e --- /dev/null +++ b/src/main/java/org/cbioportal/domain/sample/Sample.java @@ -0,0 +1,27 @@ +package org.cbioportal.domain.sample; + +import org.cbioportal.legacy.model.Patient; + +import java.util.Objects; + +public record Sample (Integer internalId, String stableId, SampleType sampleType, Integer patientId, + String patientStableId, Patient patient, + String cancerStudyIdentifier, Boolean sequenced, Boolean copyNumberSegmentPresent, + String uniqueSampleKey, String uniquePatientKey) { + + public Sample(Integer internalId, String stableId, String patientStableId, String cancerStudyIdentifier){ + this(internalId,stableId,null,null,patientStableId,null, cancerStudyIdentifier, null, null,null, null); + } + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof Sample)) return false; + Sample sample = (Sample) o; + return stableId.equals(sample.stableId) && cancerStudyIdentifier.equals(sample.cancerStudyIdentifier); + } + + @Override + public int hashCode() { + return Objects.hash(stableId, cancerStudyIdentifier); + } +} diff --git a/src/main/java/org/cbioportal/domain/sample/SampleType.java b/src/main/java/org/cbioportal/domain/sample/SampleType.java new file mode 100644 index 00000000000..a163560ccb7 --- /dev/null +++ b/src/main/java/org/cbioportal/domain/sample/SampleType.java @@ -0,0 +1,37 @@ +package org.cbioportal.domain.sample; + +public enum SampleType { + PRIMARY_SOLID_TUMOR("Primary Solid Tumor"), + RECURRENT_SOLID_TUMOR("Recurrent Solid Tumor"), + PRIMARY_BLOOD_TUMOR("Primary Blood Tumor"), + RECURRENT_BLOOD_TUMOR("Recurrent Blood Tumor"), + METASTATIC("Metastatic"), + BLOOD_NORMAL("Blood Derived Normal"), + SOLID_NORMAL("Solid Tissues Normal"); + + private String value; + + SampleType(String value) { + this.value = value; + } + + public String getValue() { + return value; + } + + public static SampleType fromString(String value) { + + if (value != null) { + for (SampleType sampleType : SampleType.values()) { + if (value.equalsIgnoreCase(sampleType.value)) { + return sampleType; + } + } + } + return null; + } + @Override + public String toString() { + return value; + } +} diff --git a/src/main/java/org/cbioportal/domain/sample/repository/SampleRepository.java b/src/main/java/org/cbioportal/domain/sample/repository/SampleRepository.java new file mode 100644 index 00000000000..9115fa165c1 --- /dev/null +++ b/src/main/java/org/cbioportal/domain/sample/repository/SampleRepository.java @@ -0,0 +1,31 @@ +package org.cbioportal.domain.sample.repository; + +import org.cbioportal.domain.sample.Sample; +import org.cbioportal.domain.studyview.StudyViewFilterContext; + +import java.util.List; + +/** + * Repository interface for performing operations related to sample data. + * This interface defines methods for retrieving filtered samples and their respective counts + * based on the filter criteria provided in the study view filter context. + */ +public interface SampleRepository { + + /** + * Retrieves the samples that match the filter criteria specified in the study view filter context. + * + * @param studyViewFilterContext the context containing the filter criteria for the study view + * @return a list of {@link Sample} representing the samples that match the filter criteria + */ + List getFilteredSamples(StudyViewFilterContext studyViewFilterContext); + + /** + * Retrieves the total count of samples that match the filter criteria specified in the study view filter context. + * + * @param studyViewFilterContext the context containing the filter criteria for the study view + * @return the total count of filtered samples + */ + int getFilteredSamplesCount(StudyViewFilterContext studyViewFilterContext); +} + diff --git a/src/main/java/org/cbioportal/domain/sample/usecase/GetFilteredSamplesCountUseCase.java b/src/main/java/org/cbioportal/domain/sample/usecase/GetFilteredSamplesCountUseCase.java new file mode 100644 index 00000000000..1836e9df14a --- /dev/null +++ b/src/main/java/org/cbioportal/domain/sample/usecase/GetFilteredSamplesCountUseCase.java @@ -0,0 +1,39 @@ +package org.cbioportal.domain.sample.usecase; + +import org.cbioportal.domain.sample.repository.SampleRepository; +import org.cbioportal.domain.studyview.StudyViewFilterContext; +import org.springframework.context.annotation.Profile; +import org.springframework.stereotype.Service; + + +@Service +@Profile("clickhouse") +/** + * Use case for retrieving the count of filtered samples. + * This class interacts with the {@link SampleRepository} to fetch the number of samples + * that match the given filter criteria specified in the study view filter context. + */ +public class GetFilteredSamplesCountUseCase { + + private final SampleRepository sampleRepository; + + /** + * Constructs a {@code GetFilteredSamplesCountUseCase} with the provided {@link SampleRepository}. + * + * @param sampleRepository the repository to be used for retrieving the filtered samples count + */ + public GetFilteredSamplesCountUseCase(SampleRepository sampleRepository) { + this.sampleRepository = sampleRepository; + } + + /** + * Executes the use case to retrieve the count of filtered samples based on the given study view filter context. + * + * @param studyViewFilterContext the context of the study view filter to apply + * @return the count of filtered samples + */ + public int execute(StudyViewFilterContext studyViewFilterContext) { + return sampleRepository.getFilteredSamplesCount(studyViewFilterContext); + } +} + diff --git a/src/main/java/org/cbioportal/domain/sample/usecase/GetFilteredSamplesUseCase.java b/src/main/java/org/cbioportal/domain/sample/usecase/GetFilteredSamplesUseCase.java new file mode 100644 index 00000000000..0176454712a --- /dev/null +++ b/src/main/java/org/cbioportal/domain/sample/usecase/GetFilteredSamplesUseCase.java @@ -0,0 +1,24 @@ +package org.cbioportal.domain.sample.usecase; + +import org.cbioportal.domain.sample.Sample; +import org.cbioportal.domain.sample.repository.SampleRepository; +import org.cbioportal.domain.studyview.StudyViewFilterContext; +import org.springframework.context.annotation.Profile; +import org.springframework.stereotype.Service; + +import java.util.List; + +@Service +@Profile("clickhouse") +public final class GetFilteredSamplesUseCase { + + private final SampleRepository sampleRepository; + + public GetFilteredSamplesUseCase(SampleRepository sampleRepository) { + this.sampleRepository = sampleRepository; + } + + public List execute(StudyViewFilterContext studyViewFilterContext) { + return this.sampleRepository.getFilteredSamples(studyViewFilterContext); + } +} diff --git a/src/main/java/org/cbioportal/domain/studyview/StudyViewFilterContext.java b/src/main/java/org/cbioportal/domain/studyview/StudyViewFilterContext.java new file mode 100644 index 00000000000..0b761ba3cc6 --- /dev/null +++ b/src/main/java/org/cbioportal/domain/studyview/StudyViewFilterContext.java @@ -0,0 +1,58 @@ +package org.cbioportal.domain.studyview; + +import org.cbioportal.legacy.model.AlterationFilter; +import org.cbioportal.legacy.model.GeneFilter; +import org.cbioportal.legacy.model.StudyViewStructuralVariantFilter; +import org.cbioportal.legacy.web.parameter.CategorizedGenericAssayDataCountFilter; +import org.cbioportal.legacy.web.parameter.ClinicalDataFilter; +import org.cbioportal.legacy.web.parameter.CustomSampleIdentifier; +import org.cbioportal.legacy.web.parameter.DataFilter; +import org.cbioportal.legacy.web.parameter.GenericAssayDataFilter; +import org.cbioportal.legacy.web.parameter.GenomicDataFilter; +import org.cbioportal.legacy.web.parameter.MutationDataFilter; +import org.cbioportal.legacy.web.parameter.SampleIdentifier; +import org.cbioportal.legacy.web.parameter.filter.AndedSampleTreatmentFilters; +import org.cbioportal.legacy.web.parameter.filter.AndedPatientTreatmentFilters; + +import java.util.List; + +public record StudyViewFilterContext( + List sampleIdentifiers, + List studyIds, + List clinicalDataFilters, + List geneFilters, + List structuralVariantFilters, + AndedSampleTreatmentFilters sampleTreatmentFilters, + AndedSampleTreatmentFilters sampleTreatmentGroupFilters, + AndedSampleTreatmentFilters sampleTreatmentTargetFilters, + AndedPatientTreatmentFilters patientTreatmentFilters, + AndedPatientTreatmentFilters patientTreatmentGroupFilters, + AndedPatientTreatmentFilters patientTreatmentTargetFilters, + List> genomicProfiles, + List genomicDataFilters, + List genericAssayDataFilters, + List> caseLists, + List customDataFilters, + AlterationFilter alterationFilter, + List clinicalEventFilters, + List mutationDataFilters, + List customSampleIdentifiers, + List customDataFilterCancerStudies, + CategorizedGenericAssayDataCountFilter categorizedGenericAssayDataCountFilter +) { + + public String[] filteredSampleIdentifiers() { + if (sampleIdentifiers != null) { + return sampleIdentifiers.stream() + .map(sampleIdentifier -> sampleIdentifier.getStudyId() + "_" + sampleIdentifier.getSampleId()) + .toArray(String[]::new); + } else { + return new String[0]; + } + } + + public boolean isCategoricalClinicalDataFilter(ClinicalDataFilter clinicalDataFilter) { + var filterValue = clinicalDataFilter.getValues().getFirst(); + return filterValue.getValue() != null; + } +} diff --git a/src/main/java/org/cbioportal/domain/studyview/StudyViewFilterFactory.java b/src/main/java/org/cbioportal/domain/studyview/StudyViewFilterFactory.java new file mode 100644 index 00000000000..d7455517ec7 --- /dev/null +++ b/src/main/java/org/cbioportal/domain/studyview/StudyViewFilterFactory.java @@ -0,0 +1,63 @@ +package org.cbioportal.domain.studyview; + +import org.cbioportal.legacy.model.MolecularProfile; +import org.cbioportal.legacy.persistence.enums.DataSource; +import org.cbioportal.legacy.web.columnar.util.CustomDataFilterUtil; +import org.cbioportal.legacy.web.parameter.CategorizedGenericAssayDataCountFilter; +import org.cbioportal.legacy.web.parameter.ClinicalDataFilter; +import org.cbioportal.legacy.web.parameter.CustomSampleIdentifier; +import org.cbioportal.legacy.web.parameter.GenericAssayDataFilter; +import org.cbioportal.legacy.web.parameter.GenomicDataFilter; +import org.cbioportal.legacy.web.parameter.StudyViewFilter; +import org.cbioportal.shared.DataFilterUtil; + +import java.util.List; +import java.util.Map; + +public abstract class StudyViewFilterFactory { + private StudyViewFilterFactory() {} + + public static StudyViewFilterContext make(StudyViewFilter base, + CustomDataFilterUtil customDataFilterUtil, + Map> genericAssayProfilesMap) { + List customSampleIdentifiers = customDataFilterUtil.extractCustomDataSamples(base); + List involvedCancerStudies = customDataFilterUtil.extractInvolvedCancerStudies(base); + CategorizedGenericAssayDataCountFilter categorizedGenericAssayDataCountFilter = + CategorizedGenericAssayDataCountFilter.getBuilder(genericAssayProfilesMap, base).build(); + + + // Merge data filters + if (base.getGenomicDataFilters() != null && !base.getGenomicDataFilters().isEmpty()) { + List mergedGenomicDataFilters = + DataFilterUtil.mergeDataFilters(base.getGenomicDataFilters()); + base.setGenomicDataFilters(mergedGenomicDataFilters); + } + if (base.getClinicalDataFilters() != null && !base.getClinicalDataFilters().isEmpty()) { + List mergedClinicalDataFilters = + DataFilterUtil.mergeDataFilters(base.getClinicalDataFilters()); + base.setClinicalDataFilters(mergedClinicalDataFilters); + } + if (base.getGenericAssayDataFilters() != null && !base.getGenericAssayDataFilters().isEmpty()) { + List mergedGenericAssayDataFilters = + DataFilterUtil.mergeDataFilters(base.getGenericAssayDataFilters()); + base.setGenericAssayDataFilters(mergedGenericAssayDataFilters); + } + + return make(base, customSampleIdentifiers, involvedCancerStudies, categorizedGenericAssayDataCountFilter); + } + + public static StudyViewFilterContext make(StudyViewFilter base, + List customSampleIdentifiers, + List involvedCancerStudies, + CategorizedGenericAssayDataCountFilter categorizedGenericAssayDataCountFilter){ + return new StudyViewFilterContext(base.getSampleIdentifiers(), base.getStudyIds(), + base.getClinicalDataFilters(), base.getGeneFilters(), base.getStructuralVariantFilters(), + base.getSampleTreatmentFilters(), base.getSampleTreatmentGroupFilters(), + base.getSampleTreatmentTargetFilters(), base.getPatientTreatmentFilters(), + base.getPatientTreatmentGroupFilters(), base.getPatientTreatmentTargetFilters(), + base.getGenomicProfiles(), base.getGenomicDataFilters(), base.getGenericAssayDataFilters(), + base.getCaseLists(), base.getCustomDataFilters(), base.getAlterationFilter(), + base.getClinicalEventFilters(), base.getMutationDataFilters(),customSampleIdentifiers, + involvedCancerStudies, categorizedGenericAssayDataCountFilter); + } +} diff --git a/src/main/java/org/cbioportal/domain/studyview/StudyViewService.java b/src/main/java/org/cbioportal/domain/studyview/StudyViewService.java new file mode 100644 index 00000000000..90dc15d631f --- /dev/null +++ b/src/main/java/org/cbioportal/domain/studyview/StudyViewService.java @@ -0,0 +1,299 @@ +package org.cbioportal.domain.studyview; + +import org.cbioportal.domain.alteration.usecase.AlterationCountByGeneUseCases; +import org.cbioportal.domain.clinical_attributes.usecase.GetClinicalAttributesDataTypeMapUseCase; +import org.cbioportal.domain.clinical_attributes.usecase.GetClinicalAttributesForStudiesUseCase; +import org.cbioportal.domain.clinical_data.usecase.ClinicalDataUseCases; +import org.cbioportal.domain.clinical_event.usecase.GetClinicalEventTypeCountsUseCase; +import org.cbioportal.domain.generic_assay.usecase.GenericAssayUseCases; +import org.cbioportal.domain.genomic_data.usecase.GenomicDataUseCases; +import org.cbioportal.legacy.model.AlterationCountByGene; +import org.cbioportal.legacy.model.AlterationType; +import org.cbioportal.legacy.model.CaseListDataCount; +import org.cbioportal.legacy.model.ClinicalAttribute; +import org.cbioportal.legacy.model.ClinicalData; +import org.cbioportal.legacy.model.ClinicalDataCountItem; +import org.cbioportal.legacy.model.ClinicalEventTypeCount; +import org.cbioportal.legacy.model.CopyNumberCountByGene; +import org.cbioportal.legacy.model.GenericAssayDataCountItem; +import org.cbioportal.legacy.model.GenomicDataCount; +import org.cbioportal.legacy.model.GenomicDataCountItem; +import org.cbioportal.legacy.model.MolecularProfile; +import org.cbioportal.legacy.model.PatientTreatmentReport; +import org.cbioportal.legacy.model.SampleTreatmentReport; +import org.cbioportal.legacy.persistence.enums.DataSource; +import org.cbioportal.legacy.service.exception.StudyNotFoundException; +import org.cbioportal.legacy.service.util.StudyViewColumnarServiceUtil; +import org.cbioportal.legacy.web.columnar.util.CustomDataFilterUtil; +import org.cbioportal.legacy.web.parameter.ClinicalDataType; +import org.cbioportal.legacy.web.parameter.GenericAssayDataBinFilter; +import org.cbioportal.legacy.web.parameter.GenericAssayDataFilter; +import org.cbioportal.legacy.web.parameter.GenomicDataBinFilter; +import org.cbioportal.legacy.web.parameter.GenomicDataFilter; +import org.cbioportal.legacy.web.parameter.StudyViewFilter; +import org.cbioportal.domain.patient.usecase.GetCaseListDataCountsUseCase; +import org.cbioportal.domain.sample.Sample; +import org.cbioportal.domain.sample.usecase.GetFilteredSamplesUseCase; +import org.cbioportal.shared.util.ClinicalDataCountItemUtil; +import org.cbioportal.domain.treatment.usecase.TreatmentCountReportUseCases; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.context.annotation.Profile; +import org.springframework.stereotype.Service; + +import java.util.ArrayList; +import java.util.EnumMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +@Service +@Profile("clickhouse") +/** + * A service class responsible for handling study view-related operations, including retrieving filtered samples, + * genomic data counts, clinical data, and other study-specific information. This class acts as a central hub + * for coordinating various use cases and delegating tasks to the appropriate repositories and utilities. + */ +public class StudyViewService { + + private final GetFilteredSamplesUseCase getFilteredSamplesUseCase; + private final AlterationCountByGeneUseCases alterationCountByGeneUseCase; + private final GetClinicalEventTypeCountsUseCase getClinicalEventTypeCountsUseCase; + private final TreatmentCountReportUseCases treatmentCountReportUseCases; + private final GetClinicalAttributesForStudiesUseCase getClinicalAttributesForStudiesUseCase; + private final GetCaseListDataCountsUseCase getCaseListDataCountsUseCase; + private final GetClinicalAttributesDataTypeMapUseCase getClinicalAttributesDataTypeMapUseCase; + private final ClinicalDataUseCases clinicalDataUseCases; + private final GenomicDataUseCases genomicDataUseCases; + private final GenericAssayUseCases genericAssayUseCases; + private final CustomDataFilterUtil customDataFilterUtil; + + private Map> genericAssayProfilesMap = new EnumMap<>(DataSource.class); + + + public StudyViewService(GetFilteredSamplesUseCase getFilteredSamplesUseCase, + AlterationCountByGeneUseCases alterationCountByGeneUseCase, + GetClinicalEventTypeCountsUseCase getClinicalEventTypeCountsUseCase, + TreatmentCountReportUseCases treatmentCountReportUseCases, + GetClinicalAttributesForStudiesUseCase getClinicalAttributesForStudiesUseCase, + GetCaseListDataCountsUseCase getCaseListDataCountsUseCase, + GetClinicalAttributesDataTypeMapUseCase getClinicalAttributesDataTypeMapUseCase, + ClinicalDataUseCases clinicalDataUseCases, + GenomicDataUseCases genomicDataUseCases, GenericAssayUseCases genericAssayUseCases, + CustomDataFilterUtil customDataFilterUtil) { + this.getFilteredSamplesUseCase = getFilteredSamplesUseCase; + this.alterationCountByGeneUseCase = alterationCountByGeneUseCase; + this.clinicalDataUseCases = clinicalDataUseCases; + this.genomicDataUseCases = genomicDataUseCases; + this.getClinicalEventTypeCountsUseCase = getClinicalEventTypeCountsUseCase; + this.treatmentCountReportUseCases = treatmentCountReportUseCases; + this.getClinicalAttributesForStudiesUseCase = getClinicalAttributesForStudiesUseCase; + this.getCaseListDataCountsUseCase = getCaseListDataCountsUseCase; + this.getClinicalAttributesDataTypeMapUseCase = getClinicalAttributesDataTypeMapUseCase; + this.genericAssayUseCases = genericAssayUseCases; + this.customDataFilterUtil = customDataFilterUtil; + } + + @Cacheable( + cacheResolver = "staticRepositoryCacheOneResolver", + condition = "@cacheEnabledConfig.getEnabledClickhouse() && @studyViewFilterUtil.isUnfilteredQuery(#studyViewFilter)" + ) + public List getFilteredSamples(StudyViewFilter studyViewFilter){ + return getFilteredSamplesUseCase.execute(buildStudyViewFilterContext(studyViewFilter)); + } + + @Cacheable( + cacheResolver = "staticRepositoryCacheOneResolver", + condition = "@cacheEnabledConfig.getEnabledClickhouse() && @studyViewFilterUtil.isUnfilteredQuery(#studyViewFilter)" + ) + public List getMutatedGenes(StudyViewFilter studyViewFilter) throws StudyNotFoundException { + return alterationCountByGeneUseCase.getAlterationCountByGeneUseCase() + .execute(buildStudyViewFilterContext(studyViewFilter), AlterationType.MUTATION_EXTENDED); + } + + @Cacheable( + cacheResolver = "staticRepositoryCacheOneResolver", + condition = "@cacheEnabledConfig.getEnabledClickhouse() && @studyViewFilterUtil.isUnfilteredQuery(#studyViewFilter)" + ) + public List getCnaGenes(StudyViewFilter studyViewFilter) throws StudyNotFoundException { + return alterationCountByGeneUseCase.getCnaAlterationCountByGeneUseCase().execute(buildStudyViewFilterContext(studyViewFilter)); + } + + @Cacheable( + cacheResolver = "staticRepositoryCacheOneResolver", + condition = "@cacheEnabledConfig.getEnabledClickhouse() && @studyViewFilterUtil.isUnfilteredQuery(#studyViewFilter)" + ) + public List getStructuralVariantGenes(StudyViewFilter studyViewFilter) throws StudyNotFoundException { + return alterationCountByGeneUseCase.getAlterationCountByGeneUseCase() + .execute(buildStudyViewFilterContext(studyViewFilter), AlterationType.STRUCTURAL_VARIANT); + } + + @Cacheable( + cacheResolver = "staticRepositoryCacheOneResolver", + condition = "@cacheEnabledConfig.getEnabledClickhouse() && @studyViewFilterUtil.isUnfilteredQuery(#studyViewFilter)" + ) + public List getMolecularProfileSampleCounts(StudyViewFilter studyViewFilter) throws StudyNotFoundException { + return genomicDataUseCases.getMolecularProfileSampleCountsUseCase().execute(buildStudyViewFilterContext(studyViewFilter)); + } + + @Cacheable( + cacheResolver = "staticRepositoryCacheOneResolver", + condition = "@cacheEnabledConfig.getEnabledClickhouse() && @studyViewFilterUtil.isUnfilteredQuery(#studyViewFilter)" + ) + public List getClinicalEventTypeCounts(StudyViewFilter studyViewFilter) { + return getClinicalEventTypeCountsUseCase.execute(buildStudyViewFilterContext(studyViewFilter)); + } + + @Cacheable( + cacheResolver = "staticRepositoryCacheOneResolver", + condition = "@cacheEnabledConfig.getEnabledClickhouse() && @studyViewFilterUtil.isUnfilteredQuery(#studyViewFilter)" + ) + public PatientTreatmentReport getPatientTreatmentReport(StudyViewFilter studyViewFilter) { + return treatmentCountReportUseCases.getPatientTreatmentReportUseCase().execute(buildStudyViewFilterContext(studyViewFilter)); + } + + @Cacheable( + cacheResolver = "staticRepositoryCacheOneResolver", + condition = "@cacheEnabledConfig.getEnabledClickhouse() && @studyViewFilterUtil.isUnfilteredQuery(#studyViewFilter)" + ) + public SampleTreatmentReport getSampleTreatmentReport(StudyViewFilter studyViewFilter) { + return treatmentCountReportUseCases.getSampleTreatmentReportUseCase().execute(buildStudyViewFilterContext(studyViewFilter)); + } + + @Cacheable( + cacheResolver = "staticRepositoryCacheOneResolver", + condition = "@cacheEnabledConfig.getEnabledClickhouse() && @studyViewFilterUtil.isUnfilteredQuery(#studyViewFilter)" + ) + public List getGenomicDataBinCounts(StudyViewFilter studyViewFilter, + List genomicDataBinFilters) { + return ClinicalDataCountItemUtil.generateDataCountItems(genomicDataUseCases.getGenomicDataBinCountsUseCase().execute(buildStudyViewFilterContext(studyViewFilter), genomicDataBinFilters)); + } + + @Cacheable( + cacheResolver = "staticRepositoryCacheOneResolver", + condition = "@cacheEnabledConfig.getEnabledClickhouse() && @studyViewFilterUtil.isUnfilteredQuery(#studyViewFilter)" + ) + public List getGenericAssayDataBinCounts(StudyViewFilter studyViewFilter, + List genericAssayDataBinFilters) { + return ClinicalDataCountItemUtil.generateDataCountItems(genericAssayUseCases.getGenericAssayDataBinCounts().execute(buildStudyViewFilterContext(studyViewFilter), genericAssayDataBinFilters)); + } + + @Cacheable( + cacheResolver = "staticRepositoryCacheOneResolver", + condition = "@cacheEnabledConfig.getEnabledClickhouse() && @studyViewFilterUtil.isUnfilteredQuery(#studyViewFilter)" + ) + public Map getClinicalAttributeDataTypeMap(StudyViewFilter studyViewFilter) { + return getClinicalAttributesDataTypeMapUseCase.execute(); + } + + @Cacheable( + cacheResolver = "staticRepositoryCacheOneResolver", + condition = "@cacheEnabledConfig.getEnabledClickhouse() && @studyViewFilterUtil.isUnfilteredQuery(#studyViewFilter)" + ) + public List getClinicalDataCounts(StudyViewFilter studyViewFilter, + List filteredAttributes){ + return clinicalDataUseCases.getClinicalDataCountsUseCase().execute(buildStudyViewFilterContext(studyViewFilter) + , filteredAttributes); + } + + @Cacheable( + cacheResolver = "staticRepositoryCacheOneResolver", + condition = "@cacheEnabledConfig.getEnabledClickhouse() && @studyViewFilterUtil.isUnfilteredQuery(#studyViewFilter)" + ) + public List getClinicalAttributesForStudies(List studyIds){ + return getClinicalAttributesForStudiesUseCase.execute(studyIds); + } + + @Cacheable( + cacheResolver = "staticRepositoryCacheOneResolver", + condition = "@cacheEnabledConfig.getEnabledClickhouse() && @studyViewFilterUtil.isUnfilteredQuery(#studyViewFilter)" + ) + public List getCaseListDataCounts(StudyViewFilter studyViewFilter){ + return StudyViewColumnarServiceUtil.mergeCaseListCounts(getCaseListDataCountsUseCase.execute(buildStudyViewFilterContext(studyViewFilter))); + } + + @Cacheable( + cacheResolver = "staticRepositoryCacheOneResolver", + condition = "@cacheEnabledConfig.getEnabledClickhouse() && @studyViewFilterUtil.isUnfilteredQuery(#studyViewFilter)" + ) + public List getPatientClinicalData(StudyViewFilter studyViewFilter, List attributeIds){ + return clinicalDataUseCases.getPatientClinicalDataUseCase().execute(buildStudyViewFilterContext(studyViewFilter), attributeIds); + } + + @Cacheable( + cacheResolver = "staticRepositoryCacheOneResolver", + condition = "@cacheEnabledConfig.getEnabledClickhouse() && @studyViewFilterUtil.isUnfilteredQuery(#studyViewFilter)" + ) + public List getSampleClinicalData(StudyViewFilter studyViewFilter,List attributeIds){ + return clinicalDataUseCases.getSampleClinicalDataUseCase().execute(buildStudyViewFilterContext(studyViewFilter), attributeIds); + } + + @Cacheable( + cacheResolver = "staticRepositoryCacheOneResolver", + condition = "@cacheEnabledConfig.getEnabledClickhouse() && @studyViewFilterUtil.isUnfilteredQuery(#studyViewFilter)" + ) + public List getCNACountsByGeneSpecific(StudyViewFilter studyViewFilter, + List genomicDataFilters){ + return genomicDataUseCases.getCNACountsByGeneSpecificUseCase().execute(buildStudyViewFilterContext(studyViewFilter), genomicDataFilters); + } + + @Cacheable( + cacheResolver = "staticRepositoryCacheOneResolver", + condition = "@cacheEnabledConfig.getEnabledClickhouse() && @studyViewFilterUtil.isUnfilteredQuery(#studyViewFilter)" + ) + public List getGenericAssayDataCounts(StudyViewFilter studyViewFilter, + List genericAssayDataFilters){ + return genericAssayUseCases.getGenericAssayDataCountsUseCase().execute(buildStudyViewFilterContext(studyViewFilter), genericAssayDataFilters); + } + + @Cacheable( + cacheResolver = "staticRepositoryCacheOneResolver", + condition = "@cacheEnabledConfig.getEnabledClickhouse() && @studyViewFilterUtil.isUnfilteredQuery(#studyViewFilter)" + ) + public List getMutationCountsByGeneSpecific(StudyViewFilter studyViewFilter, + List genomicDataFilters){ + List genomicDataCountItemList = new ArrayList<>(); + for (GenomicDataFilter genomicDataFilter : genomicDataFilters) { + Map counts = + genomicDataUseCases.getMutationCountsUseCase().execute(buildStudyViewFilterContext(studyViewFilter), genomicDataFilter); + genomicDataCountItemList.add(StudyViewColumnarServiceUtil.createGenomicDataCountItemFromMutationCounts(genomicDataFilter, counts)); + } + return genomicDataCountItemList; + } + + @Cacheable( + cacheResolver = "staticRepositoryCacheOneResolver", + condition = "@cacheEnabledConfig.getEnabledClickhouse() && @studyViewFilterUtil.isUnfilteredQuery(#studyViewFilter)" + ) + public List getMutationTypeCountsByGeneSpecific(StudyViewFilter studyViewFilter, + List genomicDataFilters){ + return genomicDataUseCases.getMutationCountsByTypeUseCase().execute(buildStudyViewFilterContext(studyViewFilter), genomicDataFilters); + } + + @Cacheable( + cacheResolver = "staticRepositoryCacheOneResolver", + condition = "@cacheEnabledConfig.getEnabledClickhouse() && @studyViewFilterUtil.isUnfilteredQuery(#studyViewFilter)" + ) + public List getClinicalDataForXyPlot(StudyViewFilter studyViewFilter, List attributeIds, + boolean shouldFilterNonEmptyClinicalData){ + return clinicalDataUseCases.getClinicalDataForXyPlotUseCase().execute(buildStudyViewFilterContext(studyViewFilter),attributeIds, + shouldFilterNonEmptyClinicalData); + } + + private StudyViewFilterContext buildStudyViewFilterContext(StudyViewFilter studyViewFilter){ + return StudyViewFilterFactory.make(studyViewFilter,this.customDataFilterUtil, getGenericAssayProfilesMap() ); + } + + private Map> getGenericAssayProfilesMap() { + if (genericAssayProfilesMap.isEmpty()) { + buildGenericAssayProfilesMap(); + } + return genericAssayProfilesMap; + } + + private void buildGenericAssayProfilesMap() { + genericAssayProfilesMap = genericAssayUseCases.getGenericAssayProfilesUseCase().execute() + .stream() + .collect(Collectors.groupingBy(ca -> ca.getPatientLevel() ? DataSource.PATIENT : DataSource.SAMPLE)); + } + +} diff --git a/src/main/java/org/cbioportal/domain/treatment/repository/TreatmentRepository.java b/src/main/java/org/cbioportal/domain/treatment/repository/TreatmentRepository.java new file mode 100644 index 00000000000..01e1cb19d67 --- /dev/null +++ b/src/main/java/org/cbioportal/domain/treatment/repository/TreatmentRepository.java @@ -0,0 +1,47 @@ +package org.cbioportal.domain.treatment.repository; + +import org.cbioportal.legacy.model.PatientTreatment; +import org.cbioportal.legacy.model.SampleTreatment; +import org.cbioportal.domain.studyview.StudyViewFilterContext; + +import java.util.List; + +/** + * Repository interface for performing operations related to patient and sample treatments. + * This interface defines methods for retrieving patient treatments, sample treatments, + * and their respective total counts based on the filter criteria provided in the study view filter context. + */ +public interface TreatmentRepository { + + /** + * Retrieves the treatments associated with patients based on the provided study view filter context. + * + * @param studyViewFilterContext the context containing the filter criteria for the study view + * @return a list of {@link PatientTreatment} representing the treatments for patients + */ + List getPatientTreatments(StudyViewFilterContext studyViewFilterContext); + + /** + * Retrieves the total count of patient treatments based on the provided study view filter context. + * + * @param studyViewFilterContext the context containing the filter criteria for the study view + * @return the total count of patient treatments + */ + int getTotalPatientTreatmentCount(StudyViewFilterContext studyViewFilterContext); + + /** + * Retrieves the treatments associated with samples based on the provided study view filter context. + * + * @param studyViewFilterContext the context containing the filter criteria for the study view + * @return a list of {@link SampleTreatment} representing the treatments for samples + */ + List getSampleTreatments(StudyViewFilterContext studyViewFilterContext); + + /** + * Retrieves the total count of sample treatments based on the provided study view filter context. + * + * @param studyViewFilterContext the context containing the filter criteria for the study view + * @return the total count of sample treatments + */ + int getTotalSampleTreatmentCount(StudyViewFilterContext studyViewFilterContext); +} diff --git a/src/main/java/org/cbioportal/domain/treatment/usecase/GetPatientTreatmentReportUseCase.java b/src/main/java/org/cbioportal/domain/treatment/usecase/GetPatientTreatmentReportUseCase.java new file mode 100644 index 00000000000..d2853435c43 --- /dev/null +++ b/src/main/java/org/cbioportal/domain/treatment/usecase/GetPatientTreatmentReportUseCase.java @@ -0,0 +1,36 @@ +package org.cbioportal.domain.treatment.usecase; + +import org.cbioportal.domain.studyview.StudyViewFilterContext; +import org.cbioportal.domain.treatment.repository.TreatmentRepository; +import org.cbioportal.legacy.model.PatientTreatmentReport; +import org.springframework.context.annotation.Profile; +import org.springframework.stereotype.Service; + +@Service +@Profile("clickhouse") +public class GetPatientTreatmentReportUseCase { + private final TreatmentRepository treatmentRepository; + + + /** + * Constructs a new use case with the given treatment repository. + * + * @param treatmentRepository the repository used to fetch treatment data + */ + public GetPatientTreatmentReportUseCase(TreatmentRepository treatmentRepository) { + this.treatmentRepository = treatmentRepository; + } + + + /** + * Executes the use case to retrieve a patient treatment report based on the given filter context. + * + * @param studyViewFilterContext the filtering criteria for retrieving patient treatments + * @return a {@link PatientTreatmentReport} containing treatment data for patients + */ + public PatientTreatmentReport execute(StudyViewFilterContext studyViewFilterContext){ + var patientTreatments = treatmentRepository.getPatientTreatments(studyViewFilterContext); + var totalPatientTreatmentCount = treatmentRepository.getTotalPatientTreatmentCount(studyViewFilterContext); + return new PatientTreatmentReport(totalPatientTreatmentCount, 0, patientTreatments); + } +} diff --git a/src/main/java/org/cbioportal/domain/treatment/usecase/GetSampleTreatmentReportUseCase.java b/src/main/java/org/cbioportal/domain/treatment/usecase/GetSampleTreatmentReportUseCase.java new file mode 100644 index 00000000000..5237f04b880 --- /dev/null +++ b/src/main/java/org/cbioportal/domain/treatment/usecase/GetSampleTreatmentReportUseCase.java @@ -0,0 +1,41 @@ +package org.cbioportal.domain.treatment.usecase; + +import org.cbioportal.domain.studyview.StudyViewFilterContext; +import org.cbioportal.domain.treatment.repository.TreatmentRepository; +import org.cbioportal.legacy.model.SampleTreatmentReport; +import org.cbioportal.legacy.model.SampleTreatmentRow; +import org.cbioportal.legacy.model.TemporalRelation; +import org.springframework.context.annotation.Profile; +import org.springframework.stereotype.Service; + +import java.util.Set; +import java.util.stream.Stream; + +@Service +@Profile("clickhouse") +public class GetSampleTreatmentReportUseCase { + private final TreatmentRepository treatmentRepository; + + public GetSampleTreatmentReportUseCase(TreatmentRepository treatmentRepository) { + this.treatmentRepository = treatmentRepository; + } + + /** + * Executes the use case to retrieve a sample treatment report based on the given filter context. + * + * @param studyViewFilterContext the filtering criteria for retrieving sample treatments + * @return a {@link SampleTreatmentReport} containing treatment data for samples + */ + public SampleTreatmentReport execute(StudyViewFilterContext studyViewFilterContext){ + var sampleTreatments = treatmentRepository.getSampleTreatments(studyViewFilterContext) + .stream() + .flatMap(sampleTreatment -> + Stream.of(new SampleTreatmentRow(TemporalRelation.Pre, sampleTreatment.treatment(), sampleTreatment.preSampleCount(), Set.of()), + new SampleTreatmentRow(TemporalRelation.Post, sampleTreatment.treatment(), sampleTreatment.postSampleCount(), Set.of() )) + ) + .filter(sampleTreatment -> sampleTreatment.getCount() > 0 ) + .toList(); + var totalSampleTreatmentCount = treatmentRepository.getTotalSampleTreatmentCount(studyViewFilterContext); + return new SampleTreatmentReport(totalSampleTreatmentCount, sampleTreatments); + } +} diff --git a/src/main/java/org/cbioportal/domain/treatment/usecase/TreatmentCountReportUseCases.java b/src/main/java/org/cbioportal/domain/treatment/usecase/TreatmentCountReportUseCases.java new file mode 100644 index 00000000000..bcfb4685199 --- /dev/null +++ b/src/main/java/org/cbioportal/domain/treatment/usecase/TreatmentCountReportUseCases.java @@ -0,0 +1,12 @@ +package org.cbioportal.domain.treatment.usecase; + +import org.springframework.context.annotation.Profile; +import org.springframework.stereotype.Service; + +@Service +@Profile("clickhouse") +public record TreatmentCountReportUseCases( + GetPatientTreatmentReportUseCase getPatientTreatmentReportUseCase, + GetSampleTreatmentReportUseCase getSampleTreatmentReportUseCase) { + +} diff --git a/src/main/java/org/cbioportal/infrastructure/config/ClickhouseMyBatisConfig.java b/src/main/java/org/cbioportal/infrastructure/config/ClickhouseMyBatisConfig.java index a60a7365661..5ce2455341a 100644 --- a/src/main/java/org/cbioportal/infrastructure/config/ClickhouseMyBatisConfig.java +++ b/src/main/java/org/cbioportal/infrastructure/config/ClickhouseMyBatisConfig.java @@ -1,18 +1,31 @@ package org.cbioportal.infrastructure.config; +import org.cbioportal.legacy.persistence.mybatis.typehandler.SampleTypeTypeHandler; import org.mybatis.spring.SqlSessionFactoryBean; +import org.mybatis.spring.annotation.MapperScan; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Profile; +import javax.sql.DataSource; import java.io.IOException; @Configuration +@Profile("clickhouse") +@MapperScan(value= "org.cbioportal.infrastructure.repository.clickhouse", + sqlSessionFactoryRef = "sqlColumnarSessionFactory") public class ClickhouseMyBatisConfig { - - public void addClickhouseMybatisConfig( @Qualifier("sqlColumnarSessionFactory") SqlSessionFactoryBean sqlSessionFactoryBean, - ApplicationContext applicationContext) throws IOException { - sqlSessionFactoryBean.addMapperLocations( - applicationContext.getResources("classpath:mappers/clickhouse/**/*.xml")); + + @Bean("sqlColumnarSessionFactory") + public SqlSessionFactoryBean sqlColumnarSessionFactory(@Qualifier("clickhouseDataSource") DataSource dataSource, ApplicationContext applicationContext) throws IOException { + SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean(); + sessionFactory.setDataSource(dataSource); + sessionFactory.addMapperLocations( + applicationContext.getResources("classpath:mappers/clickhouse/**/*.xml")); + + sessionFactory.setTypeHandlers(new SampleTypeTypeHandler()); + return sessionFactory; } } diff --git a/src/main/java/org/cbioportal/infrastructure/repository/clickhouse/alteration/ClickhouseAlterationMapper.java b/src/main/java/org/cbioportal/infrastructure/repository/clickhouse/alteration/ClickhouseAlterationMapper.java new file mode 100644 index 00000000000..424e0d8670d --- /dev/null +++ b/src/main/java/org/cbioportal/infrastructure/repository/clickhouse/alteration/ClickhouseAlterationMapper.java @@ -0,0 +1,83 @@ +package org.cbioportal.infrastructure.repository.clickhouse.alteration; + +import org.cbioportal.legacy.model.AlterationCountByGene; +import org.cbioportal.legacy.model.CopyNumberCountByGene; +import org.cbioportal.legacy.model.GenePanelToGene; +import org.cbioportal.legacy.model.MolecularProfile; +import org.cbioportal.legacy.persistence.helper.AlterationFilterHelper; +import org.cbioportal.domain.studyview.StudyViewFilterContext; + +import java.util.List; + +/** + * Mapper interface for retrieving alteration-related data from ClickHouse. + * This interface provides methods for fetching mutated gene counts, copy number alteration counts, + * structural variant gene counts, and more, based on the provided study view filter context and alteration filters. + */ +public interface ClickhouseAlterationMapper { + + /** + * Retrieves mutated gene counts based on the study view filter context and alteration filter. + * + * @param studyViewFilterContext the context of the study view filter + * @param alterationFilterHelper the helper for applying alteration filters + * @return a list of mutated genes with their respective counts + */ + List getMutatedGenes(StudyViewFilterContext studyViewFilterContext, AlterationFilterHelper alterationFilterHelper); + + /** + * Retrieves copy number alteration (CNA) gene counts based on the study view filter context and alteration filter. + * + * @param studyViewFilterContext the context of the study view filter + * @param alterationFilterHelper the helper for applying alteration filters + * @return a list of CNA genes with their respective counts + */ + List getCnaGenes(StudyViewFilterContext studyViewFilterContext, AlterationFilterHelper alterationFilterHelper); + + /** + * Retrieves structural variant gene counts based on the study view filter context and alteration filter. + * + * @param studyViewFilterContext the context of the study view filter + * @param alterationFilterHelper the helper for applying alteration filters + * @return a list of structural variant genes with their respective counts + */ + List getStructuralVariantGenes(StudyViewFilterContext studyViewFilterContext, + AlterationFilterHelper alterationFilterHelper); + + /** + * Retrieves the total profiled count for a given alteration type. + * + * @param studyViewFilterContext the context of the study view filter + * @param alterationType the type of alteration (e.g., mutation, CNA, etc.) + * @return the total profiled count for the given alteration type + */ + int getTotalProfiledCountByAlterationType(StudyViewFilterContext studyViewFilterContext, String alterationType); + + /** + * Retrieves the matching gene panel IDs for a given alteration type. + * + * @param studyViewFilterContext the context of the study view filter + * @param alterationType the type of alteration (e.g., mutation, CNA, etc.) + * @return a list of matching gene panel IDs + */ + List getMatchingGenePanelIds(StudyViewFilterContext studyViewFilterContext, String alterationType); + + /** + * Retrieves the total profiled counts for a given alteration type and molecular profiles. + * + * @param studyViewFilterContext the context of the study view filter + * @param alterationType the type of alteration (e.g., mutation, CNA, etc.) + * @param molecularProfiles the list of molecular profiles to be considered + * @return a list of alteration counts by gene + */ + List getTotalProfiledCounts(StudyViewFilterContext studyViewFilterContext, String alterationType, List molecularProfiles); + + /** + * Retrieves the sample profile count without panel data for a given alteration type. + * + * @param studyViewFilterContext the context of the study view filter + * @param alterationType the type of alteration (e.g., mutation, CNA, etc.) + * @return the sample profile count without panel data + */ + int getSampleProfileCountWithoutPanelData(StudyViewFilterContext studyViewFilterContext, String alterationType); +} diff --git a/src/main/java/org/cbioportal/infrastructure/repository/clickhouse/alteration/ClickhouseAlterationRepository.java b/src/main/java/org/cbioportal/infrastructure/repository/clickhouse/alteration/ClickhouseAlterationRepository.java new file mode 100644 index 00000000000..7aef74b9c1f --- /dev/null +++ b/src/main/java/org/cbioportal/infrastructure/repository/clickhouse/alteration/ClickhouseAlterationRepository.java @@ -0,0 +1,69 @@ +package org.cbioportal.infrastructure.repository.clickhouse.alteration; + +import org.cbioportal.domain.alteration.repository.AlterationRepository; +import org.cbioportal.legacy.model.AlterationCountByGene; +import org.cbioportal.legacy.model.CopyNumberCountByGene; +import org.cbioportal.legacy.model.GenePanelToGene; +import org.cbioportal.legacy.model.MolecularProfile; +import org.cbioportal.legacy.persistence.helper.AlterationFilterHelper; +import org.cbioportal.domain.studyview.StudyViewFilterContext; +import org.springframework.context.annotation.Profile; +import org.springframework.stereotype.Repository; + +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; + +@Repository +@Profile("clickhouse") +public class ClickhouseAlterationRepository implements AlterationRepository { + + private final ClickhouseAlterationMapper mapper; + + public ClickhouseAlterationRepository(ClickhouseAlterationMapper mapper) { + this.mapper = mapper; + } + + @Override + public List getMutatedGenes(StudyViewFilterContext studyViewFilterContext) { + return mapper.getMutatedGenes(studyViewFilterContext, + AlterationFilterHelper.build(studyViewFilterContext.alterationFilter())); + } + + @Override + public List getStructuralVariantGenes(StudyViewFilterContext studyViewFilterContext) { + return mapper.getStructuralVariantGenes(studyViewFilterContext, AlterationFilterHelper.build(studyViewFilterContext.alterationFilter())); + } + + @Override + public List getCnaGenes(StudyViewFilterContext studyViewFilterContext) { + return mapper.getCnaGenes(studyViewFilterContext, AlterationFilterHelper.build(studyViewFilterContext.alterationFilter())); + } + + @Override + public int getTotalProfiledCountsByAlterationType(StudyViewFilterContext studyViewFilterContext, String alterationType) { + return mapper.getTotalProfiledCountByAlterationType(studyViewFilterContext, alterationType); + } + + @Override + public Map getTotalProfiledCounts(StudyViewFilterContext studyViewFilterContext, String alterationType, List molecularProfiles) { + return mapper.getTotalProfiledCounts(studyViewFilterContext,alterationType,molecularProfiles) + .stream() + .collect(Collectors.groupingBy(AlterationCountByGene::getHugoGeneSymbol, + Collectors.mapping(AlterationCountByGene::getNumberOfProfiledCases, Collectors.summingInt(Integer::intValue)))); + } + + @Override + public Map> getMatchingGenePanelIds(StudyViewFilterContext studyViewFilterContext, String alterationType) { + return mapper.getMatchingGenePanelIds(studyViewFilterContext, alterationType) + .stream() + .collect(Collectors.groupingBy(GenePanelToGene::getHugoGeneSymbol, + Collectors.mapping(GenePanelToGene::getGenePanelId, Collectors.toSet()))); + } + + @Override + public int getSampleProfileCountWithoutPanelData(StudyViewFilterContext studyViewFilterContext, String alterationType) { + return mapper.getSampleProfileCountWithoutPanelData(studyViewFilterContext, alterationType); + } +} diff --git a/src/main/java/org/cbioportal/infrastructure/repository/clickhouse/cancerstudy/ClickhouseCancerStudyMapper.java b/src/main/java/org/cbioportal/infrastructure/repository/clickhouse/cancerstudy/ClickhouseCancerStudyMapper.java index 68ae7968782..041d1e5a512 100644 --- a/src/main/java/org/cbioportal/infrastructure/repository/clickhouse/cancerstudy/ClickhouseCancerStudyMapper.java +++ b/src/main/java/org/cbioportal/infrastructure/repository/clickhouse/cancerstudy/ClickhouseCancerStudyMapper.java @@ -1,7 +1,9 @@ package org.cbioportal.infrastructure.repository.clickhouse.cancerstudy; -import org.cbioportal.cancerstudy.CancerStudyMetadata; +import org.apache.ibatis.annotations.Param; +import org.cbioportal.domain.cancerstudy.CancerStudyMetadata; import org.cbioportal.shared.SortAndSearchCriteria; +import org.cbioportal.domain.studyview.StudyViewFilterContext; import java.util.List; @@ -43,4 +45,6 @@ public interface ClickhouseCancerStudyMapper { * The list may be empty if no studies match the criteria. */ List getCancerStudiesMetadataSummary(SortAndSearchCriteria sortAndSearchCriteria, List studyIds); + + List getFilteredStudyIds(@Param("studyViewFilterContext") StudyViewFilterContext studyViewFilterContext); } diff --git a/src/main/java/org/cbioportal/infrastructure/repository/clickhouse/cancerstudy/ClickhouseCancerStudyRepository.java b/src/main/java/org/cbioportal/infrastructure/repository/clickhouse/cancerstudy/ClickhouseCancerStudyRepository.java index a523ee1f5f4..c84b633cfde 100644 --- a/src/main/java/org/cbioportal/infrastructure/repository/clickhouse/cancerstudy/ClickhouseCancerStudyRepository.java +++ b/src/main/java/org/cbioportal/infrastructure/repository/clickhouse/cancerstudy/ClickhouseCancerStudyRepository.java @@ -1,8 +1,9 @@ package org.cbioportal.infrastructure.repository.clickhouse.cancerstudy; -import org.cbioportal.cancerstudy.CancerStudyMetadata; -import org.cbioportal.cancerstudy.repository.CancerStudyRepository; +import org.cbioportal.domain.cancerstudy.CancerStudyMetadata; +import org.cbioportal.domain.cancerstudy.repository.CancerStudyRepository; import org.cbioportal.shared.SortAndSearchCriteria; +import org.cbioportal.domain.studyview.StudyViewFilterContext; import org.springframework.context.annotation.Profile; import org.springframework.stereotype.Repository; @@ -50,4 +51,13 @@ public List getCancerStudiesMetadata(SortAndSearchCriteria public List getCancerStudiesMetadataSummary(SortAndSearchCriteria sortAndSearchCriteria) { return cancerStudyMapper.getCancerStudiesMetadataSummary(sortAndSearchCriteria, List.of()); } + + /** + * @param studyViewFilterContext + * @return + */ + @Override + public List getFilteredStudyIds(StudyViewFilterContext studyViewFilterContext) { + return cancerStudyMapper.getFilteredStudyIds(studyViewFilterContext); + } } diff --git a/src/main/java/org/cbioportal/infrastructure/repository/clickhouse/clinical_attributes/ClickhouseClinicalAttributesMapper.java b/src/main/java/org/cbioportal/infrastructure/repository/clickhouse/clinical_attributes/ClickhouseClinicalAttributesMapper.java new file mode 100644 index 00000000000..41a97b85bf5 --- /dev/null +++ b/src/main/java/org/cbioportal/infrastructure/repository/clickhouse/clinical_attributes/ClickhouseClinicalAttributesMapper.java @@ -0,0 +1,28 @@ +package org.cbioportal.infrastructure.repository.clickhouse.clinical_attributes; + +import org.cbioportal.legacy.model.ClinicalAttribute; + +import java.util.List; + +/** + * Mapper interface for retrieving clinical attributes data from ClickHouse. + * This interface provides methods to fetch clinical attributes either globally or for specific studies. + */ +public interface ClickhouseClinicalAttributesMapper { + + /** + * Retrieves the list of all clinical attributes. + * + * @return a list of clinical attributes + */ + List getClinicalAttributes(); + + /** + * Retrieves the list of clinical attributes for the specified study IDs. + * + * @param studyIds the list of study IDs to filter by + * @return a list of clinical attributes for the given studies + */ + List getClinicalAttributesForStudies(List studyIds); +} + diff --git a/src/main/java/org/cbioportal/infrastructure/repository/clickhouse/clinical_attributes/ClickhouseClinicalAttributesRepository.java b/src/main/java/org/cbioportal/infrastructure/repository/clickhouse/clinical_attributes/ClickhouseClinicalAttributesRepository.java new file mode 100644 index 00000000000..f520e920a6b --- /dev/null +++ b/src/main/java/org/cbioportal/infrastructure/repository/clickhouse/clinical_attributes/ClickhouseClinicalAttributesRepository.java @@ -0,0 +1,57 @@ +package org.cbioportal.infrastructure.repository.clickhouse.clinical_attributes; + +import org.cbioportal.domain.clinical_attributes.repository.ClinicalAttributesRepository; +import org.cbioportal.legacy.model.ClinicalAttribute; +import org.cbioportal.legacy.persistence.enums.DataSource; +import org.cbioportal.legacy.web.parameter.ClinicalDataType; +import org.springframework.context.annotation.Profile; +import org.springframework.stereotype.Repository; + +import java.util.EnumMap; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +@Repository +@Profile("clickhouse") +public class ClickhouseClinicalAttributesRepository implements ClinicalAttributesRepository { + + private Map> clinicalAttributesMap = new EnumMap<>(DataSource.class); + + private final ClickhouseClinicalAttributesMapper mapper; + + public ClickhouseClinicalAttributesRepository(ClickhouseClinicalAttributesMapper mapper) { + this.mapper = mapper; + } + + @Override + public List getClinicalAttributesForStudies(List studyIds) { + return mapper.getClinicalAttributesForStudies(studyIds); + } + + @Override + public Map getClinicalAttributeDatatypeMap() { + if (clinicalAttributesMap.isEmpty()) { + buildClinicalAttributeNameMap(); + } + + Map attributeDatatypeMap = new HashMap<>(); + + clinicalAttributesMap + .get(DataSource.SAMPLE) + .forEach(attribute -> attributeDatatypeMap.put(attribute.getAttrId(), ClinicalDataType.SAMPLE)); + + clinicalAttributesMap + .get(DataSource.PATIENT) + .forEach(attribute -> attributeDatatypeMap.put(attribute.getAttrId(), ClinicalDataType.PATIENT)); + + return attributeDatatypeMap; + } + + private void buildClinicalAttributeNameMap() { + clinicalAttributesMap = mapper.getClinicalAttributes() + .stream() + .collect(Collectors.groupingBy(ca -> ca.getPatientAttribute().booleanValue() ? DataSource.PATIENT : DataSource.SAMPLE)); + } +} diff --git a/src/main/java/org/cbioportal/infrastructure/repository/clickhouse/clinical_data/ClickhouseClinicalDataMapper.java b/src/main/java/org/cbioportal/infrastructure/repository/clickhouse/clinical_data/ClickhouseClinicalDataMapper.java new file mode 100644 index 00000000000..01d093ac677 --- /dev/null +++ b/src/main/java/org/cbioportal/infrastructure/repository/clickhouse/clinical_data/ClickhouseClinicalDataMapper.java @@ -0,0 +1,43 @@ +package org.cbioportal.infrastructure.repository.clickhouse.clinical_data; + +import org.cbioportal.legacy.model.ClinicalData; +import org.cbioportal.legacy.model.ClinicalDataCountItem; +import org.cbioportal.domain.studyview.StudyViewFilterContext; + +import java.util.List; + +/** + * Mapper interface for retrieving clinical data from ClickHouse. + * This interface provides methods to fetch clinical data counts and clinical data for samples and patients. + */ +public interface ClickhouseClinicalDataMapper { + + /** + * Retrieves clinical data counts based on the study view filter context, attribute IDs, and filtered attribute values. + * + * @param studyViewFilterContext the context of the study view filter + * @param attributeIds the list of attribute IDs to filter by + * @param filteredAttributeValues the list of filtered attribute values + * @return a list of clinical data count items + */ + List getClinicalDataCounts(StudyViewFilterContext studyViewFilterContext, List attributeIds, List filteredAttributeValues); + + /** + * Retrieves sample clinical data based on the study view filter context and attribute IDs. + * + * @param studyViewFilterContext the context of the study view filter + * @param attributeIds the list of attribute IDs to filter by + * @return a list of sample clinical data + */ + List getSampleClinicalDataFromStudyViewFilter(StudyViewFilterContext studyViewFilterContext, List attributeIds); + + /** + * Retrieves patient clinical data based on the study view filter context and attribute IDs. + * + * @param studyViewFilterContext the context of the study view filter + * @param attributeIds the list of attribute IDs to filter by + * @return a list of patient clinical data + */ + List getPatientClinicalDataFromStudyViewFilter(StudyViewFilterContext studyViewFilterContext, List attributeIds); +} + diff --git a/src/main/java/org/cbioportal/infrastructure/repository/clickhouse/clinical_data/ClickhouseClinicalDataRepository.java b/src/main/java/org/cbioportal/infrastructure/repository/clickhouse/clinical_data/ClickhouseClinicalDataRepository.java new file mode 100644 index 00000000000..67129d04e54 --- /dev/null +++ b/src/main/java/org/cbioportal/infrastructure/repository/clickhouse/clinical_data/ClickhouseClinicalDataRepository.java @@ -0,0 +1,40 @@ +package org.cbioportal.infrastructure.repository.clickhouse.clinical_data; + +import org.cbioportal.domain.clinical_data.repository.ClinicalDataRepository; +import org.cbioportal.legacy.model.ClinicalData; +import org.cbioportal.legacy.model.ClinicalDataCountItem; +import org.cbioportal.domain.studyview.StudyViewFilterContext; +import org.springframework.context.annotation.Profile; +import org.springframework.stereotype.Repository; + +import java.util.Collections; +import java.util.List; + +@Repository +@Profile("clickhouse") +public class ClickhouseClinicalDataRepository implements ClinicalDataRepository { + + private static final List FILTERED_CLINICAL_ATTR_VALUES = Collections.emptyList(); + + private final ClickhouseClinicalDataMapper mapper; + + public ClickhouseClinicalDataRepository(ClickhouseClinicalDataMapper mapper) { + this.mapper = mapper; + } + + + @Override + public List getPatientClinicalData(StudyViewFilterContext studyViewFilterContext, List filteredAttributes) { + return mapper.getPatientClinicalDataFromStudyViewFilter(studyViewFilterContext, filteredAttributes); + } + + @Override + public List getSampleClinicalData(StudyViewFilterContext studyViewFilterContext, List filteredAttributes) { + return mapper.getSampleClinicalDataFromStudyViewFilter(studyViewFilterContext, filteredAttributes); + } + + @Override + public List getClinicalDataCounts(StudyViewFilterContext studyViewFilterContext, List filteredAttributes) { + return mapper.getClinicalDataCounts(studyViewFilterContext, filteredAttributes, FILTERED_CLINICAL_ATTR_VALUES); + } +} diff --git a/src/main/java/org/cbioportal/infrastructure/repository/clickhouse/clinical_event/ClickhouseClinicalEventMapper.java b/src/main/java/org/cbioportal/infrastructure/repository/clickhouse/clinical_event/ClickhouseClinicalEventMapper.java new file mode 100644 index 00000000000..9b14b7449f0 --- /dev/null +++ b/src/main/java/org/cbioportal/infrastructure/repository/clickhouse/clinical_event/ClickhouseClinicalEventMapper.java @@ -0,0 +1,23 @@ +package org.cbioportal.infrastructure.repository.clickhouse.clinical_event; + +import org.apache.ibatis.annotations.Param; +import org.cbioportal.legacy.model.ClinicalEventTypeCount; +import org.cbioportal.domain.studyview.StudyViewFilterContext; + +import java.util.List; + +/** + * Mapper interface for retrieving clinical event type data from ClickHouse. + * This interface provides a method to fetch clinical event type counts based on the study view filter context. + */ +public interface ClickhouseClinicalEventMapper { + + /** + * Retrieves the clinical event type counts based on the study view filter context. + * + * @param studyViewFilterContext the context of the study view filter + * @return a list of clinical event type counts + */ + List getClinicalEventTypeCounts(@Param("studyViewFilterContext") StudyViewFilterContext studyViewFilterContext); +} + diff --git a/src/main/java/org/cbioportal/infrastructure/repository/clickhouse/clinical_event/ClickhouseClinicalEventRepository.java b/src/main/java/org/cbioportal/infrastructure/repository/clickhouse/clinical_event/ClickhouseClinicalEventRepository.java new file mode 100644 index 00000000000..ac4e4a73dd5 --- /dev/null +++ b/src/main/java/org/cbioportal/infrastructure/repository/clickhouse/clinical_event/ClickhouseClinicalEventRepository.java @@ -0,0 +1,25 @@ +package org.cbioportal.infrastructure.repository.clickhouse.clinical_event; + +import org.cbioportal.domain.clinical_event.repository.ClinicalEventRepository; +import org.cbioportal.legacy.model.ClinicalEventTypeCount; +import org.cbioportal.domain.studyview.StudyViewFilterContext; +import org.springframework.context.annotation.Profile; +import org.springframework.stereotype.Repository; + +import java.util.List; + +@Repository +@Profile("clickhouse") +public class ClickhouseClinicalEventRepository implements ClinicalEventRepository { + + private final ClickhouseClinicalEventMapper mapper; + + public ClickhouseClinicalEventRepository(ClickhouseClinicalEventMapper mapper) { + this.mapper = mapper; + } + + @Override + public List getClinicalEventTypeCounts(StudyViewFilterContext studyViewFilterContext) { + return mapper.getClinicalEventTypeCounts(studyViewFilterContext); + } +} diff --git a/src/main/java/org/cbioportal/infrastructure/repository/clickhouse/generic_assay/ClickhouseGenericAssayMapper.java b/src/main/java/org/cbioportal/infrastructure/repository/clickhouse/generic_assay/ClickhouseGenericAssayMapper.java new file mode 100644 index 00000000000..3b9478fa89d --- /dev/null +++ b/src/main/java/org/cbioportal/infrastructure/repository/clickhouse/generic_assay/ClickhouseGenericAssayMapper.java @@ -0,0 +1,53 @@ +package org.cbioportal.infrastructure.repository.clickhouse.generic_assay; + +import org.cbioportal.legacy.model.ClinicalDataCount; +import org.cbioportal.legacy.model.GenericAssayDataCountItem; +import org.cbioportal.legacy.model.MolecularProfile; +import org.cbioportal.legacy.web.parameter.GenericAssayDataBinFilter; +import org.cbioportal.legacy.web.parameter.GenericAssayDataFilter; +import org.cbioportal.domain.studyview.StudyViewFilterContext; + +import java.util.List; + +/** + * Mapper interface for retrieving generic assay data from ClickHouse. + * This interface provides methods to fetch molecular profiles and generic assay data counts, + * as well as filtered molecular profiles by alteration type. + */ +public interface ClickhouseGenericAssayMapper { + + /** + * Retrieves the list of molecular profiles from the generic assay data. + * + * @return a list of molecular profiles + */ + List getGenericAssayProfiles(); + + /** + * Retrieves the filtered molecular profiles based on the study view filter context and alteration type. + * + * @param studyViewFilterContext the context of the study view filter + * @param alterationType the alteration type (e.g., mutation, CNA) + * @return a list of filtered molecular profiles + */ + List getFilteredMolecularProfilesByAlterationType(StudyViewFilterContext studyViewFilterContext, String alterationType); + + /** + * Retrieves the generic assay data bin counts based on the study view filter context and the provided bin filters. + * + * @param studyViewFilterContext the context of the study view filter + * @param genericAssayDataBinFilters the list of bin filters + * @return a list of generic assay data bin counts + */ + List getGenericAssayDataBinCounts(StudyViewFilterContext studyViewFilterContext, List genericAssayDataBinFilters); + + /** + * Retrieves the generic assay data counts based on the study view filter context and the provided data filters. + * + * @param studyViewFilterContext the context of the study view filter + * @param genericAssayDataFilters the list of data filters + * @return a list of generic assay data counts + */ + List getGenericAssayDataCounts(StudyViewFilterContext studyViewFilterContext, List genericAssayDataFilters); +} + diff --git a/src/main/java/org/cbioportal/infrastructure/repository/clickhouse/generic_assay/ClickhouseGenericAssayRepository.java b/src/main/java/org/cbioportal/infrastructure/repository/clickhouse/generic_assay/ClickhouseGenericAssayRepository.java new file mode 100644 index 00000000000..12d697380df --- /dev/null +++ b/src/main/java/org/cbioportal/infrastructure/repository/clickhouse/generic_assay/ClickhouseGenericAssayRepository.java @@ -0,0 +1,44 @@ +package org.cbioportal.infrastructure.repository.clickhouse.generic_assay; + +import org.cbioportal.domain.generic_assay.repository.GenericAssayRepository; +import org.cbioportal.legacy.model.ClinicalDataCount; +import org.cbioportal.legacy.model.GenericAssayDataCountItem; +import org.cbioportal.legacy.model.MolecularProfile; +import org.cbioportal.legacy.web.parameter.GenericAssayDataBinFilter; +import org.cbioportal.legacy.web.parameter.GenericAssayDataFilter; +import org.cbioportal.domain.studyview.StudyViewFilterContext; +import org.springframework.context.annotation.Profile; +import org.springframework.stereotype.Repository; + +import java.util.List; + +@Repository +@Profile("clickhouse") +public class ClickhouseGenericAssayRepository implements GenericAssayRepository { + + private final ClickhouseGenericAssayMapper mapper; + + public ClickhouseGenericAssayRepository(ClickhouseGenericAssayMapper mapper) { + this.mapper = mapper; + } + + @Override + public List getGenericAssayProfiles() { + return mapper.getGenericAssayProfiles(); + } + + @Override + public List getFilteredMolecularProfilesByAlterationType(StudyViewFilterContext studyViewFilterContext, String alterationType) { + return mapper.getFilteredMolecularProfilesByAlterationType(studyViewFilterContext, alterationType); + } + + @Override + public List getGenericAssayDataBinCounts(StudyViewFilterContext studyViewFilterContext, List genericAssayDataBinFilters) { + return mapper.getGenericAssayDataBinCounts(studyViewFilterContext, genericAssayDataBinFilters); + } + + @Override + public List getGenericAssayDataCounts(StudyViewFilterContext studyViewFilterContext, List genericAssayDataFilters) { + return mapper.getGenericAssayDataCounts(studyViewFilterContext, genericAssayDataFilters); + } +} diff --git a/src/main/java/org/cbioportal/infrastructure/repository/clickhouse/genomic_data/ClickhouseGenomicDataMapper.java b/src/main/java/org/cbioportal/infrastructure/repository/clickhouse/genomic_data/ClickhouseGenomicDataMapper.java new file mode 100644 index 00000000000..3587cf95551 --- /dev/null +++ b/src/main/java/org/cbioportal/infrastructure/repository/clickhouse/genomic_data/ClickhouseGenomicDataMapper.java @@ -0,0 +1,66 @@ +package org.cbioportal.infrastructure.repository.clickhouse.genomic_data; + +import org.apache.ibatis.annotations.Param; +import org.cbioportal.legacy.model.ClinicalDataCount; +import org.cbioportal.legacy.model.GenomicDataCount; +import org.cbioportal.legacy.model.GenomicDataCountItem; +import org.cbioportal.legacy.web.parameter.GenomicDataBinFilter; +import org.cbioportal.legacy.web.parameter.GenomicDataFilter; +import org.cbioportal.domain.studyview.StudyViewFilterContext; + +import java.util.List; +import java.util.Map; + +/** + * Mapper interface for retrieving genomic data from ClickHouse. + * This interface provides methods to fetch genomic data counts, including mutation counts and CNAs, + * based on the study view filter context and genomic data filters. + */ +public interface ClickhouseGenomicDataMapper { + + /** + * Retrieves the molecular profile sample counts based on the study view filter context. + * + * @param studyViewFilterContext the context of the study view filter + * @return a list of genomic data counts by molecular profile + */ + List getMolecularProfileSampleCounts(@Param("studyViewFilterContext") StudyViewFilterContext studyViewFilterContext); + + /** + * Retrieves the genomic data bin counts based on the study view filter context and genomic data bin filters. + * + * @param studyViewFilterContext the context of the study view filter + * @param genomicDataBinFilters the list of genomic data bin filters + * @return a list of genomic data bin counts + */ + List getGenomicDataBinCounts(StudyViewFilterContext studyViewFilterContext, List genomicDataBinFilters); + + /** + * Retrieves CNAs counts based on the study view filter context and genomic data filters. + * + * @param studyViewFilterContext the context of the study view filter + * @param genomicDataFilters the list of genomic data filters + * @return a list of CNA counts + */ + List getCNACounts(StudyViewFilterContext studyViewFilterContext, List genomicDataFilters); + + /** + * Retrieves mutation counts based on the study view filter context and genomic data filter. + * + * @param studyViewFilterContext the context of the study view filter + * @param genomicDataFilter the genomic data filter + * @return a map of mutation counts by gene + */ + Map getMutationCounts(StudyViewFilterContext studyViewFilterContext, GenomicDataFilter genomicDataFilter); + + /** + * Retrieves mutation counts by type based on the study view filter context and genomic data filters. + * + * @param studyViewFilterContext the context of the study view filter + * @param genomicDataFilters the list of genomic data filters + * @return a list of mutation counts by type + */ + List getMutationCountsByType(StudyViewFilterContext studyViewFilterContext, List genomicDataFilters); +} + + diff --git a/src/main/java/org/cbioportal/infrastructure/repository/clickhouse/genomic_data/ClickhouseGenomicDataRepository.java b/src/main/java/org/cbioportal/infrastructure/repository/clickhouse/genomic_data/ClickhouseGenomicDataRepository.java new file mode 100644 index 00000000000..7cae3cd2fe7 --- /dev/null +++ b/src/main/java/org/cbioportal/infrastructure/repository/clickhouse/genomic_data/ClickhouseGenomicDataRepository.java @@ -0,0 +1,51 @@ +package org.cbioportal.infrastructure.repository.clickhouse.genomic_data; + +import org.cbioportal.domain.genomic_data.repository.GenomicDataRepository; +import org.cbioportal.legacy.model.ClinicalDataCount; +import org.cbioportal.legacy.model.GenomicDataCount; +import org.cbioportal.legacy.model.GenomicDataCountItem; +import org.cbioportal.legacy.web.parameter.GenomicDataBinFilter; +import org.cbioportal.legacy.web.parameter.GenomicDataFilter; +import org.cbioportal.domain.studyview.StudyViewFilterContext; +import org.springframework.context.annotation.Profile; +import org.springframework.stereotype.Repository; + +import java.util.List; +import java.util.Map; + +@Repository +@Profile("clickhouse") +public class ClickhouseGenomicDataRepository implements GenomicDataRepository { + + private final ClickhouseGenomicDataMapper mapper; + + public ClickhouseGenomicDataRepository(ClickhouseGenomicDataMapper mapper) { + this.mapper = mapper; + } + + @Override + public List getMolecularProfileSampleCounts(StudyViewFilterContext studyViewFilterContext) { + return mapper.getMolecularProfileSampleCounts(studyViewFilterContext); + } + + @Override + public List getGenomicDataBinCounts(StudyViewFilterContext studyViewFilterContext, List genomicDataBinFilters) { + return mapper.getGenomicDataBinCounts(studyViewFilterContext, genomicDataBinFilters); + } + + @Override + public List getCNACounts(StudyViewFilterContext studyViewFilterContext, List genomicDataFilters) { + return mapper.getCNACounts(studyViewFilterContext, genomicDataFilters); + } + + @Override + public Map getMutationCounts(StudyViewFilterContext studyViewFilterContext, + GenomicDataFilter genomicDataFilter) { + return mapper.getMutationCounts(studyViewFilterContext, genomicDataFilter); + } + + @Override + public List getMutationCountsByType(StudyViewFilterContext studyViewFilterContext, List genomicDataFilters) { + return mapper.getMutationCountsByType(studyViewFilterContext, genomicDataFilters); + } +} diff --git a/src/main/java/org/cbioportal/infrastructure/repository/clickhouse/patient/ClickhousePatientMapper.java b/src/main/java/org/cbioportal/infrastructure/repository/clickhouse/patient/ClickhousePatientMapper.java new file mode 100644 index 00000000000..ce27293c6fa --- /dev/null +++ b/src/main/java/org/cbioportal/infrastructure/repository/clickhouse/patient/ClickhousePatientMapper.java @@ -0,0 +1,31 @@ +package org.cbioportal.infrastructure.repository.clickhouse.patient; + +import org.apache.ibatis.annotations.Param; +import org.cbioportal.legacy.model.CaseListDataCount; +import org.cbioportal.domain.studyview.StudyViewFilterContext; + +import java.util.List; + +/** + * Mapper interface for retrieving patient data from ClickHouse. + * This interface provides methods for fetching patient counts and case list data counts. + */ +public interface ClickhousePatientMapper { + + /** + * Retrieves the patient count based on the study view filter context. + * + * @param studyViewFilterContext the context of the study view filter + * @return the patient count + */ + int getPatientCount(@Param("studyViewFilterContext") StudyViewFilterContext studyViewFilterContext); + + /** + * Retrieves case list data counts based on the study view filter context. + * + * @param studyViewFilterContext the context of the study view filter + * @return a list of case list data counts + */ + List getCaseListDataCounts(@Param("studyViewFilterContext") StudyViewFilterContext studyViewFilterContext); +} + diff --git a/src/main/java/org/cbioportal/infrastructure/repository/clickhouse/patient/ClickhousePatientRepository.java b/src/main/java/org/cbioportal/infrastructure/repository/clickhouse/patient/ClickhousePatientRepository.java new file mode 100644 index 00000000000..35b620aa035 --- /dev/null +++ b/src/main/java/org/cbioportal/infrastructure/repository/clickhouse/patient/ClickhousePatientRepository.java @@ -0,0 +1,30 @@ +package org.cbioportal.infrastructure.repository.clickhouse.patient; + +import org.cbioportal.legacy.model.CaseListDataCount; +import org.cbioportal.domain.patient.repository.PatientRepository; +import org.cbioportal.domain.studyview.StudyViewFilterContext; +import org.springframework.context.annotation.Profile; +import org.springframework.stereotype.Repository; + +import java.util.List; + +@Repository +@Profile("clickhouse") +public class ClickhousePatientRepository implements PatientRepository { + + private final ClickhousePatientMapper mapper; + + public ClickhousePatientRepository(ClickhousePatientMapper mapper) { + this.mapper = mapper; + } + + @Override + public int getFilteredPatientCount(StudyViewFilterContext studyViewFilterContext) { + return mapper.getPatientCount(studyViewFilterContext); + } + + @Override + public List getCaseListDataCounts(StudyViewFilterContext studyViewFilterContext) { + return mapper.getCaseListDataCounts(studyViewFilterContext); + } +} diff --git a/src/main/java/org/cbioportal/infrastructure/repository/clickhouse/sample/ClickhouseSampleMapper.java b/src/main/java/org/cbioportal/infrastructure/repository/clickhouse/sample/ClickhouseSampleMapper.java new file mode 100644 index 00000000000..e0cdda1942c --- /dev/null +++ b/src/main/java/org/cbioportal/infrastructure/repository/clickhouse/sample/ClickhouseSampleMapper.java @@ -0,0 +1,31 @@ +package org.cbioportal.infrastructure.repository.clickhouse.sample; + +import org.apache.ibatis.annotations.Param; +import org.cbioportal.domain.sample.Sample; +import org.cbioportal.domain.studyview.StudyViewFilterContext; + +import java.util.List; + +/** + * Mapper interface for retrieving sample data from ClickHouse. + * This interface provides methods for fetching filtered samples and sample counts based on the study view filter context. + */ +public interface ClickhouseSampleMapper { + + /** + * Retrieves filtered samples based on the study view filter context. + * + * @param studyViewFilterContext the context of the study view filter + * @return a list of filtered samples + */ + List getFilteredSamples(@Param("studyViewFilterContext") StudyViewFilterContext studyViewFilterContext); + + /** + * Retrieves the sample count based on the study view filter context. + * + * @param studyViewFilterContext the context of the study view filter + * @return the sample count + */ + int getSampleCount(@Param("studyViewFilterContext") StudyViewFilterContext studyViewFilterContext); +} + diff --git a/src/main/java/org/cbioportal/infrastructure/repository/clickhouse/sample/ClickhouseSampleRepository.java b/src/main/java/org/cbioportal/infrastructure/repository/clickhouse/sample/ClickhouseSampleRepository.java new file mode 100644 index 00000000000..12d25cd5889 --- /dev/null +++ b/src/main/java/org/cbioportal/infrastructure/repository/clickhouse/sample/ClickhouseSampleRepository.java @@ -0,0 +1,30 @@ +package org.cbioportal.infrastructure.repository.clickhouse.sample; + +import org.cbioportal.domain.sample.Sample; +import org.cbioportal.domain.sample.repository.SampleRepository; +import org.cbioportal.domain.studyview.StudyViewFilterContext; +import org.springframework.context.annotation.Profile; +import org.springframework.stereotype.Repository; + +import java.util.List; + +@Repository +@Profile("clickhouse") +public class ClickhouseSampleRepository implements SampleRepository { + + private final ClickhouseSampleMapper mapper; + + public ClickhouseSampleRepository(ClickhouseSampleMapper clickhouseSampleMapper) { + this.mapper = clickhouseSampleMapper; + } + + @Override + public List getFilteredSamples(StudyViewFilterContext studyViewFilterContext) { + return mapper.getFilteredSamples(studyViewFilterContext); + } + + @Override + public int getFilteredSamplesCount(StudyViewFilterContext studyViewFilterContext) { + return mapper.getSampleCount(studyViewFilterContext); + } +} diff --git a/src/main/java/org/cbioportal/infrastructure/repository/clickhouse/studyview/ClickhouseStudyViewFilterMapper.java b/src/main/java/org/cbioportal/infrastructure/repository/clickhouse/studyview/ClickhouseStudyViewFilterMapper.java new file mode 100644 index 00000000000..cc3760b7f63 --- /dev/null +++ b/src/main/java/org/cbioportal/infrastructure/repository/clickhouse/studyview/ClickhouseStudyViewFilterMapper.java @@ -0,0 +1,4 @@ +package org.cbioportal.infrastructure.repository.clickhouse.studyview; + +public interface ClickhouseStudyViewFilterMapper { +} diff --git a/src/main/java/org/cbioportal/infrastructure/repository/clickhouse/treatment/ClickhouseTreatmentMapper.java b/src/main/java/org/cbioportal/infrastructure/repository/clickhouse/treatment/ClickhouseTreatmentMapper.java new file mode 100644 index 00000000000..16f3e7fa1d3 --- /dev/null +++ b/src/main/java/org/cbioportal/infrastructure/repository/clickhouse/treatment/ClickhouseTreatmentMapper.java @@ -0,0 +1,48 @@ +package org.cbioportal.infrastructure.repository.clickhouse.treatment; + +import org.apache.ibatis.annotations.Param; +import org.cbioportal.legacy.model.PatientTreatment; +import org.cbioportal.legacy.model.SampleTreatment; +import org.cbioportal.domain.studyview.StudyViewFilterContext; + +import java.util.List; + +/** + * Mapper interface for retrieving treatment-related data from ClickHouse. + * This interface provides methods to fetch patient treatments, sample treatment counts, and more. + */ +public interface ClickhouseTreatmentMapper { + + /** + * Retrieves patient treatments based on the study view filter context. + * + * @param studyViewFilterContext the context of the study view filter + * @return a list of patient treatments + */ + List getPatientTreatments(@Param("studyViewFilterContext") StudyViewFilterContext studyViewFilterContext); + + /** + * Retrieves the patient treatment counts based on the study view filter context. + * + * @param studyViewFilterContext the context of the study view filter + * @return the patient treatment count + */ + int getPatientTreatmentCounts(@Param("studyViewFilterContext") StudyViewFilterContext studyViewFilterContext); + + /** + * Retrieves sample treatment counts based on the study view filter context. + * + * @param studyViewFilterContext the context of the study view filter + * @return a list of sample treatment counts + */ + List getSampleTreatmentCounts(@Param("studyViewFilterContext") StudyViewFilterContext studyViewFilterContext); + + /** + * Retrieves the total sample treatment counts based on the study view filter context. + * + * @param studyViewFilterContext the context of the study view filter + * @return the total sample treatment count + */ + int getTotalSampleTreatmentCounts(@Param("studyViewFilterContext") StudyViewFilterContext studyViewFilterContext); +} + diff --git a/src/main/java/org/cbioportal/infrastructure/repository/clickhouse/treatment/ClickhouseTreatmentRepository.java b/src/main/java/org/cbioportal/infrastructure/repository/clickhouse/treatment/ClickhouseTreatmentRepository.java new file mode 100644 index 00000000000..583a0a3cf25 --- /dev/null +++ b/src/main/java/org/cbioportal/infrastructure/repository/clickhouse/treatment/ClickhouseTreatmentRepository.java @@ -0,0 +1,40 @@ +package org.cbioportal.infrastructure.repository.clickhouse.treatment; + +import org.cbioportal.legacy.model.PatientTreatment; +import org.cbioportal.legacy.model.SampleTreatment; +import org.cbioportal.domain.studyview.StudyViewFilterContext; +import org.cbioportal.domain.treatment.repository.TreatmentRepository; +import org.springframework.context.annotation.Profile; +import org.springframework.stereotype.Repository; + +import java.util.List; + +@Repository +@Profile("clickhouse") +public class ClickhouseTreatmentRepository implements TreatmentRepository { + private final ClickhouseTreatmentMapper mapper; + + public ClickhouseTreatmentRepository(ClickhouseTreatmentMapper mapper) { + this.mapper = mapper; + } + + @Override + public List getPatientTreatments(StudyViewFilterContext studyViewFilterContext) { + return mapper.getPatientTreatments(studyViewFilterContext); + } + + @Override + public int getTotalPatientTreatmentCount(StudyViewFilterContext studyViewFilterContext) { + return mapper.getPatientTreatmentCounts(studyViewFilterContext); + } + + @Override + public List getSampleTreatments(StudyViewFilterContext studyViewFilterContext) { + return mapper.getSampleTreatmentCounts(studyViewFilterContext); + } + + @Override + public int getTotalSampleTreatmentCount(StudyViewFilterContext studyViewFilterContext) { + return mapper.getTotalSampleTreatmentCounts(studyViewFilterContext); + } +} diff --git a/src/main/java/org/cbioportal/infrastructure/service/BasicDataBinner.java b/src/main/java/org/cbioportal/infrastructure/service/BasicDataBinner.java new file mode 100644 index 00000000000..8e6ece160be --- /dev/null +++ b/src/main/java/org/cbioportal/infrastructure/service/BasicDataBinner.java @@ -0,0 +1,379 @@ +package org.cbioportal.infrastructure.service; + +import org.cbioportal.legacy.model.Binnable; +import org.cbioportal.legacy.model.ClinicalData; +import org.cbioportal.legacy.model.ClinicalDataBin; +import org.cbioportal.legacy.model.ClinicalDataCount; +import org.cbioportal.legacy.model.ClinicalDataCountItem; +import org.cbioportal.legacy.model.DataBin; +import org.cbioportal.legacy.model.GenericAssayDataBin; +import org.cbioportal.legacy.model.GenomicDataBin; +import org.cbioportal.legacy.service.CustomDataService; +import org.cbioportal.legacy.service.util.CustomDataSession; +import org.cbioportal.legacy.web.columnar.util.CustomDataFilterUtil; +import org.cbioportal.legacy.web.columnar.util.NewClinicalDataBinUtil; +import org.cbioportal.legacy.web.parameter.ClinicalDataBinCountFilter; +import org.cbioportal.legacy.web.parameter.ClinicalDataBinFilter; +import org.cbioportal.legacy.web.parameter.ClinicalDataType; +import org.cbioportal.legacy.web.parameter.DataBinCountFilter; +import org.cbioportal.legacy.web.parameter.DataBinFilter; +import org.cbioportal.legacy.web.parameter.DataBinMethod; +import org.cbioportal.legacy.web.parameter.GenericAssayDataBinCountFilter; +import org.cbioportal.legacy.web.parameter.GenericAssayDataBinFilter; +import org.cbioportal.legacy.web.parameter.GenomicDataBinCountFilter; +import org.cbioportal.legacy.web.parameter.GenomicDataBinFilter; +import org.cbioportal.legacy.web.parameter.SampleIdentifier; +import org.cbioportal.legacy.web.parameter.StudyViewFilter; +import org.cbioportal.legacy.web.util.DataBinner; +import org.cbioportal.legacy.web.util.StudyViewFilterUtil; +import org.cbioportal.domain.studyview.StudyViewService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.context.annotation.Profile; +import org.springframework.stereotype.Component; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import static java.util.Collections.emptyList; +import static java.util.stream.Collectors.toMap; + +// BasicDataBinner is a generalized class derived from ClinicalDataBinner +// BasicDataBinner should eventually deprecate ClinicalDataBinner +// we are using BasicDataBinner for genomic data, generic assay, and custom data bin counts now +// but BasicDataBinner can support clinical data counts too +// after we switched clinical data counts to use this, then We can remove ClinicalDataBinner +@Deprecated(forRemoval = true) +@Component +@Profile("clickhouse") +public class BasicDataBinner { + private final StudyViewService studyViewService; + private final DataBinner dataBinner; + private final CustomDataFilterUtil customDataFilterUtil; + private final CustomDataService customDataService; + private final StudyViewFilterUtil studyViewFilterUtil; + + @Autowired + public BasicDataBinner( + StudyViewService studyViewService, + DataBinner dataBinner, + CustomDataFilterUtil customDataFilterUtil, + CustomDataService customDataService, + StudyViewFilterUtil studyViewFilterUtil + ) { + this.studyViewService = studyViewService; + this.dataBinner = dataBinner; + this.customDataFilterUtil = customDataFilterUtil; + this.customDataService = customDataService; + this.studyViewFilterUtil = studyViewFilterUtil; + } + + // convert from counts to clinical data + private List convertCountsToData(List clinicalDataCounts) + { + return clinicalDataCounts + .stream() + .map(NewClinicalDataBinUtil::generateClinicalDataFromClinicalDataCount) + .flatMap(Collection::stream) + .toList(); + } + + @Cacheable(cacheResolver = "generalRepositoryCacheResolver", condition = "@cacheEnabledConfig.getEnabled()") + public List getDataBins( + DataBinMethod dataBinMethod, + T dataBinCountFilter, + boolean shouldRemoveSelfFromFilter) { + // get data bin filters based on the type of the filter + // either Genomic data or Generic Assay data or custom data or clinical data + List dataBinFilters = fetchDataBinFilters(dataBinCountFilter); + StudyViewFilter studyViewFilter = dataBinCountFilter.getStudyViewFilter(); + // define result variables + List resultDataBins = Collections.emptyList(); + // if no data bin filters or no study view filer object is passed in + // return empty result + if (dataBinFilters.isEmpty() || studyViewFilter == null) { + return resultDataBins; + } + + if (shouldRemoveSelfFromFilter && dataBinFilters.size() == 1) { + removeSelfFromFilter(dataBinFilters.get(0), studyViewFilter); + } + + List uniqueKeys = dataBinFilters.stream().map(this::getDataBinFilterUniqueKey).toList(); + + // a new StudyView filter to partially filter by study and sample ids only + // we need this additional partial filter because we always need to know the bins generated for the initial state + // which allows us to keep the number of bins and bin ranges consistent even if there are additional data filters. + // we only want to update the counts for each bin, we don't want to regenerate the bins for the filtered data. + // NOTE: partial filter is only needed when dataBinMethod == DataBinMethod.STATIC but that's always the case + // for the frontend implementation. we can't really use dataBinMethod == DataBinMethod.DYNAMIC because of the + // complication it brings to the frontend visualization and filtering + StudyViewFilter partialFilter = new StudyViewFilter(); + partialFilter.setStudyIds(studyViewFilter.getStudyIds()); + partialFilter.setSampleIdentifiers(studyViewFilter.getSampleIdentifiers()); + + // we need to fetch data for the partial filter in order to generate the bins for initial state + // we use the filtered data to calculate the counts for each bin, we do not regenerate bins for the filtered data + List unfilteredClinicalDataCounts; + List filteredClinicalDataCounts; + Map attributeDatatypeMap; + switch (dataBinCountFilter) { + // TODO: first case is to support clinical data, but clinical data is not using this now. We should update controller to use this method later + case ClinicalDataBinCountFilter clinicalDataBinCountFilter when !customDataService.getCustomDataSessions(uniqueKeys).isEmpty() -> { + Map customDataSessions = customDataService.getCustomDataSessions(uniqueKeys); + List unfilteredSampleIdentifiers = + studyViewService.getFilteredSamples(partialFilter) + .stream() + .map(sample -> studyViewFilterUtil.buildSampleIdentifier(sample.cancerStudyIdentifier(), sample.stableId())) + .toList(); + unfilteredClinicalDataCounts = customDataFilterUtil.getCustomDataCounts(unfilteredSampleIdentifiers, customDataSessions); + List filteredSampleIdentifiers = studyViewService.getFilteredSamples(studyViewFilter) + .stream() + .map(sample -> studyViewFilterUtil.buildSampleIdentifier(sample.cancerStudyIdentifier(), sample.stableId())) + .toList(); + filteredClinicalDataCounts = customDataFilterUtil.getCustomDataCounts(filteredSampleIdentifiers, customDataSessions); + attributeDatatypeMap = customDataSessions.entrySet().stream().collect(toMap( + Map.Entry::getKey, + NewClinicalDataBinUtil::getDataType + )); + } + case ClinicalDataBinCountFilter clinicalDataBinCountFilter -> { + unfilteredClinicalDataCounts = studyViewService.getClinicalDataCounts(partialFilter, uniqueKeys); + filteredClinicalDataCounts = studyViewService.getClinicalDataCounts(studyViewFilter, uniqueKeys); + attributeDatatypeMap = studyViewService.getClinicalAttributeDataTypeMap(studyViewFilter); + } + case GenomicDataBinCountFilter genomicDataBinCountFilter -> { + unfilteredClinicalDataCounts = studyViewService.getGenomicDataBinCounts(partialFilter, genomicDataBinCountFilter.getGenomicDataBinFilters()); + filteredClinicalDataCounts = studyViewService.getGenomicDataBinCounts(studyViewFilter, genomicDataBinCountFilter.getGenomicDataBinFilters()); + attributeDatatypeMap = Collections.emptyMap(); + } + case GenericAssayDataBinCountFilter genericAssayDataBinCountFilter -> { + unfilteredClinicalDataCounts = studyViewService.getGenericAssayDataBinCounts(partialFilter, genericAssayDataBinCountFilter.getGenericAssayDataBinFilters()); + filteredClinicalDataCounts = studyViewService.getGenericAssayDataBinCounts(studyViewFilter, genericAssayDataBinCountFilter.getGenericAssayDataBinFilters()); + attributeDatatypeMap = Collections.emptyMap(); + } + default -> { + unfilteredClinicalDataCounts = Collections.emptyList(); + filteredClinicalDataCounts = Collections.emptyList(); + attributeDatatypeMap = Collections.emptyMap(); + } + } + + // TODO ignoring conflictingPatientAttributeIds for now + List unfilteredClinicalData = convertCountsToData( + unfilteredClinicalDataCounts.stream().flatMap(c -> c.getCounts().stream()).toList() + ); + List filteredClinicalData = convertCountsToData( + filteredClinicalDataCounts.stream().flatMap(c -> c.getCounts().stream()).toList() + ); + + Map> unfilteredClinicalDataByAttributeId = + unfilteredClinicalData.stream().collect(Collectors.groupingBy(Binnable::getAttrId)); + + Map> filteredClinicalDataByAttributeId = + filteredClinicalData.stream().collect(Collectors.groupingBy(Binnable::getAttrId)); + + // TODO: need to update attributeDatatypeMap to include patient level data for Generic Assay Profiles + if (dataBinMethod == DataBinMethod.STATIC) { + if (!unfilteredClinicalData.isEmpty()) { + resultDataBins = calculateStaticDataBins( + dataBinner, + dataBinFilters, + attributeDatatypeMap, + unfilteredClinicalDataByAttributeId, + filteredClinicalDataByAttributeId + ); + } + } + // TODO: need to update attributeDatatypeMap to include patient level data for Generic Assay Profiles + else { // dataBinMethod == DataBinMethod.DYNAMIC + // TODO we should consider removing dynamic binning support + // we never use dynamic binning in the frontend because number of bins and the bin ranges can change + // each time there is a new filter which makes the frontend implementation complicated + if (!filteredClinicalData.isEmpty()) { + resultDataBins = calculateDynamicDataBins( + dataBinner, + dataBinFilters, + attributeDatatypeMap, + filteredClinicalDataByAttributeId + ); + } + } + + return resultDataBins; + } + + private void removeSelfFromFilter(S dataBinFilter, StudyViewFilter studyViewFilter) { + switch (dataBinFilter) { + case ClinicalDataBinFilter clinicalDataBinFilter -> { + if (studyViewFilter.getClinicalDataFilters() != null) { + studyViewFilter.getClinicalDataFilters().removeIf(f -> f.getAttributeId().equals(clinicalDataBinFilter.getAttributeId())); + } + if (studyViewFilter.getCustomDataFilters() != null) { + studyViewFilter.getCustomDataFilters().removeIf(f -> f.getAttributeId().equals(clinicalDataBinFilter.getAttributeId())); + } + } + case GenomicDataBinFilter genomicDataBinFilter when studyViewFilter.getGenomicDataFilters() != null -> + studyViewFilter.getGenomicDataFilters().removeIf(f -> + f.getHugoGeneSymbol().equals(genomicDataBinFilter.getHugoGeneSymbol()) + && f.getProfileType().equals(genomicDataBinFilter.getProfileType()) + ); + case GenericAssayDataBinFilter genericAssayDataBinFilter when studyViewFilter.getGenericAssayDataFilters() != null -> + studyViewFilter.getGenericAssayDataFilters().removeIf(f -> + f.getStableId().equals(genericAssayDataBinFilter.getStableId()) + && f.getProfileType().equals(genericAssayDataBinFilter.getProfileType()) + ); + default -> { + // Do not remove any filters + } + } + } + + private List fetchDataBinFilters(T dataBinCountFilter) { + switch (dataBinCountFilter) { + case ClinicalDataBinCountFilter clinicalDataBinCountFilter -> { + return (List) clinicalDataBinCountFilter.getAttributes(); + } + case GenomicDataBinCountFilter genomicDataBinCountFilter -> { + return (List) genomicDataBinCountFilter.getGenomicDataBinFilters(); + } + case GenericAssayDataBinCountFilter genericAssayDataBinCountFilter -> { + return (List) genericAssayDataBinCountFilter.getGenericAssayDataBinFilters(); + } + default -> { + return new ArrayList<>(); + } + } + } + + private String getDataBinFilterUniqueKey(S dataBinFilter) { + switch (dataBinFilter) { + case ClinicalDataBinFilter clinicalDataBinFilter -> { + return clinicalDataBinFilter.getAttributeId(); + } + case GenomicDataBinFilter genomicDataBinFilter -> { + return genomicDataBinFilter.getHugoGeneSymbol() + genomicDataBinFilter.getProfileType(); + } + case GenericAssayDataBinFilter genericAssayDataBinFilter -> { + return genericAssayDataBinFilter.getStableId() + genericAssayDataBinFilter.getProfileType(); + } + default -> { + return null; + } + } + } + + private List calculateStaticDataBins( + DataBinner dataBinner, + List dataBinFilters, + Map attributeDatatypeMap, + Map> unfilteredClinicalDataByAttributeId, + Map> filteredClinicalDataByAttributeId + ) { + List result = new ArrayList<>(); + + for (T dataBinFilter : dataBinFilters) { + // if there is data for requested attribute + if (attributeDatatypeMap.isEmpty() || attributeDatatypeMap.containsKey(getDataBinFilterUniqueKey(dataBinFilter))) { + List dataBins = dataBinner + .calculateClinicalDataBins( + dataBinFilter, + filteredClinicalDataByAttributeId.getOrDefault(getDataBinFilterUniqueKey(dataBinFilter), emptyList()), + unfilteredClinicalDataByAttributeId.getOrDefault(getDataBinFilterUniqueKey(dataBinFilter), emptyList()) + ) + .stream() + .map(dataBin -> (U) transform(dataBinFilter, dataBin)) + .toList(); + + result.addAll(dataBins); + } + } + + return result; + } + + private List calculateDynamicDataBins( + DataBinner dataBinner, + List dataBinFilters, + Map attributeDatatypeMap, + Map> filteredClinicalDataByAttributeId + ) { + List result = new ArrayList<>(); + + for (T dataBinFilter : dataBinFilters) { + // if there is data for requested attribute + if (attributeDatatypeMap.isEmpty() || attributeDatatypeMap.containsKey(getDataBinFilterUniqueKey(dataBinFilter))) { + List dataBins = dataBinner + .calculateDataBins( + dataBinFilter, + filteredClinicalDataByAttributeId.getOrDefault(getDataBinFilterUniqueKey(dataBinFilter), emptyList()) + ) + .stream() + .map(dataBin -> (U) transform(dataBinFilter, dataBin)) + .toList(); + result.addAll(dataBins); + } + } + + return result; + } + + private T transform(S dataBinFilter, DataBin dataBin) { + switch (dataBinFilter) { + case ClinicalDataBinFilter clinicalDataBinFilter -> { + return (T) dataBinToClinicalDataBin(clinicalDataBinFilter, dataBin); + } + case GenomicDataBinFilter genomicDataBinFilter -> { + return (T) dataBintoGenomicDataBin(genomicDataBinFilter, dataBin); + } + case GenericAssayDataBinFilter genericAssayDataBinFilter -> { + return (T) dataBintoGenericAssayDataBin(genericAssayDataBinFilter, dataBin); + } + default -> { + return null; + } + } + } + + private ClinicalDataBin dataBinToClinicalDataBin(ClinicalDataBinFilter attribute, DataBin dataBin) { + ClinicalDataBin clinicalDataBin = new ClinicalDataBin(); + clinicalDataBin.setAttributeId(attribute.getAttributeId()); + setCommonDataBinProperties(dataBin, clinicalDataBin); + return clinicalDataBin; + } + + private GenomicDataBin dataBintoGenomicDataBin(GenomicDataBinFilter genomicDataBinFilter, DataBin dataBin) { + GenomicDataBin genomicDataBin = new GenomicDataBin(); + genomicDataBin.setHugoGeneSymbol(genomicDataBinFilter.getHugoGeneSymbol()); + genomicDataBin.setProfileType(genomicDataBinFilter.getProfileType()); + setCommonDataBinProperties(dataBin, genomicDataBin); + return genomicDataBin; + } + + private GenericAssayDataBin dataBintoGenericAssayDataBin(GenericAssayDataBinFilter genericAssayDataBinFilter, + DataBin dataBin) { + GenericAssayDataBin genericAssayDataBin = new GenericAssayDataBin(); + genericAssayDataBin.setStableId(genericAssayDataBinFilter.getStableId()); + genericAssayDataBin.setProfileType(genericAssayDataBinFilter.getProfileType()); + setCommonDataBinProperties(dataBin, genericAssayDataBin); + return genericAssayDataBin; + } + + private void setCommonDataBinProperties(DataBin originalDataBin, U targetDatabin) { + targetDatabin.setCount(originalDataBin.getCount()); + if (originalDataBin.getSpecialValue() != null) { + targetDatabin.setSpecialValue(originalDataBin.getSpecialValue()); + } + if (originalDataBin.getStart() != null) { + targetDatabin.setStart(originalDataBin.getStart()); + } + if (originalDataBin.getEnd() != null) { + targetDatabin.setEnd(originalDataBin.getEnd()); + } + } + +} diff --git a/src/main/java/org/cbioportal/infrastructure/service/ClinicalDataBinner.java b/src/main/java/org/cbioportal/infrastructure/service/ClinicalDataBinner.java new file mode 100644 index 00000000000..8e4577022f3 --- /dev/null +++ b/src/main/java/org/cbioportal/infrastructure/service/ClinicalDataBinner.java @@ -0,0 +1,131 @@ +package org.cbioportal.infrastructure.service; + +import org.cbioportal.legacy.model.Binnable; +import org.cbioportal.legacy.model.ClinicalData; +import org.cbioportal.legacy.model.ClinicalDataBin; +import org.cbioportal.legacy.model.ClinicalDataCount; +import org.cbioportal.legacy.model.ClinicalDataCountItem; +import org.cbioportal.legacy.web.columnar.util.NewClinicalDataBinUtil; +import org.cbioportal.legacy.web.parameter.ClinicalDataBinCountFilter; +import org.cbioportal.legacy.web.parameter.ClinicalDataBinFilter; +import org.cbioportal.legacy.web.parameter.ClinicalDataType; +import org.cbioportal.legacy.web.parameter.DataBinMethod; +import org.cbioportal.legacy.web.parameter.StudyViewFilter; +import org.cbioportal.legacy.web.util.DataBinner; +import org.cbioportal.domain.studyview.StudyViewService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.context.annotation.Profile; +import org.springframework.stereotype.Component; + +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +@Deprecated(forRemoval = true) +@Component +@Profile("clickhouse") +public class ClinicalDataBinner { + private final StudyViewService studyViewService; + private final DataBinner dataBinner; + + @Autowired + public ClinicalDataBinner( + StudyViewService studyViewService, + DataBinner dataBinner + ) { + this.studyViewService = studyViewService; + this.dataBinner = dataBinner; + } + + private List convertCountsToData(List clinicalDataCounts) + { + return clinicalDataCounts + .stream() + .map(NewClinicalDataBinUtil::generateClinicalDataFromClinicalDataCount) + .flatMap(Collection::stream) + .toList(); + } + + @Cacheable( + cacheResolver = "staticRepositoryCacheOneResolver", + condition = "@cacheEnabledConfig.getEnabled()" + ) + public List fetchClinicalDataBinCounts( + DataBinMethod dataBinMethod, + ClinicalDataBinCountFilter dataBinCountFilter, + boolean shouldRemoveSelfFromFilter + ) { + List attributes = dataBinCountFilter.getAttributes(); + StudyViewFilter studyViewFilter = dataBinCountFilter.getStudyViewFilter(); + + if (shouldRemoveSelfFromFilter) { + studyViewFilter = NewClinicalDataBinUtil.removeSelfFromFilter(dataBinCountFilter); + } + + List attributeIds = attributes.stream().map(ClinicalDataBinFilter::getAttributeId).toList(); + + // a new StudyView filter to partially filter by study and sample ids only + // we need this additional partial filter because we always need to know the bins generated for the initial state + // which allows us to keep the number of bins and bin ranges consistent even if there are additional data filters. + // we only want to update the counts for each bin, we don't want to regenerate the bins for the filtered data. + // NOTE: partial filter is only needed when dataBinMethod == DataBinMethod.STATIC but that's always the case + // for the frontend implementation. we can't really use dataBinMethod == DataBinMethod.DYNAMIC because of the + // complication it brings to the frontend visualization and filtering + StudyViewFilter partialFilter = new StudyViewFilter(); + partialFilter.setStudyIds(studyViewFilter.getStudyIds()); + partialFilter.setSampleIdentifiers(studyViewFilter.getSampleIdentifiers()); + + // we need the clinical data for the partial filter in order to generate the bins for initial state + // we use the filtered data to calculate the counts for each bin, we do not regenerate bins for the filtered data + List unfilteredClinicalDataCounts = studyViewService.getClinicalDataCounts(partialFilter, attributeIds); + List filteredClinicalDataCounts = studyViewService.getClinicalDataCounts(studyViewFilter, attributeIds); + + // TODO ignoring conflictingPatientAttributeIds for now + List unfilteredClinicalData = convertCountsToData( + unfilteredClinicalDataCounts.stream().flatMap(c -> c.getCounts().stream()).toList() + ); + List filteredClinicalData = convertCountsToData( + filteredClinicalDataCounts.stream().flatMap(c -> c.getCounts().stream()).toList() + ); + + Map attributeDatatypeMap = studyViewService.getClinicalAttributeDataTypeMap(studyViewFilter); + + Map> unfilteredClinicalDataByAttributeId = + unfilteredClinicalData.stream().collect(Collectors.groupingBy(Binnable::getAttrId)); + + Map> filteredClinicalDataByAttributeId = + filteredClinicalData.stream().collect(Collectors.groupingBy(Binnable::getAttrId)); + + List clinicalDataBins = Collections.emptyList(); + + if (dataBinMethod == DataBinMethod.STATIC) { + if (!unfilteredClinicalData.isEmpty()) { + clinicalDataBins = NewClinicalDataBinUtil.calculateStaticDataBins( + dataBinner, + attributes, + attributeDatatypeMap, + unfilteredClinicalDataByAttributeId, + filteredClinicalDataByAttributeId + ); + } + } + else { // dataBinMethod == DataBinMethod.DYNAMIC + // TODO we should consider removing dynamic binning support + // we never use dynamic binning in the frontend because number of bins and the bin ranges can change + // each time there is a new filter which makes the frontend implementation complicated + if (!filteredClinicalData.isEmpty()) { + clinicalDataBins = NewClinicalDataBinUtil.calculateDynamicDataBins( + dataBinner, + attributes, + attributeDatatypeMap, + filteredClinicalDataByAttributeId + ); + } + } + + return clinicalDataBins; + } +} diff --git a/src/main/java/org/cbioportal/legacy/persistence/mybatis/config/PersistenceConfig.java b/src/main/java/org/cbioportal/legacy/persistence/mybatis/config/PersistenceConfig.java index 0e93dbbbfa3..6500c692416 100644 --- a/src/main/java/org/cbioportal/legacy/persistence/mybatis/config/PersistenceConfig.java +++ b/src/main/java/org/cbioportal/legacy/persistence/mybatis/config/PersistenceConfig.java @@ -10,6 +10,7 @@ import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Profile; import org.springframework.jdbc.datasource.DataSourceTransactionManager; import javax.sql.DataSource; @@ -35,12 +36,13 @@ public void customize(org.apache.ibatis.session.Configuration configuration) { } @Bean("sqlSessionFactory") - @ConditionalOnProperty(name = "clickhouse_mode", havingValue = "true") + @Profile("clickhouse") public SqlSessionFactoryBean sqlSessionFactorySpecifyDataSource(@Qualifier("mysqlDataSource") DataSource dataSource, ApplicationContext applicationContext) throws IOException { return sqlSessionFactory(dataSource, applicationContext); } @Bean("sqlSessionFactory") + @Profile("default") @ConditionalOnProperty(name = "clickhouse_mode", havingValue = "false", matchIfMissing = true) public SqlSessionFactoryBean sqlSessionFactoryDefault(DataSource dataSource, ApplicationContext applicationContext) throws IOException { return sqlSessionFactory(dataSource, applicationContext); @@ -58,7 +60,7 @@ private SqlSessionFactoryBean sqlSessionFactory(DataSource dataSource, Applicati } @Bean - @ConditionalOnProperty(name = "clickhouse_mode", havingValue = "true") + @Profile("clickhouse") public DataSourceTransactionManager transactionManager(@Qualifier("mysqlDataSource") DataSource dataSource) { return new DataSourceTransactionManager(dataSource); } diff --git a/src/main/java/org/cbioportal/legacy/persistence/mybatisclickhouse/StudyViewMapper.java b/src/main/java/org/cbioportal/legacy/persistence/mybatisclickhouse/StudyViewMapper.java index 3a2eea2f9b2..4baa6fb333e 100644 --- a/src/main/java/org/cbioportal/legacy/persistence/mybatisclickhouse/StudyViewMapper.java +++ b/src/main/java/org/cbioportal/legacy/persistence/mybatisclickhouse/StudyViewMapper.java @@ -28,6 +28,7 @@ import java.util.Map; +@Deprecated(forRemoval = true) public interface StudyViewMapper { List getFilteredSamples(@Param("studyViewFilterHelper") StudyViewFilterHelper studyViewFilterHelper); diff --git a/src/main/java/org/cbioportal/legacy/persistence/mybatisclickhouse/StudyViewMyBatisRepository.java b/src/main/java/org/cbioportal/legacy/persistence/mybatisclickhouse/StudyViewMyBatisRepository.java index ef76a7926ca..3b22731953c 100644 --- a/src/main/java/org/cbioportal/legacy/persistence/mybatisclickhouse/StudyViewMyBatisRepository.java +++ b/src/main/java/org/cbioportal/legacy/persistence/mybatisclickhouse/StudyViewMyBatisRepository.java @@ -39,7 +39,8 @@ import java.util.stream.Collectors; @Repository -@ConditionalOnProperty(name = "clickhouse_mode", havingValue = "true") +@Deprecated(forRemoval = true) +@ConditionalOnProperty(name = "clickhouse_mode", havingValue = "test") public class StudyViewMyBatisRepository implements StudyViewRepository { private final StudyViewMapper studyViewMapper; diff --git a/src/main/java/org/cbioportal/legacy/persistence/mybatisclickhouse/config/PersistenceColumnarConfig.java b/src/main/java/org/cbioportal/legacy/persistence/mybatisclickhouse/config/PersistenceColumnarConfig.java deleted file mode 100644 index b9f09e41284..00000000000 --- a/src/main/java/org/cbioportal/legacy/persistence/mybatisclickhouse/config/PersistenceColumnarConfig.java +++ /dev/null @@ -1,38 +0,0 @@ -package org.cbioportal.legacy.persistence.mybatisclickhouse.config; - -import org.cbioportal.legacy.persistence.mybatis.typehandler.SampleTypeTypeHandler; -import org.cbioportal.legacy.utils.config.annotation.ConditionalOnProperty; -import org.mybatis.spring.SqlSessionFactoryBean; -import org.mybatis.spring.annotation.MapperScan; -import org.springframework.beans.factory.annotation.Qualifier; -import org.springframework.context.ApplicationContext; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; - -import javax.sql.DataSource; -import java.io.IOException; - - -@Configuration -@ConditionalOnProperty(name = "clickhouse_mode", havingValue = "true") -@MapperScan(value= "org.cbioportal.legacy.persistence.mybatisclickhouse", - sqlSessionFactoryRef ="sqlColumnarSessionFactory") -@MapperScan(value= "org.cbioportal.infrastructure.repository.clickhouse", - sqlSessionFactoryRef = "sqlColumnarSessionFactory") -public class PersistenceColumnarConfig { - - @Bean("sqlColumnarSessionFactory") - public SqlSessionFactoryBean sqlColumnarSessionFactory(@Qualifier("clickhouseDataSource") DataSource dataSource, ApplicationContext applicationContext) throws IOException { - SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean(); - sessionFactory.setDataSource(dataSource); - sessionFactory.setMapperLocations( - applicationContext.getResources("classpath:org/cbioportal/persistence/mybatisclickhouse/*.xml") - ); - sessionFactory.addMapperLocations( - applicationContext.getResources("classpath:mappers/clickhouse/**/*.xml")); - - sessionFactory.setTypeHandlers(new SampleTypeTypeHandler()); - return sessionFactory; - } - -} diff --git a/src/main/java/org/cbioportal/legacy/properties/CustomDataSourceConfiguration.java b/src/main/java/org/cbioportal/legacy/properties/CustomDataSourceConfiguration.java index d2b78d4e4e9..3a224bfae51 100644 --- a/src/main/java/org/cbioportal/legacy/properties/CustomDataSourceConfiguration.java +++ b/src/main/java/org/cbioportal/legacy/properties/CustomDataSourceConfiguration.java @@ -1,15 +1,15 @@ package org.cbioportal.legacy.properties; -import org.cbioportal.legacy.utils.config.annotation.ConditionalOnProperty; import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Profile; import javax.sql.DataSource; @Configuration -@ConditionalOnProperty(name = "clickhouse_mode", havingValue = "true") +@Profile("clickhouse") public class CustomDataSourceConfiguration { @Bean @ConfigurationProperties("spring.datasource.mysql") diff --git a/src/main/java/org/cbioportal/legacy/service/ViolinPlotService.java b/src/main/java/org/cbioportal/legacy/service/ViolinPlotService.java index e3177b33b72..28498e8b351 100644 --- a/src/main/java/org/cbioportal/legacy/service/ViolinPlotService.java +++ b/src/main/java/org/cbioportal/legacy/service/ViolinPlotService.java @@ -7,11 +7,12 @@ import java.math.BigDecimal; import java.util.List; +import java.util.Set; public interface ViolinPlotService { ClinicalViolinPlotData getClinicalViolinPlotData( List sampleClinicalDataForViolinPlot, - List samplesForSampleCounts, + Set samplesForSampleCountsIds, BigDecimal axisStart, BigDecimal axisEnd, BigDecimal numCurvePoints, diff --git a/src/main/java/org/cbioportal/legacy/service/alteration/AlterationCountByGeneService.java b/src/main/java/org/cbioportal/legacy/service/alteration/AlterationCountByGeneService.java deleted file mode 100644 index bd43d19924b..00000000000 --- a/src/main/java/org/cbioportal/legacy/service/alteration/AlterationCountByGeneService.java +++ /dev/null @@ -1,14 +0,0 @@ -package org.cbioportal.legacy.service.alteration; - -import org.cbioportal.legacy.model.AlterationCountByGene; -import org.cbioportal.legacy.model.CopyNumberCountByGene; -import org.cbioportal.legacy.model.StudyViewFilterContext; -import org.cbioportal.legacy.service.exception.StudyNotFoundException; - -import java.util.List; - -public interface AlterationCountByGeneService { - List getMutatedGenes(StudyViewFilterContext studyViewFilterContext) throws StudyNotFoundException; - List getCnaGenes(StudyViewFilterContext studyViewFilterContext) throws StudyNotFoundException; - List getStructuralVariantGenes(StudyViewFilterContext studyViewFilterContext) throws StudyNotFoundException; -} diff --git a/src/main/java/org/cbioportal/legacy/service/alteration/AlterationCountByGeneServiceImpl.java b/src/main/java/org/cbioportal/legacy/service/alteration/AlterationCountByGeneServiceImpl.java deleted file mode 100644 index 18cdc722dff..00000000000 --- a/src/main/java/org/cbioportal/legacy/service/alteration/AlterationCountByGeneServiceImpl.java +++ /dev/null @@ -1,218 +0,0 @@ -package org.cbioportal.legacy.service.alteration; - -import org.apache.commons.math3.util.Pair; -import org.cbioportal.legacy.model.AlterationCountByGene; -import org.cbioportal.legacy.model.AlterationType; -import org.cbioportal.legacy.model.CopyNumberCountByGene; -import org.cbioportal.legacy.model.Gistic; -import org.cbioportal.legacy.model.MolecularProfile; -import org.cbioportal.legacy.model.MutSig; -import org.cbioportal.legacy.model.StudyViewFilterContext; -import org.cbioportal.legacy.persistence.StudyViewRepository; -import org.cbioportal.legacy.service.SignificantCopyNumberRegionService; -import org.cbioportal.legacy.service.SignificantlyMutatedGeneService; -import org.cbioportal.legacy.service.exception.StudyNotFoundException; -import org.cbioportal.legacy.service.util.AlterationCountServiceUtil; -import org.cbioportal.legacy.utils.config.annotation.ConditionalOnProperty; -import org.cbioportal.legacy.web.parameter.Projection; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.lang.NonNull; -import org.springframework.stereotype.Service; - -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.function.Function; -import java.util.stream.Collectors; - -/** - * Implementation of the AlterationCountService interface, providing methods for retrieving and processing - * alteration counts for samples and patients based on various criteria. - */ -@Service -@ConditionalOnProperty(name = "clickhouse_mode", havingValue = "true") -public class AlterationCountByGeneServiceImpl implements AlterationCountByGeneService { - private final StudyViewRepository studyViewRepository; - private final SignificantlyMutatedGeneService significantlyMutatedGeneService; - private final SignificantCopyNumberRegionService significantCopyNumberRegionService; - - /** - * Constructor for AlterationCountByGeneServiceImpl. - * - * @param studyViewRepository Repository for study-related queries. - * @param significantlyMutatedGeneService Service for retrieving significantly mutated genes. - * @param significantCopyNumberRegionService Service for retrieving significant copy number regions. - */ - @Autowired - public AlterationCountByGeneServiceImpl(StudyViewRepository studyViewRepository, SignificantlyMutatedGeneService significantlyMutatedGeneService, SignificantCopyNumberRegionService significantCopyNumberRegionService) { - this.studyViewRepository = studyViewRepository; - this.significantlyMutatedGeneService = significantlyMutatedGeneService; - this.significantCopyNumberRegionService = significantCopyNumberRegionService; - } - - /** - * Retrieves a list of mutated genes and their alteration counts for a given filter context. - * - * @param studyViewFilterContext Context containing filter criteria. - * @return List of AlterationCountByGene objects representing mutated genes. - * @throws StudyNotFoundException if the specified study is not found. - */ - @Override - public List getMutatedGenes(StudyViewFilterContext studyViewFilterContext) throws StudyNotFoundException { - var alterationCountByGenes = populateAlterationCounts(AlterationCountServiceUtil.combineAlterationCountsWithConflictingHugoSymbols(studyViewRepository.getMutatedGenes(studyViewFilterContext)), - studyViewFilterContext, AlterationType.MUTATION_EXTENDED); - return populateAlterationCountsWithMutSigQValue(alterationCountByGenes, studyViewFilterContext); - } - - /** - * Retrieves a list of genes with copy number alterations (CNA) and their alteration counts for a given filter context. - * - * @param studyViewFilterContext Context containing filter criteria. - * @return List of CopyNumberCountByGene objects representing genes with CNAs. - * @throws StudyNotFoundException if the specified study is not found. - */ - public List getCnaGenes(StudyViewFilterContext studyViewFilterContext) throws StudyNotFoundException { - var copyNumberAlterationCounts = populateAlterationCounts(AlterationCountServiceUtil.combineCopyNumberCountsWithConflictingHugoSymbols(studyViewRepository.getCnaGenes(studyViewFilterContext)), studyViewFilterContext, AlterationType.COPY_NUMBER_ALTERATION); - return populateAlterationCountsWithCNASigQValue(copyNumberAlterationCounts, studyViewFilterContext); - } - - /** - * Retrieves a list of structural variant genes and their alteration counts for a given filter context. - * - * @param studyViewFilterContext Context containing filter criteria. - * @return List of AlterationCountByGene objects representing structural variant genes. - * @throws StudyNotFoundException if the specified study is not found. - */ - @Override - public List getStructuralVariantGenes(StudyViewFilterContext studyViewFilterContext) throws StudyNotFoundException { - var alterationCountByGenes = populateAlterationCounts(AlterationCountServiceUtil.combineAlterationCountsWithConflictingHugoSymbols(studyViewRepository.getStructuralVariantGenes(studyViewFilterContext)), - studyViewFilterContext, AlterationType.STRUCTURAL_VARIANT); - return populateAlterationCountsWithMutSigQValue(alterationCountByGenes, studyViewFilterContext); - } - - /** - * Populates alteration counts with profile data, including the total profiled count and matching gene panel IDs. - * - * @param alterationCounts List of alteration counts to enrich. - * @param studyViewFilterContext Context containing filter criteria. - * @param alterationType Type of alteration (e.g., mutation, CNA, structural variant). - * @param The type of alteration count. - * @return List of enriched alteration counts. - */ - private List populateAlterationCounts(@NonNull List alterationCounts, - @NonNull StudyViewFilterContext studyViewFilterContext, - @NonNull AlterationType alterationType) { - final var firstMolecularProfileForEachStudy = getFirstMolecularProfileGroupedByStudy(studyViewFilterContext, alterationType); - final int totalProfiledCount = studyViewRepository.getTotalProfiledCountsByAlterationType(studyViewFilterContext, alterationType.toString()); - var profiledCountsMap = studyViewRepository.getTotalProfiledCounts(studyViewFilterContext, alterationType.toString(), firstMolecularProfileForEachStudy); - final var matchingGenePanelIdsMap = studyViewRepository.getMatchingGenePanelIds(studyViewFilterContext, alterationType.toString()); - final int sampleProfileCountWithoutGenePanelData = studyViewRepository.getSampleProfileCountWithoutPanelData(studyViewFilterContext, alterationType.toString()); - - alterationCounts.parallelStream() - .forEach(alterationCountByGene -> { - String hugoGeneSymbol = alterationCountByGene.getHugoGeneSymbol(); - Set matchingGenePanelIds = matchingGenePanelIdsMap.get(hugoGeneSymbol) != null ? - matchingGenePanelIdsMap.get(hugoGeneSymbol) : Collections.emptySet(); - - int alterationTotalProfiledCount = AlterationCountServiceUtil.computeTotalProfiledCount(AlterationCountServiceUtil.hasGenePanelData(matchingGenePanelIds), - profiledCountsMap.getOrDefault(hugoGeneSymbol, 0), - sampleProfileCountWithoutGenePanelData, totalProfiledCount); - - alterationCountByGene.setNumberOfProfiledCases(alterationTotalProfiledCount); - - alterationCountByGene.setMatchingGenePanelIds(matchingGenePanelIds); - - }); - return alterationCounts; - } - - /** - * Updates alteration counts with MutSig Q-value data for significance. - * - * @param alterationCountByGenes List of alteration counts to update. - * @param studyViewFilterContext Context containing filter criteria. - * @return List of alteration counts updated with MutSig Q-value. - * @throws StudyNotFoundException if the specified study is not found. - */ - private List populateAlterationCountsWithMutSigQValue(List alterationCountByGenes, StudyViewFilterContext studyViewFilterContext) throws StudyNotFoundException { - final var mutSigs = getMutSigs(studyViewFilterContext); - // If MutSig is not empty update Mutated Genes - return AlterationCountServiceUtil.updateAlterationCountsWithMutSigQValue(alterationCountByGenes, mutSigs); - } - - /** - * Updates copy number alteration counts with GISTIC significance data. - * - * @param alterationCountByGenes List of alteration counts to update. - * @param studyViewFilterContext Context containing filter criteria. - * @return List of alteration counts updated with GISTIC significance data. - * @throws StudyNotFoundException if the specified study is not found. - */ - private List populateAlterationCountsWithCNASigQValue(List alterationCountByGenes, StudyViewFilterContext studyViewFilterContext) throws StudyNotFoundException { - final var gisticMap = getGisticMap(studyViewFilterContext); - return AlterationCountServiceUtil.updateAlterationCountsWithCNASigQValue(alterationCountByGenes, gisticMap); - } - - /** - * Retrieves the first molecular profile for each study based on the alteration type. - * - * @param studyViewFilterContext Context containing filter criteria. - * @param alterationType Type of alteration (e.g., mutation, CNA, structural variant). - * @return List of MolecularProfile objects representing the first profile for each study. - */ - private List getFirstMolecularProfileGroupedByStudy(StudyViewFilterContext studyViewFilterContext, AlterationType alterationType) { - final var molecularProfiles = studyViewRepository.getFilteredMolecularProfilesByAlterationType(studyViewFilterContext, alterationType.toString()); - return AlterationCountServiceUtil.getFirstMolecularProfileGroupedByStudy(molecularProfiles); - } - - /** - * Retrieves MutSig data for significantly mutated genes in the specified studies. - * - * @param studyViewFilterContext Context containing filter criteria. - * @return Map of MutSig objects keyed by Hugo gene symbol. - * @throws StudyNotFoundException if the specified study is not found. - */ - private Map getMutSigs(StudyViewFilterContext studyViewFilterContext) throws StudyNotFoundException { - var distinctStudyIds = studyViewRepository.getFilteredStudyIds(studyViewFilterContext); - Map mutSigs = new HashMap<>(); - if (distinctStudyIds.size() == 1) { - var studyId = distinctStudyIds.getFirst(); - mutSigs = significantlyMutatedGeneService.getSignificantlyMutatedGenes( - studyId, - Projection.SUMMARY.name(), - null, - null, - null, - null) - .stream() - .collect(Collectors.toMap(MutSig::getHugoGeneSymbol, Function.identity())); - } - return mutSigs; - } - - /** - * Retrieves GISTIC data for significant copy number alterations in the specified studies. - * - * @param studyViewFilterContext Context containing filter criteria. - * @return Map of GISTIC objects keyed by gene and G-score rank. - * @throws StudyNotFoundException if the specified study is not found. - */ - private Map, Gistic> getGisticMap(StudyViewFilterContext studyViewFilterContext) throws StudyNotFoundException { - var distinctStudyIds = studyViewRepository.getFilteredStudyIds(studyViewFilterContext); - Map, Gistic> gisticMap = new HashMap<>(); - if (distinctStudyIds.size() == 1) { - var studyId = distinctStudyIds.getFirst(); - List gisticList = significantCopyNumberRegionService.getSignificantCopyNumberRegions( - studyId, - Projection.SUMMARY.name(), - null, - null, - null, - null); - AlterationCountServiceUtil.setupGisticMap(gisticList, gisticMap); - } - return gisticMap; - } -} diff --git a/src/main/java/org/cbioportal/legacy/service/impl/ClinicalDataDensityPlotServiceImpl.java b/src/main/java/org/cbioportal/legacy/service/impl/ClinicalDataDensityPlotServiceImpl.java index f153b2ef134..118f5761930 100644 --- a/src/main/java/org/cbioportal/legacy/service/impl/ClinicalDataDensityPlotServiceImpl.java +++ b/src/main/java/org/cbioportal/legacy/service/impl/ClinicalDataDensityPlotServiceImpl.java @@ -7,7 +7,6 @@ import org.cbioportal.legacy.model.DensityPlotBin; import org.cbioportal.legacy.model.DensityPlotData; import org.cbioportal.legacy.service.ClinicalDataDensityPlotService; -import org.cbioportal.legacy.web.columnar.StudyViewColumnStoreController; import org.cbioportal.legacy.web.parameter.StudyViewFilter; import org.cbioportal.legacy.web.util.DensityPlotParameters; import org.springframework.cache.annotation.Cacheable; diff --git a/src/main/java/org/cbioportal/legacy/service/impl/StudyViewColumnarServiceImpl.java b/src/main/java/org/cbioportal/legacy/service/impl/StudyViewColumnarServiceImpl.java deleted file mode 100644 index 4e24dcf881d..00000000000 --- a/src/main/java/org/cbioportal/legacy/service/impl/StudyViewColumnarServiceImpl.java +++ /dev/null @@ -1,325 +0,0 @@ -package org.cbioportal.legacy.service.impl; - -import org.cbioportal.legacy.model.AlterationCountByGene; -import org.cbioportal.legacy.model.CaseListDataCount; -import org.cbioportal.legacy.model.ClinicalAttribute; -import org.cbioportal.legacy.model.ClinicalData; -import org.cbioportal.legacy.model.ClinicalDataCount; -import org.cbioportal.legacy.model.ClinicalDataCountItem; -import org.cbioportal.legacy.model.ClinicalEventTypeCount; -import org.cbioportal.legacy.model.CopyNumberCountByGene; -import org.cbioportal.legacy.model.GenericAssayDataCountItem; -import org.cbioportal.legacy.model.GenomicDataCount; -import org.cbioportal.legacy.model.PatientTreatmentReport; -import org.cbioportal.legacy.model.GenomicDataCountItem; -import org.cbioportal.legacy.model.Sample; -import org.cbioportal.legacy.model.SampleTreatmentReport; -import org.cbioportal.legacy.model.StudyViewFilterContext; -import org.cbioportal.legacy.persistence.StudyViewRepository; -import org.cbioportal.legacy.service.StudyViewColumnarService; -import org.cbioportal.legacy.service.alteration.AlterationCountByGeneService; -import org.cbioportal.legacy.service.exception.StudyNotFoundException; -import org.cbioportal.legacy.service.treatment.TreatmentCountReportService; -import org.cbioportal.legacy.service.util.StudyViewColumnarServiceUtil; -import org.cbioportal.legacy.utils.config.annotation.ConditionalOnProperty; -import org.cbioportal.legacy.web.parameter.ClinicalDataType; -import org.cbioportal.legacy.web.parameter.CustomSampleIdentifier; -import org.cbioportal.legacy.web.parameter.GenericAssayDataBinFilter; -import org.cbioportal.legacy.web.parameter.GenericAssayDataFilter; -import org.cbioportal.legacy.web.parameter.GenomicDataBinFilter; -import org.cbioportal.legacy.web.parameter.GenomicDataFilter; -import org.cbioportal.legacy.web.parameter.StudyViewFilter; -import org.cbioportal.legacy.web.columnar.util.CustomDataFilterUtil; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.cache.annotation.Cacheable; -import org.springframework.stereotype.Service; - -import static org.cbioportal.legacy.web.columnar.util.ClinicalDataXyPlotUtil.combineClinicalDataForXyPlot; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; - -@Service -@ConditionalOnProperty(name = "clickhouse_mode", havingValue = "true") -public class StudyViewColumnarServiceImpl implements StudyViewColumnarService { - - - private final StudyViewRepository studyViewRepository; - private final CustomDataFilterUtil customDataFilterUtil; - - private final AlterationCountByGeneService alterationCountByGeneService; - private final TreatmentCountReportService treatmentCountReportService; - - @Autowired - public StudyViewColumnarServiceImpl(StudyViewRepository studyViewRepository, AlterationCountByGeneService alterationCountByGeneService, TreatmentCountReportService treatmentCountReportService, CustomDataFilterUtil customDataFilterUtil) { - this.studyViewRepository = studyViewRepository; - this.alterationCountByGeneService = alterationCountByGeneService; - this.treatmentCountReportService = treatmentCountReportService; - this.customDataFilterUtil = customDataFilterUtil; - } - - @Cacheable( - cacheResolver = "staticRepositoryCacheOneResolver", - condition = "@cacheEnabledConfig.getEnabledClickhouse() && @studyViewFilterUtil.isUnfilteredQuery(#studyViewFilter)" - ) - @Override - public List getFilteredSamples(StudyViewFilter studyViewFilter) { - - return studyViewRepository.getFilteredSamples(createContext(studyViewFilter)); - } - - @Cacheable( - cacheResolver = "staticRepositoryCacheOneResolver", - condition = "@cacheEnabledConfig.getEnabledClickhouse() && @studyViewFilterUtil.isUnfilteredQuery(#studyViewFilter)" - ) - @Override - public List getMutatedGenes(StudyViewFilter studyViewFilter) throws StudyNotFoundException { - return alterationCountByGeneService.getMutatedGenes(createContext(studyViewFilter)); - } - - @Cacheable( - cacheResolver = "staticRepositoryCacheOneResolver", - condition = "@cacheEnabledConfig.getEnabledClickhouse() && @studyViewFilterUtil.isUnfilteredQuery(#studyViewFilter)" - ) - @Override - public List getMolecularProfileSampleCounts(StudyViewFilter studyViewFilter) { - return studyViewRepository.getMolecularProfileSampleCounts(createContext(studyViewFilter)); - } - - @Cacheable( - cacheResolver = "staticRepositoryCacheOneResolver", - condition = "@cacheEnabledConfig.getEnabledClickhouse() && @studyViewFilterUtil.isUnfilteredQuery(#studyViewFilter)" - ) - @Override - public List getClinicalEventTypeCounts(StudyViewFilter studyViewFilter) { - return studyViewRepository.getClinicalEventTypeCounts(createContext(studyViewFilter)); - } - - @Cacheable( - cacheResolver = "staticRepositoryCacheOneResolver", - condition = "@cacheEnabledConfig.getEnabledClickhouse() && @studyViewFilterUtil.isUnfilteredQuery(#studyViewFilter)" - ) - @Override - public PatientTreatmentReport getPatientTreatmentReport(StudyViewFilter studyViewFilter) { - return treatmentCountReportService.getPatientTreatmentReport(createContext(studyViewFilter)); - } - - @Cacheable( - cacheResolver = "staticRepositoryCacheOneResolver", - condition = "@cacheEnabledConfig.getEnabledClickhouse() && @studyViewFilterUtil.isUnfilteredQuery(#studyViewFilter)" - ) - @Override - public SampleTreatmentReport getSampleTreatmentReport(StudyViewFilter studyViewFilter) { - return treatmentCountReportService.getSampleTreatmentReport(createContext(studyViewFilter)); - } - - @Cacheable( - cacheResolver = "staticRepositoryCacheOneResolver", - condition = "@cacheEnabledConfig.getEnabledClickhouse() && @studyViewFilterUtil.isUnfilteredQuery(#studyViewFilter)" - ) - @Override - public List getGenomicDataBinCounts(StudyViewFilter studyViewFilter, List genomicDataBinFilters) { - return generateDataCountItemsFromDataCounts(studyViewRepository.getGenomicDataBinCounts(createContext(studyViewFilter), genomicDataBinFilters)); - } - - @Cacheable( - cacheResolver = "staticRepositoryCacheOneResolver", - condition = "@cacheEnabledConfig.getEnabledClickhouse() && @studyViewFilterUtil.isUnfilteredQuery(#studyViewFilter)" - ) - @Override - public List getGenericAssayDataBinCounts(StudyViewFilter studyViewFilter, List genericAssayDataBinFilters) { - return generateDataCountItemsFromDataCounts(studyViewRepository.getGenericAssayDataBinCounts(createContext(studyViewFilter), genericAssayDataBinFilters)); - } - - public List getCnaGenes(StudyViewFilter studyViewFilter) throws StudyNotFoundException { - return alterationCountByGeneService.getCnaGenes(createContext(studyViewFilter)); - } - - @Cacheable( - cacheResolver = "staticRepositoryCacheOneResolver", - condition = "@cacheEnabledConfig.getEnabledClickhouse() && @studyViewFilterUtil.isUnfilteredQuery(#studyViewFilter)" - ) - @Override - public List getStructuralVariantGenes(StudyViewFilter studyViewFilter) throws StudyNotFoundException { - return alterationCountByGeneService.getStructuralVariantGenes(createContext(studyViewFilter)); - } - - @Cacheable( - cacheResolver = "staticRepositoryCacheOneResolver", - condition = "@cacheEnabledConfig.getEnabledClickhouse() && @studyViewFilterUtil.isUnfilteredQuery(#studyViewFilter)" - ) - @Override - public Map getClinicalAttributeDatatypeMap(StudyViewFilter studyViewFilter) { - return studyViewRepository.getClinicalAttributeDatatypeMap(); - } - - @Cacheable( - cacheResolver = "staticRepositoryCacheOneResolver", - condition = "@cacheEnabledConfig.getEnabledClickhouse() && @studyViewFilterUtil.isUnfilteredQuery(#studyViewFilter)" - ) - @Override - public List getClinicalDataCounts(StudyViewFilter studyViewFilter, List filteredAttributes) { - - var context = createContext(studyViewFilter); - - List involvedCancerStudies = context.involvedCancerStudies(); - - var result = studyViewRepository.getClinicalDataCounts(context, filteredAttributes); - - // normalize data counts so that values like TRUE, True, and true are all merged in one count - result.forEach(item -> item.setCounts(StudyViewColumnarServiceUtil.normalizeDataCounts(item.getCounts()))); - - // attributes may be missing in result set because they have been filtered out - // e.g. if the filtered samples happen to have no SEX data, they will not appear in the list - // even though the inferred value of those attributes is NA - // the following code restores these counts for missing attributes - if (result.size() != filteredAttributes.size()) { - var attributes = getClinicalAttributesForStudies(involvedCancerStudies) - .stream() - .filter(attribute -> filteredAttributes.contains(attribute.getAttrId())) - .toList(); - - Integer filteredSampleCount = studyViewRepository.getFilteredSamplesCount(createContext(studyViewFilter)); - Integer filteredPatientCount = studyViewRepository.getFilteredPatientCount(createContext(studyViewFilter)); - - result = StudyViewColumnarServiceUtil.addClinicalDataCountsForMissingAttributes( - result, - attributes, - filteredSampleCount, - filteredPatientCount - ); - } - - return StudyViewColumnarServiceUtil.mergeClinicalDataCounts(result); - - } - - @Cacheable( - cacheResolver = "staticRepositoryCacheOneResolver", - condition = "@cacheEnabledConfig.getEnabledClickhouse()" - ) - public List getClinicalAttributesForStudies(List studyIds) { - return studyViewRepository.getClinicalAttributesForStudies(studyIds).stream().toList(); - } - - @Cacheable( - cacheResolver = "staticRepositoryCacheOneResolver", - condition = "@cacheEnabledConfig.getEnabledClickhouse() && @studyViewFilterUtil.isUnfilteredQuery(#studyViewFilter)" - ) - @Override - public List getCaseListDataCounts(StudyViewFilter studyViewFilter) { - // the study view merges case lists by type across studies - // type is determined by the suffix of case list name (after study name) - var caseListDataCountsPerStudy = studyViewRepository.getCaseListDataCountsPerStudy(createContext(studyViewFilter)); - return StudyViewColumnarServiceUtil.mergeCaseListCounts(caseListDataCountsPerStudy); - } - - @Cacheable( - cacheResolver = "staticRepositoryCacheOneResolver", - condition = "@cacheEnabledConfig.getEnabledClickhouse() && @studyViewFilterUtil.isUnfilteredQuery(#studyViewFilter)" - ) - @Override - public List getPatientClinicalData(StudyViewFilter studyViewFilter, List attributeIds) { - return studyViewRepository.getPatientClinicalData(createContext(studyViewFilter), attributeIds); - } - - @Cacheable( - cacheResolver = "staticRepositoryCacheOneResolver", - condition = "@cacheEnabledConfig.getEnabledClickhouse() && @studyViewFilterUtil.isUnfilteredQuery(#studyViewFilter)" - ) - @Override - public List getSampleClinicalData(StudyViewFilter studyViewFilter, List attributeIds) { - return studyViewRepository.getSampleClinicalData(createContext(studyViewFilter), attributeIds); - } - - @Cacheable( - cacheResolver = "staticRepositoryCacheOneResolver", - condition = "@cacheEnabledConfig.getEnabledClickhouse() && @studyViewFilterUtil.isUnfilteredQuery(#studyViewFilter)" - ) - @Override - public List getCNACountsByGeneSpecific(StudyViewFilter studyViewFilter, List genomicDataFilters) { - return studyViewRepository.getCNACounts(createContext(studyViewFilter), genomicDataFilters); - } - - @Cacheable( - cacheResolver = "staticRepositoryCacheOneResolver", - condition = "@cacheEnabledConfig.getEnabledClickhouse() && @studyViewFilterUtil.isUnfilteredQuery(#studyViewFilter)" - ) - @Override - public List getGenericAssayDataCounts(StudyViewFilter studyViewFilter, List genericAssayDataFilters) { - return studyViewRepository.getGenericAssayDataCounts(createContext(studyViewFilter), genericAssayDataFilters); - } - - @Cacheable( - cacheResolver = "staticRepositoryCacheOneResolver", - condition = "@cacheEnabledConfig.getEnabledClickhouse() && @studyViewFilterUtil.isUnfilteredQuery(#studyViewFilter)" - ) - @Override - public List getMutationCountsByGeneSpecific(StudyViewFilter studyViewFilter, List genomicDataFilters) { - List genomicDataCountItemList = new ArrayList<>(); - for (GenomicDataFilter genomicDataFilter : genomicDataFilters) { - Map counts = studyViewRepository.getMutationCounts(createContext(studyViewFilter), genomicDataFilter); - genomicDataCountItemList.add(StudyViewColumnarServiceUtil.createGenomicDataCountItemFromMutationCounts(genomicDataFilter, counts)); - } - return genomicDataCountItemList; - } - - @Cacheable( - cacheResolver = "staticRepositoryCacheOneResolver", - condition = "@cacheEnabledConfig.getEnabledClickhouse() && @studyViewFilterUtil.isUnfilteredQuery(#studyViewFilter)" - ) - @Override - public List getMutationTypeCountsByGeneSpecific(StudyViewFilter studyViewFilter, List genomicDataFilters) { - return studyViewRepository.getMutationCountsByType(createContext(studyViewFilter), genomicDataFilters); - } - - @Cacheable( - cacheResolver = "staticRepositoryCacheOneResolver", - condition = "@cacheEnabledConfig.getEnabledClickhouse() && @studyViewFilterUtil.isUnfilteredQuery(#studyViewFilter)" - ) - @Override - public List fetchClinicalDataForXyPlot( - StudyViewFilter studyViewFilter, - List attributeIds, - boolean shouldFilterNonEmptyClinicalData - ) { - List sampleClinicalDataList = this.getSampleClinicalData(studyViewFilter, attributeIds); - List patientClinicalDataList = this.getPatientClinicalData(studyViewFilter, attributeIds); - List samples = Collections.emptyList(); - - if (!patientClinicalDataList.isEmpty()) { - // fetch samples for the given study view filter. - // we need this to construct the complete patient to sample map. - samples = this.getFilteredSamples(studyViewFilter); - } - - return combineClinicalDataForXyPlot( - sampleClinicalDataList, - patientClinicalDataList, - samples, - shouldFilterNonEmptyClinicalData - ); - } - - private StudyViewFilterContext createContext(StudyViewFilter studyViewFilter) { - List customSampleIdentifiers = customDataFilterUtil.extractCustomDataSamples(studyViewFilter); - List involvedCancerStudies = customDataFilterUtil.extractInvolvedCancerStudies(studyViewFilter); - return new StudyViewFilterContext(studyViewFilter, customSampleIdentifiers, involvedCancerStudies); - } - - private List generateDataCountItemsFromDataCounts(List dataCounts) { - return dataCounts.stream().collect(Collectors.groupingBy(ClinicalDataCount::getAttributeId)) - .entrySet().parallelStream().map(e -> { - ClinicalDataCountItem item = new ClinicalDataCountItem(); - item.setAttributeId(e.getKey()); - item.setCounts(StudyViewColumnarServiceUtil.normalizeDataCounts(e.getValue())); - return item; - }).toList(); - } - - - -} diff --git a/src/main/java/org/cbioportal/legacy/service/impl/ViolinPlotServiceImpl.java b/src/main/java/org/cbioportal/legacy/service/impl/ViolinPlotServiceImpl.java index 545edd70595..3bb0666b73c 100644 --- a/src/main/java/org/cbioportal/legacy/service/impl/ViolinPlotServiceImpl.java +++ b/src/main/java/org/cbioportal/legacy/service/impl/ViolinPlotServiceImpl.java @@ -15,7 +15,13 @@ import org.springframework.stereotype.Service; import java.math.BigDecimal; -import java.util.*; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; import java.util.stream.Collectors; @Service @@ -30,7 +36,7 @@ public class ViolinPlotServiceImpl implements ViolinPlotService { ) public ClinicalViolinPlotData getClinicalViolinPlotData( List sampleClinicalDataForViolinPlot, - List samplesForSampleCounts, + Set samplesForSampleCountsIds, BigDecimal axisStart, BigDecimal axisEnd, BigDecimal numCurvePoints, @@ -43,12 +49,7 @@ public ClinicalViolinPlotData getClinicalViolinPlotData( result.setAxisEnd(Double.NEGATIVE_INFINITY); result.setRows(new ArrayList<>()); - // collect filtered samples into a set for quick lookup - Set samplesForSampleCountsIds = - samplesForSampleCounts.stream() - .map(Sample::getInternalId) - .collect(Collectors.toSet()); - + // clinicalDataMap is a map sampleId->studyId->data Map>> clinicalDataMap = sampleClinicalDataForViolinPlot.stream() .collect(Collectors.groupingBy(ClinicalData::getSampleId, Collectors.groupingBy(ClinicalData::getStudyId))); diff --git a/src/main/java/org/cbioportal/legacy/service/treatment/TreatmentCountReportService.java b/src/main/java/org/cbioportal/legacy/service/treatment/TreatmentCountReportService.java deleted file mode 100644 index 82ca2829d96..00000000000 --- a/src/main/java/org/cbioportal/legacy/service/treatment/TreatmentCountReportService.java +++ /dev/null @@ -1,14 +0,0 @@ -package org.cbioportal.legacy.service.treatment; - -import org.cbioportal.legacy.model.PatientTreatmentReport; -import org.cbioportal.legacy.model.SampleTreatmentReport; -import org.cbioportal.legacy.model.StudyViewFilterContext; -import org.cbioportal.legacy.web.parameter.CustomSampleIdentifier; -import org.cbioportal.legacy.web.parameter.StudyViewFilter; - -import java.util.List; - -public interface TreatmentCountReportService { - PatientTreatmentReport getPatientTreatmentReport(StudyViewFilterContext studyViewFilterContext); - SampleTreatmentReport getSampleTreatmentReport(StudyViewFilterContext studyViewFilterContext); -} diff --git a/src/main/java/org/cbioportal/legacy/service/treatment/TreatmentCountReportServiceImpl.java b/src/main/java/org/cbioportal/legacy/service/treatment/TreatmentCountReportServiceImpl.java deleted file mode 100644 index 1cbdc366a29..00000000000 --- a/src/main/java/org/cbioportal/legacy/service/treatment/TreatmentCountReportServiceImpl.java +++ /dev/null @@ -1,48 +0,0 @@ -package org.cbioportal.legacy.service.treatment; - -import org.cbioportal.legacy.model.PatientTreatmentReport; -import org.cbioportal.legacy.model.SampleTreatmentReport; -import org.cbioportal.legacy.model.SampleTreatmentRow; -import org.cbioportal.legacy.model.StudyViewFilterContext; -import org.cbioportal.legacy.model.TemporalRelation; -import org.cbioportal.legacy.persistence.StudyViewRepository; -import org.cbioportal.legacy.utils.config.annotation.ConditionalOnProperty; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; - -import java.util.Set; -import java.util.stream.Stream; - -@Service -@ConditionalOnProperty(name = "clickhouse_mode", havingValue = "true") -public class TreatmentCountReportServiceImpl implements TreatmentCountReportService { - - private final StudyViewRepository studyViewRepository; - - @Autowired - public TreatmentCountReportServiceImpl(StudyViewRepository studyViewRepository) { - this.studyViewRepository = studyViewRepository; - } - - @Override - public PatientTreatmentReport getPatientTreatmentReport(StudyViewFilterContext studyViewFilterContext) { - var patientTreatments = studyViewRepository.getPatientTreatments(studyViewFilterContext); - var totalPatientTreatmentCount = studyViewRepository.getTotalPatientTreatmentCount(studyViewFilterContext); - return new PatientTreatmentReport(totalPatientTreatmentCount, 0, patientTreatments); - } - - @Override - public SampleTreatmentReport getSampleTreatmentReport(StudyViewFilterContext studyViewFilterContext) { - var sampleTreatments = studyViewRepository.getSampleTreatments(studyViewFilterContext) - .stream() - .flatMap(sampleTreatment -> - Stream.of(new SampleTreatmentRow(TemporalRelation.Pre, sampleTreatment.treatment(), sampleTreatment.preSampleCount(), Set.of()), - new SampleTreatmentRow(TemporalRelation.Post, sampleTreatment.treatment(), sampleTreatment.postSampleCount(), Set.of() )) - ) - .filter(sampleTreatment -> sampleTreatment.getCount() > 0 ) - .toList(); - var totalSampleTreatmentCount = studyViewRepository.getTotalSampleTreatmentCount(studyViewFilterContext); - return new SampleTreatmentReport(totalSampleTreatmentCount, sampleTreatments); - } - -} diff --git a/src/main/java/org/cbioportal/legacy/web/StudyViewController.java b/src/main/java/org/cbioportal/legacy/web/StudyViewController.java index 2db202c5db9..42f526adca6 100644 --- a/src/main/java/org/cbioportal/legacy/web/StudyViewController.java +++ b/src/main/java/org/cbioportal/legacy/web/StudyViewController.java @@ -95,9 +95,12 @@ import java.util.List; import java.util.Map; import java.util.Objects; +import java.util.Set; import java.util.function.Function; import java.util.stream.Collectors; +import static java.util.stream.Collectors.toSet; + @InternalApi @RestController() @RequestMapping("/api") @@ -856,10 +859,14 @@ public ResponseEntity fetchClinicalDataViolinPlots( boolean useLogScale = logScale && StudyViewController.isLogScalePossibleForAttribute(numericalAttributeId); - + + Set sampleIdsSet = filteredSamples + .stream() + .map(s -> s.getInternalId()) + .collect(toSet()); result = violinPlotService.getClinicalViolinPlotData( sampleClinicalDataList, - filteredSamples, + sampleIdsSet, axisStart, axisEnd, numCurvePoints, diff --git a/src/main/java/org/cbioportal/legacy/web/columnar/BasicDataBinner.java b/src/main/java/org/cbioportal/legacy/web/columnar/BasicDataBinner.java index 5f9755830b6..869d5cbaf74 100644 --- a/src/main/java/org/cbioportal/legacy/web/columnar/BasicDataBinner.java +++ b/src/main/java/org/cbioportal/legacy/web/columnar/BasicDataBinner.java @@ -44,7 +44,8 @@ // but BasicDataBinner can support clinical data counts too // after we switched clinical data counts to use this, then We can remove ClinicalDataBinner @Component -@ConditionalOnProperty(name = "clickhouse_mode", havingValue = "true") +@Deprecated(forRemoval = true) +@ConditionalOnProperty(name = "clickhouse_mode", havingValue = "test") public class BasicDataBinner { private final StudyViewColumnarService studyViewColumnarService; private final DataBinner dataBinner; diff --git a/src/main/java/org/cbioportal/legacy/web/columnar/ClinicalDataBinner.java b/src/main/java/org/cbioportal/legacy/web/columnar/ClinicalDataBinner.java index 2e8b9375b93..9da46656c0a 100644 --- a/src/main/java/org/cbioportal/legacy/web/columnar/ClinicalDataBinner.java +++ b/src/main/java/org/cbioportal/legacy/web/columnar/ClinicalDataBinner.java @@ -22,7 +22,8 @@ import java.util.stream.Collectors; @Component -@ConditionalOnProperty(name = "clickhouse_mode", havingValue = "true") +@Deprecated(forRemoval = true) +@ConditionalOnProperty(name = "clickhouse_mode", havingValue = "test") public class ClinicalDataBinner { private final StudyViewColumnarService studyViewColumnarService; private final DataBinner dataBinner; diff --git a/src/main/java/org/cbioportal/legacy/web/columnar/StudyViewColumnStoreController.java b/src/main/java/org/cbioportal/legacy/web/columnar/StudyViewColumnStoreController.java deleted file mode 100644 index 3686d3ad7f6..00000000000 --- a/src/main/java/org/cbioportal/legacy/web/columnar/StudyViewColumnStoreController.java +++ /dev/null @@ -1,679 +0,0 @@ -package org.cbioportal.legacy.web.columnar; - -import io.swagger.v3.oas.annotations.Hidden; -import io.swagger.v3.oas.annotations.Operation; -import io.swagger.v3.oas.annotations.Parameter; -import io.swagger.v3.oas.annotations.media.ArraySchema; -import io.swagger.v3.oas.annotations.media.Content; -import io.swagger.v3.oas.annotations.media.Schema; -import io.swagger.v3.oas.annotations.responses.ApiResponse; -import jakarta.validation.Valid; -import org.cbioportal.legacy.model.AlterationCountByGene; -import org.cbioportal.legacy.model.AlterationFilter; -import org.cbioportal.legacy.model.CaseListDataCount; -import org.cbioportal.legacy.model.ClinicalData; -import org.cbioportal.legacy.model.ClinicalDataBin; -import org.cbioportal.legacy.model.ClinicalDataCountItem; -import org.cbioportal.legacy.model.ClinicalEventKeyCode; -import org.cbioportal.legacy.model.ClinicalEventTypeCount; -import org.cbioportal.legacy.model.ClinicalViolinPlotData; -import org.cbioportal.legacy.model.CopyNumberCountByGene; -import org.cbioportal.legacy.model.DensityPlotData; -import org.cbioportal.legacy.model.GenericAssayDataBin; -import org.cbioportal.legacy.model.GenericAssayDataCountItem; -import org.cbioportal.legacy.model.GenomicDataBin; -import org.cbioportal.legacy.model.GenomicDataCount; -import org.cbioportal.legacy.model.PatientTreatmentReport; -import org.cbioportal.legacy.model.Sample; -import org.cbioportal.legacy.model.SampleTreatmentReport; -import org.cbioportal.legacy.service.ClinicalDataDensityPlotService; -import org.cbioportal.legacy.model.GenomicDataCountItem; -import org.cbioportal.legacy.service.CustomDataService; -import org.cbioportal.legacy.service.StudyViewColumnarService; -import org.cbioportal.legacy.service.ViolinPlotService; -import org.cbioportal.legacy.service.exception.StudyNotFoundException; -import org.cbioportal.legacy.service.util.CustomDataSession; -import org.cbioportal.legacy.utils.config.annotation.ConditionalOnProperty; -import org.cbioportal.legacy.web.columnar.util.CustomDataFilterUtil; -import org.cbioportal.legacy.web.columnar.util.NewStudyViewFilterUtil; -import org.cbioportal.legacy.web.config.annotation.InternalApi; -import org.cbioportal.legacy.web.parameter.ClinicalDataBinCountFilter; -import org.cbioportal.legacy.web.parameter.ClinicalDataCountFilter; -import org.cbioportal.legacy.web.parameter.ClinicalDataFilter; -import org.cbioportal.legacy.web.parameter.DataBinMethod; -import org.cbioportal.legacy.web.parameter.GenericAssayDataBinCountFilter; -import org.cbioportal.legacy.web.parameter.GenericAssayDataCountFilter; -import org.cbioportal.legacy.web.parameter.GenericAssayDataFilter; -import org.cbioportal.legacy.web.parameter.GenomicDataBinCountFilter; -import org.cbioportal.legacy.web.parameter.GenomicDataCountFilter; -import org.cbioportal.legacy.web.parameter.GenomicDataFilter; -import org.cbioportal.legacy.web.parameter.MutationOption; -import org.cbioportal.legacy.web.parameter.Projection; -import org.cbioportal.legacy.web.parameter.SampleIdentifier; -import org.cbioportal.legacy.web.parameter.StudyViewFilter; -import org.cbioportal.legacy.web.util.DensityPlotParameters; -import org.cbioportal.legacy.web.util.StudyViewFilterUtil; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.http.HttpStatus; -import org.springframework.http.MediaType; -import org.springframework.http.ResponseEntity; -import org.springframework.security.access.prepost.PreAuthorize; -import org.springframework.validation.annotation.Validated; -import org.springframework.web.bind.annotation.RequestAttribute; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestMethod; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.RestController; - -import java.math.BigDecimal; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; - -@InternalApi -@RestController() -@RequestMapping("/api") -@Validated -@ConditionalOnProperty(name = "clickhouse_mode", havingValue = "true") -public class StudyViewColumnStoreController { - - private final StudyViewColumnarService studyViewColumnarService; - private final ClinicalDataBinner clinicalDataBinner; - - private final BasicDataBinner basicDataBinner; - private final ClinicalDataDensityPlotService clinicalDataDensityPlotService; - private final ViolinPlotService violinPlotService; - private final CustomDataService customDataService; - private final StudyViewFilterUtil studyViewFilterUtil; - private final CustomDataFilterUtil customDataFilterUtil; - - @Autowired - public StudyViewColumnStoreController(StudyViewColumnarService studyViewColumnarService, - ClinicalDataBinner clinicalDataBinner, - BasicDataBinner basicDataBinner, - ClinicalDataDensityPlotService clinicalDataDensityPlotService, - ViolinPlotService violinPlotService, - CustomDataService customDataService, - StudyViewFilterUtil studyViewFilterUtil, - CustomDataFilterUtil customDataFilterUtil - ) { - this.studyViewColumnarService = studyViewColumnarService; - this.clinicalDataBinner = clinicalDataBinner; - this.basicDataBinner = basicDataBinner; - this.clinicalDataDensityPlotService = clinicalDataDensityPlotService; - this.violinPlotService = violinPlotService; - this.customDataService = customDataService; - this.studyViewFilterUtil = studyViewFilterUtil; - this.customDataFilterUtil = customDataFilterUtil; - } - - - @Hidden // should unhide when we remove legacy controller - @PreAuthorize("hasPermission(#involvedCancerStudies, 'Collection', T(org.cbioportal.legacy.utils.security.AccessLevel).READ)") - @RequestMapping(value = "/column-store/filtered-samples/fetch", - consumes = MediaType.APPLICATION_JSON_VALUE, method=RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE) - public ResponseEntity> fetchFilteredSamples( - @RequestParam(defaultValue = "false") Boolean negateFilters, - @RequestAttribute(required = false, value = "involvedCancerStudies") Collection involvedCancerStudies, - @RequestAttribute(required = false, value = "interceptedStudyViewFilter") StudyViewFilter interceptedStudyViewFilter, - @RequestBody(required = false) StudyViewFilter studyViewFilter) { - return new ResponseEntity<>( - studyViewColumnarService.getFilteredSamples(interceptedStudyViewFilter), - HttpStatus.OK - ); - } - - @Hidden // should unhide when we remove legacy controller - @PreAuthorize("hasPermission(#involvedCancerStudies, 'Collection', T(org.cbioportal.legacy.utils.security.AccessLevel).READ)") - @RequestMapping(value = "/column-store/mutated-genes/fetch", - consumes = MediaType.APPLICATION_JSON_VALUE, method=RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE) - public ResponseEntity> fetchMutatedGenes( - @RequestBody(required = false) StudyViewFilter studyViewFilter, - @RequestAttribute(required = false, value = "involvedCancerStudies") Collection involvedCancerStudies, - @RequestAttribute(required = false, value = "interceptedStudyViewFilter") StudyViewFilter interceptedStudyViewFilter - ) throws StudyNotFoundException { - AlterationFilter annotationFilters = interceptedStudyViewFilter.getAlterationFilter(); - return new ResponseEntity<>( - studyViewColumnarService.getMutatedGenes(interceptedStudyViewFilter), - HttpStatus.OK - ); - } - - @Hidden // should unhide when we remove legacy controller - @PreAuthorize("hasPermission(#involvedCancerStudies, 'Collection', T(org.cbioportal.legacy.utils.security.AccessLevel).READ)") - @RequestMapping(value = "/column-store/molecular-profile-sample-counts/fetch", method = RequestMethod.POST, - consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE) - @Operation(description = "Fetch sample counts by study view filter") - @ApiResponse(responseCode = "200", description = "OK", - content = @Content(array = @ArraySchema(schema = @Schema(implementation = GenomicDataCount.class)))) - public ResponseEntity> fetchMolecularProfileSampleCounts( - @Parameter(required = true, description = "Study view filter") - @Valid @RequestBody(required = false) StudyViewFilter studyViewFilter, - @Parameter(hidden = true) // prevent reference to this attribute in the swagger-ui interface - @RequestAttribute(required = false, value = "involvedCancerStudies") Collection involvedCancerStudies, - @Parameter(hidden = true) // prevent reference to this attribute in the swagger-ui interface. this attribute is needed for the @PreAuthorize tag above. - @Valid @RequestAttribute(required = false, value = "interceptedStudyViewFilter") StudyViewFilter interceptedStudyViewFilter - ) - { - return new ResponseEntity>( - studyViewColumnarService.getMolecularProfileSampleCounts(interceptedStudyViewFilter) - , HttpStatus.OK); - } - - @Hidden // should unhide when we remove legacy controller - @RequestMapping(value = "/column-store/cna-genes/fetch", - consumes = MediaType.APPLICATION_JSON_VALUE, method=RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE) - public ResponseEntity> fetchCnaGenes( - @RequestBody(required = false) StudyViewFilter studyViewFilter, - @RequestAttribute(required = false, value = "involvedCancerStudies") Collection involvedCancerStudies, - @RequestAttribute(required = false, value = "interceptedStudyViewFilter") StudyViewFilter interceptedStudyViewFilter - ) throws StudyNotFoundException { - return new ResponseEntity<>( - studyViewColumnarService.getCnaGenes(interceptedStudyViewFilter), - HttpStatus.OK - ); - } - - @Hidden // should unhide when we remove legacy controller - @RequestMapping(value = "/column-store/structuralvariant-genes/fetch", - consumes = MediaType.APPLICATION_JSON_VALUE, method=RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE) - @Operation(description = "Fetch structural variant genes by study view filter") - @ApiResponse(responseCode = "200", description = "OK", - content = @Content(array = @ArraySchema(schema = @Schema(implementation = AlterationCountByGene.class)))) - public ResponseEntity> fetchStructuralVariantGenes( - @Parameter(required = true, description = "Study view filter") - @Valid @RequestBody(required = false) StudyViewFilter studyViewFilter, - @Parameter(hidden = true) // prevent reference to this attribute in the swagger-ui interface. This attribute is needed for the @PreAuthorize tag above. - @RequestAttribute(required = false, value = "involvedCancerStudies") Collection involvedCancerStudies, - @Parameter(hidden = true) // prevent reference to this attribute in the swagger-ui interface. - @Valid @RequestAttribute(required = false, value = "interceptedStudyViewFilter") StudyViewFilter interceptedStudyViewFilter - ) throws StudyNotFoundException { - return new ResponseEntity<>(studyViewColumnarService.getStructuralVariantGenes(interceptedStudyViewFilter), HttpStatus.OK); - } - - @Hidden // should unhide when we remove legacy controller - @PreAuthorize("hasPermission(#involvedCancerStudies, 'Collection', T(org.cbioportal.legacy.utils.security.AccessLevel).READ)") - @RequestMapping(value = "/column-store/clinical-data-counts/fetch", - method=RequestMethod.POST, - consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE) - public ResponseEntity> fetchClinicalDataCounts( - @RequestBody(required = false) ClinicalDataCountFilter clinicalDataCountFilter, - @RequestAttribute(required = false, value = "involvedCancerStudies") Collection involvedCancerStudies, - @RequestAttribute(required = false, value = "interceptedClinicalDataCountFilter") ClinicalDataCountFilter interceptedClinicalDataCountFilter) { - - List attributes = interceptedClinicalDataCountFilter.getAttributes(); - StudyViewFilter studyViewFilter = interceptedClinicalDataCountFilter.getStudyViewFilter(); - - if (attributes.size() == 1) { - NewStudyViewFilterUtil.removeClinicalDataFilter(attributes.getFirst().getAttributeId(), studyViewFilter.getClinicalDataFilters()); - } - List result = studyViewColumnarService.getClinicalDataCounts( - studyViewFilter, - attributes.stream().map(ClinicalDataFilter::getAttributeId).collect(Collectors.toList())); - return new ResponseEntity<>(result, HttpStatus.OK); - - } - - @Hidden // should unhide when we remove legacy controller - @PreAuthorize("hasPermission(#involvedCancerStudies, 'Collection', T(org.cbioportal.legacy.utils.security.AccessLevel).READ)") - @RequestMapping(value = "/column-store/sample-lists-counts/fetch", method = RequestMethod.POST, - consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE) - @Operation(description = "Fetch case list sample counts by study view filter") - public List fetchCaseListCounts( - @Parameter(required = true, description = "Study view filter") - @Valid @RequestBody(required = false) StudyViewFilter studyViewFilter, - @Parameter(hidden = true) // prevent reference to this attribute in the swagger-ui interface - @RequestAttribute(required = false, value = "involvedCancerStudies") Collection involvedCancerStudies, - @Parameter(hidden = true) // prevent reference to this attribute in the swagger-ui interface. this attribute is needed for the @PreAuthorize tag above. - @Valid @RequestAttribute(required = false, value = "interceptedStudyViewFilter") StudyViewFilter interceptedStudyViewFilter) { - - return studyViewColumnarService.getCaseListDataCounts(interceptedStudyViewFilter); - - } - - @Hidden // should unhide when we remove legacy controller - @PreAuthorize("hasPermission(#involvedCancerStudies, 'Collection', T(org.cbioportal.legacy.utils.security.AccessLevel).READ)") - @RequestMapping(value = "/column-store/clinical-data-bin-counts/fetch", method = RequestMethod.POST, - consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE) - public ResponseEntity> fetchClinicalDataBinCounts( - @RequestParam(defaultValue = "DYNAMIC") DataBinMethod dataBinMethod, - @RequestBody(required = false) ClinicalDataBinCountFilter clinicalDataBinCountFilter, - @RequestAttribute(required = false, value = "involvedCancerStudies") Collection involvedCancerStudies, - @RequestAttribute(required = false, value = "interceptedClinicalDataBinCountFilter") ClinicalDataBinCountFilter interceptedClinicalDataBinCountFilter - ) { - List clinicalDataBins = clinicalDataBinner.fetchClinicalDataBinCounts( - dataBinMethod, - interceptedClinicalDataBinCountFilter, - true - ); - return new ResponseEntity<>(clinicalDataBins, HttpStatus.OK); - } - - @Hidden // should unhide when we remove legacy controller - @PreAuthorize("hasPermission(#involvedCancerStudies, 'Collection', T(org.cbioportal.legacy.utils.security.AccessLevel).READ)") - @RequestMapping(value = "/column-store/clinical-data-density-plot/fetch", - method = RequestMethod.POST, - consumes = MediaType.APPLICATION_JSON_VALUE, - produces = MediaType.APPLICATION_JSON_VALUE) - @Operation(description = "Fetch clinical data density plot bins by study view filter") - @ApiResponse(responseCode = "200", description = "OK", - content = @Content(schema = @Schema(implementation = DensityPlotData.class))) - @Validated - public ResponseEntity fetchClinicalDataDensityPlot( - @Parameter(required = true, description = "Clinical Attribute ID of the X axis") - @RequestParam String xAxisAttributeId, - @Parameter(description = "Number of the bins in X axis") - @RequestParam(defaultValue = "50") Integer xAxisBinCount, - @Parameter(description = "Starting point of the X axis, if different than smallest value") - @RequestParam(required = false) BigDecimal xAxisStart, - @Parameter(description = "Starting point of the X axis, if different than largest value") - @RequestParam(required = false) BigDecimal xAxisEnd, - @Parameter(required = true, description = "Clinical Attribute ID of the Y axis") - @RequestParam String yAxisAttributeId, - @Parameter(description = "Number of the bins in Y axis") - @RequestParam(defaultValue = "50") Integer yAxisBinCount, - @Parameter(description = "Starting point of the Y axis, if different than smallest value") - @RequestParam(required = false) BigDecimal yAxisStart, - @Parameter(description = "Starting point of the Y axis, if different than largest value") - @RequestParam(required = false) BigDecimal yAxisEnd, - @Parameter(description="Use log scale for X axis") - @RequestParam(required = false, defaultValue = "false") Boolean xAxisLogScale, - @Schema(defaultValue = "false") - @Parameter(description="Use log scale for Y axis") - @RequestParam(required = false, defaultValue = "false") Boolean yAxisLogScale, - @Parameter(hidden = true) // prevent reference to this attribute in the swagger-ui interface - @RequestAttribute(required = false, value = "involvedCancerStudies") Collection involvedCancerStudies, - @Parameter(hidden = true) // prevent reference to this attribute in the swagger-ui interface. this attribute is needed for the @PreAuthorize tag above. - @Valid @RequestAttribute(required = false, value = "interceptedStudyViewFilter") StudyViewFilter interceptedStudyViewFilter, - @Parameter(required = true, description = "Study view filter") - @RequestBody(required = false) StudyViewFilter studyViewFilter - ) { - DensityPlotParameters densityPlotParameters = - new DensityPlotParameters.Builder() - .xAxisAttributeId(xAxisAttributeId) - .yAxisAttributeId(yAxisAttributeId) - .xAxisBinCount(xAxisBinCount) - .yAxisBinCount(yAxisBinCount) - .xAxisStart(xAxisStart) - .yAxisStart(yAxisStart) - .xAxisEnd(xAxisEnd) - .yAxisEnd(yAxisEnd) - .xAxisLogScale(xAxisLogScale) - .yAxisLogScale(yAxisLogScale) - .build(); - - List combinedClinicalDataList = studyViewColumnarService.fetchClinicalDataForXyPlot( - interceptedStudyViewFilter, - List.of(xAxisAttributeId, yAxisAttributeId), - false - ); - - DensityPlotData result = clinicalDataDensityPlotService.getDensityPlotData( - combinedClinicalDataList, - densityPlotParameters, - interceptedStudyViewFilter - ); - - return new ResponseEntity<>(result, HttpStatus.OK); - } - - @Hidden // should unhide when we remove legacy controller - @PreAuthorize("hasPermission(#involvedCancerStudies, 'Collection', T(org.cbioportal.legacy.utils.security.AccessLevel).READ)") - @RequestMapping(value = "/column-store/clinical-data-violin-plots/fetch", - method = RequestMethod.POST, - consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE) - @Operation(description = "Fetch violin plot curves per categorical clinical data value, filtered by study view filter") - @ApiResponse(responseCode = "200", description = "OK", - content = @Content(schema = @Schema(implementation = ClinicalViolinPlotData.class))) - public ResponseEntity fetchClinicalDataViolinPlots( - @Parameter(required = true, description = "Clinical Attribute ID of the categorical attribute") - @RequestParam String categoricalAttributeId, - @Parameter(required = true, description = "Clinical Attribute ID of the numerical attribute") - @RequestParam String numericalAttributeId, - @Parameter(description = "Starting point of the violin plot axis, if different than smallest value") - @RequestParam(required = false) BigDecimal axisStart, - @Parameter(description = "Ending point of the violin plot axis, if different than largest value") - @RequestParam(required = false) BigDecimal axisEnd, - @Parameter(description = "Number of points in the curve") - @RequestParam(required = false, defaultValue = "100") BigDecimal numCurvePoints, - @Parameter(description="Use log scale for the numerical attribute") - @RequestParam(required = false, defaultValue = "false") Boolean logScale, - @Parameter(description="Sigma stepsize multiplier") - @RequestParam(required = false, defaultValue = "1") BigDecimal sigmaMultiplier, - @Parameter(hidden = true) // prevent reference to this attribute in the swagger-ui interface - @RequestAttribute(required = false, value = "involvedCancerStudies") Collection involvedCancerStudies, - @Parameter(hidden = true) // prevent reference to this attribute in the swagger-ui interface. this attribute is needed for the @PreAuthorize tag above. - @Valid @RequestAttribute(required = false, value = "interceptedStudyViewFilter") StudyViewFilter interceptedStudyViewFilter, - @Parameter(required = true, description = "Study view filter") - @Valid @RequestBody(required = false) StudyViewFilter studyViewFilter - ) { - // fetch the samples by using the provided study view filter - List filteredSamples = studyViewColumnarService.getFilteredSamples(interceptedStudyViewFilter); - - // remove the numerical clinical data filter from the study view filter. - // this new modified filter is used to fetch sample and patient clinical data. - // this is required to get the complete violin plot data. - // filteredSamples reflects only the original unmodified study view filter. - // we will need to fetch samples again to get the samples corresponding to this modified filter, - // otherwise patient to sample mapping may be incomplete. - if (interceptedStudyViewFilter.getClinicalDataFilters() != null) { - interceptedStudyViewFilter.getClinicalDataFilters().stream() - .filter(f->f.getAttributeId().equals(numericalAttributeId)) - .findAny() - .ifPresent(f->interceptedStudyViewFilter.getClinicalDataFilters().remove(f)); - } - - List combinedClinicalDataList = studyViewColumnarService.fetchClinicalDataForXyPlot( - interceptedStudyViewFilter, - List.of(numericalAttributeId, categoricalAttributeId), - true // filter out clinical data with empty attribute values due to Clickhouse migration - ); - - // Only mutation count can use log scale - boolean useLogScale = logScale && numericalAttributeId.equals("MUTATION_COUNT"); - - ClinicalViolinPlotData result = violinPlotService.getClinicalViolinPlotData( - combinedClinicalDataList, - filteredSamples, - axisStart, - axisEnd, - numCurvePoints, - useLogScale, - sigmaMultiplier, - interceptedStudyViewFilter - ); - - return new ResponseEntity<>(result, HttpStatus.OK); - } - - @Hidden // should unhide when we remove legacy controller - @PreAuthorize("hasPermission(#involvedCancerStudies, 'Collection', T(org.cbioportal.legacy.utils.security.AccessLevel).READ)") - @RequestMapping(value = "/column-store/genomic-data-counts/fetch", - method = RequestMethod.POST, - consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE) - @Operation(description = "Fetch genomic data counts by GenomicDataCountFilter") - @ApiResponse(responseCode = "200", description = "OK", - content = @Content(array = @ArraySchema(schema = @Schema(implementation = GenomicDataCountItem.class)))) - public ResponseEntity> fetchGenomicDataCounts( - @Parameter(required = true, description = "Genomic data count filter") @Valid @RequestBody(required = false) GenomicDataCountFilter genomicDataCountFilter, - @Parameter(hidden = true) // prevent reference to this attribute in the swagger-ui interface - @RequestAttribute(required = false, value = "involvedCancerStudies") Collection involvedCancerStudies, - @Parameter(required = true, description = "Intercepted Genomic Data Count Filter") - @Valid @RequestAttribute(required = false, value = "interceptedGenomicDataCountFilter") GenomicDataCountFilter interceptedGenomicDataCountFilter - ) throws StudyNotFoundException { - List genomicDataFilters = interceptedGenomicDataCountFilter.getGenomicDataFilters(); - StudyViewFilter studyViewFilter = interceptedGenomicDataCountFilter.getStudyViewFilter(); - // when there is only one filter, it means study view is doing a single chart filter operation - // remove filter from studyViewFilter to return all data counts - // the reason we do this is to make sure after chart get filtered, user can still see unselected portion of the chart - if (genomicDataFilters.size() == 1) { - studyViewFilterUtil.removeSelfFromGenomicDataFilter( - genomicDataFilters.get(0).getHugoGeneSymbol(), - genomicDataFilters.get(0).getProfileType(), - studyViewFilter); - } - - // This endpoint is CNA specific. The name choice of "genomic data" does not imply it support other genomic data types - List result = studyViewColumnarService.getCNACountsByGeneSpecific(studyViewFilter, genomicDataFilters); - - return new ResponseEntity<>(result, HttpStatus.OK); - } - - @Hidden // should unhide when we remove legacy controller - @PreAuthorize("hasPermission(#involvedCancerStudies, 'Collection', T(org.cbioportal.legacy.utils.security.AccessLevel).READ)") - @RequestMapping(value = "/column-store/generic-assay-data-counts/fetch", - method = RequestMethod.POST, - consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE) - @Operation(description = "Fetch generic assay data counts by study view filter") - @ApiResponse(responseCode = "200", description = "OK", - content = @Content(array = @ArraySchema(schema = @Schema(implementation = GenericAssayDataCountItem.class)))) - public ResponseEntity> fetchGenericAssayDataCounts( - @Parameter(required = true, description = "Generic assay data count filter") @Valid @RequestBody(required = false) GenericAssayDataCountFilter genericAssayDataCountFilter, - @Parameter(hidden = true) // prevent reference to this attribute in the swagger-ui interface - @RequestAttribute(required = false, value = "involvedCancerStudies") Collection involvedCancerStudies, - @Parameter(hidden = true) // prevent reference to this attribute in the swagger-ui interface. this - // attribute is needed for the @PreAuthorize tag above. - @Valid @RequestAttribute(required = false, value = "interceptedGenericAssayDataCountFilter") GenericAssayDataCountFilter interceptedGenericAssayDataCountFilter) { - - List gaFilters = interceptedGenericAssayDataCountFilter.getGenericAssayDataFilters(); - StudyViewFilter studyViewFilter = interceptedGenericAssayDataCountFilter.getStudyViewFilter(); - // when there is only one filter, it means study view is doing a single chart filter operation - // remove filter from studyViewFilter to return all data counts - // the reason we do this is to make sure after chart get filtered, user can still see unselected portion of the chart - - if (gaFilters.size() == 1) { - studyViewFilterUtil.removeSelfFromGenericAssayFilter(gaFilters.getFirst().getStableId(), studyViewFilter); - } - - return new ResponseEntity<>(studyViewColumnarService.getGenericAssayDataCounts(studyViewFilter, gaFilters), HttpStatus.OK); - } - - @Hidden // should unhide when we remove legacy controller - @PreAuthorize("hasPermission(#involvedCancerStudies, 'Collection', T(org.cbioportal.legacy.utils.security.AccessLevel).READ)") - @RequestMapping(value = "/column-store/mutation-data-counts/fetch", - method = RequestMethod.POST, - consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE) - @Operation(description = "Fetch mutation data counts by GenomicDataCountFilter") - public ResponseEntity> fetchMutationDataCounts( - @Parameter(description = "Level of detail of the response") - @RequestParam(defaultValue = "SUMMARY") Projection projection, - @Parameter(required = true, description = "Genomic data count filter") - @Valid @RequestBody(required = false) GenomicDataCountFilter genomicDataCountFilter, - @Parameter(hidden = true) // prevent reference to this attribute in the swagger-ui interface - @RequestAttribute(required = false, value = "involvedCancerStudies") Collection involvedCancerStudies, - @Parameter(hidden = true) // prevent reference to this attribute in the swagger-ui interface - @Valid @RequestAttribute(required = false, value = "interceptedGenomicDataCountFilter") GenomicDataCountFilter interceptedGenomicDataCountFilter - ) { - List genomicDataFilters = interceptedGenomicDataCountFilter.getGenomicDataFilters(); - StudyViewFilter studyViewFilter = interceptedGenomicDataCountFilter.getStudyViewFilter(); - // when there is only one filter, it means study view is doing a single chart filter operation - // remove filter from studyViewFilter to return all data counts - // the reason we do this is to make sure after chart get filtered, user can still see unselected portion of the chart - if (genomicDataFilters.size() == 1 && projection == Projection.SUMMARY) { - studyViewFilterUtil.removeSelfFromMutationDataFilter( - genomicDataFilters.get(0).getHugoGeneSymbol(), - genomicDataFilters.get(0).getProfileType(), - MutationOption.MUTATED, - studyViewFilter); - } - - List result = projection == Projection.SUMMARY ? - studyViewColumnarService.getMutationCountsByGeneSpecific(studyViewFilter, genomicDataFilters) : - studyViewColumnarService.getMutationTypeCountsByGeneSpecific(studyViewFilter, genomicDataFilters); - - return new ResponseEntity<>(result, HttpStatus.OK); - } - - @Hidden // should unhide when we remove legacy controller - @PreAuthorize("hasPermission(#involvedCancerStudies, 'Collection', T(org.cbioportal.legacy.utils.security.AccessLevel).READ)") - @RequestMapping(value = "/column-store/clinical-event-type-counts/fetch", - method = RequestMethod.POST, - consumes = MediaType.APPLICATION_JSON_VALUE, - produces = MediaType.APPLICATION_JSON_VALUE) - @Operation(description = "Get Counts of Clinical Event Types by Study View Filter") - @ApiResponse(responseCode = "200", description = "OK", - content = @Content(array = @ArraySchema(schema = @Schema(implementation = ClinicalEventTypeCount.class)))) - public ResponseEntity> getClinicalEventTypeCounts( - @Parameter(required = true, description = "Study view filter") - @Valid - @RequestBody(required = false) - StudyViewFilter studyViewFilter, - - @Parameter(hidden = true) // prevent reference to this attribute in the swagger-ui interface - @RequestAttribute(required = false, value = "involvedCancerStudies") - Collection involvedCancerStudies, - - @Parameter(hidden = true) // prevent reference to this attribute in the swagger-ui interface. this attribute is needed for the @PreAuthorize tag above. - @Valid - @RequestAttribute(required = false, value = "interceptedStudyViewFilter") - StudyViewFilter interceptedStudyViewFilter - ) { - return new ResponseEntity<>(studyViewColumnarService.getClinicalEventTypeCounts(interceptedStudyViewFilter), HttpStatus.OK); - } - - @PreAuthorize("hasPermission(#involvedCancerStudies, 'Collection', T(org.cbioportal.legacy.utils.security.AccessLevel).READ)") - @RequestMapping(value = "/column-store/treatments/patient-counts/fetch", - method = RequestMethod.POST, - produces = MediaType.APPLICATION_JSON_VALUE) - @Operation(description = "Get all patient level treatments") - @ApiResponse(responseCode = "200", description = "OK", - content = @Content(schema = @Schema(implementation = PatientTreatmentReport.class))) - public ResponseEntity fetchPatientTreatmentCounts( - @Parameter(required = false ) - @RequestParam(name = "tier", required = false, defaultValue = "Agent") - ClinicalEventKeyCode tier, - - @Parameter(required = true, description = "Study view filter") - @Valid - @RequestBody(required = false) - StudyViewFilter studyViewFilter, - - @Parameter(hidden = true) // prevent reference to this attribute in the swagger-ui interface - @RequestAttribute(required = false, value = "involvedCancerStudies") - Collection involvedCancerStudies, - - @Parameter(hidden = true) // prevent reference to this attribute in the swagger-ui interface. this attribute is needed for the @PreAuthorize tag above. - @Valid - @RequestAttribute(required = false, value = "interceptedStudyViewFilter") - StudyViewFilter interceptedStudyViewFilter - ) { - return new ResponseEntity<>(studyViewColumnarService.getPatientTreatmentReport(interceptedStudyViewFilter), - HttpStatus.OK); - } - - @PreAuthorize("hasPermission(#involvedCancerStudies, 'Collection', T(org.cbioportal.legacy.utils.security.AccessLevel).READ)") - @RequestMapping(value = "/column-store/treatments/sample-counts/fetch", - method = RequestMethod.POST, - produces = MediaType.APPLICATION_JSON_VALUE) - @ApiResponse(responseCode = "200", description = "OK", - content = @Content(schema = @Schema(implementation = SampleTreatmentReport.class))) - public ResponseEntity fetchSampleTreatmentCounts( - @Parameter(required = false ) - @RequestParam(name = "tier", required = false, defaultValue = "Agent") - ClinicalEventKeyCode tier, - - @Parameter(required = true, description = "Study view filter") - @Valid - @RequestBody(required = false) - StudyViewFilter studyViewFilter, - - @Parameter(hidden = true) // prevent reference to this attribute in the swagger-ui interface - @RequestAttribute(required = false, value = "involvedCancerStudies") - Collection involvedCancerStudies, - - @Parameter(hidden = true) // prevent reference to this attribute in the swagger-ui interface. this attribute is needed for the @PreAuthorize tag above. - @Valid - @RequestAttribute(required = false, value = "interceptedStudyViewFilter") - StudyViewFilter interceptedStudyViewFilter - ) { - return new ResponseEntity<>(studyViewColumnarService.getSampleTreatmentReport(interceptedStudyViewFilter), - HttpStatus.OK); - } - - @Hidden // should unhide when we remove legacy controller - @PreAuthorize("hasPermission(#involvedCancerStudies, 'Collection', T(org.cbioportal.legacy.utils.security.AccessLevel).READ)") - @RequestMapping(value = "/column-store/custom-data-counts/fetch", - method=RequestMethod.POST, - consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE) - @Operation(description = "Fetch custom data counts by study view filter") - @ApiResponse(responseCode = "200", description = "OK", - content = @Content(array = @ArraySchema(schema = @Schema(implementation = ClinicalDataCountItem.class)))) - public ResponseEntity> fetchCustomDataCounts( - @Parameter(required = true, description = "Custom data count filter") @Valid @RequestBody(required = false) ClinicalDataCountFilter clinicalDataCountFilter, - @Parameter(hidden = true) // prevent reference to this attribute in the swagger-ui - // interface - @RequestAttribute(required = false, value = "involvedCancerStudies") Collection involvedCancerStudies, - @Parameter(hidden = true) // prevent reference to this attribute in the swagger-ui - // interface. this attribute is needed for the - // @PreAuthorize tag above. - @Valid @RequestAttribute(required = false, value = "interceptedClinicalDataCountFilter") ClinicalDataCountFilter interceptedClinicalDataCountFilter) { - - List attributes = interceptedClinicalDataCountFilter.getAttributes(); - StudyViewFilter studyViewFilter = interceptedClinicalDataCountFilter.getStudyViewFilter(); - if (attributes.size() == 1) { - NewStudyViewFilterUtil.removeClinicalDataFilter(attributes.getFirst().getAttributeId(), studyViewFilter.getCustomDataFilters()); - } - - List filteredSampleIdentifiers = studyViewColumnarService.getFilteredSamples(studyViewFilter).stream().map(sample -> studyViewFilterUtil.buildSampleIdentifier(sample.getCancerStudyIdentifier(), sample.getStableId())).toList(); - - if (filteredSampleIdentifiers.isEmpty()) { - return new ResponseEntity<>(new ArrayList<>(), HttpStatus.OK); - } - - final List attributeIds = attributes.stream().map(ClinicalDataFilter::getAttributeId).toList(); - Map customDataSessionsMap = customDataService.getCustomDataSessions(attributeIds); - - List result = customDataFilterUtil.getCustomDataCounts(filteredSampleIdentifiers, customDataSessionsMap); - - return new ResponseEntity<>(result, HttpStatus.OK); - } - - @Hidden // should unhide when we remove legacy controller - @PreAuthorize("hasPermission(#involvedCancerStudies, 'Collection', T(org.cbioportal.legacy.utils.security.AccessLevel).READ)") - @RequestMapping(value = "/column-store/custom-data-bin-counts/fetch", - consumes = MediaType.APPLICATION_JSON_VALUE, method= RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE) - @Operation(description = "Fetch custom data bin counts by study view filter") - @ApiResponse(responseCode = "200", description = "OK", - content = @Content(array = @ArraySchema(schema = @Schema(implementation = ClinicalDataBin.class)))) - public ResponseEntity> fetchCustomDataBinCounts( - @Parameter(description = "Method for data binning") - @RequestParam(defaultValue = "DYNAMIC") DataBinMethod dataBinMethod, - @Parameter(required = true, description = "Clinical data bin count filter") - @Valid @RequestBody(required = false) ClinicalDataBinCountFilter clinicalDataBinCountFilter, - @Parameter(hidden = true) // prevent reference to this attribute in the swagger-ui interface - @RequestAttribute(required = false, value = "involvedCancerStudies") Collection involvedCancerStudies, - @Parameter(hidden = true) // prevent reference to this attribute in the swagger-ui interface. this attribute is needed for the @PreAuthorize tag above. - @Valid @RequestAttribute(required = false, value = "interceptedClinicalDataBinCountFilter") ClinicalDataBinCountFilter interceptedClinicalDataBinCountFilter - ) { - List customDataBins = basicDataBinner.getDataBins( - dataBinMethod, - interceptedClinicalDataBinCountFilter, - true - ); - - return new ResponseEntity<>(customDataBins, HttpStatus.OK); - } - - @Hidden // should unhide when we remove legacy controller - @PreAuthorize("hasPermission(#involvedCancerStudies, 'Collection', T(org.cbioportal.legacy.utils.security.AccessLevel).READ)") - @RequestMapping(value = "/column-store/genomic-data-bin-counts/fetch", - consumes = MediaType.APPLICATION_JSON_VALUE, method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE) - @ApiResponse(responseCode = "200", description = "OK", - content = @Content(array = @ArraySchema(schema = @Schema(implementation = GenomicDataBin.class)))) - public ResponseEntity> fetchGenomicDataBinCounts( - @RequestParam(defaultValue = "DYNAMIC") DataBinMethod dataBinMethod, - @RequestBody(required = false) GenomicDataBinCountFilter genomicDataBinCountFilter, - @RequestAttribute(required = false, value = "involvedCancerStudies") Collection involvedCancerStudies, - @RequestAttribute(required = false, value = "interceptedGenomicDataBinCountFilter") GenomicDataBinCountFilter interceptedGenomicDataBinCountFilter - ) { - List genomicDataBins = basicDataBinner.getDataBins( - dataBinMethod, - interceptedGenomicDataBinCountFilter, - true - ); - return new ResponseEntity<>(genomicDataBins, HttpStatus.OK); - } - - @Hidden // should unhide when we remove legacy controller - @PreAuthorize("hasPermission(#involvedCancerStudies, 'Collection', T(org.cbioportal.legacy.utils.security.AccessLevel).READ)") - @RequestMapping(value = "/column-store/generic-assay-data-bin-counts/fetch", - consumes = MediaType.APPLICATION_JSON_VALUE, method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE) - @ApiResponse(responseCode = "200", description = "OK", - content = @Content(array = @ArraySchema(schema = @Schema(implementation = GenericAssayDataBin.class)))) - public ResponseEntity> fetchGenericAssayDataBinCounts( - @RequestParam(defaultValue = "DYNAMIC") DataBinMethod dataBinMethod, - @RequestBody(required = false) GenericAssayDataBinCountFilter genericAssayDataBinCountFilter, - @RequestAttribute(required = false, value = "involvedCancerStudies") Collection involvedCancerStudies, - @RequestAttribute(required = false, value = "interceptedGenericAssayDataBinCountFilter") GenericAssayDataBinCountFilter interceptedGenericAssayDataBinCountFilter - ) { - List genericAssayDataBins = basicDataBinner.getDataBins( - dataBinMethod, - interceptedGenericAssayDataBinCountFilter, - true - ); - return new ResponseEntity<>(genericAssayDataBins, HttpStatus.OK); - } -} diff --git a/src/main/java/org/cbioportal/legacy/web/columnar/util/ClinicalDataXyPlotUtil.java b/src/main/java/org/cbioportal/legacy/web/columnar/util/ClinicalDataXyPlotUtil.java index 5c75cf806a6..a0dd1d7bf00 100644 --- a/src/main/java/org/cbioportal/legacy/web/columnar/util/ClinicalDataXyPlotUtil.java +++ b/src/main/java/org/cbioportal/legacy/web/columnar/util/ClinicalDataXyPlotUtil.java @@ -8,7 +8,7 @@ import java.util.Map; import java.util.stream.Collectors; import java.util.stream.Stream; - +@Deprecated(forRemoval = true) public class ClinicalDataXyPlotUtil { public static List combineClinicalDataForXyPlot( List sampleClinicalDataList, diff --git a/src/main/java/org/cbioportal/legacy/web/columnar/util/CustomDataFilterUtil.java b/src/main/java/org/cbioportal/legacy/web/columnar/util/CustomDataFilterUtil.java index 786c695e5f3..cf00524afa9 100644 --- a/src/main/java/org/cbioportal/legacy/web/columnar/util/CustomDataFilterUtil.java +++ b/src/main/java/org/cbioportal/legacy/web/columnar/util/CustomDataFilterUtil.java @@ -24,7 +24,7 @@ import java.util.function.Function; import java.util.stream.Collectors; import java.util.stream.Stream; - +@Deprecated(forRemoval = true) @Component public class CustomDataFilterUtil { private final StudyViewFilterUtil studyViewFilterUtil; diff --git a/src/main/java/org/cbioportal/legacy/web/columnar/util/NewClinicalDataBinUtil.java b/src/main/java/org/cbioportal/legacy/web/columnar/util/NewClinicalDataBinUtil.java index 8ea39ca19da..7d63bc4c931 100644 --- a/src/main/java/org/cbioportal/legacy/web/columnar/util/NewClinicalDataBinUtil.java +++ b/src/main/java/org/cbioportal/legacy/web/columnar/util/NewClinicalDataBinUtil.java @@ -18,7 +18,7 @@ import java.util.Map; import static java.util.Collections.emptyList; - +@Deprecated(forRemoval = true) public class NewClinicalDataBinUtil { public static StudyViewFilter removeSelfFromFilter(ClinicalDataBinCountFilter dataBinCountFilter) { List attributes = dataBinCountFilter.getAttributes(); diff --git a/src/main/java/org/cbioportal/legacy/web/columnar/util/NewStudyViewFilterUtil.java b/src/main/java/org/cbioportal/legacy/web/columnar/util/NewStudyViewFilterUtil.java index d42bb7e8786..8edd9e8d359 100644 --- a/src/main/java/org/cbioportal/legacy/web/columnar/util/NewStudyViewFilterUtil.java +++ b/src/main/java/org/cbioportal/legacy/web/columnar/util/NewStudyViewFilterUtil.java @@ -2,14 +2,51 @@ import org.cbioportal.legacy.web.parameter.ClinicalDataFilter; +import org.cbioportal.legacy.web.parameter.MutationOption; +import org.cbioportal.legacy.web.parameter.SampleIdentifier; +import org.cbioportal.legacy.web.parameter.StudyViewFilter; import java.util.List; +@Deprecated(forRemoval = true) +public abstract class NewStudyViewFilterUtil { -public class NewStudyViewFilterUtil { + private NewStudyViewFilterUtil() {} public static void removeClinicalDataFilter(String attributeId, List dataFilterList ) { if (dataFilterList != null) { dataFilterList.removeIf(f -> f.getAttributeId().equals(attributeId)); } } + + public static void removeSelfFromGenomicDataFilter(String hugoGeneSymbol, String profileType, + StudyViewFilter studyViewFilter) { + if (studyViewFilter != null && studyViewFilter.getGenomicDataFilters() != null) { + studyViewFilter.getGenomicDataFilters().removeIf(f -> + f.getHugoGeneSymbol().equals(hugoGeneSymbol) && f.getProfileType().equals(profileType) + ); + } + } + + public static void removeSelfFromGenericAssayFilter(String stableId, StudyViewFilter studyViewFilter) { + if (studyViewFilter != null && studyViewFilter.getGenericAssayDataFilters() != null) { + studyViewFilter.getGenericAssayDataFilters().removeIf(f -> f.getStableId().equals(stableId)); + } + } + + public static void removeSelfFromMutationDataFilter(String hugoGeneSymbol, String profileType, + MutationOption categorization, StudyViewFilter studyViewFilter) { + if (studyViewFilter != null && studyViewFilter.getMutationDataFilters() != null) { + studyViewFilter.getMutationDataFilters().removeIf(f -> + f.getHugoGeneSymbol().equals(hugoGeneSymbol) && + f.getProfileType().equals(profileType) && + f.getCategorization().equals(categorization) + ); + } + } + public static SampleIdentifier buildSampleIdentifier(String studyId, String sampleId) { + SampleIdentifier sampleIdentifier = new SampleIdentifier(); + sampleIdentifier.setStudyId(studyId); + sampleIdentifier.setSampleId(sampleId); + return sampleIdentifier; + } } diff --git a/src/main/java/org/cbioportal/legacy/web/parameter/CategorizedGenericAssayDataCountFilter.java b/src/main/java/org/cbioportal/legacy/web/parameter/CategorizedGenericAssayDataCountFilter.java index f46ff86da14..0e160c6ea25 100644 --- a/src/main/java/org/cbioportal/legacy/web/parameter/CategorizedGenericAssayDataCountFilter.java +++ b/src/main/java/org/cbioportal/legacy/web/parameter/CategorizedGenericAssayDataCountFilter.java @@ -1,13 +1,25 @@ package org.cbioportal.legacy.web.parameter; +import org.cbioportal.legacy.model.MolecularProfile; +import org.cbioportal.legacy.persistence.enums.DataSource; +import org.springframework.lang.Nullable; + import java.util.List; +import java.util.Map; +// TODO Remove public final class CategorizedGenericAssayDataCountFilter { public static Builder getBuilder() { return new Builder(); } + public static Builder getBuilder(@Nullable Map> genericAssayProfilesMap, StudyViewFilter studyViewFilter) { + if (genericAssayProfilesMap == null) { + return new Builder(); + } + return new Builder(genericAssayProfilesMap, studyViewFilter); + } private final List sampleNumericalGenericAssayDataFilters; private final List sampleCategoricalGenericAssayDataFilters; private final List patientNumericalGenericAssayDataFilters; @@ -45,6 +57,41 @@ private Builder(){ } + private Builder(Map> genericAssayProfilesMap, StudyViewFilter studyViewFilter){ + if ((studyViewFilter.getGenericAssayDataFilters() == null || genericAssayProfilesMap.isEmpty())) { + return ; + } + + // No BINARY in the database yet + if (genericAssayProfilesMap.containsKey(DataSource.SAMPLE)) { + List sampleNumericalProfileTypes = genericAssayProfilesMap.get(DataSource.SAMPLE) + .stream().filter(profile -> profile.getDatatype().equals("LIMIT-VALUE")) + .map(profile -> profile.getStableId().replace(profile.getCancerStudyIdentifier() + "_", "")) + .toList(); + sampleNumericalGenericAssayDataFilters = studyViewFilter.getGenericAssayDataFilters().stream() + .filter(genericAssayDataFilter -> sampleNumericalProfileTypes.contains(genericAssayDataFilter.getProfileType())) + .toList(); + List sampleCategoricalProfileTypes = genericAssayProfilesMap.get(DataSource.SAMPLE) + .stream().filter(profile -> profile.getDatatype().equals("CATEGORICAL") || profile.getDatatype().equals("BINARY")) + .map(profile -> profile.getStableId().replace(profile.getCancerStudyIdentifier() + "_", "")) + .toList(); + sampleCategoricalGenericAssayDataFilters = studyViewFilter.getGenericAssayDataFilters().stream() + .filter(genericAssayDataFilter -> sampleCategoricalProfileTypes.contains(genericAssayDataFilter.getProfileType())) + .toList(); + } + + // patient level profile only have categorical for now + if (genericAssayProfilesMap.containsKey(DataSource.PATIENT)) { + List patientCategoricalProfileTypes = genericAssayProfilesMap.get(DataSource.PATIENT) + .stream().filter(profile -> profile.getDatatype().equals("CATEGORICAL") || profile.getDatatype().equals("BINARY")) + .map(profile -> profile.getStableId().replace(profile.getCancerStudyIdentifier() + "_", "")) + .toList(); + patientCategoricalGenericAssayDataFilters = studyViewFilter.getGenericAssayDataFilters().stream() + .filter(genericAssayDataFilter -> patientCategoricalProfileTypes.contains(genericAssayDataFilter.getProfileType())) + .toList(); + } + } + public Builder setSampleCategoricalGenericAssayDataFilters(List sampleCategoricalGenericAssayDataFilters) { this.sampleCategoricalGenericAssayDataFilters = sampleCategoricalGenericAssayDataFilters; return this; diff --git a/src/main/java/org/cbioportal/legacy/web/parameter/StudyViewFilter.java b/src/main/java/org/cbioportal/legacy/web/parameter/StudyViewFilter.java index 61d3f7f5356..93d529b8d1c 100644 --- a/src/main/java/org/cbioportal/legacy/web/parameter/StudyViewFilter.java +++ b/src/main/java/org/cbioportal/legacy/web/parameter/StudyViewFilter.java @@ -1,8 +1,11 @@ package org.cbioportal.legacy.web.parameter; import java.io.Serializable; +import java.util.HashSet; import java.util.List; import java.util.Objects; +import java.util.Set; +import java.util.stream.Collectors; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonInclude.Include; @@ -98,6 +101,17 @@ public void setStudyIds(List studyIds) { this.studyIds = studyIds; } + public Set getUniqueStudyIds() { + Set uniqueStudyIds = new HashSet<>(); + if (sampleIdentifiers != null && !sampleIdentifiers.isEmpty()) { + uniqueStudyIds.addAll(sampleIdentifiers.stream().map(SampleIdentifier::getStudyId).collect(Collectors.toSet())); + } + if (studyIds != null && !studyIds.isEmpty()) { + uniqueStudyIds.addAll(studyIds); + } + return uniqueStudyIds; + } + public List getClinicalDataFilters() { return clinicalDataFilters; } diff --git a/src/main/java/org/cbioportal/legacy/web/util/InvolvedCancerStudyExtractorInterceptor.java b/src/main/java/org/cbioportal/legacy/web/util/InvolvedCancerStudyExtractorInterceptor.java index 9cc19225fe2..2ff92a20a2c 100644 --- a/src/main/java/org/cbioportal/legacy/web/util/InvolvedCancerStudyExtractorInterceptor.java +++ b/src/main/java/org/cbioportal/legacy/web/util/InvolvedCancerStudyExtractorInterceptor.java @@ -145,7 +145,7 @@ public class InvolvedCancerStudyExtractorInterceptor implements HandlerIntercept // reset this to 'String requestPathInfo = request.getPathInfo();' String requestPathInfo = request.getPathInfo() == null? request.getServletPath() : request.getPathInfo(); requestPathInfo = requestPathInfo.replaceFirst("^/api", ""); - requestPathInfo = StringUtils.removeStart(requestPathInfo, "/column-store"); + //requestPathInfo = StringUtils.removeStart(requestPathInfo, "/column-store"); if (requestPathInfo.equals(PATIENT_FETCH_PATH)) { return extractAttributesFromPatientFilter(request); } else if (requestPathInfo.equals(SAMPLE_FETCH_PATH)) { diff --git a/src/main/java/org/cbioportal/shared/DataFilterUtil.java b/src/main/java/org/cbioportal/shared/DataFilterUtil.java new file mode 100644 index 00000000000..a0733f7e8c7 --- /dev/null +++ b/src/main/java/org/cbioportal/shared/DataFilterUtil.java @@ -0,0 +1,132 @@ +package org.cbioportal.shared; + +import org.cbioportal.legacy.web.parameter.DataFilter; +import org.cbioportal.legacy.web.parameter.DataFilterValue; + +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.List; + +public abstract class DataFilterUtil { + private DataFilterUtil(){} + + /** + * Merge the range of numerical bins in DataFilters to reduce the number of scans that runs on the database when filtering. + */ + public static List mergeDataFilters(List filters) { + // this should throw error or move to all binning endpoints in the future for input validation + if (!areValidFilters(filters)) { + return filters; + } + + boolean hasNumericalValue = false; + List mergedDataFilters = new ArrayList<>(); + + for (T filter : filters) { + List mergedValues = new ArrayList<>(); + List nonNumericalValues = new ArrayList<>(); + + // record the start and end of current merging range + BigDecimal mergedStart = null; + BigDecimal mergedEnd = null; + // for each value + for (DataFilterValue dataFilterValue : filter.getValues()) { + // if it is non-numerical, leave it as is + if (dataFilterValue.getValue() != null) { + nonNumericalValues.add(dataFilterValue); + continue; + } + // else it is numerical so start merging process + hasNumericalValue = true; + BigDecimal start = dataFilterValue.getStart(); + BigDecimal end = dataFilterValue.getEnd(); + + // if current merging range is null, we take current bin's range + if (mergedStart == null && mergedEnd == null) { + mergedStart = start; + mergedEnd = end; + } + // else we already has a merging range, we check if this one is consecutive of our range + else if (mergedEnd.equals(start)) { + // if true, we expand our range + mergedEnd = end; + } + else { + // otherwise it's a gap, so we save our current range first, and then use current bin to start the next range + mergedValues.add(new DataFilterValue(mergedStart, mergedEnd)); + mergedStart = start; + mergedEnd = end; + } + } + + // in the end we need to save the final range, but if everything is non-numerical then no need to + if (hasNumericalValue) { + mergedValues.add(new DataFilterValue(mergedStart, mergedEnd)); + } + mergedValues.addAll(nonNumericalValues); + filter.setValues(mergedValues); + mergedDataFilters.add(filter); + } + + return mergedDataFilters; + } + + public static boolean areValidFilters(List filters) { + if (filters == null || filters.isEmpty()) { + return false; + } + + for (T filter : filters) { + if (!isValidFilter(filter)) { + return false; + } + } + return true; + } + + private static boolean isValidFilter(T filter) { + if (filter == null || filter.getValues() == null || filter.getValues().isEmpty()) { + return false; + } + + BigDecimal start = null; + BigDecimal end = null; + for (DataFilterValue value : filter.getValues()) { + if (!validateDataFilterValue(value, start, end)) { + return false; + } + // update start and end values to check next bin range + if (value.getStart() != null) { + start = value.getStart(); + } + if (value.getEnd() != null) { + end = value.getEnd(); + } + } + return true; + } + + private static boolean validateDataFilterValue(DataFilterValue value, BigDecimal lastStart, BigDecimal lastEnd) { + // non-numerical value should not have numerical value + if (value.getValue() != null) { + return value.getStart() == null && value.getEnd() == null; + } + + // check if start < end + if (value.getStart() != null && value.getEnd() != null + && value.getStart().compareTo(value.getEnd()) >= 0) { + return false; + } + + // check if start stays increasing and no overlapping + if (value.getStart() != null + && ((lastStart != null && lastStart.compareTo(value.getStart()) >= 0) + || (lastEnd != null && value.getStart().compareTo(lastEnd) < 0))) { + return false; + } + + // check if end stays increasing + return value.getEnd() == null || lastEnd == null + || lastEnd.compareTo(value.getEnd()) < 0; + } +} diff --git a/src/main/java/org/cbioportal/shared/util/ClinicalDataCountItemUtil.java b/src/main/java/org/cbioportal/shared/util/ClinicalDataCountItemUtil.java new file mode 100644 index 00000000000..a502a98b50d --- /dev/null +++ b/src/main/java/org/cbioportal/shared/util/ClinicalDataCountItemUtil.java @@ -0,0 +1,22 @@ +package org.cbioportal.shared.util; + +import org.cbioportal.legacy.model.ClinicalDataCount; +import org.cbioportal.legacy.model.ClinicalDataCountItem; +import org.cbioportal.legacy.service.util.StudyViewColumnarServiceUtil; + +import java.util.List; +import java.util.stream.Collectors; + +public abstract class ClinicalDataCountItemUtil { + private ClinicalDataCountItemUtil() {} + + public static List generateDataCountItems(List dataCounts){ + return dataCounts.stream().collect(Collectors.groupingBy(ClinicalDataCount::getAttributeId)) + .entrySet().parallelStream().map(e -> { + ClinicalDataCountItem item = new ClinicalDataCountItem(); + item.setAttributeId(e.getKey()); + item.setCounts(StudyViewColumnarServiceUtil.normalizeDataCounts(e.getValue())); + return item; + }).toList(); + } +} diff --git a/src/main/resources/mappers/clickhouse/alteration/ClickhouseAlterationFilterMapper.xml b/src/main/resources/mappers/clickhouse/alteration/ClickhouseAlterationFilterMapper.xml new file mode 100644 index 00000000000..b320f223b17 --- /dev/null +++ b/src/main/resources/mappers/clickhouse/alteration/ClickhouseAlterationFilterMapper.xml @@ -0,0 +1,120 @@ + + + + + + + NULL + + AND + lower(genomic_event_derived.mutation_type) + + + NOT IN + + + IN + + + + lower(#{type}) + + + + + + + + + + NULL + + AND + genomic_event_derived.cna_alteration IN + + #{type} + + + + + + + + + + + + OR + lower(genomic_event_derived.mutation_status) LIKE '%germline%' + + + OR + lower(genomic_event_derived.mutation_status) = 'somatic' + + + OR + lower(genomic_event_derived.mutation_status) != 'somatic' AND lower(genomic_event_derived.mutation_status) NOT LIKE '%germline%' + + + + + AND NULL + + + + + + + + + + + + + OR lower(driver_filter) = 'putative_driver' + + + OR lower(driver_filter) = 'putative_passenger' + + + OR driver_filter IS NULL + OR lower(driver_filter) IN ('unknown', 'na', '') + + + + + AND NULL + + + + + + + + + + + + + + OR driver_tiers_filter IN + + #{item} + + + + OR driver_tiers_filter IS NULL + OR lower(driver_tiers_filter) IN ('', 'na', 'unknown') + + + + + AND NULL + + + + + + + \ No newline at end of file diff --git a/src/main/resources/mappers/clickhouse/alteration/ClickhouseAlterationMapper.xml b/src/main/resources/mappers/clickhouse/alteration/ClickhouseAlterationMapper.xml new file mode 100644 index 00000000000..06c9d462cc8 --- /dev/null +++ b/src/main/resources/mappers/clickhouse/alteration/ClickhouseAlterationMapper.xml @@ -0,0 +1,134 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/main/resources/mappers/clickhouse/cancerstudy/CancerStudyMapper.xml b/src/main/resources/mappers/clickhouse/cancerstudy/CancerStudyMapper.xml index fbdc8b4c720..970196a7443 100644 --- a/src/main/resources/mappers/clickhouse/cancerstudy/CancerStudyMapper.xml +++ b/src/main/resources/mappers/clickhouse/cancerstudy/CancerStudyMapper.xml @@ -137,7 +137,7 @@ + type="org.cbioportal.domain.cancerstudy.CancerStudyMetadata"> @@ -164,12 +164,12 @@ - + + type="org.cbioportal.domain.cancerstudy.CancerStudyMetadata"> @@ -183,11 +183,11 @@ - + - + @@ -196,4 +196,13 @@ + + \ No newline at end of file diff --git a/src/main/resources/mappers/clickhouse/clinical_attributes/ClickhouseClinicalAttributesMapper.xml b/src/main/resources/mappers/clickhouse/clinical_attributes/ClickhouseClinicalAttributesMapper.xml new file mode 100644 index 00000000000..7d1df775ed5 --- /dev/null +++ b/src/main/resources/mappers/clickhouse/clinical_attributes/ClickhouseClinicalAttributesMapper.xml @@ -0,0 +1,33 @@ + + + + + + + + + \ No newline at end of file diff --git a/src/main/resources/mappers/clickhouse/clinical_data/ClickhouseClinicalDataMapper.xml b/src/main/resources/mappers/clickhouse/clinical_data/ClickhouseClinicalDataMapper.xml new file mode 100644 index 00000000000..d4aa6b46be7 --- /dev/null +++ b/src/main/resources/mappers/clickhouse/clinical_data/ClickhouseClinicalDataMapper.xml @@ -0,0 +1,123 @@ + + + + + + + + + + + + + + ( + WITH clinical_data_query AS ( + SELECT + attribute_name AS attributeId, + attribute_value AS value, + cast(count(*) AS INTEGER) as count + FROM clinical_data_derived + + type='${type}' + AND + + + + != 'NA' + AND + + + + + + + + + AND attribute_name IN + + #{attributeId} + + + GROUP BY attribute_name, value ), + clinical_data_sum AS (SELECT attributeId, sum(count) AS sum FROM clinical_data_query GROUP BY attributeId) + + SELECT * FROM clinical_data_query + UNION ALL + SELECT attributeId, + 'NA' AS value, + (( + + + + + + + + + ) - clinical_data_sum.sum) AS count + FROM clinical_data_sum + + count > 0 + + ) + + + + + + + + + + + + \ No newline at end of file diff --git a/src/main/resources/mappers/clickhouse/clinical_event/ClickhouseClinicalEventMapper.xml b/src/main/resources/mappers/clickhouse/clinical_event/ClickhouseClinicalEventMapper.xml new file mode 100644 index 00000000000..b3df3a75def --- /dev/null +++ b/src/main/resources/mappers/clickhouse/clinical_event/ClickhouseClinicalEventMapper.xml @@ -0,0 +1,17 @@ + + + + + + + \ No newline at end of file diff --git a/src/main/resources/mappers/clickhouse/generic_assay/GenericAssayMapper.xml b/src/main/resources/mappers/clickhouse/generic_assay/GenericAssayMapper.xml new file mode 100644 index 00000000000..e82fa21273e --- /dev/null +++ b/src/main/resources/mappers/clickhouse/generic_assay/GenericAssayMapper.xml @@ -0,0 +1,157 @@ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/main/resources/mappers/clickhouse/genomic_data/ClickhouseGenomicDataMapper.xml b/src/main/resources/mappers/clickhouse/genomic_data/ClickhouseGenomicDataMapper.xml new file mode 100644 index 00000000000..9b257688c23 --- /dev/null +++ b/src/main/resources/mappers/clickhouse/genomic_data/ClickhouseGenomicDataMapper.xml @@ -0,0 +1,190 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/main/resources/mappers/clickhouse/patient/ClickhousePatientMapper.xml b/src/main/resources/mappers/clickhouse/patient/ClickhousePatientMapper.xml new file mode 100644 index 00000000000..7486f242023 --- /dev/null +++ b/src/main/resources/mappers/clickhouse/patient/ClickhousePatientMapper.xml @@ -0,0 +1,34 @@ + + + + + + + SELECT count(distinct patient_unique_id) as count + FROM sample_derived + + + + + + + + + + \ No newline at end of file diff --git a/src/main/resources/mappers/clickhouse/sample/ClickhouseSampleMapper.xml b/src/main/resources/mappers/clickhouse/sample/ClickhouseSampleMapper.xml new file mode 100644 index 00000000000..2ff1ff4dc0b --- /dev/null +++ b/src/main/resources/mappers/clickhouse/sample/ClickhouseSampleMapper.xml @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + + + + SELECT count(distinct sample_unique_id) as count + FROM sample_derived + + + + + \ No newline at end of file diff --git a/src/main/resources/mappers/clickhouse/studyview/ClickhouseStudyViewFilterMapper.xml b/src/main/resources/mappers/clickhouse/studyview/ClickhouseStudyViewFilterMapper.xml new file mode 100644 index 00000000000..9028134e052 --- /dev/null +++ b/src/main/resources/mappers/clickhouse/studyview/ClickhouseStudyViewFilterMapper.xml @@ -0,0 +1,806 @@ + + + + + + + + INTERSECT + SELECT sample_unique_id + FROM sample_derived + WHERE cancer_study_identifier IN + + #{studyId} + + + + + INTERSECT + -- case list filtering allows both UNION (OR) and INTERSECTION (AND) LOGIC + -- caseLists is an array of arrays wherein the top level is INTERSECTION + -- AND THE INTERNAL ARRAYS ARE UNION (OR) + SELECT * FROM ( + + SELECT sample_unique_id + FROM sample_list_list sll + LEFT JOIN sample_derived s ON sll.sample_id=s.internal_id + LEFT JOIN sample_list sl on sll.list_id=sl.list_id + WHERE + + sl.stable_id LIKE concat('%_', #{list}) + + + ) + + + + INTERSECT + SELECT * FROM ( + + SELECT sample_derived.sample_unique_id + FROM sample_profile GYMP + JOIN genetic_profile gp ON sample_profile.genetic_profile_id = gp.genetic_profile_id + JOIN cancer_study cs ON gp.cancer_study_id = cs.cancer_study_id + JOIN sample_derived on sample_profile.sample_id = sample_derived.internal_id + + + sample_derived.cancer_study_identifier IN + + #{studyId} + + AND + + + gp.stable_id=concat(#{studyId}, '_', #{genomicProfileId}) + + + + + + ) + + + + + INTERSECT + SELECT sample_unique_id + FROM sample_derived + WHERE sample_unique_id IN + ( + #{filteredSampleIdentifiers, typeHandler=org.apache.ibatis.type.ArrayTypeHandler} + ) + + + INTERSECT + SELECT sample_unique_id + FROM sample_derived + WHERE + + + + AND + ( + + + + sample_unique_id IN ( + '', + + + #{sampleIdentifier.uniqueSampleId} + + + ) + + + + + OR + sample_unique_id NOT IN ( + '', + + + #{sampleIdentifier.uniqueSampleId} + + + ) + + + ) + + + + + + + SELECT sample_unique_id + FROM genomic_event_derived + + genetic_profile_stable_id IN + + #{molecularProfileId} + + + + hugo_gene_symbol = #{geneFilterQuery.hugoGeneSymbol} + + + cna_alteration = #{alteration.code} + + + + + + + + + + + + + + + + + + + + ( + + + + + + + + + ) + + + + + + + + + + + + + + + + + + + + + + + + + + SELECT concat(ced.cancer_study_identifier, '_', ced.sample_id) AS sample_unique_id + FROM ( + + SELECT + ced.value AS sample_id, + ced.patient_unique_id AS patient_unique_id, + min(ced.start_date) AS time_taken, + ced.cancer_study_identifier AS cancer_study_identifier + FROM clinical_event_derived ced + + key = 'SAMPLE_ID' + AND (event_type ILIKE 'Sample Acquisition' OR event_type ILIKE 'SPECIMEN') + + GROUP BY patient_unique_id, ced.value, cancer_study_identifier + ) ced + INNER JOIN ( + + SELECT + patient_unique_id, + value AS treatment, + argMin(start_date, start_date) AS treatment_time_taken + FROM clinical_event_derived + WHERE lower(event_type) = 'treatment' + AND key = 'AGENT' + GROUP BY patient_unique_id, value + ) ced_inner ON ced_inner.patient_unique_id = ced.patient_unique_id + + + ced_inner.treatment = #{sampleTreatmentFilter.treatment} + + + AND ced.time_taken <= ced_inner.treatment_time_taken + + + AND ced.time_taken > ced_inner.treatment_time_taken + + + + + GROUP BY patient_unique_id, ced.sample_id, ced.time_taken, ced.cancer_study_identifier, ced_inner.treatment, ced_inner.treatment_time_taken + + + + + + SELECT sample_unique_id + FROM sample_derived + WHERE patient_unique_id in ( + SELECT patient_unique_id + FROM clinical_event_derived + + + event_type = #{dataFilterValue.value} + + + ) + + + + + + SELECT sample_unique_id + FROM sample_derived + WHERE patient_unique_id in ( + SELECT patient_unique_id + FROM clinical_event_derived + + lower(event_type) = 'treatment' + AND key = 'AGENT' + AND value = #{patientTreatmentFilter.treatment} + + + ) + + + + + + + + + AND + + + + + + + AND + ${attribute_value} ILIKE #{dataFilterValue.value} + + + + AND match(${attribute_value}, '^>?=?[-+]?[0-9]*[.,]?[0-9]+$') + + + AND match(${attribute_value}, '^<?=?[-+]?[0-9]*[.,]?[0-9]+$') + + + AND match(${attribute_value}, '^[-+]?[0-9]*[.,]?[0-9]+$') + + + + + + AND abs( + minus( + + + , + cast(#{dataFilterValue.start} as float) + ) + ) < exp(-11) + + + + AND + + + > cast(#{dataFilterValue.start} as float) + + + AND + + + <= cast(#{dataFilterValue.end} as float) + + + + + + + + + + + + ( + + + + + + + + + + + + + + + + + + UNION DISTINCT + SELECT sample_unique_id + FROM sample_derived + WHERE patient_unique_id in ( + + + + + + + + + + + + + + + + + ) + ) + + + + + + + + + + + + + + + + + + + ( + + + SELECT DISTINCT ${unique_id} + FROM sample_derived sd + LEFT JOIN () AS categorical_clinical_data + ON + + + sd.sample_unique_id = categorical_clinical_data.sample_unique_id + + + sd.patient_unique_id = categorical_clinical_data.patient_unique_id + + + WHERE empty(attribute_value) + AND EXISTS () + + + + + UNION ALL + + + + + SELECT ${unique_id} + FROM ${table_name} + WHERE attribute_name = #{clinicalDataFilter.attributeId} AND + type='${type}' + AND + + + + + + ) + + + + SELECT sample_unique_id, patient_unique_id, attribute_value + FROM clinical_data_derived + WHERE attribute_name = #{clinicalDataFilter.attributeId} AND type='${type}' + + AND cancer_study_identifier IN + + #{studyId} + + + + + + ( + SELECT ${unique_id} + FROM sample_derived sd + LEFT JOIN () AS categorical_clinical_data + ON + + + sd.sample_unique_id = categorical_clinical_data.sample_unique_id + + + sd.patient_unique_id = categorical_clinical_data.patient_unique_id + + + WHERE + + + + empty(attribute_value) + OR + + + = 'NA' + + + attribute_value ILIKE #{dataFilterValue.value} + + + + AND EXISTS () + ) + + + + + + + + + + + + + + + + + + + SELECT DISTINCT sd.sample_unique_id + FROM sample_derived sd + LEFT JOIN () AS genomic_numerical_query ON sd.sample_unique_id = genomic_numerical_query.sample_unique_id + WHERE alteration_value IS null + + + + UNION ALL + + + + SELECT DISTINCT sample_unique_id + FROM () AS genomic_numerical_query + WHERE + + + + + + + + + SELECT sample_unique_id, alteration_value + FROM genetic_alteration_derived + WHERE profile_type = #{genomicDataFilter.profileType} + AND hugo_gene_symbol = #{genomicDataFilter.hugoGeneSymbol} + + AND cancer_study_identifier IN + + #{studyId} + + + + + + + + ( + + + + ) + + + + + ( + + + + ) + + + -- patient level profile only have categorical for now + + + ( + + + + ) + + + + + + SELECT sample_unique_id, patient_unique_id, value, datatype + FROM generic_assay_data_derived + WHERE profile_type = #{genericAssayDataFilter.profileType} + AND entity_stable_id = #{genericAssayDataFilter.stableId} + + + + + + + + + + + + + + + + + + + + SELECT DISTINCT sd.sample_unique_id + FROM sample_derived sd + LEFT JOIN () AS generic_numerical_query ON sd.sample_unique_id = generic_numerical_query.sample_unique_id + WHERE datatype = 'LIMIT-VALUE' + AND value IS null OR + + + = 'NA' + + + + UNION ALL + + + + SELECT DISTINCT sample_unique_id + FROM () AS generic_numerical_query + WHERE + datatype = 'LIMIT-VALUE' + AND + + + != 'NA' + AND + + + + + + + + + SELECT sample_unique_id + FROM sample_derived sd + LEFT JOIN () AS generic_assay_query + ON + + + sd.sample_unique_id = generic_assay_query.sample_unique_id + + + sd.patient_unique_id = generic_assay_query.patient_unique_id + + + + datatype != 'LIMIT-VALUE' + + + + value IS null OR + + + = 'NA' + + + value ILIKE #{dataFilterValue.value} + + + + + + + + + + WITH all_samples AS ( + SELECT sample_unique_id + FROM sample_derived + WHERE cancer_study_identifier IN + + + #{studyId} + + + ), + profiled_samples AS ( + SELECT DISTINCT sgp.sample_unique_id + FROM sample_to_gene_panel_derived sgp + JOIN gene_panel_to_gene_derived gpg ON sgp.gene_panel_id = gpg.gene_panel_id + WHERE + + cancer_study_identifier IN + + #{studyId} + + AND + + gpg.gene = #{mutationDataFilter.hugoGeneSymbol} + AND sgp.alteration_type = 'MUTATION_EXTENDED' + ), + mutated_samples AS ( + SELECT DISTINCT sample_unique_id + FROM genomic_event_derived + WHERE + + cancer_study_identifier IN + + #{studyId} + + AND + + hugo_gene_symbol = #{mutationDataFilter.hugoGeneSymbol} + AND variant_type = 'mutation' + ) + SELECT DISTINCT sample_unique_id + FROM + + + + SELECT sample_unique_id FROM mutated_samples + + + SELECT sample_unique_id FROM profiled_samples + WHERE sample_unique_id NOT IN (SELECT sample_unique_id FROM mutated_samples) + + + SELECT sample_unique_id FROM all_samples + WHERE sample_unique_id NOT IN (SELECT sample_unique_id FROM profiled_samples) + + + + + + + + SELECT DISTINCT sample_unique_id + FROM genomic_event_derived + WHERE hugo_gene_symbol = #{mutationDataFilter.hugoGeneSymbol} + AND variant_type = 'mutation' + AND mutation_type IN + + #{dataFilterValue.value} + + + + + + + + WITH cna_query AS ( + SELECT sample_unique_id as sampleUniqueId, alteration_value + FROM genetic_alteration_derived + WHERE profile_type = #{genomicDataFilter.profileType} + AND hugo_gene_symbol = #{genomicDataFilter.hugoGeneSymbol} + + AND cancer_study_identifier IN + + #{studyId} + + + ) + SELECT DISTINCT sd.sample_unique_id + + FROM sample_derived sd + LEFT JOIN cna_query ON sd.sample_unique_id = cna_query.sampleUniqueId + WHERE + + cancer_study_identifier IN + + #{studyId} + + AND + + + + + alteration_value IS null + + alteration_value == #{dataFilterValue.value} + + + + + + + multiIf( + -- This condition is to prevent casting non numerical values to float + NOT match(${attribute_value}, '^[><]?=?[-+]?[0-9]*[.,]?[0-9]+$'), + NULL, + (startsWith(${attribute_value}, '<=') OR startsWith(${attribute_value}, '>=')), + cast(substr(${attribute_value}, 3) as float), + startsWith(${attribute_value}, '<'), + cast(substr(${attribute_value}, 2) as float) - exp(-10), + startsWith(${attribute_value}, '>'), + cast(substr(${attribute_value}, 2) as float) + exp(-10), + cast(${attribute_value} as float) + ) + + + + + ${attribute_value}='' + OR upperUTF8(${attribute_value})='NA' + OR upperUTF8(${attribute_value})='NAN' + OR upperUTF8(${attribute_value})='N/A' + + + + multiIf( + + + , + 'NA', + ${attribute_value} + ) + + + + patient_unique_id in ( + SELECT patient_unique_id + FROM sample_derived + + sample_unique_id IN () + + ) + + + + sample_unique_id IN () + + \ No newline at end of file diff --git a/src/main/resources/mappers/clickhouse/treatment/ClickhouseTreatmentMapper.xml b/src/main/resources/mappers/clickhouse/treatment/ClickhouseTreatmentMapper.xml new file mode 100644 index 00000000000..4f3ba5a1421 --- /dev/null +++ b/src/main/resources/mappers/clickhouse/treatment/ClickhouseTreatmentMapper.xml @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/test/java/org/cbioportal/cancerstudy/usecase/GetCancerStudyMetadataUseCaseTest.java b/src/test/java/org/cbioportal/cancerstudy/usecase/GetCancerStudyMetadataUseCaseTest.java index 771ae3b040e..86e8dfa8c86 100644 --- a/src/test/java/org/cbioportal/cancerstudy/usecase/GetCancerStudyMetadataUseCaseTest.java +++ b/src/test/java/org/cbioportal/cancerstudy/usecase/GetCancerStudyMetadataUseCaseTest.java @@ -1,6 +1,7 @@ package org.cbioportal.cancerstudy.usecase; -import org.cbioportal.cancerstudy.repository.CancerStudyRepository; +import org.cbioportal.domain.cancerstudy.repository.CancerStudyRepository; +import org.cbioportal.domain.cancerstudy.usecase.GetCancerStudyMetadataUseCase; import org.cbioportal.shared.SortAndSearchCriteria; import org.cbioportal.shared.enums.ProjectionType; import org.junit.Assert; diff --git a/src/test/java/org/cbioportal/legacy/persistence/mybatisclickhouse/AbstractTestcontainers.java b/src/test/java/org/cbioportal/infrastructure/repository/clickhouse/AbstractTestcontainers.java similarity index 95% rename from src/test/java/org/cbioportal/legacy/persistence/mybatisclickhouse/AbstractTestcontainers.java rename to src/test/java/org/cbioportal/infrastructure/repository/clickhouse/AbstractTestcontainers.java index fb1d8117aff..2b05d1282ea 100644 --- a/src/test/java/org/cbioportal/legacy/persistence/mybatisclickhouse/AbstractTestcontainers.java +++ b/src/test/java/org/cbioportal/infrastructure/repository/clickhouse/AbstractTestcontainers.java @@ -1,7 +1,6 @@ -package org.cbioportal.legacy.persistence.mybatisclickhouse; +package org.cbioportal.infrastructure.repository.clickhouse; import org.junit.BeforeClass; - import org.junit.ClassRule; import org.springframework.boot.test.util.TestPropertyValues; import org.springframework.context.ApplicationContextInitializer; @@ -32,6 +31,7 @@ public static class Initializer implements ApplicationContextInitializer Objects.equals(a.getHugoGeneSymbol(), "BRCA1")).findFirst(); + assert (testBrca1AlterationCount.isPresent()); + assertEquals(Integer.valueOf(5), testBrca1AlterationCount.get().getTotalCount()); + } + + @Test + public void getMutatedGenesWithAlterationFilter() { + StudyViewFilter studyViewFilter = new StudyViewFilter(); + studyViewFilter.setStudyIds(List.of(STUDY_TCGA_PUB)); + + // Create AlterationFilter + AlterationFilter alterationFilter = new AlterationFilter(); + Map mutationEventTypeFilterMap = new HashMap<>(); + mutationEventTypeFilterMap.put(MutationEventType.nonsense_mutation, Boolean.TRUE); + mutationEventTypeFilterMap.put(MutationEventType.other, Boolean.FALSE); + alterationFilter.setMutationEventTypes(mutationEventTypeFilterMap); + + var alterationCountByGenes = mapper.getMutatedGenes(StudyViewFilterFactory.make(studyViewFilter, null, studyViewFilter.getStudyIds(), null), + AlterationFilterHelper.build(alterationFilter)); + assertEquals(2, alterationCountByGenes.size()); + + AlterationFilter onlyMutationStatusFilter = new AlterationFilter(); + onlyMutationStatusFilter.setMutationEventTypes(new HashMap<>()); + onlyMutationStatusFilter.setIncludeGermline(false); + onlyMutationStatusFilter.setIncludeSomatic(false); + onlyMutationStatusFilter.setIncludeUnknownStatus(true); + + var alterationCountByGenes1 = mapper.getMutatedGenes(StudyViewFilterFactory.make(studyViewFilter, null, studyViewFilter.getStudyIds(), null), + AlterationFilterHelper.build(onlyMutationStatusFilter)); + assertEquals(1, alterationCountByGenes1.size()); + + AlterationFilter mutationTypeAndStatusFilter = new AlterationFilter(); + mutationTypeAndStatusFilter.setMutationEventTypes(mutationEventTypeFilterMap); + mutationTypeAndStatusFilter.setMutationEventTypes(new HashMap<>()); + mutationTypeAndStatusFilter.setIncludeGermline(false); + mutationTypeAndStatusFilter.setIncludeSomatic(false); + mutationTypeAndStatusFilter.setIncludeUnknownStatus(true); + + var alterationCountByGenes2 = mapper.getMutatedGenes(StudyViewFilterFactory.make(studyViewFilter, null, studyViewFilter.getStudyIds(), null), + AlterationFilterHelper.build(onlyMutationStatusFilter)); + assertEquals(1, alterationCountByGenes2.size()); + } + + @Test + public void getCnaGenes() { + StudyViewFilter studyViewFilter = new StudyViewFilter(); + studyViewFilter.setStudyIds(List.of(STUDY_TCGA_PUB)); + var alterationCountByGenes = mapper.getCnaGenes(StudyViewFilterFactory.make(studyViewFilter, null, + studyViewFilter.getStudyIds(), null), + AlterationFilterHelper.build(studyViewFilter.getAlterationFilter())); + assertEquals(3, alterationCountByGenes.size()); + + // Test cna count for akt1 + var testAKT1AlterationCount = alterationCountByGenes.stream().filter(a -> Objects.equals(a.getHugoGeneSymbol(), "AKT1")) + .mapToInt(c -> c.getTotalCount().intValue()) + .sum(); + assertEquals(3, testAKT1AlterationCount); + } + + @Test + public void getCnaGenesWithAlterationFilter() { + StudyViewFilter studyViewFilter = new StudyViewFilter(); + studyViewFilter.setStudyIds(List.of(STUDY_TCGA_PUB)); + + // Create AlterationFilter + AlterationFilter alterationFilter = new AlterationFilter(); + Map cnaEventTypeFilterMap = new HashMap<>(); + cnaEventTypeFilterMap.put(CNA.HOMDEL, false); + cnaEventTypeFilterMap.put(CNA.AMP, true); + alterationFilter.setCopyNumberAlterationEventTypes(cnaEventTypeFilterMap); + + var alterationCountByGenes = mapper.getCnaGenes(StudyViewFilterFactory.make(studyViewFilter, null, + studyViewFilter.getStudyIds(), null), + AlterationFilterHelper.build(alterationFilter)); + assertEquals(2, alterationCountByGenes.size()); + + // Test cna count for akt1 filtering for AMP + var testAKT1AlterationCount = alterationCountByGenes.stream().filter(a -> Objects.equals(a.getHugoGeneSymbol(), "AKT1")) + .mapToInt(c -> c.getTotalCount().intValue()) + .sum(); + assertEquals(2, testAKT1AlterationCount); + } + + @Test + public void getStructuralVariantGenes() { + StudyViewFilter studyViewFilter = new StudyViewFilter(); + studyViewFilter.setStudyIds(List.of(STUDY_TCGA_PUB, STUDY_ACC_TCGA)); + var alterationCountByGenes = mapper.getStructuralVariantGenes(StudyViewFilterFactory.make(studyViewFilter, null, + studyViewFilter.getStudyIds(), null), + AlterationFilterHelper.build(studyViewFilter.getAlterationFilter())); + assertEquals(8, alterationCountByGenes.size()); + + // Test sv count for eml4 which is in one study + var testeml4AlterationCount = alterationCountByGenes.stream().filter(a -> Objects.equals(a.getHugoGeneSymbol(), "eml4")) + .mapToInt(c -> c.getTotalCount().intValue()) + .sum(); + assertEquals(1, testeml4AlterationCount); + + // Test sv count for ncoa4 which is in both studies + var testncoa4AlterationCount = alterationCountByGenes.stream().filter(a -> Objects.equals(a.getHugoGeneSymbol(), "ncoa4")) + .mapToInt(c -> c.getTotalCount().intValue()) + .sum(); + assertEquals(3, testncoa4AlterationCount); + } + + @Test + public void getTotalProfiledCountsByGene() { + StudyViewFilter studyViewFilter = new StudyViewFilter(); + studyViewFilter.setStudyIds(List.of(STUDY_TCGA_PUB)); + + // Testing profiled counts on samples with gene panel data and WES for one study + var totalProfiledCountsForMutationsMap = mapper.getTotalProfiledCounts(StudyViewFilterFactory.make(studyViewFilter, null, studyViewFilter.getStudyIds(), null), + "MUTATION_EXTENDED", List.of()); + var totalProfiledCountsForCnaMap = mapper.getTotalProfiledCounts(StudyViewFilterFactory.make(studyViewFilter, null, studyViewFilter.getStudyIds(), null), + "COPY_NUMBER_ALTERATION", List.of()); + var sampleProfiledCountsForMutationsWithoutPanelDataMap = mapper.getSampleProfileCountWithoutPanelData(StudyViewFilterFactory.make(studyViewFilter, null, studyViewFilter.getStudyIds(), null), + "MUTATION_EXTENDED"); + var sampleProfiledCountsForCnaWithoutPanelDataMap = mapper.getSampleProfileCountWithoutPanelData(StudyViewFilterFactory.make(studyViewFilter, null, studyViewFilter.getStudyIds(), null), + "COPY_NUMBER_ALTERATION"); + + // Assert the count of genes with profiled cases for mutations + assertEquals(5, totalProfiledCountsForMutationsMap.size()); + // Assert the count of genes with profiled cases for CNA + assertEquals(5, totalProfiledCountsForCnaMap.size()); + // Assert the profiled counts for mutations without panel data (WES) + assertEquals(6, sampleProfiledCountsForMutationsWithoutPanelDataMap); + // Assert the profiled counts for CNA without panel data (WES) + assertEquals(11, sampleProfiledCountsForCnaWithoutPanelDataMap); + + // Assert the profiled counts for AKT2 mutations + // AKT2 is on testpanel2 in STUDY_TCGA_PUB + var akt2TotalProfiledCountsForMutations = totalProfiledCountsForMutationsMap.stream().filter(c -> c.getHugoGeneSymbol().equals("AKT2")).findFirst(); + assertTrue(akt2TotalProfiledCountsForMutations.isPresent()); + assertEquals(4, akt2TotalProfiledCountsForMutations.get().getNumberOfProfiledCases().intValue()); + // Assert the profiled counts for BRCA1 mutations + // BRCA1 is on testpanel1 in STUDY_TCGA_PUB + var brca1TotalProfiledCountsForMutations = totalProfiledCountsForMutationsMap.stream().filter(c -> c.getHugoGeneSymbol().equals("BRCA1")).findFirst(); + assertTrue(brca1TotalProfiledCountsForMutations.isPresent()); + assertEquals(1, brca1TotalProfiledCountsForMutations.get().getNumberOfProfiledCases().intValue()); + // Assert the profiled counts for AKT1 mutations + // AKT1 is on both testpanel1 and testpanel2 in STUDY_TCGA_PUB + var akt1TotalProfiledCountsForMutations = totalProfiledCountsForMutationsMap.stream().filter(c -> c.getHugoGeneSymbol().equals("AKT1")).findFirst(); + assertTrue(akt1TotalProfiledCountsForMutations.isPresent()); + assertEquals(5, akt1TotalProfiledCountsForMutations.get().getNumberOfProfiledCases().intValue()); + + // Assert the profiled counts for AKT2 CNA + // AKT2 is on testpanel2 in STUDY_TCGA_PUB + var akt2TotalProfiledCountsForCna = totalProfiledCountsForCnaMap.stream().filter(c -> c.getHugoGeneSymbol().equals("AKT2")).findFirst(); + assertTrue(akt2TotalProfiledCountsForCna.isPresent()); + assertEquals(6, akt2TotalProfiledCountsForCna.get().getNumberOfProfiledCases().intValue()); + // Assert the profiled counts for BRCA1 CNA + // BRCA1 is on testpanel1 in STUDY_TCGA_PUB + var brca1TotalProfiledCountsForCna = totalProfiledCountsForCnaMap.stream().filter(c -> c.getHugoGeneSymbol().equals("BRCA1")).findFirst(); + assertTrue(brca1TotalProfiledCountsForCna.isPresent()); + assertEquals(2, brca1TotalProfiledCountsForCna.get().getNumberOfProfiledCases().intValue()); + // Assert the profiled counts for AKT1 CNA + // AKT1 is on both testpanel1 and testpanel2 in STUDY_TCGA_PUB + var akt1TotalProfiledCountsForCna = totalProfiledCountsForCnaMap.stream().filter(c -> c.getHugoGeneSymbol().equals("AKT1")).findFirst(); + assertTrue(akt1TotalProfiledCountsForCna.isPresent()); + assertEquals(8, akt1TotalProfiledCountsForCna.get().getNumberOfProfiledCases().intValue()); + + // Testing profiled counts on combined studies + studyViewFilter.setStudyIds(List.of(STUDY_TCGA_PUB, STUDY_GENIE_PUB)); + + // Testing profiled counts on samples with gene panel data and WES for a combined study + var totalProfiledCountsForMutationsMap1 = mapper.getTotalProfiledCounts(StudyViewFilterFactory.make(studyViewFilter, null, studyViewFilter.getStudyIds(), null), + "MUTATION_EXTENDED", List.of()); + var totalProfiledCountsForCnaMap1 = mapper.getTotalProfiledCounts(StudyViewFilterFactory.make(studyViewFilter, null, studyViewFilter.getStudyIds(), null), + "COPY_NUMBER_ALTERATION", List.of()); + var sampleProfiledCountsForMutationsWithoutPanelDataMap1 = mapper.getSampleProfileCountWithoutPanelData(StudyViewFilterFactory.make(studyViewFilter, null, studyViewFilter.getStudyIds(), null), + "MUTATION_EXTENDED"); + var sampleProfiledCountsForCnaWithoutPanelDataMap1 = mapper.getSampleProfileCountWithoutPanelData(StudyViewFilterFactory.make(studyViewFilter, null, studyViewFilter.getStudyIds(), null), + "COPY_NUMBER_ALTERATION"); + + // Assert the count of genes with profiled cases for mutations in a combined study + assertEquals(8, totalProfiledCountsForMutationsMap1.size()); + // Assert the count of genes with profiled cases for CNA in a combined study + assertEquals(8, totalProfiledCountsForCnaMap1.size()); + // Assert the profiled counts for mutations without panel data (WES) in a combined study + assertEquals(8, sampleProfiledCountsForMutationsWithoutPanelDataMap1); + // Assert the profiled counts for CNA without panel data (WES) in a combined study + assertEquals(12, sampleProfiledCountsForCnaWithoutPanelDataMap1); + + // Assert the profiled counts for BRCA1 mutations + // BRCA1 is on testpanel1 in STUDY_TCGA_PUB + var brca1TotalProfiledCountsForMutations1 = totalProfiledCountsForMutationsMap1.stream().filter(c -> c.getHugoGeneSymbol().equals("BRCA1")).findFirst(); + assertTrue(brca1TotalProfiledCountsForMutations1.isPresent()); + assertEquals(1, brca1TotalProfiledCountsForMutations1.get().getNumberOfProfiledCases().intValue()); + // Assert the profiled counts for BRCA2 mutations + // BRCA2 is on testpanel3 and testpanel4 in STUDY_GENIE_PUB + var brca2TotalProfiledCountsForMutations1 = totalProfiledCountsForMutationsMap1.stream().filter(c -> c.getHugoGeneSymbol().equals("BRCA2")).findFirst(); + assertTrue(brca2TotalProfiledCountsForMutations1.isPresent()); + assertEquals(2, brca2TotalProfiledCountsForMutations1.get().getNumberOfProfiledCases().intValue()); + // Assert the profiled counts for AKT2 mutations + // AKT2 is on testpanel2 in STUDY_TCGA_PUB and testpanel4 in STUDY_GENIE_PUB + var akt2TotalProfiledCountsForMutations1 = totalProfiledCountsForMutationsMap1.stream().filter(c -> c.getHugoGeneSymbol().equals("AKT2")).findFirst(); + assertTrue(akt2TotalProfiledCountsForMutations1.isPresent()); + assertEquals(4, akt2TotalProfiledCountsForMutations1.get().getNumberOfProfiledCases().intValue()); + + // Assert the profiled counts for BRCA1 CNA + // BRCA1 is on testpanel1 in STUDY_TCGA_PUB + var brca1TotalProfiledCountsForCna1 = totalProfiledCountsForCnaMap1.stream().filter(c -> c.getHugoGeneSymbol().equals("BRCA1")).findFirst(); + assertTrue(brca1TotalProfiledCountsForCna1.isPresent()); + assertEquals(2, brca1TotalProfiledCountsForCna1.get().getNumberOfProfiledCases().intValue()); + // Assert the profiled counts for BRCA2 CNA + // BRCA2 is on testpanel3 and testpanel4 in STUDY_GENIE_PUB + var brca2TotalProfiledCountsForCna1 = totalProfiledCountsForCnaMap1.stream().filter(c -> c.getHugoGeneSymbol().equals("BRCA2")).findFirst(); + assertTrue(brca2TotalProfiledCountsForCna1.isPresent()); + assertEquals(3, brca2TotalProfiledCountsForCna1.get().getNumberOfProfiledCases().intValue()); + // Assert the profiled counts for AKT2 CNA + // AKT2 is on testpanel2 in STUDY_TCGA_PUB and testpanel4 in STUDY_GENIE_PUB + var akt2TotalProfiledCountsForCna1 = totalProfiledCountsForCnaMap1.stream().filter(c -> c.getHugoGeneSymbol().equals("AKT2")).findFirst(); + assertTrue(akt2TotalProfiledCountsForCna1.isPresent()); + assertEquals(7, akt2TotalProfiledCountsForCna1.get().getNumberOfProfiledCases().intValue()); + } +} \ No newline at end of file diff --git a/src/test/java/org/cbioportal/legacy/persistence/mybatisclickhouse/StudyViewMapperClinicalDataCountTest.java b/src/test/java/org/cbioportal/infrastructure/repository/clickhouse/clinical_data/ClickhouseClinicalDataMapperTest.java similarity index 76% rename from src/test/java/org/cbioportal/legacy/persistence/mybatisclickhouse/StudyViewMapperClinicalDataCountTest.java rename to src/test/java/org/cbioportal/infrastructure/repository/clickhouse/clinical_data/ClickhouseClinicalDataMapperTest.java index a7d74ae3b3d..a0cc83be843 100644 --- a/src/test/java/org/cbioportal/legacy/persistence/mybatisclickhouse/StudyViewMapperClinicalDataCountTest.java +++ b/src/test/java/org/cbioportal/infrastructure/repository/clickhouse/clinical_data/ClickhouseClinicalDataMapperTest.java @@ -1,8 +1,9 @@ -package org.cbioportal.legacy.persistence.mybatisclickhouse; +package org.cbioportal.infrastructure.repository.clickhouse.clinical_data; +import org.cbioportal.domain.studyview.StudyViewFilterFactory; +import org.cbioportal.infrastructure.repository.clickhouse.AbstractTestcontainers; +import org.cbioportal.infrastructure.repository.clickhouse.config.MyBatisConfig; import org.cbioportal.legacy.model.ClinicalDataCount; -import org.cbioportal.legacy.persistence.helper.StudyViewFilterHelper; -import org.cbioportal.legacy.persistence.mybatisclickhouse.config.MyBatisConfig; import org.cbioportal.legacy.web.parameter.ClinicalDataFilter; import org.cbioportal.legacy.web.parameter.DataFilterValue; import org.cbioportal.legacy.web.parameter.StudyViewFilter; @@ -20,39 +21,38 @@ import java.util.Collections; import java.util.List; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; +import static org.junit.Assert.*; @RunWith(SpringRunner.class) @Import(MyBatisConfig.class) @DataJpaTest @DirtiesContext -@AutoConfigureTestDatabase(replace= AutoConfigureTestDatabase.Replace.NONE) +@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE) @ContextConfiguration(initializers = AbstractTestcontainers.Initializer.class) -public class StudyViewMapperClinicalDataCountTest extends AbstractTestcontainers { +public class ClickhouseClinicalDataMapperTest { private static final String STUDY_ACC_TCGA = "acc_tcga"; - private static final String STUDY_GENIE_PUB = "study_genie_pub"; - - @Autowired - private StudyViewMapper studyViewMapper; + private static final String STUDY_GENIE_PUB = "study_genie_pub"; + @Autowired + private ClickhouseClinicalDataMapper mapper; + @Test public void getMutationCounts() { StudyViewFilter studyViewFilter = new StudyViewFilter(); studyViewFilter.setStudyIds(List.of(STUDY_GENIE_PUB)); - var clinicalDataCountItems = studyViewMapper.getClinicalDataCounts( - StudyViewFilterHelper.build(studyViewFilter, null, null, studyViewFilter.getStudyIds()), - List.of("mutation_count"), - Collections.emptyList() + var clinicalDataCountItems = mapper.getClinicalDataCounts( + StudyViewFilterFactory.make(studyViewFilter, null, studyViewFilter.getStudyIds(), null), + List.of("mutation_count"), + Collections.emptyList() ); - + var mutationsCountsOptional = clinicalDataCountItems.stream() - .filter(c -> c.getAttributeId().equals("mutation_count")).findFirst(); - + .filter(c -> c.getAttributeId().equals("mutation_count")).findFirst(); + assertTrue(mutationsCountsOptional.isPresent()); var mutationsCounts = mutationsCountsOptional.get().getCounts(); - + assertEquals(6, mutationsCounts.size()); assertEquals(1, findClinicaDataCount(mutationsCounts, "11")); assertEquals(1, findClinicaDataCount(mutationsCounts, "6")); @@ -62,20 +62,20 @@ public void getMutationCounts() { // 1 empty string + 1 'NAN' + 15 samples with no data assertEquals(17, findClinicaDataCount(mutationsCounts, "NA")); } - + @Test public void getCenterCounts() { StudyViewFilter studyViewFilter = new StudyViewFilter(); studyViewFilter.setStudyIds(List.of(STUDY_GENIE_PUB)); - var clinicalDataCounts = studyViewMapper.getClinicalDataCounts( - StudyViewFilterHelper.build(studyViewFilter, null, null, studyViewFilter.getStudyIds()), - List.of("center"), - Collections.emptyList() + var clinicalDataCounts = mapper.getClinicalDataCounts( + StudyViewFilterFactory.make(studyViewFilter, null, studyViewFilter.getStudyIds(), null), + List.of("center"), + Collections.emptyList() ); var categoricalClinicalDataCountsOptional = clinicalDataCounts.stream() - .filter(c -> c.getAttributeId().equals("center")).findFirst(); + .filter(c -> c.getAttributeId().equals("center")).findFirst(); assertTrue(categoricalClinicalDataCountsOptional.isPresent()); var categoricalClinicalDataCounts = categoricalClinicalDataCountsOptional.get().getCounts(); @@ -96,14 +96,14 @@ public void getDeadCounts() { StudyViewFilter studyViewFilter = new StudyViewFilter(); studyViewFilter.setStudyIds(List.of(STUDY_GENIE_PUB)); - var clinicalDataCounts = studyViewMapper.getClinicalDataCounts( - StudyViewFilterHelper.build(studyViewFilter, null, null, studyViewFilter.getStudyIds()), - List.of("dead"), - Collections.emptyList() + var clinicalDataCounts = mapper.getClinicalDataCounts( + StudyViewFilterFactory.make(studyViewFilter, null, studyViewFilter.getStudyIds(), null), + List.of("dead"), + Collections.emptyList() ); var categoricalClinicalDataCountsOptional = clinicalDataCounts.stream() - .filter(c -> c.getAttributeId().equals("dead")).findFirst(); + .filter(c -> c.getAttributeId().equals("dead")).findFirst(); assertTrue(categoricalClinicalDataCountsOptional.isPresent()); var categoricalClinicalDataCounts = categoricalClinicalDataCountsOptional.get().getCounts(); @@ -127,10 +127,10 @@ public void getMutationAndCenterCounts() { StudyViewFilter studyViewFilter = new StudyViewFilter(); studyViewFilter.setStudyIds(List.of(STUDY_GENIE_PUB)); - var combinedClinicalDataCounts = studyViewMapper.getClinicalDataCounts( - StudyViewFilterHelper.build(studyViewFilter, null, null, studyViewFilter.getStudyIds()), - List.of("mutation_count", "center"), - Collections.emptyList() + var combinedClinicalDataCounts = mapper.getClinicalDataCounts( + StudyViewFilterFactory.make(studyViewFilter, null, studyViewFilter.getStudyIds(), null), + List.of("mutation_count", "center"), + Collections.emptyList() ); assertEquals(2, combinedClinicalDataCounts.size()); @@ -141,20 +141,20 @@ public void getAgeCounts() { StudyViewFilter studyViewFilter = new StudyViewFilter(); studyViewFilter.setStudyIds(List.of(STUDY_GENIE_PUB)); - var clinicalDataCountItems = studyViewMapper.getClinicalDataCounts( - StudyViewFilterHelper.build(studyViewFilter, null, null, studyViewFilter.getStudyIds()), - List.of("age"), - Collections.emptyList() + var clinicalDataCountItems = mapper.getClinicalDataCounts( + StudyViewFilterFactory.make(studyViewFilter, null, studyViewFilter.getStudyIds(), null), + List.of("age"), + Collections.emptyList() ); var ageCountsOptional = clinicalDataCountItems.stream() - .filter(c -> c.getAttributeId().equals("age")).findFirst(); + .filter(c -> c.getAttributeId().equals("age")).findFirst(); assertTrue(ageCountsOptional.isPresent()); - var ageCounts = ageCountsOptional.get().getCounts(); + var ageCounts = ageCountsOptional.get().getCounts(); assertAgeCounts(ageCounts); - + // 1 empty string + 1 'NAN' + 1 'N/A' + 1 patient without data assertEquals(4, findClinicaDataCount(ageCounts, "NA")); } @@ -164,18 +164,18 @@ public void getAgeCountsForMultipleStudies() { StudyViewFilter studyViewFilter = new StudyViewFilter(); studyViewFilter.setStudyIds(List.of(STUDY_GENIE_PUB, STUDY_ACC_TCGA)); - var clinicalDataCountItems = studyViewMapper.getClinicalDataCounts( - StudyViewFilterHelper.build(studyViewFilter, null, null, studyViewFilter.getStudyIds()), - List.of("age"), - Collections.emptyList() + var clinicalDataCountItems = mapper.getClinicalDataCounts( + StudyViewFilterFactory.make(studyViewFilter, null, studyViewFilter.getStudyIds(), null), + List.of("age"), + Collections.emptyList() ); var ageCountsOptional = clinicalDataCountItems.stream() - .filter(c -> c.getAttributeId().equals("age")).findFirst(); + .filter(c -> c.getAttributeId().equals("age")).findFirst(); assertTrue(ageCountsOptional.isPresent()); var ageCounts = ageCountsOptional.get().getCounts(); - + // everything should be exactly the same as single study (STUDY_GENIE_PUB) filter // except NA counts assertAgeCounts(ageCounts); @@ -183,10 +183,10 @@ public void getAgeCountsForMultipleStudies() { // 1 empty string + 1 'NAN' + 1 'N/A' + 1 GENIE_PUB patient without data + 4 ACC_TCGA data without data assertEquals(8, findClinicaDataCount(ageCounts, "NA")); } - + private void assertAgeCounts(List ageCounts) { assertEquals(15, ageCounts.size()); - + assertEquals(3, findClinicaDataCount(ageCounts, "<18")); assertEquals(1, findClinicaDataCount(ageCounts, "18")); assertEquals(1, findClinicaDataCount(ageCounts, "22")); @@ -203,25 +203,25 @@ private void assertAgeCounts(List ageCounts) { assertEquals(2, findClinicaDataCount(ageCounts, ">89")); assertEquals(1, findClinicaDataCount(ageCounts, "UNKNOWN")); } - + @Test public void getMutationCountsFilteredByAge() { StudyViewFilter studyViewFilter = new StudyViewFilter(); studyViewFilter.setStudyIds(List.of(STUDY_GENIE_PUB)); - + // filter patients with age between 20 and 70 // (there are 5 patients within this range, which are 307..311) ClinicalDataFilter filter = buildClinicalDataFilter("age", 20, 70); studyViewFilter.setClinicalDataFilters(List.of(filter)); - - var clinicalDataCountItems = studyViewMapper.getClinicalDataCounts( - StudyViewFilterHelper.build(studyViewFilter, null, null, studyViewFilter.getStudyIds()), - List.of("mutation_count"), - Collections.emptyList() + + var clinicalDataCountItems = mapper.getClinicalDataCounts( + StudyViewFilterFactory.make(studyViewFilter, null, studyViewFilter.getStudyIds(), null), + List.of("mutation_count"), + Collections.emptyList() ); var mutationsCountsOptional = clinicalDataCountItems.stream() - .filter(c -> c.getAttributeId().equals("mutation_count")).findFirst(); + .filter(c -> c.getAttributeId().equals("mutation_count")).findFirst(); assertTrue(mutationsCountsOptional.isPresent()); var mutationCountsFiltered = mutationsCountsOptional.get().getCounts(); @@ -242,18 +242,18 @@ public void getMutationCountsFilteredByAgeWithOpenStartValues() { ClinicalDataFilter filter = buildClinicalDataFilter("age", null, 20); studyViewFilter.setClinicalDataFilters(List.of(filter)); - var clinicalDataCountItems = studyViewMapper.getClinicalDataCounts( - StudyViewFilterHelper.build(studyViewFilter, null, null, studyViewFilter.getStudyIds()), - List.of("mutation_count"), - Collections.emptyList() + var clinicalDataCountItems = mapper.getClinicalDataCounts( + StudyViewFilterFactory.make(studyViewFilter, null, studyViewFilter.getStudyIds(), null), + List.of("mutation_count"), + Collections.emptyList() ); var mutationsCountsOptional = clinicalDataCountItems.stream() - .filter(c -> c.getAttributeId().equals("mutation_count")).findFirst(); + .filter(c -> c.getAttributeId().equals("mutation_count")).findFirst(); assertTrue(mutationsCountsOptional.isPresent()); var mutationCountsFiltered = mutationsCountsOptional.get().getCounts(); - + assertEquals(4, mutationCountsFiltered.size()); assertEquals(1, findClinicaDataCount(mutationCountsFiltered, "11")); // patient 301 assertEquals(1, findClinicaDataCount(mutationCountsFiltered, "6")); // patient 302 @@ -261,7 +261,7 @@ public void getMutationCountsFilteredByAgeWithOpenStartValues() { assertEquals(1, findClinicaDataCount(mutationCountsFiltered, "2")); // patient 306 // no patients/samples with NA - assertEquals(0, findClinicaDataCount(mutationCountsFiltered, "NA")); + assertEquals(0, findClinicaDataCount(mutationCountsFiltered, "NA")); } @Test @@ -274,14 +274,14 @@ public void getMutationCountsFilteredByAgeWithOpenEndValues() { ClinicalDataFilter filter = buildClinicalDataFilter("age", 80, null); studyViewFilter.setClinicalDataFilters(List.of(filter)); - var clinicalDataCountItems = studyViewMapper.getClinicalDataCounts( - StudyViewFilterHelper.build(studyViewFilter, null, null, studyViewFilter.getStudyIds()), - List.of("mutation_count"), - Collections.emptyList() + var clinicalDataCountItems = mapper.getClinicalDataCounts( + StudyViewFilterFactory.make(studyViewFilter, null, studyViewFilter.getStudyIds(), null), + List.of("mutation_count"), + Collections.emptyList() ); var mutationsCountsOptional = clinicalDataCountItems.stream() - .filter(c -> c.getAttributeId().equals("mutation_count")).findFirst(); + .filter(c -> c.getAttributeId().equals("mutation_count")).findFirst(); assertTrue(mutationsCountsOptional.isPresent()); var mutationCountsFiltered = mutationsCountsOptional.get().getCounts(); @@ -293,7 +293,7 @@ public void getMutationCountsFilteredByAgeWithOpenEndValues() { // patients/samples with NA data: 317, 318, and 319 assertEquals(3, findClinicaDataCount(mutationCountsFiltered, "NA")); } - + private ClinicalDataFilter buildClinicalDataFilter(String attributeId, Integer start, Integer end) { DataFilterValue value = new DataFilterValue(); if (start != null) { @@ -306,13 +306,14 @@ private ClinicalDataFilter buildClinicalDataFilter(String attributeId, Integer s ClinicalDataFilter filter = new ClinicalDataFilter(); filter.setAttributeId(attributeId); filter.setValues(List.of(value)); - + return filter; } - + private int findClinicaDataCount(List counts, String attrValue) { var count = counts.stream().filter(c -> c.getValue().equals(attrValue)).findAny().orElse(null); return count == null ? 0 : count.getCount(); } -} + +} \ No newline at end of file diff --git a/src/test/java/org/cbioportal/legacy/persistence/mybatisclickhouse/ClinicalEventTypeCountsTest.java b/src/test/java/org/cbioportal/infrastructure/repository/clickhouse/clinical_event/ClickhouseClinicalEventMapperTest.java similarity index 67% rename from src/test/java/org/cbioportal/legacy/persistence/mybatisclickhouse/ClinicalEventTypeCountsTest.java rename to src/test/java/org/cbioportal/infrastructure/repository/clickhouse/clinical_event/ClickhouseClinicalEventMapperTest.java index 24684b768dc..10773030c07 100644 --- a/src/test/java/org/cbioportal/legacy/persistence/mybatisclickhouse/ClinicalEventTypeCountsTest.java +++ b/src/test/java/org/cbioportal/infrastructure/repository/clickhouse/clinical_event/ClickhouseClinicalEventMapperTest.java @@ -1,7 +1,9 @@ -package org.cbioportal.legacy.persistence.mybatisclickhouse; +package org.cbioportal.infrastructure.repository.clickhouse.clinical_event; -import org.cbioportal.legacy.persistence.helper.StudyViewFilterHelper; -import org.cbioportal.legacy.persistence.mybatisclickhouse.config.MyBatisConfig; +import org.cbioportal.domain.studyview.StudyViewFilterContext; +import org.cbioportal.domain.studyview.StudyViewFilterFactory; +import org.cbioportal.infrastructure.repository.clickhouse.AbstractTestcontainers; +import org.cbioportal.infrastructure.repository.clickhouse.config.MyBatisConfig; import org.cbioportal.legacy.web.parameter.DataFilter; import org.cbioportal.legacy.web.parameter.DataFilterValue; import org.cbioportal.legacy.web.parameter.StudyViewFilter; @@ -13,39 +15,37 @@ import org.springframework.context.annotation.Import; import org.springframework.test.annotation.DirtiesContext; import org.springframework.test.context.ContextConfiguration; -import org.springframework.test.context.TestPropertySource; import org.springframework.test.context.junit4.SpringRunner; import java.util.List; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; - +import static org.junit.Assert.*; @RunWith(SpringRunner.class) @Import(MyBatisConfig.class) @DataJpaTest @DirtiesContext @AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE) @ContextConfiguration(initializers = AbstractTestcontainers.Initializer.class) -public class ClinicalEventTypeCountsTest extends AbstractTestcontainers { - +public class ClickhouseClinicalEventMapperTest { private static final String STUDY_TCGA_PUB = "study_tcga_pub"; @Autowired - private StudyViewMapper studyViewMapper; + private ClickhouseClinicalEventMapper mapper; @Test public void getClinicalEventTypeCounts() { StudyViewFilter studyViewFilter = new StudyViewFilter(); studyViewFilter.setStudyIds(List.of(STUDY_TCGA_PUB)); - var clinicalEventTypeCounts = studyViewMapper.getClinicalEventTypeCounts(StudyViewFilterHelper.build(studyViewFilter, null, null, studyViewFilter.getStudyIds())); + StudyViewFilterContext studyViewFilterContext = StudyViewFilterFactory.make(studyViewFilter, null, + studyViewFilter.getStudyIds(), null ); + + var clinicalEventTypeCounts = mapper.getClinicalEventTypeCounts(studyViewFilterContext); assertEquals(4, clinicalEventTypeCounts.size()); var clinicalEventTypeCountOptional = clinicalEventTypeCounts.stream().filter(ce -> ce.getEventType().equals("Treatment")) - .findFirst(); + .findFirst(); assertTrue(clinicalEventTypeCountOptional.isPresent()); assertEquals(1, clinicalEventTypeCountOptional.get().getCount().intValue()); @@ -56,13 +56,15 @@ public void getClinicalEventTypeCounts() { dataFilter.setValues(List.of(dataFilterValue)); studyViewFilter.setClinicalEventFilters(List.of(dataFilter)); - clinicalEventTypeCounts = studyViewMapper.getClinicalEventTypeCounts(StudyViewFilterHelper.build(studyViewFilter, null, null, studyViewFilter.getStudyIds())); + clinicalEventTypeCounts = mapper.getClinicalEventTypeCounts( + StudyViewFilterFactory.make(studyViewFilter, null, + studyViewFilter.getStudyIds(), null )); assertEquals(3, clinicalEventTypeCounts.size()); clinicalEventTypeCountOptional = clinicalEventTypeCounts.stream().filter(ce -> ce.getEventType().equals("status")) - .findFirst(); + .findFirst(); assertFalse(clinicalEventTypeCountOptional.isPresent()); } -} +} \ No newline at end of file diff --git a/src/test/java/org/cbioportal/legacy/persistence/mybatisclickhouse/config/MyBatisConfig.java b/src/test/java/org/cbioportal/infrastructure/repository/clickhouse/config/MyBatisConfig.java similarity index 54% rename from src/test/java/org/cbioportal/legacy/persistence/mybatisclickhouse/config/MyBatisConfig.java rename to src/test/java/org/cbioportal/infrastructure/repository/clickhouse/config/MyBatisConfig.java index 174c55207ff..6eaf0973089 100644 --- a/src/test/java/org/cbioportal/legacy/persistence/mybatisclickhouse/config/MyBatisConfig.java +++ b/src/test/java/org/cbioportal/infrastructure/repository/clickhouse/config/MyBatisConfig.java @@ -1,10 +1,11 @@ -package org.cbioportal.legacy.persistence.mybatisclickhouse.config; +package org.cbioportal.infrastructure.repository.clickhouse.config; import org.mybatis.spring.SqlSessionFactoryBean; import org.mybatis.spring.annotation.MapperScan; import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.test.context.TestConfiguration; +import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.core.io.ResourceLoader; @@ -12,7 +13,7 @@ import java.io.IOException; @TestConfiguration -@MapperScan("org.cbioportal.legacy.persistence.mybatisclickhouse") +@MapperScan(value= "org.cbioportal.infrastructure.repository.clickhouse") public class MyBatisConfig { @Bean @@ -24,25 +25,18 @@ public DataSourceProperties clickhouseDatSourceProperties() { @Bean public DataSource dataSource() { return clickhouseDatSourceProperties() - .initializeDataSourceBuilder() - .build(); + .initializeDataSourceBuilder() + .build(); } @Bean - public SqlSessionFactoryBean sqlColumnarSessionFactory(ResourceLoader resourceLoader, DataSource dataSource) throws IOException { + public SqlSessionFactoryBean sqlColumnarSessionFactory(ResourceLoader resourceLoader, DataSource dataSource, + ApplicationContext context) throws IOException { SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean(); sessionFactory.setDataSource(dataSource); - var studyViewMapperResource = resourceLoader.getResource("classpath:org/cbioportal/persistence/mybatisclickhouse/StudyViewMapper.xml") ; - var studyViewFilterMapperResource = resourceLoader.getResource("classpath:org/cbioportal/persistence/mybatisclickhouse/StudyViewFilterMapper.xml"); - var alterationFilterMapperResource = resourceLoader.getResource("classpath:org/cbioportal/persistence/mybatisclickhouse/StudyViewAlterationFilterMapper.xml"); - sessionFactory.setMapperLocations( - studyViewMapperResource,studyViewFilterMapperResource, alterationFilterMapperResource - ); + sessionFactory.addMapperLocations( + context.getResources("classpath:mappers/clickhouse/**/*.xml")); return sessionFactory; } - - - - - } + diff --git a/src/test/java/org/cbioportal/legacy/persistence/mybatisclickhouse/GenericAssayDataCountsTest.java b/src/test/java/org/cbioportal/infrastructure/repository/clickhouse/generic_assay/ClickhouseGenericAssayMapperTest.java similarity index 53% rename from src/test/java/org/cbioportal/legacy/persistence/mybatisclickhouse/GenericAssayDataCountsTest.java rename to src/test/java/org/cbioportal/infrastructure/repository/clickhouse/generic_assay/ClickhouseGenericAssayMapperTest.java index d1e5165ab86..2468cfb37e0 100644 --- a/src/test/java/org/cbioportal/legacy/persistence/mybatisclickhouse/GenericAssayDataCountsTest.java +++ b/src/test/java/org/cbioportal/infrastructure/repository/clickhouse/generic_assay/ClickhouseGenericAssayMapperTest.java @@ -1,9 +1,10 @@ -package org.cbioportal.legacy.persistence.mybatisclickhouse; +package org.cbioportal.infrastructure.repository.clickhouse.generic_assay; +import org.cbioportal.domain.studyview.StudyViewFilterFactory; +import org.cbioportal.infrastructure.repository.clickhouse.AbstractTestcontainers; +import org.cbioportal.infrastructure.repository.clickhouse.config.MyBatisConfig; import org.cbioportal.legacy.model.GenericAssayDataCount; import org.cbioportal.legacy.model.GenericAssayDataCountItem; -import org.cbioportal.legacy.persistence.helper.StudyViewFilterHelper; -import org.cbioportal.legacy.persistence.mybatisclickhouse.config.MyBatisConfig; import org.cbioportal.legacy.web.parameter.GenericAssayDataFilter; import org.cbioportal.legacy.web.parameter.StudyViewFilter; import org.junit.Test; @@ -24,15 +25,16 @@ @Import(MyBatisConfig.class) @DataJpaTest @DirtiesContext -@AutoConfigureTestDatabase(replace= AutoConfigureTestDatabase.Replace.NONE) +@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE) @ContextConfiguration(initializers = AbstractTestcontainers.Initializer.class) -public class GenericAssayDataCountsTest extends AbstractTestcontainers { +public class ClickhouseGenericAssayMapperTest { + private static final String ACC_TCGA = "acc_tcga"; private static final String STUDY_GENIE_PUB = "study_genie_pub"; @Autowired - private StudyViewMapper studyViewMapper; + private ClickhouseGenericAssayMapper mapper; @Test public void getSampleCategoricalGenericAssayDataCounts() { @@ -40,24 +42,24 @@ public void getSampleCategoricalGenericAssayDataCounts() { studyViewFilter.setStudyIds(List.of(ACC_TCGA)); GenericAssayDataFilter genericAssayDataFilter = new GenericAssayDataFilter("1p_status", "armlevel_cna"); - List actualCounts = studyViewMapper.getGenericAssayDataCounts( - StudyViewFilterHelper.build(studyViewFilter, null, null, studyViewFilter.getStudyIds()), - List.of(genericAssayDataFilter) + List actualCounts = mapper.getGenericAssayDataCounts( + StudyViewFilterFactory.make(studyViewFilter, null, studyViewFilter.getStudyIds(), null), + List.of(genericAssayDataFilter) ); List expectedCounts = List.of( - new GenericAssayDataCountItem("1p_status", List.of( - new GenericAssayDataCount("Loss", 1), - new GenericAssayDataCount("Gain", 1), - new GenericAssayDataCount("Unchanged", 1), - new GenericAssayDataCount("NA", 1) - )) + new GenericAssayDataCountItem("1p_status", List.of( + new GenericAssayDataCount("Loss", 1), + new GenericAssayDataCount("Gain", 1), + new GenericAssayDataCount("Unchanged", 1), + new GenericAssayDataCount("NA", 1) + )) ); assertThat(actualCounts) - .usingRecursiveComparison() - .ignoringCollectionOrder() - .isEqualTo(expectedCounts); + .usingRecursiveComparison() + .ignoringCollectionOrder() + .isEqualTo(expectedCounts); } @Test @@ -66,22 +68,23 @@ public void getPatientCategoricalGenericAssayDataCounts() { studyViewFilter.setStudyIds(List.of(STUDY_GENIE_PUB)); GenericAssayDataFilter genericAssayDataFilter = new GenericAssayDataFilter("DMETS_DX_ADRENAL", "distant_mets"); - List actualCounts = studyViewMapper.getGenericAssayDataCounts( - StudyViewFilterHelper.build(studyViewFilter, null, null, studyViewFilter.getStudyIds()), - List.of(genericAssayDataFilter) + List actualCounts = mapper.getGenericAssayDataCounts( + StudyViewFilterFactory.make(studyViewFilter, null, studyViewFilter.getStudyIds(), null), + List.of(genericAssayDataFilter) ); List expectedCounts = List.of( - new GenericAssayDataCountItem("DMETS_DX_ADRENAL", List.of( - new GenericAssayDataCount("No", 9), - new GenericAssayDataCount("Yes", 1), - new GenericAssayDataCount("NA", 14) - )) + new GenericAssayDataCountItem("DMETS_DX_ADRENAL", List.of( + new GenericAssayDataCount("No", 9), + new GenericAssayDataCount("Yes", 1), + new GenericAssayDataCount("NA", 14) + )) ); assertThat(actualCounts) - .usingRecursiveComparison() - .ignoringCollectionOrder() - .isEqualTo(expectedCounts); + .usingRecursiveComparison() + .ignoringCollectionOrder() + .isEqualTo(expectedCounts); } + } \ No newline at end of file diff --git a/src/test/java/org/cbioportal/infrastructure/repository/clickhouse/genomic_data/ClickhouseGenomicDataMapperTest.java b/src/test/java/org/cbioportal/infrastructure/repository/clickhouse/genomic_data/ClickhouseGenomicDataMapperTest.java new file mode 100644 index 00000000000..ffc3e72ced0 --- /dev/null +++ b/src/test/java/org/cbioportal/infrastructure/repository/clickhouse/genomic_data/ClickhouseGenomicDataMapperTest.java @@ -0,0 +1,267 @@ +package org.cbioportal.infrastructure.repository.clickhouse.genomic_data; + +import org.cbioportal.domain.studyview.StudyViewFilterFactory; +import org.cbioportal.infrastructure.repository.clickhouse.AbstractTestcontainers; +import org.cbioportal.infrastructure.repository.clickhouse.config.MyBatisConfig; +import org.cbioportal.legacy.model.ClinicalDataCount; +import org.cbioportal.legacy.model.GenomicDataCount; +import org.cbioportal.legacy.model.GenomicDataCountItem; +import org.cbioportal.legacy.web.parameter.DataFilterValue; +import org.cbioportal.legacy.web.parameter.GenomicDataBinFilter; +import org.cbioportal.legacy.web.parameter.GenomicDataFilter; +import org.cbioportal.legacy.web.parameter.StudyViewFilter; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase; +import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; +import org.springframework.context.annotation.Import; +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringRunner; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.Assert.assertEquals; + +@RunWith(SpringRunner.class) +@Import(MyBatisConfig.class) +@DataJpaTest +@DirtiesContext +@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE) +@ContextConfiguration(initializers = AbstractTestcontainers.Initializer.class) +public class ClickhouseGenomicDataMapperTest { + private static final String STUDY_TCGA_PUB = "study_tcga_pub"; + private static final String STUDY_ACC_TCGA = "acc_tcga"; + + @Autowired + private ClickhouseGenomicDataMapper mapper; + + @Test + public void getCNACounts() { + StudyViewFilter studyViewFilter = new StudyViewFilter(); + studyViewFilter.setStudyIds(List.of(STUDY_TCGA_PUB)); + + GenomicDataFilter genomicDataFilterCNA = new GenomicDataFilter("AKT1", "cna"); + List actualCountsCNA = mapper.getCNACounts(StudyViewFilterFactory.make(studyViewFilter, + null, studyViewFilter.getStudyIds(),null), List.of(genomicDataFilterCNA)); + List expectedCountsCNA = List.of( + new GenomicDataCountItem("AKT1", "cna", List.of( + new GenomicDataCount("Homozygously deleted", "-2", 2), + new GenomicDataCount("Heterozygously deleted", "-1", 2), + new GenomicDataCount("Diploid", "0", 2), + new GenomicDataCount("Gained", "1", 2), + new GenomicDataCount("Amplified", "2", 2), + new GenomicDataCount("NA", "NA", 5) + ))); + assertThat(actualCountsCNA) + .usingRecursiveComparison() + .ignoringCollectionOrder() + .isEqualTo(expectedCountsCNA); + + GenomicDataFilter genomicDataFilterGISTIC = new GenomicDataFilter("AKT1", "gistic"); + List actualCountsGISTIC = + mapper.getCNACounts(StudyViewFilterFactory.make(studyViewFilter, null, studyViewFilter.getStudyIds() + , null), List.of(genomicDataFilterGISTIC)); + List expectedCountsGISTIC = List.of( + new GenomicDataCountItem("AKT1", "gistic", List.of( + new GenomicDataCount("Homozygously deleted", "-2", 2), + new GenomicDataCount("Heterozygously deleted", "-1", 3), + new GenomicDataCount("Diploid", "0", 3), + new GenomicDataCount("Gained", "1", 3), + new GenomicDataCount("Amplified", "2", 3), + new GenomicDataCount("NA", "NA", 1) + ))); + assertThat(actualCountsGISTIC) + .usingRecursiveComparison() + .ignoringCollectionOrder() + .isEqualTo(expectedCountsGISTIC); + } + + @Test + public void getMutationCounts() { + StudyViewFilter studyViewFilter = new StudyViewFilter(); + studyViewFilter.setStudyIds(List.of(STUDY_TCGA_PUB)); + + GenomicDataFilter genomicDataFilterMutation = new GenomicDataFilter("AKT1", "cna"); + Map actualMutationCounts = mapper.getMutationCounts(StudyViewFilterFactory.make(studyViewFilter, null, studyViewFilter.getStudyIds(), null), genomicDataFilterMutation); + Map expectedMutationCounts = new HashMap<>(); + expectedMutationCounts.put("mutatedCount", 2); + expectedMutationCounts.put("notMutatedCount", 8); + expectedMutationCounts.put("notProfiledCount", 5); + assertThat(actualMutationCounts) + .usingRecursiveComparison() + .ignoringCollectionOrder() + .isEqualTo(expectedMutationCounts); + } + + @Test + public void getMutationCountsByType() { + StudyViewFilter studyViewFilter = new StudyViewFilter(); + studyViewFilter.setStudyIds(List.of(STUDY_TCGA_PUB)); + + GenomicDataFilter genomicDataFilterMutation = new GenomicDataFilter("AKT1", "mutation"); + List actualMutationCountsByType = mapper.getMutationCountsByType(StudyViewFilterFactory.make(studyViewFilter, null, studyViewFilter.getStudyIds(), null), List.of(genomicDataFilterMutation)); + List expectedMutationCountsByType = List.of( + new GenomicDataCountItem("AKT1", "mutations", List.of( + new GenomicDataCount("nonsense mutation", "nonsense_mutation", 2, 1), + new GenomicDataCount("missense mutation", "missense_mutation", 1, 1) + ))); + assertThat(actualMutationCountsByType) + .usingRecursiveComparison() + .ignoringCollectionOrder() + .isEqualTo(expectedMutationCountsByType); + } + + @Test + public void getProteinExpressionCounts() { + // Testing combined study missing samples when one lacks a relevant genomic profile + StudyViewFilter studyViewFilter = new StudyViewFilter(); + studyViewFilter.setStudyIds(List.of(STUDY_TCGA_PUB, STUDY_ACC_TCGA)); + + GenomicDataBinFilter genomicDataBinFilterRPPA = new GenomicDataBinFilter(); + genomicDataBinFilterRPPA.setHugoGeneSymbol("AKT1"); + genomicDataBinFilterRPPA.setProfileType("rppa"); + + List actualRPPACounts1 = + mapper.getGenomicDataBinCounts(StudyViewFilterFactory.make(studyViewFilter, null, + studyViewFilter.getStudyIds(), null), List.of(genomicDataBinFilterRPPA)); + + ClinicalDataCount expectedRPPACount1 = new ClinicalDataCount(); + expectedRPPACount1.setAttributeId("AKT1rppa"); + expectedRPPACount1.setValue("0.7360"); + expectedRPPACount1.setCount(1); + ClinicalDataCount expectedRPPACount2 = new ClinicalDataCount(); + expectedRPPACount2.setAttributeId("AKT1rppa"); + expectedRPPACount2.setValue("-0.8097"); + expectedRPPACount2.setCount(1); + ClinicalDataCount expectedRPPACount3 = new ClinicalDataCount(); + expectedRPPACount3.setAttributeId("AKT1rppa"); + expectedRPPACount3.setValue("-0.1260"); + expectedRPPACount3.setCount(1); + ClinicalDataCount expectedRPPACountNA = new ClinicalDataCount(); + expectedRPPACountNA.setAttributeId("AKT1rppa"); + expectedRPPACountNA.setValue("NA"); + expectedRPPACountNA.setCount(16); + + List expectedRPPACounts1 = List.of( + expectedRPPACount1, expectedRPPACount2, expectedRPPACount3, expectedRPPACountNA + ); + assertThat(actualRPPACounts1) + .usingRecursiveComparison() + .ignoringCollectionOrder() + .isEqualTo(expectedRPPACounts1); + + + // Testing NA filtering on combined study missing samples when one lacks a relevant genomic profile + // Make genomic data filter to put in study view filter + GenomicDataFilter genomicDataFilterRPPA = new GenomicDataFilter("AKT1", "rppa"); + DataFilterValue dataFilterValue = new DataFilterValue(); + dataFilterValue.setValue("NA"); + genomicDataFilterRPPA.setValues(List.of(dataFilterValue)); + studyViewFilter.setGenomicDataFilters(List.of(genomicDataFilterRPPA)); + + List actualRPPACounts2 = + mapper.getGenomicDataBinCounts(StudyViewFilterFactory.make(studyViewFilter, null, + studyViewFilter.getStudyIds(), null), List.of(genomicDataBinFilterRPPA)); + + ClinicalDataCount expectedRPPACount = new ClinicalDataCount(); + expectedRPPACount.setAttributeId("AKT1rppa"); + expectedRPPACount.setValue("NA"); + expectedRPPACount.setCount(16); + + List expectedRPPACounts2 = List.of( + expectedRPPACount + ); + assertThat(actualRPPACounts2) + .usingRecursiveComparison() + .ignoringCollectionOrder() + .isEqualTo(expectedRPPACounts2); + } + + @Test + public void getMolecularProfileCounts() { + StudyViewFilter studyViewFilter = new StudyViewFilter(); + studyViewFilter.setStudyIds(List.of(STUDY_TCGA_PUB)); + + var profiles = new ArrayList(Arrays.asList("mutations")); + var profileGroups = new ArrayList>(Arrays.asList(profiles)); + + studyViewFilter.setGenomicProfiles(profileGroups); + + var molecularProfileCounts = + mapper.getMolecularProfileSampleCounts(StudyViewFilterFactory.make(studyViewFilter, null, studyViewFilter.getStudyIds(), null)); + + var size = molecularProfileCounts.stream().filter(gc->gc.getValue().equals("mutations")) + .findFirst().get().getCount().intValue(); + assertEquals(11, size); + + } + + @Test + public void getMolecularProfileCountsMultipleStudies() { + StudyViewFilter studyViewFilter = new StudyViewFilter(); + studyViewFilter.setStudyIds(List.of(STUDY_TCGA_PUB, STUDY_ACC_TCGA)); + + var profiles = new ArrayList(Arrays.asList("mutations")); + var profileGroups = new ArrayList>(Arrays.asList(profiles)); + + studyViewFilter.setGenomicProfiles(profileGroups); + + var molecularProfileCounts = + mapper.getMolecularProfileSampleCounts(StudyViewFilterFactory.make(studyViewFilter, null, studyViewFilter.getStudyIds(), null)); + + var size = molecularProfileCounts.stream().filter(gc->gc.getValue().equals("mutations")) + .findFirst().get().getCount().intValue(); + assertEquals(11, size); + + } + + @Test + public void getMolecularProfileCountsMultipleProfilesUnion() { + StudyViewFilter studyViewFilter = new StudyViewFilter(); + studyViewFilter.setStudyIds(List.of(STUDY_TCGA_PUB)); + + var profiles = new ArrayList(Arrays.asList("mutations","mrna")); + var profileGroups = new ArrayList>(Arrays.asList(profiles)); + + studyViewFilter.setGenomicProfiles(profileGroups); + + var molecularProfileCounts = + mapper.getMolecularProfileSampleCounts(StudyViewFilterFactory.make(studyViewFilter, null, studyViewFilter.getStudyIds(), null)); + + var sizeMutations = molecularProfileCounts.stream().filter(gc->gc.getValue().equals("mutations")) + .findFirst().get().getCount().intValue(); + assertEquals(11, sizeMutations); + + var sizeMrna = molecularProfileCounts.stream().filter(gc->gc.getValue().equals("mrna")) + .findFirst().get().getCount().intValue(); + assertEquals(9, sizeMrna); + + } + + @Test + public void getMolecularProfileCountsMultipleProfilesIntersect() { + StudyViewFilter studyViewFilter = new StudyViewFilter(); + studyViewFilter.setStudyIds(List.of(STUDY_TCGA_PUB)); + + var profile1 = new ArrayList(Arrays.asList("mutations")); + var profile2 = new ArrayList(Arrays.asList("mrna")); + var profileGroups = new ArrayList>(Arrays.asList(profile1, profile2)); + + studyViewFilter.setGenomicProfiles(profileGroups); + + var molecularProfileCounts = + mapper.getMolecularProfileSampleCounts(StudyViewFilterFactory.make(studyViewFilter, null, studyViewFilter.getStudyIds(), null)); + + var sizeMutations = molecularProfileCounts.stream().filter(gc->gc.getValue().equals("mutations")) + .findFirst().get().getCount().intValue(); + assertEquals(10, sizeMutations); + + } +} \ No newline at end of file diff --git a/src/test/java/org/cbioportal/legacy/persistence/mybatisclickhouse/StudyViewCaseListSamplesCountsTest.java b/src/test/java/org/cbioportal/infrastructure/repository/clickhouse/patient/ClickhousePatientMapperTest.java similarity index 70% rename from src/test/java/org/cbioportal/legacy/persistence/mybatisclickhouse/StudyViewCaseListSamplesCountsTest.java rename to src/test/java/org/cbioportal/infrastructure/repository/clickhouse/patient/ClickhousePatientMapperTest.java index 4ec4993d5e2..3abe20fee9c 100644 --- a/src/test/java/org/cbioportal/legacy/persistence/mybatisclickhouse/StudyViewCaseListSamplesCountsTest.java +++ b/src/test/java/org/cbioportal/infrastructure/repository/clickhouse/patient/ClickhousePatientMapperTest.java @@ -1,8 +1,8 @@ -package org.cbioportal.legacy.persistence.mybatisclickhouse; - -import org.cbioportal.legacy.persistence.helper.StudyViewFilterHelper; -import org.cbioportal.legacy.persistence.mybatisclickhouse.config.MyBatisConfig; +package org.cbioportal.infrastructure.repository.clickhouse.patient; +import org.cbioportal.domain.studyview.StudyViewFilterFactory; +import org.cbioportal.infrastructure.repository.clickhouse.AbstractTestcontainers; +import org.cbioportal.infrastructure.repository.clickhouse.config.MyBatisConfig; import org.cbioportal.legacy.service.util.StudyViewColumnarServiceUtil; import org.cbioportal.legacy.web.parameter.StudyViewFilter; import org.junit.Test; @@ -19,22 +19,23 @@ import java.util.Arrays; import java.util.List; -import static org.junit.Assert.assertEquals; +import static org.junit.Assert.*; @RunWith(SpringRunner.class) @Import(MyBatisConfig.class) @DataJpaTest @DirtiesContext -@AutoConfigureTestDatabase(replace= AutoConfigureTestDatabase.Replace.NONE) +@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE) @ContextConfiguration(initializers = AbstractTestcontainers.Initializer.class) -public class StudyViewCaseListSamplesCountsTest extends AbstractTestcontainers { - +public class ClickhousePatientMapperTest { + private static final String STUDY_TCGA_PUB = "study_tcga_pub"; private static final String STUDY_ACC_TCGA = "acc_tcga"; - @Autowired - private StudyViewMapper studyViewMapper; + @Autowired + private ClickhousePatientMapper mapper; + @Test public void getMolecularProfileCounts() { StudyViewFilter studyViewFilter = new StudyViewFilter(); @@ -44,13 +45,13 @@ public void getMolecularProfileCounts() { var caseListGroups = new ArrayList(Arrays.asList(caseList)); studyViewFilter.setCaseLists(caseListGroups); - - var sampleListCounts = studyViewMapper.getCaseListDataCountsPerStudy(StudyViewFilterHelper.build(studyViewFilter, null, null, studyViewFilter.getStudyIds()) ); + + var sampleListCounts = mapper.getCaseListDataCounts(StudyViewFilterFactory.make(studyViewFilter, null, studyViewFilter.getStudyIds(), null) ); var size = sampleListCounts.stream().filter(gc->gc.getValue().equals("mrna")) - .findFirst().get().getCount().intValue(); + .findFirst().get().getCount().intValue(); assertEquals(7, size); - + } @Test @@ -63,10 +64,10 @@ public void getMolecularProfileCountsMultipleListsOr() { studyViewFilter.setCaseLists(caseListGroups); - var sampleListCounts = studyViewMapper.getCaseListDataCountsPerStudy(StudyViewFilterHelper.build(studyViewFilter, null, null, studyViewFilter.getStudyIds()) ); + var sampleListCounts = mapper.getCaseListDataCounts(StudyViewFilterFactory.make(studyViewFilter, null, studyViewFilter.getStudyIds(), null) ); var size = sampleListCounts.stream().filter(gc->gc.getValue().equals("mrna")) - .findFirst().get().getCount().intValue(); + .findFirst().get().getCount().intValue(); assertEquals(8, size); } @@ -82,10 +83,10 @@ public void getMolecularProfileCountsMultipleListsAnd() { studyViewFilter.setCaseLists(caseListGroups); - var sampleListCounts = studyViewMapper.getCaseListDataCountsPerStudy(StudyViewFilterHelper.build(studyViewFilter, null, null, studyViewFilter.getStudyIds()) ); + var sampleListCounts = mapper.getCaseListDataCounts(StudyViewFilterFactory.make(studyViewFilter, null, studyViewFilter.getStudyIds(), null) ); var size = sampleListCounts.stream().filter(gc->gc.getValue().equals("mrna")) - .findFirst().get().getCount().intValue(); + .findFirst().get().getCount().intValue(); assertEquals(7, size); } @@ -100,21 +101,20 @@ public void getMolecularProfileCountsAcrossStudies() { studyViewFilter.setCaseLists(caseListGroups); - var unMergedCounts = studyViewMapper.getCaseListDataCountsPerStudy(StudyViewFilterHelper.build(studyViewFilter, null, null, studyViewFilter.getStudyIds()) ); - + var unMergedCounts = mapper.getCaseListDataCounts(StudyViewFilterFactory.make(studyViewFilter, null, studyViewFilter.getStudyIds(), null) ); + var caseListCountsMerged = StudyViewColumnarServiceUtil.mergeCaseListCounts( - unMergedCounts + unMergedCounts ); var sizeUnmerged = unMergedCounts.stream().filter(gc->gc.getValue().equals("all")) - .findFirst().get().getCount().intValue(); + .findFirst().get().getCount().intValue(); assertEquals(14, sizeUnmerged); - + // now we've combined the "all" from the two studies var sizeMerged = caseListCountsMerged.stream().filter(gc->gc.getValue().equals("all")) - .findFirst().get().getCount().intValue(); + .findFirst().get().getCount().intValue(); assertEquals(15, sizeMerged); } - } \ No newline at end of file diff --git a/src/test/java/org/cbioportal/legacy/persistence/mybatisclickhouse/FilteredSamplesTest.java b/src/test/java/org/cbioportal/infrastructure/repository/clickhouse/sample/ClickhouseSampleMapperTest.java similarity index 54% rename from src/test/java/org/cbioportal/legacy/persistence/mybatisclickhouse/FilteredSamplesTest.java rename to src/test/java/org/cbioportal/infrastructure/repository/clickhouse/sample/ClickhouseSampleMapperTest.java index 6d95950fafc..f4c609b0c2c 100644 --- a/src/test/java/org/cbioportal/legacy/persistence/mybatisclickhouse/FilteredSamplesTest.java +++ b/src/test/java/org/cbioportal/infrastructure/repository/clickhouse/sample/ClickhouseSampleMapperTest.java @@ -1,7 +1,9 @@ -package org.cbioportal.legacy.persistence.mybatisclickhouse; +package org.cbioportal.infrastructure.repository.clickhouse.sample; +import org.cbioportal.domain.studyview.StudyViewFilterFactory; +import org.cbioportal.infrastructure.repository.clickhouse.AbstractTestcontainers; +import org.cbioportal.infrastructure.repository.clickhouse.config.MyBatisConfig; import org.cbioportal.legacy.persistence.helper.StudyViewFilterHelper; -import org.cbioportal.legacy.persistence.mybatisclickhouse.config.MyBatisConfig; import org.cbioportal.legacy.web.parameter.ClinicalDataFilter; import org.cbioportal.legacy.web.parameter.CustomSampleIdentifier; import org.cbioportal.legacy.web.parameter.DataFilterValue; @@ -21,7 +23,7 @@ import java.util.Arrays; import java.util.List; -import static org.junit.Assert.assertEquals; +import static org.junit.Assert.*; @RunWith(SpringRunner.class) @Import(MyBatisConfig.class) @@ -29,20 +31,21 @@ @DirtiesContext @AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE) @ContextConfiguration(initializers = AbstractTestcontainers.Initializer.class) -public class FilteredSamplesTest extends AbstractTestcontainers { - +public class ClickhouseSampleMapperTest { private static final String STUDY_TCGA_PUB = "study_tcga_pub"; private static final String STUDY_ACC_TCGA = "acc_tcga"; private static final String STUDY_GENIE_PUB = "study_genie_pub"; - @Autowired - private StudyViewMapper studyViewMapper; + @Autowired + private ClickhouseSampleMapper mapper; + @Test public void getFilteredSamples() { StudyViewFilter studyViewFilter = new StudyViewFilter(); studyViewFilter.setStudyIds(Arrays.asList(STUDY_TCGA_PUB, STUDY_ACC_TCGA)); - var filteredSamples = studyViewMapper.getFilteredSamples(StudyViewFilterHelper.build(studyViewFilter, null, null, studyViewFilter.getStudyIds())); + var filteredSamples = mapper.getFilteredSamples(StudyViewFilterFactory.make(studyViewFilter, null, + studyViewFilter.getStudyIds(), null )); assertEquals(19, filteredSamples.size()); ClinicalDataFilter customDataFilter = new ClinicalDataFilter(); @@ -50,16 +53,17 @@ public void getFilteredSamples() { DataFilterValue value = new DataFilterValue(); customDataFilter.setValues(List.of(value)); studyViewFilter.setCustomDataFilters(List.of(customDataFilter)); - var filteredSamples1 = studyViewMapper.getFilteredSamples(StudyViewFilterHelper.build(studyViewFilter, null, new ArrayList<>(), studyViewFilter.getStudyIds())); + var filteredSamples1 = mapper.getFilteredSamples(StudyViewFilterFactory.make(studyViewFilter, List.of(), + studyViewFilter.getStudyIds(), null )); assertEquals(0, filteredSamples1.size()); CustomSampleIdentifier customSampleIdentifier = new CustomSampleIdentifier(); customSampleIdentifier.setStudyId("acc_tcga"); customSampleIdentifier.setSampleId("tcga-a1-a0sb-01"); - var filteredSamples2 = studyViewMapper.getFilteredSamples(StudyViewFilterHelper.build(studyViewFilter, null, Arrays.asList(customSampleIdentifier), studyViewFilter.getStudyIds())); + var filteredSamples2 = mapper.getFilteredSamples(StudyViewFilterFactory.make(studyViewFilter, + List.of(customSampleIdentifier), studyViewFilter.getStudyIds(), null )); assertEquals(1, filteredSamples2.size()); } - @Test public void getSamplesFilteredByClinicalData() { StudyViewFilter studyViewFilter = new StudyViewFilter(); @@ -67,106 +71,112 @@ public void getSamplesFilteredByClinicalData() { // samples of patients with AGE <= 20.0 studyViewFilter.setClinicalDataFilters( - List.of( - newClinicalDataFilter( - "age", List.of( - newDataFilterValue(null, 20.0, null) - ) + List.of( + newClinicalDataFilter( + "age", List.of( + newDataFilterValue(null, 20.0, null) + ) + ) ) - ) ); - var filteredSamples1 = studyViewMapper.getFilteredSamples(StudyViewFilterHelper.build(studyViewFilter, null, new ArrayList<>(), studyViewFilter.getStudyIds())); + var filteredSamples1 = mapper.getFilteredSamples(StudyViewFilterFactory.make(studyViewFilter, + List.of(),studyViewFilter.getStudyIds(), null)); assertEquals(4, filteredSamples1.size()); // samples of patients with AGE <= 20.0 or (80.0, 82.0] studyViewFilter.setClinicalDataFilters( - List.of( - newClinicalDataFilter( - "age", List.of( - newDataFilterValue(null, 20.0, null), - newDataFilterValue(80.0, 82.0, null) - ) + List.of( + newClinicalDataFilter( + "age", List.of( + newDataFilterValue(null, 20.0, null), + newDataFilterValue(80.0, 82.0, null) + ) + ) ) - ) ); - var filteredSamples2 = studyViewMapper.getFilteredSamples(StudyViewFilterHelper.build(studyViewFilter, null, new ArrayList<>(), studyViewFilter.getStudyIds())); + var filteredSamples2 = mapper.getFilteredSamples(StudyViewFilterFactory.make(studyViewFilter, + List.of(), studyViewFilter.getStudyIds(), null)); assertEquals(6, filteredSamples2.size()); // samples of patients with UNKNOWN AGE studyViewFilter.setClinicalDataFilters( - List.of( - newClinicalDataFilter( - "age", List.of( - newDataFilterValue(null, null, "Unknown") - ) + List.of( + newClinicalDataFilter( + "age", List.of( + newDataFilterValue(null, null, "Unknown") + ) + ) ) - ) ); - var filteredSamples3 = studyViewMapper.getFilteredSamples(StudyViewFilterHelper.build(studyViewFilter, null, new ArrayList<>(), studyViewFilter.getStudyIds())); + var filteredSamples3 = mapper.getFilteredSamples(StudyViewFilterFactory.make(studyViewFilter, + List.of(), studyViewFilter.getStudyIds(), null)); assertEquals(1, filteredSamples3.size()); // samples of patients with AGE <= 20.0 or (80.0, 82.0] or UNKNOWN // this is a mixed list of filters of both numerical and non-numerical values studyViewFilter.setClinicalDataFilters( - List.of( - newClinicalDataFilter( - "age", List.of( - newDataFilterValue(null, 20.0, null), - newDataFilterValue(80.0, 82.0, null), - newDataFilterValue(null, null, "unknown") - ) + List.of( + newClinicalDataFilter( + "age", List.of( + newDataFilterValue(null, 20.0, null), + newDataFilterValue(80.0, 82.0, null), + newDataFilterValue(null, null, "unknown") + ) + ) ) - ) ); - var filteredSamples4 = studyViewMapper.getFilteredSamples(StudyViewFilterHelper.build(studyViewFilter, null, new ArrayList<>(), studyViewFilter.getStudyIds())); + var filteredSamples4 = mapper.getFilteredSamples(StudyViewFilterFactory.make(studyViewFilter, + List.of(), studyViewFilter.getStudyIds(),null)); assertEquals(7, filteredSamples4.size()); - + // NA filter studyViewFilter.setClinicalDataFilters( - List.of( - newClinicalDataFilter( - "age", List.of( - newDataFilterValue(null, null, "NA") - ) + List.of( + newClinicalDataFilter( + "age", List.of( + newDataFilterValue(null, null, "NA") + ) + ) ) - ) ); - var filteredSamples5 = studyViewMapper.getFilteredSamples(StudyViewFilterHelper.build(studyViewFilter, null, new ArrayList<>(), studyViewFilter.getStudyIds())); + var filteredSamples5 = mapper.getFilteredSamples(StudyViewFilterFactory.make(studyViewFilter, + List.of(), studyViewFilter.getStudyIds(), null)); // 4 acc_tcga + 7 study_genie_pub samples with "NA" AGE data or no AGE data assertEquals(11, filteredSamples5.size()); - + // NA + UNKNOWN studyViewFilter.setClinicalDataFilters( - List.of( - newClinicalDataFilter( - "age", List.of( - newDataFilterValue(null, null, "NA"), - newDataFilterValue(null, null, "UNKNOWN") - ) + List.of( + newClinicalDataFilter( + "age", List.of( + newDataFilterValue(null, null, "NA"), + newDataFilterValue(null, null, "UNKNOWN") + ) + ) ) - ) ); - var filteredSamples6 = studyViewMapper.getFilteredSamples(StudyViewFilterHelper.build(studyViewFilter, null, new ArrayList<>(), studyViewFilter.getStudyIds())); + var filteredSamples6 = mapper.getFilteredSamples(StudyViewFilterFactory.make(studyViewFilter, + List.of(), studyViewFilter.getStudyIds(), null)); // 11 NA + 1 UNKNOWN assertEquals(12, filteredSamples6.size()); } - + private DataFilterValue newDataFilterValue(Double start, Double end, String value) { DataFilterValue dataFilterValue = new DataFilterValue(); - + dataFilterValue.setStart(start == null ? null : new BigDecimal(start)); dataFilterValue.setEnd(end == null ? null: new BigDecimal(end)); dataFilterValue.setValue(value); - + return dataFilterValue; } private ClinicalDataFilter newClinicalDataFilter(String attributeId, List values) { ClinicalDataFilter clinicalDataFilter = new ClinicalDataFilter(); - + clinicalDataFilter.setAttributeId(attributeId); clinicalDataFilter.setValues(values); - + return clinicalDataFilter; } -} +} \ No newline at end of file diff --git a/src/test/java/org/cbioportal/infrastructure/repository/clickhouse/treatment/ClickhouseTreatmentMapperTest.java b/src/test/java/org/cbioportal/infrastructure/repository/clickhouse/treatment/ClickhouseTreatmentMapperTest.java new file mode 100644 index 00000000000..1ba97f1c0ed --- /dev/null +++ b/src/test/java/org/cbioportal/infrastructure/repository/clickhouse/treatment/ClickhouseTreatmentMapperTest.java @@ -0,0 +1,106 @@ +package org.cbioportal.infrastructure.repository.clickhouse.treatment; + +import org.cbioportal.domain.studyview.StudyViewFilterFactory; +import org.cbioportal.infrastructure.repository.clickhouse.AbstractTestcontainers; +import org.cbioportal.infrastructure.repository.clickhouse.config.MyBatisConfig; +import org.cbioportal.legacy.model.TemporalRelation; +import org.cbioportal.legacy.web.parameter.StudyViewFilter; +import org.cbioportal.legacy.web.parameter.filter.AndedPatientTreatmentFilters; +import org.cbioportal.legacy.web.parameter.filter.AndedSampleTreatmentFilters; +import org.cbioportal.legacy.web.parameter.filter.OredPatientTreatmentFilters; +import org.cbioportal.legacy.web.parameter.filter.OredSampleTreatmentFilters; +import org.cbioportal.legacy.web.parameter.filter.PatientTreatmentFilter; +import org.cbioportal.legacy.web.parameter.filter.SampleTreatmentFilter; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase; +import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; +import org.springframework.context.annotation.Import; +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringRunner; + +import java.util.List; + +import static org.junit.Assert.assertEquals; + +@RunWith(SpringRunner.class) +@Import(MyBatisConfig.class) +@DataJpaTest +@DirtiesContext +@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE) +@ContextConfiguration(initializers = AbstractTestcontainers.Initializer.class) +public class ClickhouseTreatmentMapperTest { + private static final String STUDY_TCGA_PUB = "study_tcga_pub"; + + @Autowired + private ClickhouseTreatmentMapper mapper; + + @Test + public void getPatientTreatments() { + + StudyViewFilter studyViewFilter = new StudyViewFilter(); + studyViewFilter.setStudyIds(List.of(STUDY_TCGA_PUB)); + + + var patientTreatmentCounts = mapper.getPatientTreatmentCounts(StudyViewFilterFactory.make(studyViewFilter, null, studyViewFilter.getStudyIds(), null)); + + var patientTreatments = mapper.getPatientTreatments(StudyViewFilterFactory.make(studyViewFilter, null, studyViewFilter.getStudyIds(), null)); + + assertEquals(1, patientTreatmentCounts); + assertEquals("madeupanib", patientTreatments.getFirst().treatment()); + + PatientTreatmentFilter filter = new PatientTreatmentFilter(); + filter.setTreatment("madeupanib"); + + OredPatientTreatmentFilters oredPatientTreatmentFilters = new OredPatientTreatmentFilters(); + oredPatientTreatmentFilters.setFilters(List.of(filter)); + + AndedPatientTreatmentFilters andedPatientTreatmentFilters = new AndedPatientTreatmentFilters(); + andedPatientTreatmentFilters.setFilters(List.of(oredPatientTreatmentFilters)); + studyViewFilter.setPatientTreatmentFilters(andedPatientTreatmentFilters); + + patientTreatmentCounts = mapper.getPatientTreatmentCounts(StudyViewFilterFactory.make(studyViewFilter, null, studyViewFilter.getStudyIds(), null)); + + patientTreatments = mapper.getPatientTreatments(StudyViewFilterFactory.make(studyViewFilter, null, studyViewFilter.getStudyIds(), null)); + + assertEquals(1, patientTreatmentCounts); + assertEquals("madeupanib", patientTreatments.getFirst().treatment()); + + } + + @Test + public void getTotalSampleTreatmentCounts() { + StudyViewFilter studyViewFilter = new StudyViewFilter(); + studyViewFilter.setStudyIds(List.of(STUDY_TCGA_PUB)); + + + var totalSampleTreatmentCount = mapper.getTotalSampleTreatmentCounts(StudyViewFilterFactory.make(studyViewFilter, null, studyViewFilter.getStudyIds(), null)); + + var sampleTreatmentCounts = mapper.getSampleTreatmentCounts(StudyViewFilterFactory.make(studyViewFilter, null, studyViewFilter.getStudyIds(), null)); + + assertEquals(1, totalSampleTreatmentCount); + assertEquals("madeupanib", sampleTreatmentCounts.getFirst().treatment()); + assertEquals(1, sampleTreatmentCounts.getFirst().postSampleCount()); + assertEquals(0, sampleTreatmentCounts.getFirst().preSampleCount()); + + SampleTreatmentFilter filter = new SampleTreatmentFilter(); + filter.setTreatment("madeupanib"); + filter.setTime(TemporalRelation.Pre); + + OredSampleTreatmentFilters oredSampleTreatmentFilters = new OredSampleTreatmentFilters(); + oredSampleTreatmentFilters.setFilters(List.of(filter)); + + AndedSampleTreatmentFilters andedSampleTreatmentFilters = new AndedSampleTreatmentFilters(); + andedSampleTreatmentFilters.setFilters(List.of(oredSampleTreatmentFilters)); + studyViewFilter.setSampleTreatmentFilters(andedSampleTreatmentFilters); + + totalSampleTreatmentCount = mapper.getTotalSampleTreatmentCounts(StudyViewFilterFactory.make(studyViewFilter, null, studyViewFilter.getStudyIds(), null)); + + sampleTreatmentCounts = mapper.getSampleTreatmentCounts(StudyViewFilterFactory.make(studyViewFilter, null, studyViewFilter.getStudyIds(), null)); + + assertEquals(0, totalSampleTreatmentCount); + assertEquals(0, sampleTreatmentCounts.size()); + } +} \ No newline at end of file diff --git a/src/test/java/org/cbioportal/legacy/persistence/mybatisclickhouse/CNAGenesTest.java b/src/test/java/org/cbioportal/legacy/persistence/mybatisclickhouse/CNAGenesTest.java deleted file mode 100644 index 210d448534c..00000000000 --- a/src/test/java/org/cbioportal/legacy/persistence/mybatisclickhouse/CNAGenesTest.java +++ /dev/null @@ -1,76 +0,0 @@ -package org.cbioportal.legacy.persistence.mybatisclickhouse; - -import org.cbioportal.legacy.model.AlterationFilter; -import org.cbioportal.legacy.model.CNA; -import org.cbioportal.legacy.persistence.helper.AlterationFilterHelper; -import org.cbioportal.legacy.persistence.helper.StudyViewFilterHelper; -import org.cbioportal.legacy.persistence.mybatisclickhouse.config.MyBatisConfig; -import org.cbioportal.legacy.web.parameter.StudyViewFilter; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase; -import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; -import org.springframework.context.annotation.Import; -import org.springframework.test.annotation.DirtiesContext; -import org.springframework.test.context.ContextConfiguration; -import org.springframework.test.context.junit4.SpringRunner; - -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; - -import static org.junit.Assert.assertEquals; - -@RunWith(SpringRunner.class) -@Import(MyBatisConfig.class) -@DataJpaTest -@DirtiesContext -@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE) -@ContextConfiguration(initializers = AbstractTestcontainers.Initializer.class) -public class CNAGenesTest extends AbstractTestcontainers { - - private static final String STUDY_TCGA_PUB = "study_tcga_pub"; - - @Autowired - private StudyViewMapper studyViewMapper; - - @Test - public void getCnaGenes() { - StudyViewFilter studyViewFilter = new StudyViewFilter(); - studyViewFilter.setStudyIds(List.of(STUDY_TCGA_PUB)); - var alterationCountByGenes = studyViewMapper.getCnaGenes(StudyViewFilterHelper.build(studyViewFilter, null, null, studyViewFilter.getStudyIds()), - AlterationFilterHelper.build(studyViewFilter.getAlterationFilter())); - assertEquals(3, alterationCountByGenes.size()); - - // Test cna count for akt1 - var testAKT1AlterationCount = alterationCountByGenes.stream().filter(a -> Objects.equals(a.getHugoGeneSymbol(), "AKT1")) - .mapToInt(c -> c.getTotalCount().intValue()) - .sum(); - assertEquals(3, testAKT1AlterationCount); - } - - @Test - public void getCnaGenesWithAlterationFilter() { - StudyViewFilter studyViewFilter = new StudyViewFilter(); - studyViewFilter.setStudyIds(List.of(STUDY_TCGA_PUB)); - - // Create AlterationFilter - AlterationFilter alterationFilter = new AlterationFilter(); - Map cnaEventTypeFilterMap = new HashMap<>(); - cnaEventTypeFilterMap.put(CNA.HOMDEL, false); - cnaEventTypeFilterMap.put(CNA.AMP, true); - alterationFilter.setCopyNumberAlterationEventTypes(cnaEventTypeFilterMap); - - var alterationCountByGenes = studyViewMapper.getCnaGenes(StudyViewFilterHelper.build(studyViewFilter, null, null, studyViewFilter.getStudyIds()), - AlterationFilterHelper.build(alterationFilter)); - assertEquals(2, alterationCountByGenes.size()); - - // Test cna count for akt1 filtering for AMP - var testAKT1AlterationCount = alterationCountByGenes.stream().filter(a -> Objects.equals(a.getHugoGeneSymbol(), "AKT1")) - .mapToInt(c -> c.getTotalCount().intValue()) - .sum(); - assertEquals(2, testAKT1AlterationCount); - } -} diff --git a/src/test/java/org/cbioportal/legacy/persistence/mybatisclickhouse/GenomicDataCountsTest.java b/src/test/java/org/cbioportal/legacy/persistence/mybatisclickhouse/GenomicDataCountsTest.java deleted file mode 100644 index c2594b589a9..00000000000 --- a/src/test/java/org/cbioportal/legacy/persistence/mybatisclickhouse/GenomicDataCountsTest.java +++ /dev/null @@ -1,73 +0,0 @@ -package org.cbioportal.legacy.persistence.mybatisclickhouse; - -import org.cbioportal.legacy.model.GenomicDataCount; -import org.cbioportal.legacy.model.GenomicDataCountItem; -import org.cbioportal.legacy.persistence.helper.StudyViewFilterHelper; -import org.cbioportal.legacy.persistence.mybatisclickhouse.config.MyBatisConfig; -import org.cbioportal.legacy.web.parameter.GenomicDataFilter; -import org.cbioportal.legacy.web.parameter.StudyViewFilter; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase; -import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; -import org.springframework.context.annotation.Import; -import org.springframework.test.annotation.DirtiesContext; -import org.springframework.test.context.ContextConfiguration; -import org.springframework.test.context.junit4.SpringRunner; - -import java.util.List; - -import static org.assertj.core.api.Assertions.assertThat; - -@RunWith(SpringRunner.class) -@Import(MyBatisConfig.class) -@DataJpaTest -@DirtiesContext -@AutoConfigureTestDatabase(replace= AutoConfigureTestDatabase.Replace.NONE) -@ContextConfiguration(initializers = AbstractTestcontainers.Initializer.class) -public class GenomicDataCountsTest extends AbstractTestcontainers { - - private static final String STUDY_TCGA_PUB = "study_tcga_pub"; - - @Autowired - private StudyViewMapper studyViewMapper; - - @Test - public void getCNACounts() { - StudyViewFilter studyViewFilter = new StudyViewFilter(); - studyViewFilter.setStudyIds(List.of(STUDY_TCGA_PUB)); - - GenomicDataFilter genomicDataFilterCNA = new GenomicDataFilter("AKT1", "cna"); - List actualCountsCNA = studyViewMapper.getCNACounts(StudyViewFilterHelper.build(studyViewFilter, null, null, studyViewFilter.getStudyIds()), List.of(genomicDataFilterCNA)); - List expectedCountsCNA = List.of( - new GenomicDataCountItem("AKT1", "cna", List.of( - new GenomicDataCount("Homozygously deleted", "-2", 2), - new GenomicDataCount("Heterozygously deleted", "-1", 2), - new GenomicDataCount("Diploid", "0", 2), - new GenomicDataCount("Gained", "1", 2), - new GenomicDataCount("Amplified", "2", 2), - new GenomicDataCount("NA", "NA", 5) - ))); - assertThat(actualCountsCNA) - .usingRecursiveComparison() - .ignoringCollectionOrder() - .isEqualTo(expectedCountsCNA); - - GenomicDataFilter genomicDataFilterGISTIC = new GenomicDataFilter("AKT1", "gistic"); - List actualCountsGISTIC = studyViewMapper.getCNACounts(StudyViewFilterHelper.build(studyViewFilter, null, null, studyViewFilter.getStudyIds()), List.of(genomicDataFilterGISTIC)); - List expectedCountsGISTIC = List.of( - new GenomicDataCountItem("AKT1", "gistic", List.of( - new GenomicDataCount("Homozygously deleted", "-2", 2), - new GenomicDataCount("Heterozygously deleted", "-1", 3), - new GenomicDataCount("Diploid", "0", 3), - new GenomicDataCount("Gained", "1", 3), - new GenomicDataCount("Amplified", "2", 3), - new GenomicDataCount("NA", "NA", 1) - ))); - assertThat(actualCountsGISTIC) - .usingRecursiveComparison() - .ignoringCollectionOrder() - .isEqualTo(expectedCountsGISTIC); - } -} diff --git a/src/test/java/org/cbioportal/legacy/persistence/mybatisclickhouse/MolecularProfileCountTest.java b/src/test/java/org/cbioportal/legacy/persistence/mybatisclickhouse/MolecularProfileCountTest.java deleted file mode 100644 index b46492bf09a..00000000000 --- a/src/test/java/org/cbioportal/legacy/persistence/mybatisclickhouse/MolecularProfileCountTest.java +++ /dev/null @@ -1,119 +0,0 @@ -package org.cbioportal.legacy.persistence.mybatisclickhouse; - -import org.cbioportal.legacy.persistence.helper.StudyViewFilterHelper; -import org.cbioportal.legacy.persistence.mybatisclickhouse.config.MyBatisConfig; - -import org.cbioportal.legacy.web.parameter.StudyViewFilter; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase; -import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; -import org.springframework.context.annotation.Import; -import org.springframework.test.annotation.DirtiesContext; -import org.springframework.test.context.ContextConfiguration; -import org.springframework.test.context.junit4.SpringRunner; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -import static org.junit.Assert.assertEquals; - -@RunWith(SpringRunner.class) -@Import(MyBatisConfig.class) -@DataJpaTest -@DirtiesContext -@AutoConfigureTestDatabase(replace= AutoConfigureTestDatabase.Replace.NONE) -@ContextConfiguration(initializers = AbstractTestcontainers.Initializer.class) -public class MolecularProfileCountTest extends AbstractTestcontainers { - - private static final String STUDY_TCGA_PUB = "study_tcga_pub"; - private static final String STUDY_ACC_TCGA = "acc_tcga"; - - @Autowired - private StudyViewMapper studyViewMapper; - - @Test - public void getMolecularProfileCounts() { - StudyViewFilter studyViewFilter = new StudyViewFilter(); - studyViewFilter.setStudyIds(List.of(STUDY_TCGA_PUB)); - - var profiles = new ArrayList(Arrays.asList("mutations")); - var profileGroups = new ArrayList>(Arrays.asList(profiles)); - - studyViewFilter.setGenomicProfiles(profileGroups); - - var molecularProfileCounts = studyViewMapper.getMolecularProfileSampleCounts(StudyViewFilterHelper.build(studyViewFilter, null, null, studyViewFilter.getStudyIds())); - - var size = molecularProfileCounts.stream().filter(gc->gc.getValue().equals("mutations")) - .findFirst().get().getCount().intValue(); - assertEquals(11, size); - - } - - @Test - public void getMolecularProfileCountsMultipleStudies() { - StudyViewFilter studyViewFilter = new StudyViewFilter(); - studyViewFilter.setStudyIds(List.of(STUDY_TCGA_PUB, STUDY_ACC_TCGA)); - - var profiles = new ArrayList(Arrays.asList("mutations")); - var profileGroups = new ArrayList>(Arrays.asList(profiles)); - - studyViewFilter.setGenomicProfiles(profileGroups); - - var molecularProfileCounts = studyViewMapper.getMolecularProfileSampleCounts(StudyViewFilterHelper.build(studyViewFilter, null, null, studyViewFilter.getStudyIds())); - - var size = molecularProfileCounts.stream().filter(gc->gc.getValue().equals("mutations")) - .findFirst().get().getCount().intValue(); - assertEquals(11, size); - - } - - @Test - public void getMolecularProfileCountsMultipleProfilesUnion() { - StudyViewFilter studyViewFilter = new StudyViewFilter(); - studyViewFilter.setStudyIds(List.of(STUDY_TCGA_PUB)); - - var profiles = new ArrayList(Arrays.asList("mutations","mrna")); - var profileGroups = new ArrayList>(Arrays.asList(profiles)); - - studyViewFilter.setGenomicProfiles(profileGroups); - - var molecularProfileCounts = studyViewMapper.getMolecularProfileSampleCounts(StudyViewFilterHelper.build(studyViewFilter, null, null, studyViewFilter.getStudyIds())); - - var sizeMutations = molecularProfileCounts.stream().filter(gc->gc.getValue().equals("mutations")) - .findFirst().get().getCount().intValue(); - assertEquals(11, sizeMutations); - - var sizeMrna = molecularProfileCounts.stream().filter(gc->gc.getValue().equals("mrna")) - .findFirst().get().getCount().intValue(); - assertEquals(9, sizeMrna); - - } - - @Test - public void getMolecularProfileCountsMultipleProfilesIntersect() { - StudyViewFilter studyViewFilter = new StudyViewFilter(); - studyViewFilter.setStudyIds(List.of(STUDY_TCGA_PUB)); - - var profile1 = new ArrayList(Arrays.asList("mutations")); - var profile2 = new ArrayList(Arrays.asList("mrna")); - var profileGroups = new ArrayList>(Arrays.asList(profile1, profile2)); - - studyViewFilter.setGenomicProfiles(profileGroups); - - var molecularProfileCounts = studyViewMapper.getMolecularProfileSampleCounts(StudyViewFilterHelper.build(studyViewFilter, null, null, studyViewFilter.getStudyIds())); - - var sizeMutations = molecularProfileCounts.stream().filter(gc->gc.getValue().equals("mutations")) - .findFirst().get().getCount().intValue(); - assertEquals(10, sizeMutations); - - - - } - - - - -} \ No newline at end of file diff --git a/src/test/java/org/cbioportal/legacy/persistence/mybatisclickhouse/MutatedGenesTest.java b/src/test/java/org/cbioportal/legacy/persistence/mybatisclickhouse/MutatedGenesTest.java deleted file mode 100644 index 86658bc8dfb..00000000000 --- a/src/test/java/org/cbioportal/legacy/persistence/mybatisclickhouse/MutatedGenesTest.java +++ /dev/null @@ -1,89 +0,0 @@ -package org.cbioportal.legacy.persistence.mybatisclickhouse; - -import org.cbioportal.legacy.model.AlterationFilter; -import org.cbioportal.legacy.model.MutationEventType; -import org.cbioportal.legacy.persistence.helper.AlterationFilterHelper; -import org.cbioportal.legacy.persistence.helper.StudyViewFilterHelper; -import org.cbioportal.legacy.persistence.mybatisclickhouse.config.MyBatisConfig; -import org.cbioportal.legacy.web.parameter.StudyViewFilter; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase; -import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; -import org.springframework.context.annotation.Import; -import org.springframework.test.annotation.DirtiesContext; -import org.springframework.test.context.ContextConfiguration; -import org.springframework.test.context.junit4.SpringRunner; - -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; - -import static org.junit.Assert.assertEquals; - -@RunWith(SpringRunner.class) -@Import(MyBatisConfig.class) -@DataJpaTest -@DirtiesContext -@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE) -@ContextConfiguration(initializers = AbstractTestcontainers.Initializer.class) -public class MutatedGenesTest extends AbstractTestcontainers { - - private static final String STUDY_TCGA_PUB = "study_tcga_pub"; - - @Autowired - private StudyViewMapper studyViewMapper; - - @Test - public void getMutatedGenes() { - StudyViewFilter studyViewFilter = new StudyViewFilter(); - studyViewFilter.setStudyIds(List.of(STUDY_TCGA_PUB)); - var alterationCountByGenes = studyViewMapper.getMutatedGenes(StudyViewFilterHelper.build(studyViewFilter, null, null, studyViewFilter.getStudyIds()), - AlterationFilterHelper.build(studyViewFilter.getAlterationFilter())); - assertEquals(3, alterationCountByGenes.size()); - - var testBrca1AlterationCount = alterationCountByGenes.stream().filter(a -> Objects.equals(a.getHugoGeneSymbol(), "BRCA1")).findFirst(); - assert (testBrca1AlterationCount.isPresent()); - assertEquals(Integer.valueOf(5), testBrca1AlterationCount.get().getTotalCount()); - } - - @Test - public void getMutatedGenesWithAlterationFilter() { - StudyViewFilter studyViewFilter = new StudyViewFilter(); - studyViewFilter.setStudyIds(List.of(STUDY_TCGA_PUB)); - - // Create AlterationFilter - AlterationFilter alterationFilter = new AlterationFilter(); - Map mutationEventTypeFilterMap = new HashMap<>(); - mutationEventTypeFilterMap.put(MutationEventType.nonsense_mutation, Boolean.TRUE); - mutationEventTypeFilterMap.put(MutationEventType.other, Boolean.FALSE); - alterationFilter.setMutationEventTypes(mutationEventTypeFilterMap); - - var alterationCountByGenes = studyViewMapper.getMutatedGenes(StudyViewFilterHelper.build(studyViewFilter, null, null, studyViewFilter.getStudyIds()), - AlterationFilterHelper.build(alterationFilter)); - assertEquals(2, alterationCountByGenes.size()); - - AlterationFilter onlyMutationStatusFilter = new AlterationFilter(); - onlyMutationStatusFilter.setMutationEventTypes(new HashMap<>()); - onlyMutationStatusFilter.setIncludeGermline(false); - onlyMutationStatusFilter.setIncludeSomatic(false); - onlyMutationStatusFilter.setIncludeUnknownStatus(true); - - var alterationCountByGenes1 = studyViewMapper.getMutatedGenes(StudyViewFilterHelper.build(studyViewFilter, null, null, studyViewFilter.getStudyIds()), - AlterationFilterHelper.build(onlyMutationStatusFilter)); - assertEquals(1, alterationCountByGenes1.size()); - - AlterationFilter mutationTypeAndStatusFilter = new AlterationFilter(); - mutationTypeAndStatusFilter.setMutationEventTypes(mutationEventTypeFilterMap); - mutationTypeAndStatusFilter.setMutationEventTypes(new HashMap<>()); - mutationTypeAndStatusFilter.setIncludeGermline(false); - mutationTypeAndStatusFilter.setIncludeSomatic(false); - mutationTypeAndStatusFilter.setIncludeUnknownStatus(true); - - var alterationCountByGenes2 = studyViewMapper.getMutatedGenes(StudyViewFilterHelper.build(studyViewFilter, null, null, studyViewFilter.getStudyIds()), - AlterationFilterHelper.build(onlyMutationStatusFilter)); - assertEquals(1, alterationCountByGenes2.size()); - } -} diff --git a/src/test/java/org/cbioportal/legacy/persistence/mybatisclickhouse/MutationDataCountsTest.java b/src/test/java/org/cbioportal/legacy/persistence/mybatisclickhouse/MutationDataCountsTest.java deleted file mode 100644 index a7c7959a0b4..00000000000 --- a/src/test/java/org/cbioportal/legacy/persistence/mybatisclickhouse/MutationDataCountsTest.java +++ /dev/null @@ -1,72 +0,0 @@ -package org.cbioportal.legacy.persistence.mybatisclickhouse; - -import org.cbioportal.legacy.model.GenomicDataCount; -import org.cbioportal.legacy.model.GenomicDataCountItem; -import org.cbioportal.legacy.persistence.helper.StudyViewFilterHelper; -import org.cbioportal.legacy.persistence.mybatisclickhouse.config.MyBatisConfig; -import org.cbioportal.legacy.web.parameter.GenomicDataFilter; -import org.cbioportal.legacy.web.parameter.StudyViewFilter; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase; -import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; -import org.springframework.context.annotation.Import; -import org.springframework.test.annotation.DirtiesContext; -import org.springframework.test.context.ContextConfiguration; -import org.springframework.test.context.junit4.SpringRunner; - -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import static org.assertj.core.api.Assertions.assertThat; - -@RunWith(SpringRunner.class) -@Import(MyBatisConfig.class) -@DataJpaTest -@DirtiesContext -@AutoConfigureTestDatabase(replace= AutoConfigureTestDatabase.Replace.NONE) -@ContextConfiguration(initializers = AbstractTestcontainers.Initializer.class) -public class MutationDataCountsTest extends AbstractTestcontainers { - - private static final String STUDY_TCGA_PUB = "study_tcga_pub"; - - @Autowired - private StudyViewMapper studyViewMapper; - - @Test - public void getMutationCounts() { - StudyViewFilter studyViewFilter = new StudyViewFilter(); - studyViewFilter.setStudyIds(List.of(STUDY_TCGA_PUB)); - - GenomicDataFilter genomicDataFilterMutation = new GenomicDataFilter("AKT1", "cna"); - Map actualMutationCounts = studyViewMapper.getMutationCounts(StudyViewFilterHelper.build(studyViewFilter, null, null, studyViewFilter.getStudyIds()), genomicDataFilterMutation); - Map expectedMutationCounts = new HashMap<>(); - expectedMutationCounts.put("mutatedCount", 2); - expectedMutationCounts.put("notMutatedCount", 8); - expectedMutationCounts.put("notProfiledCount", 5); - assertThat(actualMutationCounts) - .usingRecursiveComparison() - .ignoringCollectionOrder() - .isEqualTo(expectedMutationCounts); - } - - @Test - public void getMutationCountsByType() { - StudyViewFilter studyViewFilter = new StudyViewFilter(); - studyViewFilter.setStudyIds(List.of(STUDY_TCGA_PUB)); - - GenomicDataFilter genomicDataFilterMutation = new GenomicDataFilter("AKT1", "mutation"); - List actualMutationCountsByType = studyViewMapper.getMutationCountsByType(StudyViewFilterHelper.build(studyViewFilter, null, null, studyViewFilter.getStudyIds()), List.of(genomicDataFilterMutation)); - List expectedMutationCountsByType = List.of( - new GenomicDataCountItem("AKT1", "mutations", List.of( - new GenomicDataCount("nonsense mutation", "nonsense_mutation", 2, 1), - new GenomicDataCount("missense mutation", "missense_mutation", 1, 1) - ))); - assertThat(actualMutationCountsByType) - .usingRecursiveComparison() - .ignoringCollectionOrder() - .isEqualTo(expectedMutationCountsByType); - } -} diff --git a/src/test/java/org/cbioportal/legacy/persistence/mybatisclickhouse/PatientTreatmentCountsTest.java b/src/test/java/org/cbioportal/legacy/persistence/mybatisclickhouse/PatientTreatmentCountsTest.java deleted file mode 100644 index f83ea3f263a..00000000000 --- a/src/test/java/org/cbioportal/legacy/persistence/mybatisclickhouse/PatientTreatmentCountsTest.java +++ /dev/null @@ -1,67 +0,0 @@ -package org.cbioportal.legacy.persistence.mybatisclickhouse; - -import org.cbioportal.legacy.persistence.helper.StudyViewFilterHelper; -import org.cbioportal.legacy.persistence.mybatisclickhouse.config.MyBatisConfig; -import org.cbioportal.legacy.web.parameter.StudyViewFilter; -import org.cbioportal.legacy.web.parameter.filter.AndedPatientTreatmentFilters; -import org.cbioportal.legacy.web.parameter.filter.OredPatientTreatmentFilters; -import org.cbioportal.legacy.web.parameter.filter.PatientTreatmentFilter; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase; -import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; -import org.springframework.context.annotation.Import; -import org.springframework.test.annotation.DirtiesContext; -import org.springframework.test.context.ContextConfiguration; -import org.springframework.test.context.junit4.SpringRunner; - -import java.util.List; - -import static org.junit.Assert.assertEquals; - -@RunWith(SpringRunner.class) -@Import(MyBatisConfig.class) -@DataJpaTest -@DirtiesContext -@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE) -@ContextConfiguration(initializers = AbstractTestcontainers.Initializer.class) -public class PatientTreatmentCountsTest extends AbstractTestcontainers { - - private static final String STUDY_TCGA_PUB = "study_tcga_pub"; - - @Autowired - private StudyViewMapper studyViewMapper; - - @Test - public void getPatientTreatmentReportCounts() { - StudyViewFilter studyViewFilter = new StudyViewFilter(); - studyViewFilter.setStudyIds(List.of(STUDY_TCGA_PUB)); - - - var patientTreatmentCounts = studyViewMapper.getPatientTreatmentCounts(StudyViewFilterHelper.build(studyViewFilter, null, null, studyViewFilter.getStudyIds())); - - var patientTreatments = studyViewMapper.getPatientTreatments(StudyViewFilterHelper.build(studyViewFilter, null, null, studyViewFilter.getStudyIds())); - - assertEquals(1, patientTreatmentCounts); - assertEquals("madeupanib", patientTreatments.getFirst().treatment()); - - PatientTreatmentFilter filter = new PatientTreatmentFilter(); - filter.setTreatment("madeupanib"); - - OredPatientTreatmentFilters oredPatientTreatmentFilters = new OredPatientTreatmentFilters(); - oredPatientTreatmentFilters.setFilters(List.of(filter)); - - AndedPatientTreatmentFilters andedPatientTreatmentFilters = new AndedPatientTreatmentFilters(); - andedPatientTreatmentFilters.setFilters(List.of(oredPatientTreatmentFilters)); - studyViewFilter.setPatientTreatmentFilters(andedPatientTreatmentFilters); - - patientTreatmentCounts = studyViewMapper.getPatientTreatmentCounts(StudyViewFilterHelper.build(studyViewFilter, null, null, studyViewFilter.getStudyIds())); - - patientTreatments = studyViewMapper.getPatientTreatments(StudyViewFilterHelper.build(studyViewFilter, null, null, studyViewFilter.getStudyIds())); - - assertEquals(1, patientTreatmentCounts); - assertEquals("madeupanib", patientTreatments.getFirst().treatment()); - - } -} diff --git a/src/test/java/org/cbioportal/legacy/persistence/mybatisclickhouse/ProfiledCountsTest.java b/src/test/java/org/cbioportal/legacy/persistence/mybatisclickhouse/ProfiledCountsTest.java deleted file mode 100644 index 6edfada6bec..00000000000 --- a/src/test/java/org/cbioportal/legacy/persistence/mybatisclickhouse/ProfiledCountsTest.java +++ /dev/null @@ -1,145 +0,0 @@ -package org.cbioportal.legacy.persistence.mybatisclickhouse; - -import org.cbioportal.legacy.persistence.helper.StudyViewFilterHelper; -import org.cbioportal.legacy.persistence.mybatisclickhouse.config.MyBatisConfig; -import org.cbioportal.legacy.web.parameter.StudyViewFilter; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase; -import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; -import org.springframework.context.annotation.Import; -import org.springframework.test.annotation.DirtiesContext; -import org.springframework.test.context.ContextConfiguration; -import org.springframework.test.context.junit4.SpringRunner; - -import java.util.List; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; - -@RunWith(SpringRunner.class) -@Import(MyBatisConfig.class) -@DataJpaTest -@DirtiesContext -@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE) -@ContextConfiguration(initializers = AbstractTestcontainers.Initializer.class) -public class ProfiledCountsTest extends AbstractTestcontainers { - - private static final String STUDY_TCGA_PUB = "study_tcga_pub"; - private static final String STUDY_GENIE_PUB = "study_genie_pub"; - - @Autowired - private StudyViewMapper studyViewMapper; - - @Test - public void getTotalProfiledCountsByGene() { - StudyViewFilter studyViewFilter = new StudyViewFilter(); - studyViewFilter.setStudyIds(List.of(STUDY_TCGA_PUB)); - - // Testing profiled counts on samples with gene panel data and WES for one study - var totalProfiledCountsForMutationsMap = studyViewMapper.getTotalProfiledCounts(StudyViewFilterHelper.build(studyViewFilter, null, null, studyViewFilter.getStudyIds()), - "MUTATION_EXTENDED", List.of()); - var totalProfiledCountsForCnaMap = studyViewMapper.getTotalProfiledCounts(StudyViewFilterHelper.build(studyViewFilter, null, null, studyViewFilter.getStudyIds()), - "COPY_NUMBER_ALTERATION", List.of()); - var sampleProfiledCountsForMutationsWithoutPanelDataMap = studyViewMapper.getSampleProfileCountWithoutPanelData(StudyViewFilterHelper.build(studyViewFilter, null, null, studyViewFilter.getStudyIds()), - "MUTATION_EXTENDED"); - var sampleProfiledCountsForCnaWithoutPanelDataMap = studyViewMapper.getSampleProfileCountWithoutPanelData(StudyViewFilterHelper.build(studyViewFilter, null, null, studyViewFilter.getStudyIds()), - "COPY_NUMBER_ALTERATION"); - - // Assert the count of genes with profiled cases for mutations - assertEquals(5, totalProfiledCountsForMutationsMap.size()); - // Assert the count of genes with profiled cases for CNA - assertEquals(5, totalProfiledCountsForCnaMap.size()); - // Assert the profiled counts for mutations without panel data (WES) - assertEquals(6, sampleProfiledCountsForMutationsWithoutPanelDataMap); - // Assert the profiled counts for CNA without panel data (WES) - assertEquals(11, sampleProfiledCountsForCnaWithoutPanelDataMap); - - // Assert the profiled counts for AKT2 mutations - // AKT2 is on testpanel2 in STUDY_TCGA_PUB - var akt2TotalProfiledCountsForMutations = totalProfiledCountsForMutationsMap.stream().filter(c -> c.getHugoGeneSymbol().equals("AKT2")).findFirst(); - assertTrue(akt2TotalProfiledCountsForMutations.isPresent()); - assertEquals(4, akt2TotalProfiledCountsForMutations.get().getNumberOfProfiledCases().intValue()); - // Assert the profiled counts for BRCA1 mutations - // BRCA1 is on testpanel1 in STUDY_TCGA_PUB - var brca1TotalProfiledCountsForMutations = totalProfiledCountsForMutationsMap.stream().filter(c -> c.getHugoGeneSymbol().equals("BRCA1")).findFirst(); - assertTrue(brca1TotalProfiledCountsForMutations.isPresent()); - assertEquals(1, brca1TotalProfiledCountsForMutations.get().getNumberOfProfiledCases().intValue()); - // Assert the profiled counts for AKT1 mutations - // AKT1 is on both testpanel1 and testpanel2 in STUDY_TCGA_PUB - var akt1TotalProfiledCountsForMutations = totalProfiledCountsForMutationsMap.stream().filter(c -> c.getHugoGeneSymbol().equals("AKT1")).findFirst(); - assertTrue(akt1TotalProfiledCountsForMutations.isPresent()); - assertEquals(5, akt1TotalProfiledCountsForMutations.get().getNumberOfProfiledCases().intValue()); - - // Assert the profiled counts for AKT2 CNA - // AKT2 is on testpanel2 in STUDY_TCGA_PUB - var akt2TotalProfiledCountsForCna = totalProfiledCountsForCnaMap.stream().filter(c -> c.getHugoGeneSymbol().equals("AKT2")).findFirst(); - assertTrue(akt2TotalProfiledCountsForCna.isPresent()); - assertEquals(6, akt2TotalProfiledCountsForCna.get().getNumberOfProfiledCases().intValue()); - // Assert the profiled counts for BRCA1 CNA - // BRCA1 is on testpanel1 in STUDY_TCGA_PUB - var brca1TotalProfiledCountsForCna = totalProfiledCountsForCnaMap.stream().filter(c -> c.getHugoGeneSymbol().equals("BRCA1")).findFirst(); - assertTrue(brca1TotalProfiledCountsForCna.isPresent()); - assertEquals(2, brca1TotalProfiledCountsForCna.get().getNumberOfProfiledCases().intValue()); - // Assert the profiled counts for AKT1 CNA - // AKT1 is on both testpanel1 and testpanel2 in STUDY_TCGA_PUB - var akt1TotalProfiledCountsForCna = totalProfiledCountsForCnaMap.stream().filter(c -> c.getHugoGeneSymbol().equals("AKT1")).findFirst(); - assertTrue(akt1TotalProfiledCountsForCna.isPresent()); - assertEquals(8, akt1TotalProfiledCountsForCna.get().getNumberOfProfiledCases().intValue()); - - // Testing profiled counts on combined studies - studyViewFilter.setStudyIds(List.of(STUDY_TCGA_PUB, STUDY_GENIE_PUB)); - - // Testing profiled counts on samples with gene panel data and WES for a combined study - var totalProfiledCountsForMutationsMap1 = studyViewMapper.getTotalProfiledCounts(StudyViewFilterHelper.build(studyViewFilter, null, null, studyViewFilter.getStudyIds()), - "MUTATION_EXTENDED", List.of()); - var totalProfiledCountsForCnaMap1 = studyViewMapper.getTotalProfiledCounts(StudyViewFilterHelper.build(studyViewFilter, null, null, studyViewFilter.getStudyIds()), - "COPY_NUMBER_ALTERATION", List.of()); - var sampleProfiledCountsForMutationsWithoutPanelDataMap1 = studyViewMapper.getSampleProfileCountWithoutPanelData(StudyViewFilterHelper.build(studyViewFilter, null, null, studyViewFilter.getStudyIds()), - "MUTATION_EXTENDED"); - var sampleProfiledCountsForCnaWithoutPanelDataMap1 = studyViewMapper.getSampleProfileCountWithoutPanelData(StudyViewFilterHelper.build(studyViewFilter, null, null, studyViewFilter.getStudyIds()), - "COPY_NUMBER_ALTERATION"); - - // Assert the count of genes with profiled cases for mutations in a combined study - assertEquals(8, totalProfiledCountsForMutationsMap1.size()); - // Assert the count of genes with profiled cases for CNA in a combined study - assertEquals(8, totalProfiledCountsForCnaMap1.size()); - // Assert the profiled counts for mutations without panel data (WES) in a combined study - assertEquals(8, sampleProfiledCountsForMutationsWithoutPanelDataMap1); - // Assert the profiled counts for CNA without panel data (WES) in a combined study - assertEquals(12, sampleProfiledCountsForCnaWithoutPanelDataMap1); - - // Assert the profiled counts for BRCA1 mutations - // BRCA1 is on testpanel1 in STUDY_TCGA_PUB - var brca1TotalProfiledCountsForMutations1 = totalProfiledCountsForMutationsMap1.stream().filter(c -> c.getHugoGeneSymbol().equals("BRCA1")).findFirst(); - assertTrue(brca1TotalProfiledCountsForMutations1.isPresent()); - assertEquals(1, brca1TotalProfiledCountsForMutations1.get().getNumberOfProfiledCases().intValue()); - // Assert the profiled counts for BRCA2 mutations - // BRCA2 is on testpanel3 and testpanel4 in STUDY_GENIE_PUB - var brca2TotalProfiledCountsForMutations1 = totalProfiledCountsForMutationsMap1.stream().filter(c -> c.getHugoGeneSymbol().equals("BRCA2")).findFirst(); - assertTrue(brca2TotalProfiledCountsForMutations1.isPresent()); - assertEquals(2, brca2TotalProfiledCountsForMutations1.get().getNumberOfProfiledCases().intValue()); - // Assert the profiled counts for AKT2 mutations - // AKT2 is on testpanel2 in STUDY_TCGA_PUB and testpanel4 in STUDY_GENIE_PUB - var akt2TotalProfiledCountsForMutations1 = totalProfiledCountsForMutationsMap1.stream().filter(c -> c.getHugoGeneSymbol().equals("AKT2")).findFirst(); - assertTrue(akt2TotalProfiledCountsForMutations1.isPresent()); - assertEquals(4, akt2TotalProfiledCountsForMutations1.get().getNumberOfProfiledCases().intValue()); - - // Assert the profiled counts for BRCA1 CNA - // BRCA1 is on testpanel1 in STUDY_TCGA_PUB - var brca1TotalProfiledCountsForCna1 = totalProfiledCountsForCnaMap1.stream().filter(c -> c.getHugoGeneSymbol().equals("BRCA1")).findFirst(); - assertTrue(brca1TotalProfiledCountsForCna1.isPresent()); - assertEquals(2, brca1TotalProfiledCountsForCna1.get().getNumberOfProfiledCases().intValue()); - // Assert the profiled counts for BRCA2 CNA - // BRCA2 is on testpanel3 and testpanel4 in STUDY_GENIE_PUB - var brca2TotalProfiledCountsForCna1 = totalProfiledCountsForCnaMap1.stream().filter(c -> c.getHugoGeneSymbol().equals("BRCA2")).findFirst(); - assertTrue(brca2TotalProfiledCountsForCna1.isPresent()); - assertEquals(3, brca2TotalProfiledCountsForCna1.get().getNumberOfProfiledCases().intValue()); - // Assert the profiled counts for AKT2 CNA - // AKT2 is on testpanel2 in STUDY_TCGA_PUB and testpanel4 in STUDY_GENIE_PUB - var akt2TotalProfiledCountsForCna1 = totalProfiledCountsForCnaMap1.stream().filter(c -> c.getHugoGeneSymbol().equals("AKT2")).findFirst(); - assertTrue(akt2TotalProfiledCountsForCna1.isPresent()); - assertEquals(7, akt2TotalProfiledCountsForCna1.get().getNumberOfProfiledCases().intValue()); - } -} diff --git a/src/test/java/org/cbioportal/legacy/persistence/mybatisclickhouse/ProteinExpressionCountsTest.java b/src/test/java/org/cbioportal/legacy/persistence/mybatisclickhouse/ProteinExpressionCountsTest.java deleted file mode 100644 index 9d352d15b0e..00000000000 --- a/src/test/java/org/cbioportal/legacy/persistence/mybatisclickhouse/ProteinExpressionCountsTest.java +++ /dev/null @@ -1,99 +0,0 @@ -package org.cbioportal.legacy.persistence.mybatisclickhouse; - -import org.cbioportal.legacy.model.ClinicalDataCount; -import org.cbioportal.legacy.persistence.helper.StudyViewFilterHelper; -import org.cbioportal.legacy.persistence.mybatisclickhouse.config.MyBatisConfig; -import org.cbioportal.legacy.web.parameter.DataFilterValue; -import org.cbioportal.legacy.web.parameter.GenomicDataBinFilter; -import org.cbioportal.legacy.web.parameter.GenomicDataFilter; -import org.cbioportal.legacy.web.parameter.StudyViewFilter; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase; -import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; -import org.springframework.context.annotation.Import; -import org.springframework.test.annotation.DirtiesContext; -import org.springframework.test.context.ContextConfiguration; -import org.springframework.test.context.junit4.SpringRunner; - -import java.util.List; - -import static org.assertj.core.api.Assertions.assertThat; - -@RunWith(SpringRunner.class) -@Import(MyBatisConfig.class) -@DataJpaTest -@DirtiesContext -@AutoConfigureTestDatabase(replace= AutoConfigureTestDatabase.Replace.NONE) -@ContextConfiguration(initializers = AbstractTestcontainers.Initializer.class) -public class ProteinExpressionCountsTest extends AbstractTestcontainers { - - private static final String STUDY_TCGA_PUB = "study_tcga_pub"; - private static final String STUDY_ACC_TCGA = "acc_tcga"; - - @Autowired - private StudyViewMapper studyViewMapper; - - @Test - public void getProteinExpressionCounts() { - // Testing combined study missing samples when one lacks a relevant genomic profile - StudyViewFilter studyViewFilter = new StudyViewFilter(); - studyViewFilter.setStudyIds(List.of(STUDY_TCGA_PUB, STUDY_ACC_TCGA)); - - GenomicDataBinFilter genomicDataBinFilterRPPA = new GenomicDataBinFilter(); - genomicDataBinFilterRPPA.setHugoGeneSymbol("AKT1"); - genomicDataBinFilterRPPA.setProfileType("rppa"); - - List actualRPPACounts1 = studyViewMapper.getGenomicDataBinCounts(StudyViewFilterHelper.build(studyViewFilter, null, null, studyViewFilter.getStudyIds()), List.of(genomicDataBinFilterRPPA)); - - ClinicalDataCount expectedRPPACount1 = new ClinicalDataCount(); - expectedRPPACount1.setAttributeId("AKT1rppa"); - expectedRPPACount1.setValue("0.7360"); - expectedRPPACount1.setCount(1); - ClinicalDataCount expectedRPPACount2 = new ClinicalDataCount(); - expectedRPPACount2.setAttributeId("AKT1rppa"); - expectedRPPACount2.setValue("-0.8097"); - expectedRPPACount2.setCount(1); - ClinicalDataCount expectedRPPACount3 = new ClinicalDataCount(); - expectedRPPACount3.setAttributeId("AKT1rppa"); - expectedRPPACount3.setValue("-0.1260"); - expectedRPPACount3.setCount(1); - ClinicalDataCount expectedRPPACountNA = new ClinicalDataCount(); - expectedRPPACountNA.setAttributeId("AKT1rppa"); - expectedRPPACountNA.setValue("NA"); - expectedRPPACountNA.setCount(16); - - List expectedRPPACounts1 = List.of( - expectedRPPACount1, expectedRPPACount2, expectedRPPACount3, expectedRPPACountNA - ); - assertThat(actualRPPACounts1) - .usingRecursiveComparison() - .ignoringCollectionOrder() - .isEqualTo(expectedRPPACounts1); - - - // Testing NA filtering on combined study missing samples when one lacks a relevant genomic profile - // Make genomic data filter to put in study view filter - GenomicDataFilter genomicDataFilterRPPA = new GenomicDataFilter("AKT1", "rppa"); - DataFilterValue dataFilterValue = new DataFilterValue(); - dataFilterValue.setValue("NA"); - genomicDataFilterRPPA.setValues(List.of(dataFilterValue)); - studyViewFilter.setGenomicDataFilters(List.of(genomicDataFilterRPPA)); - - List actualRPPACounts2 = studyViewMapper.getGenomicDataBinCounts(StudyViewFilterHelper.build(studyViewFilter, null, null, studyViewFilter.getStudyIds()), List.of(genomicDataBinFilterRPPA)); - - ClinicalDataCount expectedRPPACount = new ClinicalDataCount(); - expectedRPPACount.setAttributeId("AKT1rppa"); - expectedRPPACount.setValue("NA"); - expectedRPPACount.setCount(16); - - List expectedRPPACounts2 = List.of( - expectedRPPACount - ); - assertThat(actualRPPACounts2) - .usingRecursiveComparison() - .ignoringCollectionOrder() - .isEqualTo(expectedRPPACounts2); - } -} diff --git a/src/test/java/org/cbioportal/legacy/persistence/mybatisclickhouse/SampleTreatmentCountsTest.java b/src/test/java/org/cbioportal/legacy/persistence/mybatisclickhouse/SampleTreatmentCountsTest.java deleted file mode 100644 index 8cfd8977da4..00000000000 --- a/src/test/java/org/cbioportal/legacy/persistence/mybatisclickhouse/SampleTreatmentCountsTest.java +++ /dev/null @@ -1,71 +0,0 @@ -package org.cbioportal.legacy.persistence.mybatisclickhouse; - -import org.cbioportal.legacy.model.TemporalRelation; -import org.cbioportal.legacy.persistence.helper.StudyViewFilterHelper; -import org.cbioportal.legacy.persistence.mybatisclickhouse.config.MyBatisConfig; -import org.cbioportal.legacy.web.parameter.StudyViewFilter; -import org.cbioportal.legacy.web.parameter.filter.AndedSampleTreatmentFilters; -import org.cbioportal.legacy.web.parameter.filter.OredSampleTreatmentFilters; -import org.cbioportal.legacy.web.parameter.filter.SampleTreatmentFilter; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase; -import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; -import org.springframework.context.annotation.Import; -import org.springframework.test.annotation.DirtiesContext; -import org.springframework.test.context.ContextConfiguration; -import org.springframework.test.context.junit4.SpringRunner; - -import java.util.List; - -import static org.junit.Assert.assertEquals; - -@RunWith(SpringRunner.class) -@Import(MyBatisConfig.class) -@DataJpaTest -@DirtiesContext -@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE) -@ContextConfiguration(initializers = AbstractTestcontainers.Initializer.class) -public class SampleTreatmentCountsTest extends AbstractTestcontainers { - - private static final String STUDY_TCGA_PUB = "study_tcga_pub"; - - @Autowired - private StudyViewMapper studyViewMapper; - - @Test - public void getSampleTreatmentCounts() { - StudyViewFilter studyViewFilter = new StudyViewFilter(); - studyViewFilter.setStudyIds(List.of(STUDY_TCGA_PUB)); - - - var totalSampleTreatmentCount = studyViewMapper.getTotalSampleTreatmentCounts(StudyViewFilterHelper.build(studyViewFilter, null, null, studyViewFilter.getStudyIds())); - - var sampleTreatmentCounts = studyViewMapper.getSampleTreatmentCounts(StudyViewFilterHelper.build(studyViewFilter, null, null, studyViewFilter.getStudyIds())); - - assertEquals(1, totalSampleTreatmentCount); - assertEquals("madeupanib", sampleTreatmentCounts.getFirst().treatment()); - assertEquals(1, sampleTreatmentCounts.getFirst().postSampleCount()); - assertEquals(0, sampleTreatmentCounts.getFirst().preSampleCount()); - - SampleTreatmentFilter filter = new SampleTreatmentFilter(); - filter.setTreatment("madeupanib"); - filter.setTime(TemporalRelation.Pre); - - OredSampleTreatmentFilters oredSampleTreatmentFilters = new OredSampleTreatmentFilters(); - oredSampleTreatmentFilters.setFilters(List.of(filter)); - - AndedSampleTreatmentFilters andedSampleTreatmentFilters = new AndedSampleTreatmentFilters(); - andedSampleTreatmentFilters.setFilters(List.of(oredSampleTreatmentFilters)); - studyViewFilter.setSampleTreatmentFilters(andedSampleTreatmentFilters); - - totalSampleTreatmentCount = studyViewMapper.getTotalSampleTreatmentCounts(StudyViewFilterHelper.build(studyViewFilter, null, null, studyViewFilter.getStudyIds())); - - sampleTreatmentCounts = studyViewMapper.getSampleTreatmentCounts(StudyViewFilterHelper.build(studyViewFilter, null, null, studyViewFilter.getStudyIds())); - - assertEquals(0, totalSampleTreatmentCount); - assertEquals(0, sampleTreatmentCounts.size()); - - } -} diff --git a/src/test/java/org/cbioportal/legacy/persistence/mybatisclickhouse/StructuralVariantGenesTest.java b/src/test/java/org/cbioportal/legacy/persistence/mybatisclickhouse/StructuralVariantGenesTest.java deleted file mode 100644 index f5abdcb578f..00000000000 --- a/src/test/java/org/cbioportal/legacy/persistence/mybatisclickhouse/StructuralVariantGenesTest.java +++ /dev/null @@ -1,56 +0,0 @@ -package org.cbioportal.legacy.persistence.mybatisclickhouse; - -import org.cbioportal.legacy.persistence.helper.AlterationFilterHelper; -import org.cbioportal.legacy.persistence.helper.StudyViewFilterHelper; -import org.cbioportal.legacy.persistence.mybatisclickhouse.config.MyBatisConfig; -import org.cbioportal.legacy.web.parameter.StudyViewFilter; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase; -import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; -import org.springframework.context.annotation.Import; -import org.springframework.test.annotation.DirtiesContext; -import org.springframework.test.context.ContextConfiguration; -import org.springframework.test.context.junit4.SpringRunner; - -import java.util.List; -import java.util.Objects; - -import static org.junit.Assert.assertEquals; - -@RunWith(SpringRunner.class) -@Import(MyBatisConfig.class) -@DataJpaTest -@DirtiesContext -@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE) -@ContextConfiguration(initializers = AbstractTestcontainers.Initializer.class) -public class StructuralVariantGenesTest extends AbstractTestcontainers { - - private static final String STUDY_TCGA_PUB = "study_tcga_pub"; - private static final String STUDY_ACC_TCGA = "acc_tcga"; - - @Autowired - private StudyViewMapper studyViewMapper; - - @Test - public void getStructuralVariantGenes() { - StudyViewFilter studyViewFilter = new StudyViewFilter(); - studyViewFilter.setStudyIds(List.of(STUDY_TCGA_PUB, STUDY_ACC_TCGA)); - var alterationCountByGenes = studyViewMapper.getStructuralVariantGenes(StudyViewFilterHelper.build(studyViewFilter, null, null, studyViewFilter.getStudyIds()), - AlterationFilterHelper.build(studyViewFilter.getAlterationFilter())); - assertEquals(8, alterationCountByGenes.size()); - - // Test sv count for eml4 which is in one study - var testeml4AlterationCount = alterationCountByGenes.stream().filter(a -> Objects.equals(a.getHugoGeneSymbol(), "eml4")) - .mapToInt(c -> c.getTotalCount().intValue()) - .sum(); - assertEquals(1, testeml4AlterationCount); - - // Test sv count for ncoa4 which is in both studies - var testncoa4AlterationCount = alterationCountByGenes.stream().filter(a -> Objects.equals(a.getHugoGeneSymbol(), "ncoa4")) - .mapToInt(c -> c.getTotalCount().intValue()) - .sum(); - assertEquals(3, testncoa4AlterationCount); - } -} diff --git a/src/test/java/org/cbioportal/legacy/service/impl/ViolinPlotServiceImplTest.java b/src/test/java/org/cbioportal/legacy/service/impl/ViolinPlotServiceImplTest.java index e879097dccb..5e944efd3b7 100644 --- a/src/test/java/org/cbioportal/legacy/service/impl/ViolinPlotServiceImplTest.java +++ b/src/test/java/org/cbioportal/legacy/service/impl/ViolinPlotServiceImplTest.java @@ -16,6 +16,7 @@ import java.math.BigDecimal; import java.util.*; +import static java.util.stream.Collectors.toSet; import static org.mockito.ArgumentMatchers.anyList; @RunWith(MockitoJUnitRunner.Silent.class) @@ -72,9 +73,13 @@ public void getClinicalViolinPlotData() throws Exception { } final int NUM_CURVE_POINTS = 100; + Set sampleIdsSet = filteredSamples + .stream() + .map(s -> s.getInternalId()) + .collect(toSet()); ClinicalViolinPlotData result = violinPlotService.getClinicalViolinPlotData( sampleClinicalData, - filteredSamples, + sampleIdsSet, new BigDecimal(0), new BigDecimal(1), new BigDecimal(NUM_CURVE_POINTS),