Skip to content
Draft
Show file tree
Hide file tree
Changes from 29 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
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,31 @@
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()) )")
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
) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
package org.cbioportal.application.rest.vcolumnstore;

import io.swagger.v3.oas.annotations.Hidden;
import io.swagger.v3.oas.annotations.Parameter;
import jakarta.validation.Valid;
import jakarta.validation.constraints.Max;
import jakarta.validation.constraints.Min;
import org.cbioportal.application.rest.mapper.MutationMapper;
import org.cbioportal.application.rest.response.MutationDTO;
import org.cbioportal.domain.mutation.usecase.GetMutationUseCases;
import org.cbioportal.legacy.model.Mutation;
import org.cbioportal.legacy.model.meta.MutationMeta;
import org.cbioportal.legacy.web.parameter.*;
import org.cbioportal.legacy.web.parameter.sort.MutationSortBy;
import org.cbioportal.shared.MutationSearchCriteria;
import org.cbioportal.shared.enums.ProjectionType;
import org.springframework.context.annotation.Profile;
import org.springframework.http.HttpHeaders;
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.web.bind.annotation.*;

import java.util.Collection;
import java.util.List;


/**
* REST controller for managing and retrieving Mutation data from a column-store data
* source.
*
* <p>This controller provides an endpoint to fetch Mutation data with support for
* filtering, sorting, and controlling the level of detail in the response. It is designed to work
* with a column-store database, which is optimized for querying large datasets efficiently.
*
*/


@RestController
@RequestMapping("/api/column-store")
@Profile("clickhouse")
public class ColumnStoreMutationController {
private final GetMutationUseCases getMutationUseCases;

/**
* Constructs a new {@link ColumnStoreMutationController} with the specified use case.
*
* @param getMutationUseCases the use case responsible for retrieving Mutation metadata or Mutation
*
*/
public ColumnStoreMutationController(GetMutationUseCases getMutationUseCases) {
this.getMutationUseCases = getMutationUseCases;
}


/**
* Fetch Mutation by exactly one sampleUniqueIdentifier or molecularProfileId must or entrezGeneIds
* @return ResponseEntity containing list of Mutation data DTOs, or empty body with count header
* for META projection
*/
@Hidden
@PreAuthorize(
"hasPermission(#involvedCancerStudies, 'Collection<CancerStudyId>', T(org.cbioportal.legacy.utils.security.AccessLevel).READ)")
@PostMapping(
value = "/mutations/fetch",
consumes = MediaType.APPLICATION_JSON_VALUE,
produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<List<MutationDTO>> fetchMutationsInMultipleMolecularProfiles(
@Parameter(hidden = true) // prevent reference to this attribute in the swagger-ui interface
@RequestAttribute(required = false, value = "involvedCancerStudies")
Collection<String> involvedCancerStudies,
@Parameter(
hidden =
true) // prevent reference to this attribute in the swagger-ui interface. this
// attribute is needed for now but was needed previously for @PreAuthorize .
@Valid
@RequestBody(required = false)
MutationMultipleStudyFilter interceptedMutationMultipleStudyFilter, // This is being intercepted will leave this
@Parameter(
required = true,
description =
"List of Molecular Profile IDs or List of Molecular Profile ID / Sample ID pairs,"
+ " and List of Entrez Gene IDs")
@Valid
@RequestBody(required = false)
MutationMultipleStudyFilter mutationMultipleStudyFilter,
@Parameter(description = "Level of detail of the response")
@RequestParam(defaultValue = "SUMMARY")
ProjectionType projection,
@Parameter(description = "Page size of the result list")
@Max(PagingConstants.MAX_PAGE_SIZE)
@Min(PagingConstants.MIN_PAGE_SIZE)
@RequestParam(defaultValue = PagingConstants.DEFAULT_PAGE_SIZE)
Integer pageSize,
@Parameter(description = "Page number of the result list")
@Min(PagingConstants.MIN_PAGE_NUMBER)
@RequestParam(defaultValue = PagingConstants.DEFAULT_PAGE_NUMBER)
Integer pageNumber,
@Parameter(description = "Name of the property that the result list is sorted by")
@RequestParam(required = false)
MutationSortBy sortBy,
@Parameter(description = "Direction of the sort") @RequestParam(defaultValue = "ASC")
Direction direction) {

if (projection == ProjectionType.META) {
HttpHeaders responseHeaders = new HttpHeaders();
MutationMeta mutationMeta=getMutationUseCases.fetchMetaMutationsUseCase().execute(interceptedMutationMultipleStudyFilter);
responseHeaders.add(HeaderKeyConstants.TOTAL_COUNT, mutationMeta.getTotalCount().toString());
responseHeaders.add(
HeaderKeyConstants.SAMPLE_COUNT, mutationMeta.getSampleCount().toString());
return new ResponseEntity<>(responseHeaders, HttpStatus.OK);
}
MutationSearchCriteria mutationSearchCriteria = new MutationSearchCriteria(projection,pageSize,
pageNumber,
sortBy == null ? null : sortBy.getOriginalValue(),
direction);
List<MutationDTO> mutations= MutationMapper.INSTANCE.toDTOs(getMutationUseCases.fetchAllMutationsInProfileUseCase()
.execute(
interceptedMutationMultipleStudyFilter,
mutationSearchCriteria));
return ResponseEntity.ok(mutations);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package org.cbioportal.domain.mutation;

public record AlleleSpecificCopyNumber(
Integer ascnIntegerCopyNumber,
String ascnMethod,
Float ccfExpectedCopiesUpper,
Float ccfExpectedCopies,
String clonal,
Integer minorCopyNumber,
Integer expectedAltCopies,
Integer totalCopyNumber
) {
}
8 changes: 8 additions & 0 deletions src/main/java/org/cbioportal/domain/mutation/Gene.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package org.cbioportal.domain.mutation;

public record Gene(
Integer entrezGeneId,
String hugoGeneSymbol,
String type
) {
}
125 changes: 125 additions & 0 deletions src/main/java/org/cbioportal/domain/mutation/Mutation.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
package org.cbioportal.domain.mutation;
import java.io.Serializable;

public record Mutation(
String uniqueSampleKey,
String uniquePatientKey,
String molecularProfileId,
String sampleId,
String patientId,
Integer entrezGeneId,
Gene 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 tumorSeqAllele,
String proteinChange,
String mutationType,
String ncbiBuild,
String variantType,
String refseqMrnaId,
Integer proteinPosStart,
Integer proteinPosEnd,
String keyword,
AlleleSpecificCopyNumber alleleSpecificCopyNumber
) implements Serializable {

// Constructor for ID projection
public Mutation(String uniqueSampleKey, String uniquePatientKey, String molecularProfileId,
String sampleId, String patientId, Integer entrezGeneId, String studyId) {
this(
uniqueSampleKey,
uniquePatientKey,
molecularProfileId,
sampleId,
patientId,
entrezGeneId,
null, // Gene
studyId,
null, // driverFilter
null, // driverFilterAnnotation
null, // driverTiersFilter
null, // driverTiersFilterAnnotation
null, // center
null, // mutationStatus
null, // validationStatus
null, // tumorAltCount
null, // tumorRefCount
null, // normalAltCount
null, // normalRefCount
null, // aminoAcidChange
null, // chr
null, // startPosition
null, // endPosition
null, // referenceAllele
null, // tumorSeqAllele
null, // proteinChange
null, // mutationType
null, // ncbiBuild
null, // variantType
null, // refseqMrnaId
null, // proteinPosStart
null, // proteinPosEnd
null, // keyword
null // alleleSpecificCopyNumber
);
}


//This constructor is meant for Detailed projection something is wrong here
// public Mutation(
// String uniqueSampleKey,
// String uniquePatientKey,
// String molecularProfileId,
// String sampleId,
// String patientId,
// Integer entrezGeneId,
// Gene 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 tumorSeqAllele,
// String proteinChange,
// String mutationType,
// String ncbiBuild,
// String variantType,
// String refseqMrnaId,
// Integer proteinPosStart,
// Integer proteinPosEnd,
// String keyword,
// AlleleSpecificCopyNumber alleleSpecificCopyNumber
// ) {
// this(
// );
// }


}
Loading
Loading