Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
8e5a38c
Add mutation domain classes and use cases
i-am-leslie Aug 1, 2025
8fa7c95
Made modifications to the usecases and added methods to the repository
i-am-leslie Aug 2, 2025
8ea0ec0
Working on the infrastructure layer
i-am-leslie Aug 2, 2025
d93a153
Moved the mutation infrastructure to the right folder
i-am-leslie Aug 2, 2025
dc7b0ce
finished up the mapper class for the infrastructure
i-am-leslie Aug 2, 2025
c9f8e85
Added rest endpoint and a record class for all use cases
i-am-leslie Aug 4, 2025
930b9ab
Added rest endpoint and a record class for all use cases
i-am-leslie Aug 4, 2025
adb2887
Added rest endpoint and a record class for all use cases
i-am-leslie Aug 4, 2025
b74f90d
Refractored the controller layer adhering to clean arch principles
i-am-leslie Aug 5, 2025
8ed06a1
Started with creating the sql for clickhouse repo mutation
i-am-leslie Aug 6, 2025
0af5d3c
Added test for ferchAllMutationsProfileUseCase logic
i-am-leslie Aug 6, 2025
f94e5f7
Added test for ferchAllMutationsProfileUseCase logic
i-am-leslie Aug 6, 2025
832c7e6
Added test for ferchAllMutationsProfileUseCase logic
i-am-leslie Aug 6, 2025
66e5822
Finshed testing the utility class and usecase logic
i-am-leslie Aug 7, 2025
7ae555d
cleaned up some classes
i-am-leslie Aug 9, 2025
088adf8
Wrote the sql for getMetaMutation use case. Starting with getMutation…
i-am-leslie Aug 13, 2025
d41a619
Changed the naming for mutation controller
i-am-leslie Aug 14, 2025
cc99918
Fixed some parameters for the datamapper to control information from …
i-am-leslie Aug 17, 2025
75272dc
Refractored the mapper class method to handle each projection with it…
i-am-leslie Aug 17, 2025
d2ed0e0
Rough SQL for SUMMARY projection note, need to crosscheck
i-am-leslie Aug 24, 2025
f561c7a
Refactored repository layer to use molecularProfileCaseIdentifierUtil…
i-am-leslie Aug 26, 2025
5485aa4
Updates
i-am-leslie Aug 30, 2025
eadf94d
fixed up summary query
i-am-leslie Sep 1, 2025
e7b7949
Almost done with queries need to confirm some results
i-am-leslie Sep 1, 2025
c270509
Finished up summary and detailed projection wroks now
i-am-leslie Sep 2, 2025
b63e093
Created dto's and maooers for data received from the clincal data mapper
i-am-leslie Sep 3, 2025
064a995
corrected field variantAllele
i-am-leslie Sep 3, 2025
a8c51f3
Refactored code to make use of projectionType
i-am-leslie Sep 4, 2025
89fe9cc
Trying to adjust the queries to make use of clickhouse strengths
i-am-leslie Sep 5, 2025
585b426
put more comments for description
i-am-leslie Sep 6, 2025
1750883
Trying to optimize the query for clickhouse by batch sending the whol…
i-am-leslie Sep 13, 2025
6c0f485
Fixed the query to work for just molecularProfileId is provided
i-am-leslie Sep 18, 2025
af6b53c
Done with the query optimization need to add comments
i-am-leslie Sep 28, 2025
129b5f6
Finsished with the comments, Looking through the test to ensure its a…
i-am-leslie Sep 28, 2025
02d0b8e
Finished, i believe sql should still be checked for correectness
i-am-leslie Sep 28, 2025
9638e9f
Added condition to filter out null in mutation columns
i-am-leslie Sep 30, 2025
c6276db
Tried controlling the result of the cartesian product
i-am-leslie Oct 1, 2025
dfdc218
Refactored Id to remove arguments the proejcting did not need
i-am-leslie Oct 2, 2025
5de7fda
Started with the e2e test
i-am-leslie Oct 2, 2025
52f3d98
working on the e2e test
i-am-leslie Oct 4, 2025
90026ce
e2e test complete awaiting review
i-am-leslie Oct 5, 2025
7e35468
Added comments
i-am-leslie Oct 7, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
132 changes: 132 additions & 0 deletions src/e2e/java/org/cbioportal/ColumnStoreMutationControllerE2ETest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
package org.cbioportal;


import org.cbioportal.application.rest.response.MutationDTO;
import org.cbioportal.shared.enums.ProjectionType;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.boot.test.web.server.LocalServerPort;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.http.HttpMethod;
import org.springframework.test.context.junit.jupiter.SpringExtension;

import static org.junit.jupiter.api.Assertions.*;

@ExtendWith(SpringExtension.class)
public class ColumnStoreMutationControllerE2ETest extends AbstractE2ETest{

@Autowired
private TestRestTemplate restTemplate;

@LocalServerPort
private int port;

private static final com.fasterxml.jackson.databind.ObjectMapper OBJECT_MAPPER = new com.fasterxml.jackson.databind.ObjectMapper();


private MutationDTO[] callFetchMutationEndPoint(String testDataJson, ProjectionType projectionType)throws Exception{
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
HttpEntity<String> requestEntity = new HttpEntity<>(testDataJson, headers);

ResponseEntity<String> response = restTemplate.exchange(
"http://localhost:" + port + "/api/column-store/mutations/fetch?projection="
+ projectionType.name(),
HttpMethod.POST,
requestEntity,
String.class
);

assertEquals(HttpStatus.OK, response.getStatusCode());
assertNotNull(response.getBody());

return OBJECT_MAPPER.readValue(response.getBody(), MutationDTO[].class);

}

private String loadTestData(String filename) throws Exception {
return new String(java.nio.file.Files.readAllBytes(
java.nio.file.Paths.get("src/e2e/java/org/cbioportal/ColumnStoreMutationControllerE2ETest/" + filename)));
}

@Test
void testFetchMutationEndPointWithDataJson_IdProjection() throws Exception {
// The json has two molecularProfileId and a sampleId and entrezGeneIds to restrict search
// Two profiles meet this criteria

String testDataJson = loadTestData("mutation_filter.json");
MutationDTO[] mutationResultID = callFetchMutationEndPoint(testDataJson, ProjectionType.ID);

assertNotNull(mutationResultID, "Response should have mutation DTO");
assertEquals(2, mutationResultID.length, "Two mutations meet the search criteria of the json file");


//Compare the fields that should be equal
//MolecularProfile id should be identical
assertEquals(mutationResultID[0].molecularProfileId(), mutationResultID[1].molecularProfileId(), "molecularProfile IDs should match");
//study id should be identical;
assertEquals(mutationResultID[0].studyId(), mutationResultID[1].studyId(), "study IDs should match");


}
@Test
void testFetchMutationEndPointWithDataJson_SummaryProjection() throws Exception {
// The json has two molecularProfileId and a sampleId and entrezGeneIds to restrict search
// Two profiles meet this criteria

String testDataJson = loadTestData("mutation_filter.json");
MutationDTO[] mutationResultSummary = callFetchMutationEndPoint(testDataJson,ProjectionType.SUMMARY);

assertNotNull(mutationResultSummary, "Response should have mutation DTO");
assertEquals(2, mutationResultSummary.length, "SUMMARY projection should not add or remove records");


//Compare the fields that should be equal
//MolecularProfile id should be identical
assertEquals(mutationResultSummary[0].molecularProfileId(), mutationResultSummary[1].molecularProfileId(), "molecularProfile IDs should match");

//study id should be identical;
assertEquals(mutationResultSummary[0].studyId(), mutationResultSummary[1].studyId(), "study IDs should match");

// Testing different projection expose different fields
// SUMMARY projection should not have gene present or any AlleleSpecificCopyNumber. AlleleSpecificCopyNumber is null for this mutation profile
for (MutationDTO mutationDTO : mutationResultSummary) {
assertNull(mutationDTO.gene(), "Response should not have gene present");
assertNull(mutationDTO.alleleSpecificCopyNumber(), "Response should not have AlleleSpecificCopyNumber present");
}

}

@Test
void testFetchMutationEndPointWithDataJson_DetailedProjection() throws Exception {
// The json has two molecularProfileId and a sampleId and entrezGeneIds to restrict search
// Two profiles meet this criteria

String testDataJson = loadTestData("mutation_filter.json");
MutationDTO[] mutationResultDetailed = callFetchMutationEndPoint(testDataJson,ProjectionType.DETAILED);

assertNotNull(mutationResultDetailed, "Response should have mutation DTO");
assertEquals(2, mutationResultDetailed.length, "DETAILED projection should not add or remove records");


//Compare the fields that should be equal

//MolecularProfile id should be identical
assertEquals(mutationResultDetailed[0].molecularProfileId(), mutationResultDetailed[1].molecularProfileId(), "molecularProfile IDs should match");
//study id should be identical;
assertEquals(mutationResultDetailed[0].studyId(), mutationResultDetailed[1].studyId(), "study IDs should match");

// Testing different projection expose different fields
// Detailed projection should have gene present or any AlleleSpecificCopyNumber. AlleleSpecificCopyNumber is null for this mutation profile
for (MutationDTO mutationDTO : mutationResultDetailed) {
assertNotNull(mutationDTO.gene(), "Response should have gene present");
assertNull(mutationDTO.alleleSpecificCopyNumber(), "Response should not have AlleleSpecificCopyNumber present ");
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"sampleMolecularIdentifiers": [
{"sampleId": "P01_Pri", "molecularProfileId": "lgg_ucsf_2014_mutations"},
{"sampleId": "P05_Rec", "molecularProfileId": "lgg_ucsf_2014_mutations"}
],
"entrezGeneIds": [287,2]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package org.cbioportal.application.rest.mapper;
import org.cbioportal.application.rest.response.AlleleSpecificCopyNumberDTO;
import org.cbioportal.legacy.model.AlleleSpecificCopyNumber;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;

@Mapper
public interface AlleleSpecificCopyNumberMapper {
AlleleSpecificCopyNumberMapper INSTANCE =
Mappers.getMapper(AlleleSpecificCopyNumberMapper.class);

AlleleSpecificCopyNumberDTO toAlleleSpecificCopyNumberDTO(
AlleleSpecificCopyNumber alleleSpecificCopyNumber
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package org.cbioportal.application.rest.mapper;

import org.cbioportal.application.rest.response.GeneDTO;
import org.cbioportal.legacy.model.Gene;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;

@Mapper
public interface GeneMapper {
GeneMapper INSTANCE = Mappers.getMapper(GeneMapper.class);

GeneDTO toGeneDTO(Gene gene);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package org.cbioportal.application.rest.mapper;

import org.cbioportal.application.rest.response.MutationDTO;

import org.cbioportal.legacy.model.Mutation;
import org.cbioportal.legacy.utils.Encoder;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.factory.Mappers;

import java.util.List;

@Mapper(
imports = Encoder.class,
uses = { GeneMapper.class, AlleleSpecificCopyNumberMapper.class }
)
public interface MutationMapper {
MutationMapper INSTANCE = Mappers.getMapper(MutationMapper.class);

@Mapping(
target = "uniqueSampleKey",
expression =
"java( Encoder.calculateBase64(mutation.getSampleId()," + "mutation.getStudyId()) )")
@Mapping(
target = "uniquePatientKey",
expression =
"java( Encoder.calculateBase64(mutation.getPatientId(), " + "mutation.getStudyId()) )")
@Mapping(source = "tumorSeqAllele", target = "variantAllele")
MutationDTO toMutationDTOO(Mutation mutation);

List<MutationDTO> toDTOs(List<Mutation> mutationList);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package org.cbioportal.application.rest.response;

public record AlleleSpecificCopyNumberDTO(
Integer ascnIntegerCopyNumber,
String ascnMethod,
Float ccfExpectedCopiesUpper,
Float ccfExpectedCopies,
String clonal,
Integer minorCopyNumber,
Integer expectedAltCopies,
Integer totalCopyNumber
) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package org.cbioportal.application.rest.response;

public record GeneDTO(
Integer entrezGeneId,
String hugoGeneSymbol,
String type
) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package org.cbioportal.application.rest.response;


public record MutationDTO(
String uniqueSampleKey,
String uniquePatientKey,
String molecularProfileId,
String sampleId,
String patientId,
Integer entrezGeneId,
GeneDTO gene,
String studyId,
String driverFilter,
String driverFilterAnnotation,
String driverTiersFilter,
String driverTiersFilterAnnotation,
String center,
String mutationStatus,
String validationStatus,
Integer tumorAltCount,
Integer tumorRefCount,
Integer normalAltCount,
Integer normalRefCount,
String aminoAcidChange,
String chr,
Long startPosition,
Long endPosition,
String referenceAllele,
String variantAllele,
String proteinChange,
String mutationType,
String ncbiBuild,
String variantType,
String refseqMrnaId,
Integer proteinPosStart,
Integer proteinPosEnd,
String keyword,
AlleleSpecificCopyNumberDTO alleleSpecificCopyNumber
) {
}
Loading