diff --git a/src/main/java/org/cbioportal/model/ClinicalDataCollection.java b/src/main/java/org/cbioportal/model/ClinicalDataCollection.java deleted file mode 100644 index a1ed029ef22..00000000000 --- a/src/main/java/org/cbioportal/model/ClinicalDataCollection.java +++ /dev/null @@ -1,33 +0,0 @@ -package org.cbioportal.model; - -import java.util.ArrayList; -import java.util.List; - -public class ClinicalDataCollection { - - /** - * Paginated resource - */ - private List sampleClinicalData = new ArrayList<>(); - - /** - * Patient info associated with paginated samples - */ - private List patientClinicalData = new ArrayList<>(); - - public List getSampleClinicalData() { - return sampleClinicalData; - } - - public void setSampleClinicalData(List sampleClinicalData) { - this.sampleClinicalData = sampleClinicalData; - } - - public List getPatientClinicalData() { - return patientClinicalData; - } - - public void setPatientClinicalData(List patientClinicalData) { - this.patientClinicalData = patientClinicalData; - } -} diff --git a/src/main/java/org/cbioportal/model/SampleClinicalDataCollection.java b/src/main/java/org/cbioportal/model/SampleClinicalDataCollection.java new file mode 100644 index 00000000000..bea32238b9a --- /dev/null +++ b/src/main/java/org/cbioportal/model/SampleClinicalDataCollection.java @@ -0,0 +1,19 @@ +package org.cbioportal.model; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class SampleClinicalDataCollection { + + private Map> byUniqueSampleKey = new HashMap<>(); + + public Map> getByUniqueSampleKey() { + return byUniqueSampleKey; + } + + public void setByUniqueSampleKey(Map> byUniqueSampleKey) { + this.byUniqueSampleKey = byUniqueSampleKey; + } + +} diff --git a/src/main/java/org/cbioportal/persistence/ClinicalDataRepository.java b/src/main/java/org/cbioportal/persistence/ClinicalDataRepository.java index 2ff7c09087f..ed320908d2e 100644 --- a/src/main/java/org/cbioportal/persistence/ClinicalDataRepository.java +++ b/src/main/java/org/cbioportal/persistence/ClinicalDataRepository.java @@ -47,14 +47,6 @@ BaseMeta fetchMetaClinicalDataInStudy(String studyId, List ids, List fetchClinicalData(List studyIds, List ids, List attributeIds, String clinicalDataType, String projection); - List fetchSampleClinicalTable(List studyIds, List ids, - Integer pageSize, Integer pageNumber, String searchTerm, - String sortBy, String direction); - - @Cacheable(cacheResolver = "generalRepositoryCacheResolver", condition = "@cacheEnabledConfig.getEnabled()") - Integer fetchSampleClinicalTableCount(List studyIds, List ids, String searchTerm, - String sortBy, String direction); - @Cacheable(cacheResolver = "generalRepositoryCacheResolver", condition = "@cacheEnabledConfig.getEnabled()") BaseMeta fetchMetaClinicalData(List studyIds, List ids, List attributeIds, String clinicalDataType); @@ -65,5 +57,13 @@ List fetchClinicalDataCounts(List studyIds, List getPatientClinicalDataDetailedToSample(List studyIds, List patientIds, - List attributeIds); + List attributeIds); + + List getVisibleSampleInternalIdsForClinicalTable(List studyIds, List sampleIds, + Integer pageSize, Integer pageNumber, String searchTerm, + String sortBy, String direction); + + List getSampleClinicalDataBySampleInternalIds(List visibleSampleInternalIds); + + List getPatientClinicalDataBySampleInternalIds(List visibleSampleInternalIds); } diff --git a/src/main/java/org/cbioportal/persistence/mybatis/CancerTypeMyBatisRepository.java b/src/main/java/org/cbioportal/persistence/mybatis/CancerTypeMyBatisRepository.java index cc0ba6e58c6..00eb2f0fcac 100644 --- a/src/main/java/org/cbioportal/persistence/mybatis/CancerTypeMyBatisRepository.java +++ b/src/main/java/org/cbioportal/persistence/mybatis/CancerTypeMyBatisRepository.java @@ -4,7 +4,7 @@ import org.cbioportal.model.meta.BaseMeta; import org.cbioportal.persistence.CancerTypeRepository; import org.cbioportal.persistence.PersistenceConstants; -import org.cbioportal.persistence.mybatis.util.OffsetCalculator; +import org.cbioportal.persistence.mybatis.util.PaginationCalculator; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Repository; @@ -16,14 +16,14 @@ public class CancerTypeMyBatisRepository implements CancerTypeRepository { @Autowired private CancerTypeMapper cancerTypeMapper; @Autowired - private OffsetCalculator offsetCalculator; + private PaginationCalculator paginationCalculator; @Override public List getAllCancerTypes(String projection, Integer pageSize, Integer pageNumber, String sortBy, String direction) { return cancerTypeMapper.getAllCancerTypes(projection, pageSize, - offsetCalculator.calculate(pageSize, pageNumber), sortBy, direction); + paginationCalculator.offset(pageSize, pageNumber), sortBy, direction); } @Override diff --git a/src/main/java/org/cbioportal/persistence/mybatis/ClinicalAttributeMyBatisRepository.java b/src/main/java/org/cbioportal/persistence/mybatis/ClinicalAttributeMyBatisRepository.java index b71b1453306..4c1ceefa4bb 100644 --- a/src/main/java/org/cbioportal/persistence/mybatis/ClinicalAttributeMyBatisRepository.java +++ b/src/main/java/org/cbioportal/persistence/mybatis/ClinicalAttributeMyBatisRepository.java @@ -5,7 +5,7 @@ import org.cbioportal.model.meta.BaseMeta; import org.cbioportal.persistence.ClinicalAttributeRepository; import org.cbioportal.persistence.PersistenceConstants; -import org.cbioportal.persistence.mybatis.util.OffsetCalculator; +import org.cbioportal.persistence.mybatis.util.PaginationCalculator; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Repository; @@ -18,14 +18,14 @@ public class ClinicalAttributeMyBatisRepository implements ClinicalAttributeRepo @Autowired private ClinicalAttributeMapper clinicalAttributeMapper; @Autowired - private OffsetCalculator offsetCalculator; + private PaginationCalculator paginationCalculator; @Override public List getAllClinicalAttributes(String projection, Integer pageSize, Integer pageNumber, String sortBy, String direction) { return clinicalAttributeMapper.getClinicalAttributes(null, projection, pageSize, - offsetCalculator.calculate(pageSize, pageNumber), sortBy, direction); + paginationCalculator.offset(pageSize, pageNumber), sortBy, direction); } @Override @@ -47,7 +47,7 @@ public List getAllClinicalAttributesInStudy(String studyId, S String direction) { return clinicalAttributeMapper.getClinicalAttributes(Arrays.asList(studyId), projection, pageSize, - offsetCalculator.calculate(pageSize, pageNumber), sortBy, direction); + paginationCalculator.offset(pageSize, pageNumber), sortBy, direction); } @Override diff --git a/src/main/java/org/cbioportal/persistence/mybatis/ClinicalDataMapper.java b/src/main/java/org/cbioportal/persistence/mybatis/ClinicalDataMapper.java index 501bbe18444..50bb0c4e197 100644 --- a/src/main/java/org/cbioportal/persistence/mybatis/ClinicalDataMapper.java +++ b/src/main/java/org/cbioportal/persistence/mybatis/ClinicalDataMapper.java @@ -20,7 +20,8 @@ List getPatientClinicalData(List studyIds, List pa List getSampleClinicalTable(List studyIds, List sampleIds, String projection, Integer limit, Integer offset, String searchTerm, - String sortBy, String direction); + String sortByAttrId, Boolean sortAttrIsNumber, Boolean sortIsPatientAttr, + String direction); Integer getSampleClinicalTableCount(List studyIds, List sampleIds, String projection, String searchTerm, String sortBy, String direction); @@ -36,4 +37,13 @@ List fetchPatientClinicalDataCounts(List studyIds, Li List getPatientClinicalDataDetailedToSample(List studyIds, List patientIds, List attributeIds, String projection, Integer limit, Integer offset, String sortBy, String direction); + + List getVisibleSampleInternalIdsForClinicalTable(List studyIds, List sampleIds, + String projection, Integer limit, Integer offset, + String searchTerm, String sortAttrId, Boolean sortAttrIsNumber, + Boolean sortIsPatientAttr, String direction); + + List getSampleClinicalDataBySampleInternalIds(List sampleInternalIds); + + List getPatientClinicalDataBySampleInternalIds(List sampleInternalIds); } diff --git a/src/main/java/org/cbioportal/persistence/mybatis/ClinicalDataMyBatisRepository.java b/src/main/java/org/cbioportal/persistence/mybatis/ClinicalDataMyBatisRepository.java index 15c692f84bc..cc049d85258 100644 --- a/src/main/java/org/cbioportal/persistence/mybatis/ClinicalDataMyBatisRepository.java +++ b/src/main/java/org/cbioportal/persistence/mybatis/ClinicalDataMyBatisRepository.java @@ -1,20 +1,22 @@ package org.cbioportal.persistence.mybatis; +import org.cbioportal.model.ClinicalAttribute; import org.cbioportal.model.ClinicalData; import org.cbioportal.model.ClinicalDataCount; import org.cbioportal.model.Patient; import org.cbioportal.model.meta.BaseMeta; import org.cbioportal.persistence.ClinicalDataRepository; +import org.cbioportal.persistence.ClinicalAttributeRepository; import org.cbioportal.persistence.PatientRepository; import org.cbioportal.persistence.PersistenceConstants; -import org.cbioportal.persistence.mybatis.util.OffsetCalculator; +import org.cbioportal.persistence.mybatis.util.PaginationCalculator; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Repository; +import org.springframework.util.Assert; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; +import java.util.*; import java.util.stream.Collectors; +import java.util.stream.Stream; @Repository public class ClinicalDataMyBatisRepository implements ClinicalDataRepository { @@ -24,7 +26,9 @@ public class ClinicalDataMyBatisRepository implements ClinicalDataRepository { @Autowired private PatientRepository patientRepository; @Autowired - private OffsetCalculator offsetCalculator; + private PaginationCalculator paginationCalculator; + @Autowired + private ClinicalAttributeRepository clinicalAttributeRepository; @Override public List getAllClinicalDataOfSampleInStudy(String studyId, String sampleId, @@ -34,7 +38,7 @@ public List getAllClinicalDataOfSampleInStudy(String studyId, Stri return clinicalDataMapper.getSampleClinicalData(Arrays.asList(studyId), Arrays.asList(sampleId), attributeId != null ? Arrays.asList(attributeId) : null, projection, pageSize, - offsetCalculator.calculate(pageSize, pageNumber), sortBy, direction); + paginationCalculator.offset(pageSize, pageNumber), sortBy, direction); } @Override @@ -51,7 +55,7 @@ public List getAllClinicalDataOfPatientInStudy(String studyId, Str return clinicalDataMapper.getPatientClinicalData(Arrays.asList(studyId), Arrays.asList(patientId), attributeId != null ? Arrays.asList(attributeId) : null, projection, pageSize, - offsetCalculator.calculate(pageSize, pageNumber), sortBy, direction); + paginationCalculator.offset(pageSize, pageNumber), sortBy, direction); } @Override @@ -69,11 +73,11 @@ public List getAllClinicalDataInStudy(String studyId, String attri if (clinicalDataType.equals(PersistenceConstants.SAMPLE_CLINICAL_DATA_TYPE)) { return clinicalDataMapper.getSampleClinicalData(Arrays.asList(studyId), null, attributeId != null ? Arrays.asList(attributeId) : null, projection, pageSize, - offsetCalculator.calculate(pageSize, pageNumber), sortBy, direction); + paginationCalculator.offset(pageSize, pageNumber), sortBy, direction); } else { return clinicalDataMapper.getPatientClinicalData(Arrays.asList(studyId), null, attributeId != null ? Arrays.asList(attributeId) : null, projection, pageSize, - offsetCalculator.calculate(pageSize, pageNumber), sortBy, direction); + paginationCalculator.offset(pageSize, pageNumber), sortBy, direction); } } @@ -137,23 +141,35 @@ public List fetchClinicalData(List studyIds, List } } - @Override - public List fetchSampleClinicalTable(List studyIds, List ids, - Integer pageSize, Integer pageNumber, String searchTerm, - String sortBy, String direction) { - if (ids.isEmpty()) { + public List getVisibleSampleInternalIdsForClinicalTable(List studyIds, List sampleIds, + Integer pageSize, Integer pageNumber, String searchTerm, + String sortAttrId, String direction) { + if (sampleIds.isEmpty()) { return new ArrayList<>(); } - int offset = offsetCalculator.calculate(pageSize, pageNumber); - return clinicalDataMapper.getSampleClinicalTable(studyIds, ids,"SUMMARY", pageSize, - offset, searchTerm, sortBy, direction); + Integer offset = paginationCalculator.offset(pageSize, pageNumber); + Boolean sortAttrIsNumber = null; + Boolean sortIsPatientAttr = null; + if (sortAttrId != null && ! sortAttrId.isEmpty()) { + ClinicalAttribute clinicalAttributeMeta = getClinicalAttributeMeta(studyIds, sortAttrId); + sortAttrIsNumber = clinicalAttributeMeta.getDatatype().equals("NUMBER"); + sortIsPatientAttr = clinicalAttributeMeta.getPatientAttribute(); + } + return clinicalDataMapper.getVisibleSampleInternalIdsForClinicalTable(studyIds, sampleIds,"SUMMARY", pageSize, + offset, searchTerm, sortAttrId, sortAttrIsNumber, sortIsPatientAttr, direction); } - - @Override - public Integer fetchSampleClinicalTableCount(List studyIds, List sampleIds, - String searchTerm, String sortBy, String direction) { - return clinicalDataMapper.getSampleClinicalTableCount(studyIds, sampleIds,"SUMMARY", - searchTerm, sortBy, direction); + + private ClinicalAttribute getClinicalAttributeMeta(List studyIds, String attrId) { + Assert.notNull(studyIds, "Arguments may not be null"); + Assert.notNull(attrId, "Arguments may not be null"); + Stream uniqueStudyIds = studyIds.stream().distinct(); + Optional clinicalAttributeMeta = uniqueStudyIds + .map(studyId -> clinicalAttributeRepository.getClinicalAttribute(studyId, attrId)) + .filter(Objects::nonNull) + .findFirst(); + Assert.isTrue(clinicalAttributeMeta.isPresent(), "Clinical Attribute " + attrId + + " was not found in studies " + studyIds.stream().collect(Collectors.joining(", ")) ); + return clinicalAttributeMeta.get(); } @Override @@ -195,4 +211,16 @@ public List getPatientClinicalDataDetailedToSample(List st return clinicalDataMapper.getPatientClinicalDataDetailedToSample(studyIds, patientIds, attributeIds, "SUMMARY", 0, 0, null, null); } + + @Override + public List getSampleClinicalDataBySampleInternalIds(List sampleInternalIds) { + return sampleInternalIds == null || sampleInternalIds.isEmpty() ? + new ArrayList<>() : clinicalDataMapper.getSampleClinicalDataBySampleInternalIds(sampleInternalIds); + } + + @Override + public List getPatientClinicalDataBySampleInternalIds(List sampleInternalIds) { + return sampleInternalIds == null || sampleInternalIds.isEmpty() ? + new ArrayList<>() : clinicalDataMapper.getPatientClinicalDataBySampleInternalIds(sampleInternalIds); + } } diff --git a/src/main/java/org/cbioportal/persistence/mybatis/ClinicalEventMyBatisRepository.java b/src/main/java/org/cbioportal/persistence/mybatis/ClinicalEventMyBatisRepository.java index 40ccc3c99b1..a2f60b1f0bc 100644 --- a/src/main/java/org/cbioportal/persistence/mybatis/ClinicalEventMyBatisRepository.java +++ b/src/main/java/org/cbioportal/persistence/mybatis/ClinicalEventMyBatisRepository.java @@ -4,7 +4,7 @@ import org.cbioportal.model.ClinicalEventData; import org.cbioportal.model.meta.BaseMeta; import org.cbioportal.persistence.ClinicalEventRepository; -import org.cbioportal.persistence.mybatis.util.OffsetCalculator; +import org.cbioportal.persistence.mybatis.util.PaginationCalculator; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Repository; @@ -21,14 +21,14 @@ public class ClinicalEventMyBatisRepository implements ClinicalEventRepository { @Autowired private ClinicalEventMapper clinicalEventMapper; @Autowired - private OffsetCalculator offsetCalculator; + private PaginationCalculator paginationCalculator; @Override public List getAllClinicalEventsOfPatientInStudy(String studyId, String patientId, String projection, Integer pageSize, Integer pageNumber, String sortBy, String direction) { return clinicalEventMapper.getPatientClinicalEvent(studyId, patientId, projection, pageSize, - offsetCalculator.calculate(pageSize, pageNumber), sortBy, direction); + paginationCalculator.offset(pageSize, pageNumber), sortBy, direction); } @Override @@ -47,7 +47,7 @@ public List getDataOfClinicalEvents(List clinicalEve public List getAllClinicalEventsInStudy(String studyId, String projection, Integer pageSize, Integer pageNumber, String sortBy, String direction) { return clinicalEventMapper.getStudyClinicalEvent(studyId, projection, pageSize, - offsetCalculator.calculate(pageSize, pageNumber), sortBy, direction); + paginationCalculator.offset(pageSize, pageNumber), sortBy, direction); } @Override diff --git a/src/main/java/org/cbioportal/persistence/mybatis/CopyNumberSegmentMyBatisRepository.java b/src/main/java/org/cbioportal/persistence/mybatis/CopyNumberSegmentMyBatisRepository.java index bb53fe2b8cf..e4549a93377 100644 --- a/src/main/java/org/cbioportal/persistence/mybatis/CopyNumberSegmentMyBatisRepository.java +++ b/src/main/java/org/cbioportal/persistence/mybatis/CopyNumberSegmentMyBatisRepository.java @@ -3,7 +3,7 @@ import org.cbioportal.model.CopyNumberSeg; import org.cbioportal.model.meta.BaseMeta; import org.cbioportal.persistence.CopyNumberSegmentRepository; -import org.cbioportal.persistence.mybatis.util.OffsetCalculator; +import org.cbioportal.persistence.mybatis.util.PaginationCalculator; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Repository; @@ -16,7 +16,7 @@ public class CopyNumberSegmentMyBatisRepository implements CopyNumberSegmentRepo @Autowired private CopyNumberSegmentMapper copyNumberSegmentMapper; @Autowired - private OffsetCalculator offsetCalculator; + private PaginationCalculator paginationCalculator; @Override @@ -26,7 +26,7 @@ public List getCopyNumberSegmentsInSampleInStudy(String studyId, String direction) { return copyNumberSegmentMapper.getCopyNumberSegments(Arrays.asList(studyId), Arrays.asList(sampleId), chromosome, - projection, pageSize, offsetCalculator.calculate(pageSize, pageNumber), sortBy, direction); + projection, pageSize, paginationCalculator.offset(pageSize, pageNumber), sortBy, direction); } @Override diff --git a/src/main/java/org/cbioportal/persistence/mybatis/GeneMyBatisRepository.java b/src/main/java/org/cbioportal/persistence/mybatis/GeneMyBatisRepository.java index 0f5167060d3..d0af5b020ef 100644 --- a/src/main/java/org/cbioportal/persistence/mybatis/GeneMyBatisRepository.java +++ b/src/main/java/org/cbioportal/persistence/mybatis/GeneMyBatisRepository.java @@ -5,7 +5,7 @@ import org.cbioportal.model.meta.BaseMeta; import org.cbioportal.persistence.GeneRepository; import org.cbioportal.persistence.PersistenceConstants; -import org.cbioportal.persistence.mybatis.util.OffsetCalculator; +import org.cbioportal.persistence.mybatis.util.PaginationCalculator; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Repository; @@ -17,13 +17,13 @@ public class GeneMyBatisRepository implements GeneRepository { @Autowired private GeneMapper geneMapper; @Autowired - private OffsetCalculator offsetCalculator; + private PaginationCalculator paginationCalculator; @Override public List getAllGenes(String keyword, String alias, String projection, Integer pageSize, Integer pageNumber, String sortBy, String direction) { - return geneMapper.getGenes(keyword, alias, projection, pageSize, offsetCalculator.calculate(pageSize, pageNumber), + return geneMapper.getGenes(keyword, alias, projection, pageSize, paginationCalculator.offset(pageSize, pageNumber), sortBy, direction); } diff --git a/src/main/java/org/cbioportal/persistence/mybatis/GenePanelMyBatisRepository.java b/src/main/java/org/cbioportal/persistence/mybatis/GenePanelMyBatisRepository.java index 182e88ebd9c..dec444abb92 100644 --- a/src/main/java/org/cbioportal/persistence/mybatis/GenePanelMyBatisRepository.java +++ b/src/main/java/org/cbioportal/persistence/mybatis/GenePanelMyBatisRepository.java @@ -7,7 +7,7 @@ import org.cbioportal.model.meta.BaseMeta; import org.cbioportal.persistence.GenePanelRepository; import org.cbioportal.persistence.PersistenceConstants; -import org.cbioportal.persistence.mybatis.util.OffsetCalculator; +import org.cbioportal.persistence.mybatis.util.PaginationCalculator; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Repository; @@ -21,12 +21,12 @@ public class GenePanelMyBatisRepository implements GenePanelRepository { @Autowired private GenePanelMapper genePanelMapper; @Autowired - private OffsetCalculator offsetCalculator; + private PaginationCalculator paginationCalculator; @Override public List getAllGenePanels(String projection, Integer pageSize, Integer pageNumber, String sortBy, String direction) { - return genePanelMapper.getAllGenePanels(projection, pageSize, offsetCalculator.calculate(pageSize, pageNumber), + return genePanelMapper.getAllGenePanels(projection, pageSize, paginationCalculator.offset(pageSize, pageNumber), sortBy, direction); } diff --git a/src/main/java/org/cbioportal/persistence/mybatis/GenesetMyBatisRepository.java b/src/main/java/org/cbioportal/persistence/mybatis/GenesetMyBatisRepository.java index 69d915ca04f..600de528c0a 100644 --- a/src/main/java/org/cbioportal/persistence/mybatis/GenesetMyBatisRepository.java +++ b/src/main/java/org/cbioportal/persistence/mybatis/GenesetMyBatisRepository.java @@ -7,7 +7,7 @@ import org.cbioportal.model.meta.BaseMeta; import org.cbioportal.persistence.GenesetRepository; import org.cbioportal.persistence.PersistenceConstants; -import org.cbioportal.persistence.mybatis.util.OffsetCalculator; +import org.cbioportal.persistence.mybatis.util.PaginationCalculator; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Repository; @@ -17,12 +17,12 @@ public class GenesetMyBatisRepository implements GenesetRepository { @Autowired GenesetMapper genesetMapper; @Autowired - private OffsetCalculator offsetCalculator; + private PaginationCalculator paginationCalculator; @Override public List getAllGenesets(String projection, Integer pageSize, Integer pageNumber) { - return genesetMapper.getGenesets(projection, pageSize, offsetCalculator.calculate(pageSize, pageNumber), "EXTERNAL_ID", "ASC"); + return genesetMapper.getGenesets(projection, pageSize, paginationCalculator.offset(pageSize, pageNumber), "EXTERNAL_ID", "ASC"); } @Override diff --git a/src/main/java/org/cbioportal/persistence/mybatis/MolecularProfileMyBatisRepository.java b/src/main/java/org/cbioportal/persistence/mybatis/MolecularProfileMyBatisRepository.java index 35806a8e350..54e4d9894cd 100644 --- a/src/main/java/org/cbioportal/persistence/mybatis/MolecularProfileMyBatisRepository.java +++ b/src/main/java/org/cbioportal/persistence/mybatis/MolecularProfileMyBatisRepository.java @@ -4,7 +4,7 @@ import org.cbioportal.model.meta.BaseMeta; import org.cbioportal.persistence.MolecularProfileRepository; import org.cbioportal.persistence.PersistenceConstants; -import org.cbioportal.persistence.mybatis.util.OffsetCalculator; +import org.cbioportal.persistence.mybatis.util.PaginationCalculator; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Repository; import java.util.Arrays; @@ -17,14 +17,14 @@ public class MolecularProfileMyBatisRepository implements MolecularProfileReposi @Autowired private MolecularProfileMapper molecularProfileMapper; @Autowired - private OffsetCalculator offsetCalculator; + private PaginationCalculator paginationCalculator; @Override public List getAllMolecularProfiles(String projection, Integer pageSize, Integer pageNumber, String sortBy, String direction) { return molecularProfileMapper.getAllMolecularProfilesInStudies(null, projection, pageSize, - offsetCalculator.calculate(pageSize, pageNumber), sortBy, direction); + paginationCalculator.offset(pageSize, pageNumber), sortBy, direction); } @Override @@ -55,7 +55,7 @@ public List getAllMolecularProfilesInStudy(String studyId, Str Integer pageNumber, String sortBy, String direction) { return molecularProfileMapper.getAllMolecularProfilesInStudies(Arrays.asList(studyId), projection, pageSize, - offsetCalculator.calculate(pageSize, pageNumber), sortBy, direction); + paginationCalculator.offset(pageSize, pageNumber), sortBy, direction); } @Override diff --git a/src/main/java/org/cbioportal/persistence/mybatis/MutationMyBatisRepository.java b/src/main/java/org/cbioportal/persistence/mybatis/MutationMyBatisRepository.java index 6adc902dd9e..00bc0a4c077 100644 --- a/src/main/java/org/cbioportal/persistence/mybatis/MutationMyBatisRepository.java +++ b/src/main/java/org/cbioportal/persistence/mybatis/MutationMyBatisRepository.java @@ -6,7 +6,7 @@ import org.cbioportal.model.meta.MutationMeta; import org.cbioportal.persistence.MutationRepository; import org.cbioportal.persistence.mybatis.util.MolecularProfileCaseIdentifierUtil; -import org.cbioportal.persistence.mybatis.util.OffsetCalculator; +import org.cbioportal.persistence.mybatis.util.PaginationCalculator; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Repository; @@ -19,7 +19,7 @@ public class MutationMyBatisRepository implements MutationRepository { @Autowired private MutationMapper mutationMapper; @Autowired - private OffsetCalculator offsetCalculator; + private PaginationCalculator paginationCalculator; @Autowired private MolecularProfileCaseIdentifierUtil molecularProfileCaseIdentifierUtil; @@ -31,7 +31,7 @@ public List getMutationsInMolecularProfileBySampleListId(String molecu String direction) { return mutationMapper.getMutationsBySampleListId(molecularProfileId, sampleListId, entrezGeneIds, snpOnly, - projection, pageSize, offsetCalculator.calculate(pageSize, pageNumber), sortBy, direction); + projection, pageSize, paginationCalculator.offset(pageSize, pageNumber), sortBy, direction); } @Override @@ -58,7 +58,7 @@ public List getMutationsInMultipleMolecularProfiles(List molec null, projection, pageSize, - offsetCalculator.calculate(pageSize, pageNumber), + paginationCalculator.offset(pageSize, pageNumber), sortBy, direction).stream()) .collect(Collectors.toList()); @@ -86,7 +86,7 @@ public List getMutationsInMultipleMolecularProfilesByGeneQueries(List< null, projection, pageSize, - offsetCalculator.calculate(pageSize, pageNumber), + paginationCalculator.offset(pageSize, pageNumber), sortBy, direction, geneQueries).stream()) @@ -115,7 +115,7 @@ public List fetchMutationsInMolecularProfile(String molecularProfileId snpOnly, projection, pageSize, - offsetCalculator.calculate(pageSize, pageNumber), + paginationCalculator.offset(pageSize, pageNumber), sortBy, direction); } diff --git a/src/main/java/org/cbioportal/persistence/mybatis/PatientMyBatisRepository.java b/src/main/java/org/cbioportal/persistence/mybatis/PatientMyBatisRepository.java index 130f146fb3f..b644ad81ad0 100644 --- a/src/main/java/org/cbioportal/persistence/mybatis/PatientMyBatisRepository.java +++ b/src/main/java/org/cbioportal/persistence/mybatis/PatientMyBatisRepository.java @@ -4,7 +4,7 @@ import org.cbioportal.model.meta.BaseMeta; import org.cbioportal.persistence.PatientRepository; import org.cbioportal.persistence.PersistenceConstants; -import org.cbioportal.persistence.mybatis.util.OffsetCalculator; +import org.cbioportal.persistence.mybatis.util.PaginationCalculator; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Repository; @@ -17,13 +17,13 @@ public class PatientMyBatisRepository implements PatientRepository { @Autowired private PatientMapper patientMapper; @Autowired - private OffsetCalculator offsetCalculator; + private PaginationCalculator paginationCalculator; @Override public List getAllPatients(String keyword, String projection, Integer pageSize, Integer pageNumber, String sortBy, String direction) { return patientMapper.getPatients(null, null, keyword, projection, pageSize, - offsetCalculator.calculate(pageSize, pageNumber), sortBy, direction); + paginationCalculator.offset(pageSize, pageNumber), sortBy, direction); } @Override @@ -37,7 +37,7 @@ public List getAllPatientsInStudy(String studyId, String projection, In String sortBy, String direction) { return patientMapper.getPatients(Arrays.asList(studyId), null, null, projection, pageSize, - offsetCalculator.calculate(pageSize, pageNumber), sortBy, direction); + paginationCalculator.offset(pageSize, pageNumber), sortBy, direction); } @Override diff --git a/src/main/java/org/cbioportal/persistence/mybatis/ResourceDataMyBatisRepository.java b/src/main/java/org/cbioportal/persistence/mybatis/ResourceDataMyBatisRepository.java index 761f3d9a95c..0674dbc9729 100644 --- a/src/main/java/org/cbioportal/persistence/mybatis/ResourceDataMyBatisRepository.java +++ b/src/main/java/org/cbioportal/persistence/mybatis/ResourceDataMyBatisRepository.java @@ -4,7 +4,7 @@ import org.cbioportal.model.ResourceData; import org.cbioportal.persistence.ResourceDataRepository; -import org.cbioportal.persistence.mybatis.util.OffsetCalculator; +import org.cbioportal.persistence.mybatis.util.PaginationCalculator; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Repository; @@ -14,14 +14,14 @@ public class ResourceDataMyBatisRepository implements ResourceDataRepository { @Autowired private ResourceDataMapper resourceDataMapper; @Autowired - private OffsetCalculator offsetCalculator; + private PaginationCalculator paginationCalculator; @Override public List getAllResourceDataOfSampleInStudy(String studyId, String sampleId, String resourceId, String projection, Integer pageSize, Integer pageNumber, String sortBy, String direction) { return resourceDataMapper.getResourceDataOfSampleInStudy(studyId, sampleId, resourceId, projection, pageSize, - offsetCalculator.calculate(pageSize, pageNumber), sortBy, direction); + paginationCalculator.offset(pageSize, pageNumber), sortBy, direction); } @Override @@ -29,7 +29,7 @@ public List getAllResourceDataOfPatientInStudy(String studyId, Str String projection, Integer pageSize, Integer pageNumber, String sortBy, String direction) { return resourceDataMapper.getResourceDataOfPatientInStudy(studyId, patientId, resourceId, projection, pageSize, - offsetCalculator.calculate(pageSize, pageNumber), sortBy, direction); + paginationCalculator.offset(pageSize, pageNumber), sortBy, direction); } @Override @@ -37,7 +37,7 @@ public List getAllResourceDataForStudy(String studyId, String reso Integer pageSize, Integer pageNumber, String sortBy, String direction) { return resourceDataMapper.getResourceDataForStudy(studyId, resourceId, projection, pageSize, - offsetCalculator.calculate(pageSize, pageNumber), sortBy, direction); + paginationCalculator.offset(pageSize, pageNumber), sortBy, direction); } } diff --git a/src/main/java/org/cbioportal/persistence/mybatis/ResourceDefinitionMyBatisRepository.java b/src/main/java/org/cbioportal/persistence/mybatis/ResourceDefinitionMyBatisRepository.java index 8ddda769cd9..a3357c2704f 100644 --- a/src/main/java/org/cbioportal/persistence/mybatis/ResourceDefinitionMyBatisRepository.java +++ b/src/main/java/org/cbioportal/persistence/mybatis/ResourceDefinitionMyBatisRepository.java @@ -5,7 +5,7 @@ import org.cbioportal.model.ResourceDefinition; import org.cbioportal.persistence.PersistenceConstants; import org.cbioportal.persistence.ResourceDefinitionRepository; -import org.cbioportal.persistence.mybatis.util.OffsetCalculator; +import org.cbioportal.persistence.mybatis.util.PaginationCalculator; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Repository; @@ -15,7 +15,7 @@ public class ResourceDefinitionMyBatisRepository implements ResourceDefinitionRe @Autowired private ResourceDefinitionMapper resourceDefinitionMapper; @Autowired - private OffsetCalculator offsetCalculator; + private PaginationCalculator paginationCalculator; @Override public ResourceDefinition getResourceDefinition(String studyId, String resourceId) { @@ -26,6 +26,6 @@ public ResourceDefinition getResourceDefinition(String studyId, String resourceI @Override public List fetchResourceDefinitions(List studyIds, String projection, Integer pageSize, Integer pageNumber, String sortBy, String direction) { return resourceDefinitionMapper.getResourceDefinitions(studyIds, projection, pageSize, - offsetCalculator.calculate(pageSize, pageNumber), sortBy, direction); + paginationCalculator.offset(pageSize, pageNumber), sortBy, direction); } } diff --git a/src/main/java/org/cbioportal/persistence/mybatis/SampleListMyBatisRepository.java b/src/main/java/org/cbioportal/persistence/mybatis/SampleListMyBatisRepository.java index a619d967525..315536f6f8b 100644 --- a/src/main/java/org/cbioportal/persistence/mybatis/SampleListMyBatisRepository.java +++ b/src/main/java/org/cbioportal/persistence/mybatis/SampleListMyBatisRepository.java @@ -7,7 +7,7 @@ import org.cbioportal.persistence.PersistenceConstants; import org.cbioportal.persistence.SampleListRepository; -import org.cbioportal.persistence.mybatis.util.OffsetCalculator; +import org.cbioportal.persistence.mybatis.util.PaginationCalculator; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Repository; @@ -19,14 +19,14 @@ public class SampleListMyBatisRepository implements SampleListRepository { @Autowired private SampleListMapper sampleListMapper; @Autowired - private OffsetCalculator offsetCalculator; + private PaginationCalculator paginationCalculator; @Override public List getAllSampleLists(String projection, Integer pageSize, Integer pageNumber, String sortBy, String direction) { return sampleListMapper.getAllSampleLists(null, projection, pageSize, - offsetCalculator.calculate(pageSize, pageNumber), sortBy, direction); + paginationCalculator.offset(pageSize, pageNumber), sortBy, direction); } @Override @@ -52,7 +52,7 @@ public List getAllSampleListsInStudies(List studyIds, String Integer pageNumber, String sortBy, String direction) { return sampleListMapper.getAllSampleLists(studyIds, projection, pageSize, - offsetCalculator.calculate(pageSize, pageNumber), sortBy, direction); + paginationCalculator.offset(pageSize, pageNumber), sortBy, direction); } @Override diff --git a/src/main/java/org/cbioportal/persistence/mybatis/SampleMyBatisRepository.java b/src/main/java/org/cbioportal/persistence/mybatis/SampleMyBatisRepository.java index 090c66091d2..5d18387a5f5 100644 --- a/src/main/java/org/cbioportal/persistence/mybatis/SampleMyBatisRepository.java +++ b/src/main/java/org/cbioportal/persistence/mybatis/SampleMyBatisRepository.java @@ -4,15 +4,13 @@ import org.cbioportal.model.meta.BaseMeta; import org.cbioportal.persistence.SampleRepository; import org.cbioportal.persistence.PersistenceConstants; -import org.cbioportal.persistence.mybatis.util.OffsetCalculator; +import org.cbioportal.persistence.mybatis.util.PaginationCalculator; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Repository; import java.util.Arrays; import java.util.Collections; -import java.util.HashSet; import java.util.List; -import java.util.Set; import java.util.stream.Collectors; @Repository @@ -21,7 +19,7 @@ public class SampleMyBatisRepository implements SampleRepository { @Autowired private SampleMapper sampleMapper; @Autowired - private OffsetCalculator offsetCalculator; + private PaginationCalculator paginationCalculator; @Override public List getAllSamples( @@ -30,7 +28,7 @@ public List getAllSamples( ) { return sampleMapper.getSamples( studyIds, null, null, keyword, projection, pageSize, - offsetCalculator.calculate(pageSize, pageNumber), sort, direction); + paginationCalculator.offset(pageSize, pageNumber), sort, direction); } @Override @@ -43,7 +41,7 @@ public List getAllSamplesInStudy(String studyId, String projection, Inte String sortBy, String direction) { return sampleMapper.getSamples(Arrays.asList(studyId), null, null, null, projection, pageSize, - offsetCalculator.calculate(pageSize, pageNumber), sortBy, direction); + paginationCalculator.offset(pageSize, pageNumber), sortBy, direction); } @Override @@ -56,7 +54,7 @@ public BaseMeta getMetaSamplesInStudy(String studyId) { public List getAllSamplesInStudies(List studyIds, String projection, Integer pageSize, Integer pageNumber, String sortBy, String direction) { return sampleMapper.getSamples(studyIds, null, null, null, projection, pageSize, - offsetCalculator.calculate(pageSize, pageNumber), sortBy, direction); + paginationCalculator.offset(pageSize, pageNumber), sortBy, direction); } @Override @@ -71,7 +69,7 @@ public List getAllSamplesOfPatientInStudy(String studyId, String patient String direction) { return sampleMapper.getSamples(Arrays.asList(studyId), patientId, null, null, projection, - pageSize, offsetCalculator.calculate(pageSize, pageNumber), sortBy, direction); + pageSize, paginationCalculator.offset(pageSize, pageNumber), sortBy, direction); } @Override diff --git a/src/main/java/org/cbioportal/persistence/mybatis/SignificantCopyNumberRegionMyBatisRepository.java b/src/main/java/org/cbioportal/persistence/mybatis/SignificantCopyNumberRegionMyBatisRepository.java index e904cc115ce..4cc60089ffa 100644 --- a/src/main/java/org/cbioportal/persistence/mybatis/SignificantCopyNumberRegionMyBatisRepository.java +++ b/src/main/java/org/cbioportal/persistence/mybatis/SignificantCopyNumberRegionMyBatisRepository.java @@ -4,7 +4,7 @@ import org.cbioportal.model.GisticToGene; import org.cbioportal.model.meta.BaseMeta; import org.cbioportal.persistence.SignificantCopyNumberRegionRepository; -import org.cbioportal.persistence.mybatis.util.OffsetCalculator; +import org.cbioportal.persistence.mybatis.util.PaginationCalculator; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Repository; @@ -16,14 +16,14 @@ public class SignificantCopyNumberRegionMyBatisRepository implements Significant @Autowired private SignificantCopyNumberRegionMapper significantCopyNumberRegionMapper; @Autowired - private OffsetCalculator offsetCalculator; + private PaginationCalculator paginationCalculator; @Override public List getSignificantCopyNumberRegions(String studyId, String projection, Integer pageSize, Integer pageNumber, String sortBy, String direction) { return significantCopyNumberRegionMapper.getSignificantCopyNumberRegions(studyId, projection, pageSize, - offsetCalculator.calculate(pageSize, pageNumber), sortBy, direction); + paginationCalculator.offset(pageSize, pageNumber), sortBy, direction); } @Override diff --git a/src/main/java/org/cbioportal/persistence/mybatis/SignificantlyMutatedGeneMyBatisRepository.java b/src/main/java/org/cbioportal/persistence/mybatis/SignificantlyMutatedGeneMyBatisRepository.java index 2c78320761f..9bdb5c3f5a5 100644 --- a/src/main/java/org/cbioportal/persistence/mybatis/SignificantlyMutatedGeneMyBatisRepository.java +++ b/src/main/java/org/cbioportal/persistence/mybatis/SignificantlyMutatedGeneMyBatisRepository.java @@ -3,7 +3,7 @@ import org.cbioportal.model.MutSig; import org.cbioportal.model.meta.BaseMeta; import org.cbioportal.persistence.SignificantlyMutatedGeneRepository; -import org.cbioportal.persistence.mybatis.util.OffsetCalculator; +import org.cbioportal.persistence.mybatis.util.PaginationCalculator; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Repository; @@ -15,14 +15,14 @@ public class SignificantlyMutatedGeneMyBatisRepository implements SignificantlyM @Autowired private SignificantlyMutatedGeneMapper significantlyMutatedGeneMapper; @Autowired - private OffsetCalculator offsetCalculator; + private PaginationCalculator paginationCalculator; @Override public List getSignificantlyMutatedGenes(String studyId, String projection, Integer pageSize, Integer pageNumber, String sortBy, String direction) { return significantlyMutatedGeneMapper.getSignificantlyMutatedGenes(studyId, projection, pageSize, - offsetCalculator.calculate(pageSize, pageNumber), sortBy, direction); + paginationCalculator.offset(pageSize, pageNumber), sortBy, direction); } @Override diff --git a/src/main/java/org/cbioportal/persistence/mybatis/StudyMyBatisRepository.java b/src/main/java/org/cbioportal/persistence/mybatis/StudyMyBatisRepository.java index 4821f500558..8d60df36224 100644 --- a/src/main/java/org/cbioportal/persistence/mybatis/StudyMyBatisRepository.java +++ b/src/main/java/org/cbioportal/persistence/mybatis/StudyMyBatisRepository.java @@ -4,7 +4,7 @@ import org.cbioportal.model.CancerStudyTags; import org.cbioportal.model.meta.BaseMeta; import org.cbioportal.persistence.StudyRepository; -import org.cbioportal.persistence.mybatis.util.OffsetCalculator; +import org.cbioportal.persistence.mybatis.util.PaginationCalculator; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Repository; @@ -16,13 +16,13 @@ public class StudyMyBatisRepository implements StudyRepository { @Autowired private StudyMapper studyMapper; @Autowired - private OffsetCalculator offsetCalculator; + private PaginationCalculator paginationCalculator; @Override public List getAllStudies(String keyword, String projection, Integer pageSize, Integer pageNumber, String sortBy, String direction) { - return studyMapper.getStudies(null, keyword, projection, pageSize, offsetCalculator.calculate(pageSize, pageNumber), + return studyMapper.getStudies(null, keyword, projection, pageSize, paginationCalculator.offset(pageSize, pageNumber), sortBy, direction); } diff --git a/src/main/java/org/cbioportal/persistence/mybatis/util/OffsetCalculator.java b/src/main/java/org/cbioportal/persistence/mybatis/util/OffsetCalculator.java deleted file mode 100644 index 1d497c089b4..00000000000 --- a/src/main/java/org/cbioportal/persistence/mybatis/util/OffsetCalculator.java +++ /dev/null @@ -1,13 +0,0 @@ -package org.cbioportal.persistence.mybatis.util; - -import org.springframework.stereotype.Component; - -@Component -public class OffsetCalculator { - - public Integer calculate(Integer pageSize, Integer pageNumber) { - - return pageSize == null || pageNumber == null ? null : pageSize * pageNumber; - } - -} diff --git a/src/main/java/org/cbioportal/persistence/mybatis/util/PaginationCalculator.java b/src/main/java/org/cbioportal/persistence/mybatis/util/PaginationCalculator.java new file mode 100644 index 00000000000..0a205cf6237 --- /dev/null +++ b/src/main/java/org/cbioportal/persistence/mybatis/util/PaginationCalculator.java @@ -0,0 +1,23 @@ +package org.cbioportal.persistence.mybatis.util; + +import org.springframework.stereotype.Component; + +@Component +public class PaginationCalculator { + + // PageNumber '0' represents the first page (no offset). + public Integer offset(Integer pageSize, Integer pageNumber) { + return pageSize == null || pageNumber == null ? + null : pageSize * pageNumber; + } + + // Returns 'lastIndex' as used by the subList command; position of the last element (exclusive). + public Integer lastIndex(Integer offset, Integer pageSize, Integer listLength) { + if (offset == null || pageSize == null || listLength == null) { + return null; + } + return (offset + pageSize) <= listLength ? + (offset + pageSize) : listLength; + } + +} diff --git a/src/main/java/org/cbioportal/service/ClinicalDataService.java b/src/main/java/org/cbioportal/service/ClinicalDataService.java index 972913ce2e4..b57474d1c4f 100644 --- a/src/main/java/org/cbioportal/service/ClinicalDataService.java +++ b/src/main/java/org/cbioportal/service/ClinicalDataService.java @@ -1,7 +1,9 @@ package org.cbioportal.service; +import org.apache.commons.lang3.tuple.ImmutablePair; import org.cbioportal.model.ClinicalData; import org.cbioportal.model.ClinicalDataCountItem; +import org.cbioportal.model.SampleClinicalDataCollection; import org.cbioportal.model.meta.BaseMeta; import org.cbioportal.service.exception.PatientNotFoundException; import org.cbioportal.service.exception.SampleNotFoundException; @@ -52,9 +54,7 @@ BaseMeta fetchMetaClinicalData(List studyIds, List ids, List getPatientClinicalDataDetailedToSample(List studyIds, List patientIds, List attributeIds); - List fetchSampleClinicalTable(List studyIds, List sampleIds, Integer pageSize, - Integer pageNumber, String searchTerm, String sortBy, String direction); - - Integer fetchSampleClinicalTableCount(List studyIds, List sampleIds, String searchTerm, - String sortBy, String direction); + ImmutablePair fetchSampleClinicalTable(List studyIds, List sampleIds, Integer pageSize, + Integer pageNumber, String searchTerm, String sortBy, String direction); + } diff --git a/src/main/java/org/cbioportal/service/impl/ClinicalDataServiceImpl.java b/src/main/java/org/cbioportal/service/impl/ClinicalDataServiceImpl.java index a4d41a8f343..43fb0a616b7 100644 --- a/src/main/java/org/cbioportal/service/impl/ClinicalDataServiceImpl.java +++ b/src/main/java/org/cbioportal/service/impl/ClinicalDataServiceImpl.java @@ -1,8 +1,10 @@ package org.cbioportal.service.impl; +import org.apache.commons.lang3.tuple.ImmutablePair; import org.cbioportal.model.*; import org.cbioportal.model.meta.BaseMeta; import org.cbioportal.persistence.ClinicalDataRepository; +import org.cbioportal.persistence.mybatis.util.PaginationCalculator; import org.cbioportal.service.*; import org.cbioportal.service.exception.*; import org.cbioportal.service.util.ClinicalAttributeUtil; @@ -12,6 +14,9 @@ import java.util.*; import java.util.function.Function; import java.util.stream.Collectors; +import java.util.stream.Stream; + +import static org.cbioportal.utils.Encoding.calculateBase64; @Service public class ClinicalDataServiceImpl implements ClinicalDataService { @@ -27,7 +32,9 @@ public class ClinicalDataServiceImpl implements ClinicalDataService { @Autowired private ClinicalAttributeService clinicalAttributeService; @Autowired - private ClinicalAttributeUtil clinicalAttributeUtil ; + private ClinicalAttributeUtil clinicalAttributeUtil; + @Autowired + private PaginationCalculator paginationCalculator; @Override public List getAllClinicalDataOfSampleInStudy(String studyId, String sampleId, String attributeId, @@ -227,17 +234,44 @@ public List getPatientClinicalDataDetailedToSample(List st } @Override - public List fetchSampleClinicalTable(List studyIds, List sampleIds, Integer pageSize, - Integer pageNumber, String searchTerm, String sortBy, - String direction) { - return clinicalDataRepository.fetchSampleClinicalTable(studyIds, sampleIds, pageSize, pageNumber, searchTerm, - sortBy, direction); - } + public ImmutablePair fetchSampleClinicalTable(List studyIds, List sampleIds, Integer pageSize, Integer pageNumber, String searchTerm, String sortBy, String direction) { - @Override - public Integer fetchSampleClinicalTableCount(List studyIds, List sampleIds, - String searchTerm, String sortBy, String direction) { - return clinicalDataRepository.fetchSampleClinicalTableCount(studyIds, sampleIds, searchTerm, - sortBy, direction); + SampleClinicalDataCollection sampleClinicalDataCollection = new SampleClinicalDataCollection(); + if (studyIds == null || studyIds.isEmpty() || sampleIds == null || sampleIds.isEmpty()) { + return new ImmutablePair<>(sampleClinicalDataCollection, 0); + } + + // Request un-paginated data. + List allSampleInternalIds = clinicalDataRepository.getVisibleSampleInternalIdsForClinicalTable( + studyIds, sampleIds, + null, null, + searchTerm, sortBy, direction + ); + Integer offset = paginationCalculator.offset(pageSize, pageNumber); + + if (allSampleInternalIds.isEmpty() || offset >= allSampleInternalIds.size()) { + return new ImmutablePair<>(sampleClinicalDataCollection, 0); + } + + // Apply pagination to the sampleId list. + Integer toIndex = paginationCalculator.lastIndex(offset, pageSize, allSampleInternalIds.size()); + List visibleSampleInternalIds = allSampleInternalIds.subList(offset, toIndex); + + List sampleClinicalData = clinicalDataRepository.getSampleClinicalDataBySampleInternalIds( + visibleSampleInternalIds + ); + List patientClinicalData = clinicalDataRepository.getPatientClinicalDataBySampleInternalIds( + visibleSampleInternalIds + ); + + // Merge sample and patient level clinical data and key by unique sample-key. + sampleClinicalDataCollection.setByUniqueSampleKey( + Stream.concat(sampleClinicalData.stream(), patientClinicalData.stream()) + .collect(Collectors.groupingBy(clinicalDatum -> + calculateBase64(clinicalDatum.getSampleId(), clinicalDatum.getStudyId()) + ))); + + return new ImmutablePair<>(sampleClinicalDataCollection, allSampleInternalIds.size()); } + } diff --git a/src/main/java/org/cbioportal/utils/Encoding.java b/src/main/java/org/cbioportal/utils/Encoding.java new file mode 100644 index 00000000000..0fb19950d40 --- /dev/null +++ b/src/main/java/org/cbioportal/utils/Encoding.java @@ -0,0 +1,20 @@ +package org.cbioportal.utils; + +import java.util.Base64; + +public class Encoding { + + private static final Base64.Encoder BASE64_ENCODER = Base64.getEncoder().withoutPadding(); + private static final Base64.Decoder BASE64_DECODER = Base64.getDecoder(); + + public static final String DELIMITER = ":"; + + public static String calculateBase64(String firstInput, String secondInput) { + return BASE64_ENCODER.encodeToString((firstInput + DELIMITER + secondInput).getBytes()); + } + + public static String decodeBase64(String input) { + return new String(BASE64_DECODER.decode(input)); + } + +} diff --git a/src/main/java/org/cbioportal/web/StudyViewController.java b/src/main/java/org/cbioportal/web/StudyViewController.java index 6ff98aa3ba1..d01bee36bed 100644 --- a/src/main/java/org/cbioportal/web/StudyViewController.java +++ b/src/main/java/org/cbioportal/web/StudyViewController.java @@ -16,28 +16,7 @@ import org.apache.commons.math3.stat.correlation.PearsonsCorrelation; import org.apache.commons.math3.stat.correlation.SpearmansCorrelation; import org.apache.commons.math3.util.Pair; -import org.cbioportal.model.AlterationCountByGene; -import org.cbioportal.model.AlterationCountByStructuralVariant; -import org.cbioportal.model.AlterationFilter; -import org.cbioportal.model.CaseListDataCount; -import org.cbioportal.model.ClinicalAttribute; -import org.cbioportal.model.ClinicalData; -import org.cbioportal.model.ClinicalDataBin; -import org.cbioportal.model.ClinicalDataCollection; -import org.cbioportal.model.ClinicalDataCountItem; -import org.cbioportal.model.ClinicalEventTypeCount; -import org.cbioportal.model.ClinicalViolinPlotData; -import org.cbioportal.model.CopyNumberCountByGene; -import org.cbioportal.model.DensityPlotBin; -import org.cbioportal.model.DensityPlotData; -import org.cbioportal.model.GenericAssayDataBin; -import org.cbioportal.model.GenericAssayDataCountItem; -import org.cbioportal.model.GenomicDataBin; -import org.cbioportal.model.GenomicDataCount; -import org.cbioportal.model.GenomicDataCountItem; -import org.cbioportal.model.Patient; -import org.cbioportal.model.Sample; -import org.cbioportal.model.SampleList; +import org.cbioportal.model.*; import org.cbioportal.service.ClinicalAttributeService; import org.cbioportal.service.ClinicalDataService; import org.cbioportal.service.ClinicalEventService; @@ -65,6 +44,7 @@ import org.cbioportal.web.parameter.HeaderKeyConstants; import org.cbioportal.web.parameter.PagingConstants; import org.cbioportal.web.parameter.Projection; +import org.cbioportal.web.parameter.sort.ClinicalDataSortBy; import org.cbioportal.web.parameter.SampleIdentifier; import org.cbioportal.web.parameter.StudyViewFilter; import org.cbioportal.web.util.ClinicalDataBinUtil; @@ -1047,8 +1027,8 @@ public ResponseEntity> fetchGenericAssayDataBinCounts( consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE) @Operation(description = "Fetch clinical data for the Clinical Tab of Study View") @ApiResponse(responseCode = "200", description = "OK", - content = @Content(schema = @Schema(implementation = ClinicalDataCollection.class))) - public ResponseEntity fetchClinicalDataClinicalTable( + content = @Content(schema = @Schema(implementation = SampleClinicalDataCollection.class))) + public ResponseEntity fetchClinicalDataClinicalTable( @Parameter(required = true, description = "Study view filter") @Valid @RequestBody(required = false) StudyViewFilter studyViewFilter, @@ -1063,7 +1043,7 @@ public ResponseEntity fetchClinicalDataClinicalTable( @Min(PagingConstants.NO_PAGING_PAGE_SIZE) @RequestParam(defaultValue = PagingConstants.DEFAULT_NO_PAGING_PAGE_SIZE) Integer pageSize, - @Parameter(description = "Page number of the result list") + @Parameter(description = "Page number of the result list. Zero represents the first page.") @Min(PagingConstants.MIN_PAGE_NUMBER) @RequestParam(defaultValue = PagingConstants.DEFAULT_PAGE_NUMBER) Integer pageNumber, @@ -1079,53 +1059,48 @@ public ResponseEntity fetchClinicalDataClinicalTable( @RequestParam(defaultValue = "ASC") Direction direction ) { + + boolean singleStudyUnfiltered = studyViewFilterUtil.isSingleStudyUnfiltered(interceptedStudyViewFilter); + ImmutablePair sampleClinicalData = cachedClinicalDataTableData( + interceptedStudyViewFilter, singleStudyUnfiltered, pageNumber, pageSize, sortBy, searchTerm, direction.name() + ); + + // Because of pagination, the total number of sample matches can be larger than the items in the requested page. + SampleClinicalDataCollection aggregatedClinicalDataByUniqueSampleKey = sampleClinicalData.getLeft(); + Integer totalNumberOfResults = sampleClinicalData.getRight(); + + HttpHeaders responseHeaders = new HttpHeaders(); + responseHeaders.add(HeaderKeyConstants.TOTAL_COUNT, String.valueOf(totalNumberOfResults)); + return new ResponseEntity<>(aggregatedClinicalDataByUniqueSampleKey, responseHeaders, HttpStatus.OK); + } + + // Only cache when: + // 1) the request concerns the entire study + // 2) no sorting/searching + // 3) requesting the first page + @Cacheable( + cacheResolver = "staticRepositoryCacheOneResolver", + condition = "@cacheEnabledConfig.getEnabled() && #singleStudyUnfiltered && (#sortBy == null || #sortBy.isEmpty()) && (#searchTerm == null || #searchTerm.isEmpty()) && #pageNumber == 0" + ) + public ImmutablePair cachedClinicalDataTableData( + StudyViewFilter interceptedStudyViewFilter, boolean singleStudyUnfiltered, Integer pageNumber, + Integer pageSize, String sortBy, String searchTerm, String sortDirection + ) { + List sampleStudyIds = new ArrayList<>(); List sampleIds = new ArrayList<>(); List filteredSampleIdentifiers = studyViewFilterApplier.apply(interceptedStudyViewFilter); studyViewFilterUtil.extractStudyAndSampleIds(filteredSampleIdentifiers, sampleStudyIds, sampleIds); - - List sampleClinicalData = clinicalDataService.fetchSampleClinicalTable( + + return clinicalDataService.fetchSampleClinicalTable( sampleStudyIds, sampleIds, pageSize, pageNumber, searchTerm, sortBy, - direction.name() + sortDirection ); - Integer total = clinicalDataService.fetchSampleClinicalTableCount( - sampleStudyIds, - sampleIds, - searchTerm, - sortBy, - direction.name() - ); - - // Return empty when possible. - if (sampleClinicalData.isEmpty()) { - return new ResponseEntity<>(new ClinicalDataCollection(), HttpStatus.OK); - } - - // Resolve for which patient clinical data should be included. - final List> patientIdentifiers = sampleClinicalData.stream() - .map(d -> new ImmutablePair<>(d.getStudyId(), d.getPatientId())) - .distinct() - .collect(Collectors.toList()); - List patientStudyIds = patientIdentifiers.stream().map(p -> p.getLeft()).collect(Collectors.toList()); - List patientIds = patientIdentifiers.stream().map(p -> p.getRight()).collect(Collectors.toList()); - - - List searchAllAttributes = null; - final List patientClinicalData = clinicalDataService.fetchClinicalData(patientStudyIds, patientIds, - searchAllAttributes, ClinicalDataType.PATIENT.name(), Projection.SUMMARY.name()); - - final ClinicalDataCollection clinicalDataCollection = new ClinicalDataCollection(); - clinicalDataCollection.setSampleClinicalData(sampleClinicalData); - clinicalDataCollection.setPatientClinicalData(patientClinicalData); - - HttpHeaders responseHeaders = new HttpHeaders(); - responseHeaders.add(HeaderKeyConstants.TOTAL_COUNT, total.toString()); - return new ResponseEntity<>(clinicalDataCollection, responseHeaders, HttpStatus.OK); } @PreAuthorize("hasPermission(#involvedCancerStudies, 'Collection', T(org.cbioportal.utils.security.AccessLevel).READ)") diff --git a/src/main/java/org/cbioportal/web/interceptor/UniqueKeyInterceptor.java b/src/main/java/org/cbioportal/web/interceptor/UniqueKeyInterceptor.java index 047d50ac9db..d6052900164 100644 --- a/src/main/java/org/cbioportal/web/interceptor/UniqueKeyInterceptor.java +++ b/src/main/java/org/cbioportal/web/interceptor/UniqueKeyInterceptor.java @@ -2,7 +2,6 @@ import org.cbioportal.model.Alteration; import org.cbioportal.model.ClinicalData; -import org.cbioportal.model.ClinicalDataCollection; import org.cbioportal.model.ClinicalEvent; import org.cbioportal.model.CopyNumberSeg; import org.cbioportal.model.GenePanelData; @@ -22,15 +21,13 @@ import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.servlet.mvc.method.annotation.AbstractMappingJacksonResponseBodyAdvice; -import java.util.Base64; import java.util.List; +import static org.cbioportal.utils.Encoding.calculateBase64; + @ControllerAdvice("org.cbioportal.web") public class UniqueKeyInterceptor extends AbstractMappingJacksonResponseBodyAdvice { - private static final Base64.Encoder BASE64_ENCODER = Base64.getEncoder().withoutPadding(); - public static final String DELIMITER = ":"; - @Override protected void beforeBodyWriteInternal(MappingJacksonValue mappingJacksonValue, MediaType mediaType, MethodParameter methodParameter, ServerHttpRequest serverHttpRequest, @@ -98,25 +95,7 @@ protected void beforeBodyWriteInternal(MappingJacksonValue mappingJacksonValue, } } } - } else if (value instanceof ClinicalDataCollection) { - ClinicalDataCollection collection = (ClinicalDataCollection) value; - if (collection.getSampleClinicalData() != null) { - collection.getSampleClinicalData().forEach( - clinicalData -> { - clinicalData.setUniqueSampleKey(calculateBase64(clinicalData.getSampleId(), clinicalData.getStudyId())); - clinicalData.setUniquePatientKey(calculateBase64(clinicalData.getPatientId(), clinicalData.getStudyId())); - } - ); - } - if (collection.getPatientClinicalData() != null) { - collection.getPatientClinicalData().forEach( - clinicalData -> clinicalData.setUniquePatientKey(calculateBase64(clinicalData.getPatientId(), clinicalData.getStudyId())) - ); - } } } - - private String calculateBase64(String firstInput, String secondInput) { - return BASE64_ENCODER.encodeToString((firstInput + DELIMITER + secondInput).getBytes()); - } + } diff --git a/src/main/java/org/cbioportal/web/util/UniqueKeyExtractor.java b/src/main/java/org/cbioportal/web/util/UniqueKeyExtractor.java index 966f932127d..6cb1637cc9a 100644 --- a/src/main/java/org/cbioportal/web/util/UniqueKeyExtractor.java +++ b/src/main/java/org/cbioportal/web/util/UniqueKeyExtractor.java @@ -1,24 +1,21 @@ package org.cbioportal.web.util; -import org.cbioportal.web.interceptor.UniqueKeyInterceptor; +import org.cbioportal.utils.Encoding; import org.springframework.stereotype.Component; import java.util.List; import java.util.Collection; -import java.util.Base64; @Component public class UniqueKeyExtractor { - private static final Base64.Decoder BASE64_DECODER = Base64.getDecoder(); - public void extractUniqueKeys(List uniqueKeys, Collection studyIdsToReturn) { extractUniqueKeys(uniqueKeys, studyIdsToReturn, null); } public void extractUniqueKeys(List uniqueKeys, Collection studyIdsToReturn, Collection patientOrSampleIdsToReturn) { for (String uniqueKey : uniqueKeys) { - String uniqueId = new String(BASE64_DECODER.decode(uniqueKey)); - String[] patientOrSampleAndStudyId = uniqueId.split(UniqueKeyInterceptor.DELIMITER); + String uniqueId = Encoding.decodeBase64(uniqueKey); + String[] patientOrSampleAndStudyId = uniqueId.split(Encoding.DELIMITER); if (patientOrSampleAndStudyId.length == 2) { if (patientOrSampleIdsToReturn != null) { patientOrSampleIdsToReturn.add(patientOrSampleAndStudyId[0]); diff --git a/src/main/resources/org/cbioportal/persistence/mybatis/ClinicalDataMapper.xml b/src/main/resources/org/cbioportal/persistence/mybatis/ClinicalDataMapper.xml index c286e75d76f..bfe06321aff 100644 --- a/src/main/resources/org/cbioportal/persistence/mybatis/ClinicalDataMapper.xml +++ b/src/main/resources/org/cbioportal/persistence/mybatis/ClinicalDataMapper.xml @@ -47,11 +47,6 @@ INNER JOIN cancer_study ON patient.CANCER_STUDY_ID = cancer_study.CANCER_STUDY_ID - - - LEFT JOIN clinical_patient ON clinical_patient.INTERNAL_ID = patient.INTERNAL_ID - - FROM clinical_patient INNER JOIN patient ON clinical_patient.INTERNAL_ID = patient.INTERNAL_ID @@ -120,6 +115,32 @@ + + + + - + + + + + + + SELECT sample.INTERNAL_ID FROM sample + INNER JOIN patient ON sample.PATIENT_ID = patient.INTERNAL_ID + INNER JOIN cancer_study ON patient.CANCER_STUDY_ID = cancer_study.CANCER_STUDY_ID + + LEFT JOIN () as sortData + ON sample.INTERNAL_ID = sortData.sampleInternalId + + + INNER JOIN () as searchData + ON sample.INTERNAL_ID = searchData.sampleInternalId + + + + + + ORDER BY sample.STABLE_ID ${direction} + + + ORDER BY patient.STABLE_ID ${direction} + + + + + ORDER BY ISNULL(sortData.sortAttrValue), sortData.sortAttrValue ${direction} + + + ORDER BY sortData.sortAttrValue ${direction} NULLS LAST + + + + + + + + LIMIT #{limit} OFFSET #{offset} + - - - - INNER JOIN ( - SELECT DISTINCT clinical_sample.INTERNAL_ID - - - , sample.STABLE_ID AS SORT_BY - - - , patient.STABLE_ID AS SORT_BY - - - - - , CASE - WHEN clinical_sample.ATTR_ID = #{sortBy} THEN clinical_sample.ATTR_VALUE - WHEN clinical_patient.ATTR_ID = #{sortBy} THEN clinical_patient.ATTR_VALUE - ELSE NULL - END AS SORT_BY - - - + + SELECT + DISTINCT sample.INTERNAL_ID sampleInternalId + FROM sample + INNER JOIN patient ON patient.INTERNAL_ID = sample.PATIENT_ID + INNER JOIN cancer_study ON patient.CANCER_STUDY_ID = cancer_study.CANCER_STUDY_ID + INNER JOIN clinical_sample cs on sample.INTERNAL_ID = cs.INTERNAL_ID + INNER JOIN clinical_patient cp on patient.INTERNAL_ID = cp.INTERNAL_ID - - AND - clinical_sample.ATTR_VALUE LIKE CONCAT('%', #{searchTerm}, '%') - - - + AND ( + cs.ATTR_VALUE LIKE CONCAT('%', #{searchTerm}, '%') + OR cp.ATTR_VALUE LIKE CONCAT('%', #{searchTerm}, '%') + OR sample.STABLE_ID LIKE CONCAT('%', #{searchTerm}, '%') + OR patient.STABLE_ID LIKE CONCAT('%', #{searchTerm}, '%') + ) + + + + + + SELECT sample.INTERNAL_ID sampleInternalId, sample.STABLE_ID sampleId, patient.STABLE_ID patientId, clinical_patient.ATTR_ID sortAttrId, - - ORDER BY ISNULL(SORT_BY), SORT_BY ${direction} + CONVERT(clinical_patient.ATTR_VALUE, DECIMAL) sortAttrValue - - ORDER BY SORT_BY ${direction} NULLS LAST + + clinical_patient.ATTR_VALUE sortAttrValue + + + FROM sample + INNER JOIN patient ON sample.PATIENT_ID = patient.INTERNAL_ID + INNER JOIN cancer_study ON patient.CANCER_STUDY_ID = cancer_study.CANCER_STUDY_ID + LEFT JOIN clinical_patient ON patient.INTERNAL_ID = clinical_patient.INTERNAL_ID AND clinical_patient.ATTR_ID = #{sortAttrId} + + + SELECT sample.INTERNAL_ID sampleInternalId, sample.STABLE_ID sampleId, patient.STABLE_ID patientId, clinical_sample.ATTR_ID sortAttrId, + + + CONVERT(clinical_sample.ATTR_VALUE, DECIMAL) sortAttrValue + + clinical_sample.ATTR_VALUE sortAttrValue + - - - - LIMIT #{limit} OFFSET #{offset} - - ) AS sample_id_subquery - ON clinical_sample.INTERNAL_ID = sample_id_subquery.INTERNAL_ID + FROM clinical_sample + INNER JOIN sample ON clinical_sample.INTERNAL_ID = sample.INTERNAL_ID + INNER JOIN patient ON sample.PATIENT_ID = patient.INTERNAL_ID + INNER JOIN cancer_study ON patient.CANCER_STUDY_ID = cancer_study.CANCER_STUDY_ID + WHERE clinical_sample.ATTR_ID = #{sortAttrId} + + - + diff --git a/src/test/java/org/cbioportal/persistence/mybatis/ClinicalDataMyBatisRepositoryTest.java b/src/test/java/org/cbioportal/persistence/mybatis/ClinicalDataMyBatisRepositoryTest.java index 641d3399c56..254efa47463 100644 --- a/src/test/java/org/cbioportal/persistence/mybatis/ClinicalDataMyBatisRepositoryTest.java +++ b/src/test/java/org/cbioportal/persistence/mybatis/ClinicalDataMyBatisRepositoryTest.java @@ -9,8 +9,10 @@ import org.cbioportal.model.ClinicalData; import org.cbioportal.model.ClinicalDataCount; import org.cbioportal.model.meta.BaseMeta; +import org.cbioportal.persistence.ClinicalAttributeRepository; import org.cbioportal.persistence.PersistenceConstants; import org.cbioportal.persistence.mybatis.config.TestConfig; +import org.cbioportal.persistence.mybatis.util.PaginationCalculator; import org.junit.Assert; import org.junit.Before; import org.junit.Test; @@ -21,7 +23,13 @@ @RunWith(SpringJUnit4ClassRunner.class) -@SpringBootTest(classes = {ClinicalDataMyBatisRepository.class, PatientMyBatisRepository.class, TestConfig.class}) +@SpringBootTest(classes = { + ClinicalDataMyBatisRepository.class, + PatientMyBatisRepository.class, + ClinicalAttributeMyBatisRepository.class, + ClinicalAttributeMapper.class, + PaginationCalculator.class, + TestConfig.class}) public class ClinicalDataMyBatisRepositoryTest { private static int noPaging = 0; @@ -34,10 +42,34 @@ public class ClinicalDataMyBatisRepositoryTest { @Before public void init() { + studyIds.add("study_tcga_pub"); + studyIds.add("study_tcga_pub"); + studyIds.add("study_tcga_pub"); + studyIds.add("study_tcga_pub"); + studyIds.add("study_tcga_pub"); + studyIds.add("study_tcga_pub"); + studyIds.add("study_tcga_pub"); + studyIds.add("study_tcga_pub"); + studyIds.add("study_tcga_pub"); + studyIds.add("study_tcga_pub"); + studyIds.add("study_tcga_pub"); + studyIds.add("study_tcga_pub"); studyIds.add("study_tcga_pub"); studyIds.add("study_tcga_pub"); sampleIds.add("TCGA-A1-A0SB-01"); sampleIds.add("TCGA-A1-A0SD-01"); + sampleIds.add("TCGA-A1-A0SE-01"); + sampleIds.add("TCGA-A1-A0SF-01"); + sampleIds.add("TCGA-A1-A0SG-01"); + sampleIds.add("TCGA-A1-A0SH-01"); + sampleIds.add("TCGA-A1-A0SI-01"); + sampleIds.add("TCGA-A1-A0SJ-01"); + sampleIds.add("TCGA-A1-A0SK-01"); + sampleIds.add("TCGA-A1-A0SM-01"); + sampleIds.add("TCGA-A1-A0SN-01"); + sampleIds.add("TCGA-A1-A0SO-01"); + sampleIds.add("TCGA-A1-A0SP-01"); + sampleIds.add("TCGA-A1-A0SQ-01"); } @Autowired @@ -100,9 +132,10 @@ public void getAllClinicalDataOfSampleInStudyNullAttributeSummaryProjectionAttrI null, "SUMMARY", null, null, "attrId", "ASC"); Assert.assertEquals(4, result.size()); - Assert.assertEquals("DAYS_TO_COLLECTION", result.get(0).getAttrId()); - Assert.assertEquals("IS_FFPE", result.get(1).getAttrId()); - Assert.assertEquals("OTHER_SAMPLE_ID", result.get(2).getAttrId()); + Assert.assertTrue(result.stream().anyMatch(r -> r.getAttrId().equals("DAYS_TO_COLLECTION"))); + Assert.assertTrue(result.stream().anyMatch(r -> r.getAttrId().equals("IS_FFPE"))); + Assert.assertTrue(result.stream().anyMatch(r -> r.getAttrId().equals("OTHER_SAMPLE_ID"))); + Assert.assertTrue(result.stream().anyMatch(r -> r.getAttrId().equals("SAMPLE_TYPE"))); } @Test @@ -187,9 +220,9 @@ public void getAllClinicalDataOfPatientInStudyNullAttributeSummaryProjectionAttr "TCGA-A1-A0SB", null, "SUMMARY", null, null, "attrId", "ASC"); Assert.assertEquals(3, result.size()); - Assert.assertEquals("FORM_COMPLETION_DATE", result.get(0).getAttrId()); - Assert.assertEquals("OTHER_PATIENT_ID", result.get(1).getAttrId()); - Assert.assertEquals("RETROSPECTIVE_COLLECTION", result.get(2).getAttrId()); + Assert.assertTrue(result.stream().anyMatch(r -> r.getAttrId().equals("FORM_COMPLETION_DATE"))); + Assert.assertTrue(result.stream().anyMatch(r -> r.getAttrId().equals("OTHER_PATIENT_ID"))); + Assert.assertTrue(result.stream().anyMatch(r -> r.getAttrId().equals("RETROSPECTIVE_COLLECTION"))); } @Test @@ -368,88 +401,103 @@ public void fetchClinicalDataNullAttributeSummaryProjection() { } @Test - public void fetchClinicalSampleDataClinicalTabPagingSuccess() { + public void fetchClinicalSampleIdsClinicalTabShowAllSamples() { - List resultFirstPage = clinicalDataMyBatisRepository.fetchSampleClinicalTable(studyIds, - sampleIds, 1, 0, noSearch, noSort, "DESC"); - List resultSecondPage = clinicalDataMyBatisRepository.fetchSampleClinicalTable(studyIds, - sampleIds, 1, 1, noSearch, noSort, "DESC"); + List result = clinicalDataMyBatisRepository.getVisibleSampleInternalIdsForClinicalTable( + studyIds, sampleIds, noPaging, noPaging, noSearch, noSort, "DESC"); - Assert.assertEquals(4, resultFirstPage.size()); - Assert.assertEquals(4, resultSecondPage.size()); - - List observedAttrIds = resultFirstPage.stream().map(e -> e.getAttrId()).collect(Collectors.toList()); - observedAttrIds.addAll(resultSecondPage.stream().map(e -> e.getAttrId()).collect(Collectors.toList())); - - List expectedAttrIds = Arrays.asList("IS_FFPE", "OTHER_SAMPLE_ID", "OCT_EMBEDDED", "PATHOLOGY_REPORT_FILE_NAME", - "DAYS_TO_COLLECTION", "SAMPLE_TYPE"); - - Assert.assertTrue( - "Paginated results do not contain the expected attribute ids." + - " Expected: " + expectedAttrIds + - " Observed: " + observedAttrIds, - observedAttrIds.containsAll(expectedAttrIds) - ); + Assert.assertEquals(14, result.size()); } @Test - public void fetchClinicalSampleDataClinicalTablePagingHandleNoneExistingPage() { + public void fetchClinicalSampleIdsClinicalTablePagingHandleNoneExistingPage() { // There are only two patients in total. The second page (index 1) with pageSize 2 does not refer to any records. - List resultNonExistingPage = clinicalDataMyBatisRepository.fetchSampleClinicalTable( - studyIds, sampleIds, 2, 1, noSearch, noSort, "DESC"); + List resultNonExistingPage = clinicalDataMyBatisRepository.getVisibleSampleInternalIdsForClinicalTable( + studyIds, sampleIds, 2, 100, noSearch, noSort, "DESC"); Assert.assertEquals(0, resultNonExistingPage.size()); } @Test - public void fetchClinicalSampleDataClinicalTabSearchTermSuccess() { + public void fetchClinicalSampleIdsClinicalTabStringSort() { - List resultSample1 = clinicalDataMyBatisRepository.fetchSampleClinicalTable( - studyIds, sampleIds, noPaging, noPaging, "5C631CE8", noSort, "DESC"); - - Assert.assertEquals(4, resultSample1.size()); - List observedSampleIds = resultSample1.stream().map(s -> s.getSampleId()).distinct().collect(Collectors.toList()); - Assert.assertEquals(1, observedSampleIds.size()); - Assert.assertEquals("TCGA-A1-A0SB-01", observedSampleIds.get(0)); + List visibleSampleIdsAsc = clinicalDataMyBatisRepository.getVisibleSampleInternalIdsForClinicalTable(studyIds, + sampleIds, 2, 0, noSearch, "SAMPLE_TYPE", "ASC"); + List visibleSampleIdsDesc = clinicalDataMyBatisRepository.getVisibleSampleInternalIdsForClinicalTable(studyIds, + sampleIds, 2, 0, noSearch, "SAMPLE_TYPE", "DESC"); + + Assert.assertEquals(2, visibleSampleIdsAsc.size()); + Assert.assertEquals(2, visibleSampleIdsDesc.size()); + Assert.assertEquals(2, (int) visibleSampleIdsAsc.get(0)); + Assert.assertEquals(1, (int) visibleSampleIdsDesc.get(0)); + } + + @Test + public void fetchClinicalSampleIdsClinicalTabNumericSort() { - List resultSample2 = clinicalDataMyBatisRepository.fetchSampleClinicalTable( - studyIds, sampleIds, noPaging, noPaging, "F3408556-9259", noSort, "DESC"); + List visibleSampleIdsAsc = clinicalDataMyBatisRepository.getVisibleSampleInternalIdsForClinicalTable(studyIds, + sampleIds, 14, 0, noSearch, "DAYS_TO_COLLECTION", "ASC"); + List visibleSampleIdsDesc = clinicalDataMyBatisRepository.getVisibleSampleInternalIdsForClinicalTable(studyIds, + sampleIds, 14, 0, noSearch, "DAYS_TO_COLLECTION", "DESC"); + + Assert.assertEquals(14, visibleSampleIdsAsc.size()); + Assert.assertEquals(14, visibleSampleIdsDesc.size()); + Assert.assertEquals(1, (int) visibleSampleIdsAsc.get(0)); + Assert.assertEquals(2, (int) visibleSampleIdsDesc.get(0)); + } + + @Test + public void fetchClinicalSampleIdsClinicalTabPageing() { + + List visibleSampleIdsAsc = clinicalDataMyBatisRepository.getVisibleSampleInternalIdsForClinicalTable(studyIds, + sampleIds, 1, 1, noSearch, "SAMPLE_TYPE", "ASC"); - Assert.assertEquals(4, resultSample2.size()); - observedSampleIds = resultSample2.stream().map(s -> s.getSampleId()).distinct().collect(Collectors.toList()); - Assert.assertEquals(1, observedSampleIds.size()); - Assert.assertEquals("TCGA-A1-A0SD-01", observedSampleIds.get(0)); + Assert.assertEquals(1, visibleSampleIdsAsc.size()); + Assert.assertEquals(1, (int) visibleSampleIdsAsc.get(0)); } @Test - public void fetchClinicalSampleDataEClinicalTabEmptyStringSearchTerm() { + public void fetchClinicalSampleIdsClinicalTabSearchBySampleId() { - List result = clinicalDataMyBatisRepository.fetchSampleClinicalTable( - studyIds, sampleIds, noPaging, noPaging, "", noSort, "DESC"); - - Assert.assertEquals(8, result.size()); + List visibleSampleIdsAsc = clinicalDataMyBatisRepository.getVisibleSampleInternalIdsForClinicalTable(studyIds, + sampleIds, noPaging, noPaging, "A0SB-01", noSort, noSort); + + Assert.assertEquals(1, visibleSampleIdsAsc.size()); + Assert.assertEquals(1, (int) visibleSampleIdsAsc.get(0)); } @Test - public void fetchClinicalSampleDataClinicalTabSortSuccess() { + public void fetchClinicalSampleIdsClinicalTabSearchByEmptyStringShowsAllSample() { - List resultSortAsc = clinicalDataMyBatisRepository.fetchSampleClinicalTable(studyIds, - sampleIds, 1, 0, noSearch, "SAMPLE_TYPE", "ASC"); - List resultSortDesc = clinicalDataMyBatisRepository.fetchSampleClinicalTable(studyIds, - sampleIds, 1, 0, noSearch, "SAMPLE_TYPE", "DESC"); + List result = clinicalDataMyBatisRepository.getVisibleSampleInternalIdsForClinicalTable( + studyIds, sampleIds, noPaging, noPaging, "", noSort, "DESC"); + + Assert.assertEquals(14, result.size()); + } - Assert.assertEquals(4, resultSortAsc.size()); - Assert.assertEquals(4, resultSortDesc.size()); + @Test + public void fetchClinicalSampleIdsClinicalTabSearchByAttributeValue() { + + List visibleSampleIdsAsc = clinicalDataMyBatisRepository.getVisibleSampleInternalIdsForClinicalTable(studyIds, + sampleIds, noPaging, noPaging, "2013", noSort, noSort); - List observedSampleIdAsc = resultSortAsc.stream().map(e -> e.getSampleId()).distinct().collect(Collectors.toList()); - List observedSampleIdDesc = resultSortDesc.stream().map(e -> e.getSampleId()).distinct().collect(Collectors.toList()); + Assert.assertEquals(1, visibleSampleIdsAsc.size()); + Assert.assertEquals(1, (int) visibleSampleIdsAsc.get(0)); + } + + @Test + public void fetchClinicalSampleIdsClinicalTabSearchAndSort() { - Assert.assertEquals(1, observedSampleIdAsc.size()); - Assert.assertEquals(1, observedSampleIdDesc.size()); - Assert.assertEquals("TCGA-A1-A0SD-01", observedSampleIdAsc.get(0)); - Assert.assertEquals("TCGA-A1-A0SB-01", observedSampleIdDesc.get(0)); + List visibleSampleIdsAsc = clinicalDataMyBatisRepository.getVisibleSampleInternalIdsForClinicalTable(studyIds, + sampleIds, 2, 0, "-01", "SAMPLE_TYPE", "ASC"); + List visibleSampleIdsDesc = clinicalDataMyBatisRepository.getVisibleSampleInternalIdsForClinicalTable(studyIds, + sampleIds, 2, 0, "-01", "SAMPLE_TYPE", "DESC"); + Assert.assertEquals(2, visibleSampleIdsAsc.size()); + Assert.assertEquals(2, visibleSampleIdsDesc.size()); + Assert.assertEquals(2, (int) visibleSampleIdsAsc.get(0)); + Assert.assertEquals(1, (int) visibleSampleIdsDesc.get(0)); } @Test @@ -478,4 +526,71 @@ public void fetchClinicalDataCounts() { Assert.assertEquals("91E7F41C-17B3-4724-96EF-D3C207B964E1", clinicalDataCount2.getValue()); Assert.assertEquals((Integer) 1, clinicalDataCount2.getCount()); } + + @Test + public void getSampleClinicalDataBySampleInternalIds() { + List sampleInternalIds = List.of(1, 2); + List result = clinicalDataMyBatisRepository.getSampleClinicalDataBySampleInternalIds( + sampleInternalIds + ); + String[] attributeIds = result.stream().map(ClinicalData::getAttrId).distinct().toArray(String[]::new); + Assert.assertEquals(8, result.size()); + Assert.assertTrue(result.stream().anyMatch(r -> r.getAttrId().equals("DAYS_TO_COLLECTION"))); + Assert.assertTrue(result.stream().anyMatch(r -> r.getAttrId().equals("IS_FFPE"))); + Assert.assertTrue(result.stream().anyMatch(r -> r.getAttrId().equals("OTHER_SAMPLE_ID"))); + Assert.assertTrue(result.stream().anyMatch(r -> r.getAttrId().equals("SAMPLE_TYPE"))); + Assert.assertTrue(result.stream().anyMatch(r -> r.getAttrId().equals("OCT_EMBEDDED"))); + Assert.assertTrue(result.stream().anyMatch(r -> r.getAttrId().equals("PATHOLOGY_REPORT_FILE_NAME"))); + } + + @Test + public void getSampleClinicalDataBySampleInternalIdsEmpty() { + List sampleInternalIds = new ArrayList<>(); + List result = clinicalDataMyBatisRepository.getSampleClinicalDataBySampleInternalIds( + sampleInternalIds + ); + Assert.assertEquals(0, result.size()); + } + + @Test + public void getSampleClinicalDataBySampleInternalIdsNull() { + List sampleInternalIds = null; + List result = clinicalDataMyBatisRepository.getSampleClinicalDataBySampleInternalIds( + sampleInternalIds + ); + Assert.assertEquals(0, result.size()); + } + + @Test + public void getPatientClinicalDataBySampleInternalIds() { + List sampleInternalIds = List.of(1, 2); + List result = clinicalDataMyBatisRepository.getPatientClinicalDataBySampleInternalIds( + sampleInternalIds + ); + String[] attributeIds = result.stream().map(ClinicalData::getAttrId).distinct().toArray(String[]::new); + Assert.assertEquals(4, result.size()); + Assert.assertTrue(result.stream().anyMatch(r -> r.getAttrId().equals("FORM_COMPLETION_DATE"))); + Assert.assertTrue(result.stream().anyMatch(r -> r.getAttrId().equals("OTHER_PATIENT_ID"))); + Assert.assertTrue(result.stream().anyMatch(r -> r.getAttrId().equals("RETROSPECTIVE_COLLECTION"))); + Assert.assertTrue(result.stream().anyMatch(r -> r.getAttrId().equals("PROSPECTIVE_COLLECTION"))); + } + + @Test + public void getPatientClinicalDataBySampleInternalIdsEmpty() { + List sampleInternalIds = new ArrayList<>(); + List result = clinicalDataMyBatisRepository.getPatientClinicalDataBySampleInternalIds( + sampleInternalIds + ); + Assert.assertEquals(0, result.size()); + } + + @Test + public void getPatientClinicalDataBySampleInternalIdsNull() { + List sampleInternalIds = null; + List result = clinicalDataMyBatisRepository.getPatientClinicalDataBySampleInternalIds( + sampleInternalIds + ); + Assert.assertEquals(0, result.size()); + } + } diff --git a/src/test/java/org/cbioportal/persistence/mybatis/config/TestConfig.java b/src/test/java/org/cbioportal/persistence/mybatis/config/TestConfig.java index 91d75324a18..668e1515b67 100644 --- a/src/test/java/org/cbioportal/persistence/mybatis/config/TestConfig.java +++ b/src/test/java/org/cbioportal/persistence/mybatis/config/TestConfig.java @@ -2,12 +2,11 @@ import javax.sql.DataSource; -import org.apache.ibatis.io.Resources; import org.apache.ibatis.mapping.DatabaseIdProvider; import org.apache.ibatis.mapping.VendorDatabaseIdProvider; import org.apache.ibatis.session.SqlSessionFactory; import org.cbioportal.persistence.mybatis.typehandler.SampleTypeTypeHandler; -import org.cbioportal.persistence.mybatis.util.OffsetCalculator; +import org.cbioportal.persistence.mybatis.util.PaginationCalculator; import org.mybatis.spring.SqlSessionFactoryBean; import org.mybatis.spring.annotation.MapperScan; import org.springframework.boot.test.context.TestConfiguration; @@ -17,7 +16,6 @@ import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType; import org.springframework.transaction.PlatformTransactionManager; -import java.io.InputStream; import java.util.Properties; @TestConfiguration @@ -56,8 +54,8 @@ public SqlSessionFactory sqlSessionFactory() throws Exception { } @Bean - public OffsetCalculator offsetCalculator() { - return new OffsetCalculator(); + public PaginationCalculator PaginationCalculator() { + return new PaginationCalculator(); } @Bean diff --git a/src/test/java/org/cbioportal/persistence/mybatis/util/PaginationCalculatorTest.java b/src/test/java/org/cbioportal/persistence/mybatis/util/PaginationCalculatorTest.java new file mode 100644 index 00000000000..61c13741bfa --- /dev/null +++ b/src/test/java/org/cbioportal/persistence/mybatis/util/PaginationCalculatorTest.java @@ -0,0 +1,49 @@ +package org.cbioportal.persistence.mybatis.util; + +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(classes=PaginationCalculator.class) +public class PaginationCalculatorTest { + + @Autowired + private PaginationCalculator paginationCalculator; + + @Test + public void testOffsetNull() { + Assert.assertNull(paginationCalculator.offset(null, 1)); + Assert.assertNull(paginationCalculator.offset(1, null)); + Assert.assertNull(paginationCalculator.offset(null, null)); + } + + @Test + public void testOffset() { + Assert.assertEquals(0, (int) paginationCalculator.offset(10, 0)); + Assert.assertEquals(10, (int) paginationCalculator.offset(10, 1)); + Assert.assertEquals(100, (int) paginationCalculator.offset(10, 10)); + } + + @Test + public void testLastIndexNull() { + Assert.assertNull(paginationCalculator.lastIndex(null, 1, 1)); + Assert.assertNull(paginationCalculator.lastIndex(1, null, 1)); + Assert.assertNull(paginationCalculator.lastIndex(null, null, 1)); + Assert.assertNull(paginationCalculator.lastIndex(null, 1, 1)); + Assert.assertNull(paginationCalculator.lastIndex(1, 1, null)); + Assert.assertNull(paginationCalculator.lastIndex(null, 1, null)); + Assert.assertNull(paginationCalculator.lastIndex(1, null, null)); + Assert.assertNull(paginationCalculator.lastIndex(null, null, null)); + } + + @Test + public void testLastIndex() { + Assert.assertEquals(3, (int) paginationCalculator.lastIndex(0, 3, 26)); + Assert.assertEquals(6, (int) paginationCalculator.lastIndex(3, 3, 26)); + Assert.assertEquals(26, (int) paginationCalculator.lastIndex(25, 3, 26)); + } +} \ No newline at end of file diff --git a/src/test/java/org/cbioportal/persistence/util/fakeclient/MockInMemoryRedissonClient.java b/src/test/java/org/cbioportal/persistence/util/fakeclient/MockInMemoryRedissonClient.java index 2195033f137..92f69db4a88 100644 --- a/src/test/java/org/cbioportal/persistence/util/fakeclient/MockInMemoryRedissonClient.java +++ b/src/test/java/org/cbioportal/persistence/util/fakeclient/MockInMemoryRedissonClient.java @@ -231,6 +231,7 @@ public RLock getMultiLock(RLock... rLocks) { * @deprecated */ @Override + @Deprecated public RLock getRedLock(RLock... rLocks) { throw new UnsupportedOperationException(); } @@ -549,6 +550,7 @@ public T getRedisNodes(RedisNodes redisNodes) { * @deprecated */ @Override + @Deprecated public NodesGroup getNodesGroup() { throw new UnsupportedOperationException(); } @@ -557,6 +559,7 @@ public NodesGroup getNodesGroup() { * @deprecated */ @Override + @Deprecated public ClusterNodesGroup getClusterNodesGroup() { throw new UnsupportedOperationException(); } diff --git a/src/test/java/org/cbioportal/service/impl/ClinicalDataServiceImplTest.java b/src/test/java/org/cbioportal/service/impl/ClinicalDataServiceImplTest.java index ae0d10fcef0..b35d38d47d2 100644 --- a/src/test/java/org/cbioportal/service/impl/ClinicalDataServiceImplTest.java +++ b/src/test/java/org/cbioportal/service/impl/ClinicalDataServiceImplTest.java @@ -1,12 +1,16 @@ package org.cbioportal.service.impl; +import org.apache.commons.lang3.tuple.ImmutablePair; import org.cbioportal.model.*; import org.cbioportal.model.meta.BaseMeta; import org.cbioportal.persistence.ClinicalDataRepository; +import org.cbioportal.persistence.mybatis.util.PaginationCalculator; import org.cbioportal.service.*; import org.cbioportal.service.exception.*; import org.cbioportal.service.util.ClinicalAttributeUtil; +import org.cbioportal.utils.Encoding; import org.junit.Assert; +import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.InjectMocks; @@ -14,9 +18,13 @@ import org.mockito.Mockito; import org.mockito.Spy; import org.mockito.junit.MockitoJUnitRunner; +import org.springframework.test.context.ContextConfiguration; import java.util.*; +import static org.mockito.ArgumentMatchers.anyList; +import static org.mockito.Mockito.when; + @RunWith(MockitoJUnitRunner.class) public class ClinicalDataServiceImplTest extends BaseServiceImplTest { @@ -35,6 +43,37 @@ public class ClinicalDataServiceImplTest extends BaseServiceImplTest { private ClinicalAttributeService clinicalAttributeService; @Spy private ClinicalAttributeUtil clinicalAttributeUtil = new ClinicalAttributeUtil(); + @Spy + private PaginationCalculator paginationCalculator = new PaginationCalculator(); + + + ClinicalData datum1 = new ClinicalData(); + ClinicalData datum2 = new ClinicalData(); + String uniqueKeySample1; + String uniqueKeySample2; + List sampleStudyIds = Arrays.asList(STUDY_ID, STUDY_ID, STUDY_ID); + List sampleIds = Arrays.asList(SAMPLE_ID1, SAMPLE_ID2, SAMPLE_ID3); + + Integer pageSize = 2; + Integer pageNumber = 0; + String searchTerm = "mySearch"; + String sortBy = "column name"; + String direction = "ASC"; + List sampleInternalIds = Arrays.asList(0, 1); + List sampleInternalIdsAll = Arrays.asList(0, 1, 2, 3); + + @Before + public void init() { + + datum1.setSampleId("SampleA"); + datum1.setStudyId("Study1"); + uniqueKeySample1 = Encoding.calculateBase64("SampleA", "Study1"); + + datum2.setSampleId("SampleA"); + datum2.setStudyId("Study2"); + uniqueKeySample2 = Encoding.calculateBase64("SampleA", "Study2"); + + } @Test public void getAllClinicalDataOfSampleInStudy() throws Exception { @@ -43,7 +82,7 @@ public void getAllClinicalDataOfSampleInStudy() throws Exception { ClinicalData sampleClinicalData = new ClinicalData(); expectedSampleClinicalDataList.add(sampleClinicalData); - Mockito.when(clinicalDataRepository.getAllClinicalDataOfSampleInStudy(STUDY_ID, SAMPLE_ID1, + when(clinicalDataRepository.getAllClinicalDataOfSampleInStudy(STUDY_ID, SAMPLE_ID1, CLINICAL_ATTRIBUTE_ID_1, PROJECTION, PAGE_SIZE, PAGE_NUMBER, SORT, DIRECTION)) .thenReturn(expectedSampleClinicalDataList); @@ -56,7 +95,7 @@ public void getAllClinicalDataOfSampleInStudy() throws Exception { @Test(expected = SampleNotFoundException.class) public void getAllClinicalDataOfSampleInStudySampleNotFound() throws Exception { - Mockito.when(sampleService.getSampleInStudy(STUDY_ID, SAMPLE_ID1)) + when(sampleService.getSampleInStudy(STUDY_ID, SAMPLE_ID1)) .thenThrow(new SampleNotFoundException(STUDY_ID, SAMPLE_ID1)); clinicalDataService.getAllClinicalDataOfSampleInStudy(STUDY_ID, SAMPLE_ID1, CLINICAL_ATTRIBUTE_ID_1, PROJECTION, PAGE_SIZE, PAGE_NUMBER, SORT, DIRECTION); @@ -67,7 +106,7 @@ public void getMetaSampleClinicalData() throws Exception { BaseMeta expectedBaseMeta = new BaseMeta(); - Mockito.when(clinicalDataRepository.getMetaSampleClinicalData(STUDY_ID, SAMPLE_ID1, CLINICAL_ATTRIBUTE_ID_1)) + when(clinicalDataRepository.getMetaSampleClinicalData(STUDY_ID, SAMPLE_ID1, CLINICAL_ATTRIBUTE_ID_1)) .thenReturn(expectedBaseMeta); BaseMeta result = clinicalDataService.getMetaSampleClinicalData(STUDY_ID, SAMPLE_ID1, CLINICAL_ATTRIBUTE_ID_1); @@ -78,7 +117,7 @@ public void getMetaSampleClinicalData() throws Exception { @Test(expected = SampleNotFoundException.class) public void getMetaSampleClinicalDataSampleNotFound() throws Exception { - Mockito.when(sampleService.getSampleInStudy(STUDY_ID, SAMPLE_ID1)) + when(sampleService.getSampleInStudy(STUDY_ID, SAMPLE_ID1)) .thenThrow(new SampleNotFoundException(STUDY_ID, SAMPLE_ID1)); clinicalDataService.getMetaSampleClinicalData(STUDY_ID, SAMPLE_ID1, CLINICAL_ATTRIBUTE_ID_1); } @@ -90,7 +129,7 @@ public void getAllClinicalDataOfPatientInStudy() throws Exception { ClinicalData patientClinicalData = new ClinicalData(); expectedPatientClinicalDataList.add(patientClinicalData); - Mockito.when(clinicalDataRepository.getAllClinicalDataOfPatientInStudy(STUDY_ID, PATIENT_ID_1, + when(clinicalDataRepository.getAllClinicalDataOfPatientInStudy(STUDY_ID, PATIENT_ID_1, CLINICAL_ATTRIBUTE_ID_1, PROJECTION, PAGE_SIZE, PAGE_NUMBER, SORT, DIRECTION)) .thenReturn(expectedPatientClinicalDataList); @@ -103,7 +142,7 @@ public void getAllClinicalDataOfPatientInStudy() throws Exception { @Test(expected = PatientNotFoundException.class) public void getAllClinicalDataOfPatientInStudyPatientNotFound() throws Exception { - Mockito.when(patientService.getPatientInStudy(STUDY_ID, PATIENT_ID_1)) + when(patientService.getPatientInStudy(STUDY_ID, PATIENT_ID_1)) .thenThrow(new PatientNotFoundException(STUDY_ID, PATIENT_ID_1)); clinicalDataService.getAllClinicalDataOfPatientInStudy(STUDY_ID, PATIENT_ID_1, CLINICAL_ATTRIBUTE_ID_1, PROJECTION, PAGE_SIZE, PAGE_NUMBER, SORT, DIRECTION); @@ -114,7 +153,7 @@ public void getMetaPatientClinicalData() throws Exception { BaseMeta expectedBaseMeta = new BaseMeta(); - Mockito.when(clinicalDataRepository.getMetaPatientClinicalData(STUDY_ID, PATIENT_ID_1, CLINICAL_ATTRIBUTE_ID_1)) + when(clinicalDataRepository.getMetaPatientClinicalData(STUDY_ID, PATIENT_ID_1, CLINICAL_ATTRIBUTE_ID_1)) .thenReturn(expectedBaseMeta); BaseMeta result = clinicalDataService.getMetaPatientClinicalData(STUDY_ID, PATIENT_ID_1, @@ -126,7 +165,7 @@ public void getMetaPatientClinicalData() throws Exception { @Test(expected = PatientNotFoundException.class) public void getMetaPatientClinicalDataPatientNotFound() throws Exception { - Mockito.when(patientService.getPatientInStudy(STUDY_ID, PATIENT_ID_1)) + when(patientService.getPatientInStudy(STUDY_ID, PATIENT_ID_1)) .thenThrow(new PatientNotFoundException(STUDY_ID, PATIENT_ID_1)); clinicalDataService.getMetaPatientClinicalData(STUDY_ID, PATIENT_ID_1, CLINICAL_ATTRIBUTE_ID_1); } @@ -138,7 +177,7 @@ public void getAllClinicalDataInStudy() throws Exception { ClinicalData sampleClinicalData = new ClinicalData(); expectedSampleClinicalDataList.add(sampleClinicalData); - Mockito.when(clinicalDataRepository.getAllClinicalDataInStudy(STUDY_ID, CLINICAL_ATTRIBUTE_ID_1, + when(clinicalDataRepository.getAllClinicalDataInStudy(STUDY_ID, CLINICAL_ATTRIBUTE_ID_1, CLINICAL_DATA_TYPE, PROJECTION, PAGE_SIZE, PAGE_NUMBER, SORT, DIRECTION)) .thenReturn(expectedSampleClinicalDataList); @@ -151,7 +190,7 @@ public void getAllClinicalDataInStudy() throws Exception { @Test(expected = StudyNotFoundException.class) public void getAllClinicalDataInStudyNotFound() throws Exception { - Mockito.when(studyService.getStudy(STUDY_ID)).thenThrow(new StudyNotFoundException(STUDY_ID)); + when(studyService.getStudy(STUDY_ID)).thenThrow(new StudyNotFoundException(STUDY_ID)); clinicalDataService.getAllClinicalDataInStudy(STUDY_ID, CLINICAL_ATTRIBUTE_ID_1, CLINICAL_DATA_TYPE, PROJECTION, PAGE_SIZE, PAGE_NUMBER, SORT, DIRECTION); } @@ -162,7 +201,7 @@ public void getMetaAllClinicalData() throws Exception { BaseMeta expectedBaseMeta = new BaseMeta(); expectedBaseMeta.setTotalCount(5); - Mockito.when( + when( clinicalDataRepository.getMetaAllClinicalData(STUDY_ID, CLINICAL_ATTRIBUTE_ID_1, CLINICAL_DATA_TYPE)) .thenReturn(expectedBaseMeta); @@ -175,7 +214,7 @@ public void getMetaAllClinicalData() throws Exception { @Test(expected = StudyNotFoundException.class) public void getMetaAllClinicalDataStudyNotFound() throws Exception { - Mockito.when(studyService.getStudy(STUDY_ID)).thenThrow(new StudyNotFoundException(STUDY_ID)); + when(studyService.getStudy(STUDY_ID)).thenThrow(new StudyNotFoundException(STUDY_ID)); clinicalDataService.getMetaAllClinicalData(STUDY_ID, CLINICAL_ATTRIBUTE_ID_1, CLINICAL_DATA_TYPE); } @@ -191,7 +230,7 @@ public void fetchClinicalDataPatientClinicalDataType() throws Exception { ClinicalData patientClinicalData = new ClinicalData(); expectedPatientClinicalDataList.add(patientClinicalData); - Mockito.when(clinicalDataRepository.fetchClinicalData(studyIds, patientIds, + when(clinicalDataRepository.fetchClinicalData(studyIds, patientIds, Arrays.asList(CLINICAL_ATTRIBUTE_ID_1), CLINICAL_DATA_TYPE, PROJECTION)) .thenReturn(expectedPatientClinicalDataList); @@ -212,7 +251,7 @@ public void fetchMetaClinicalDataPatientClinicalDataType() throws Exception { BaseMeta expectedBaseMeta = new BaseMeta(); expectedBaseMeta.setTotalCount(5); - Mockito.when(clinicalDataRepository.fetchMetaClinicalData(studyIds, patientIds, + when(clinicalDataRepository.fetchMetaClinicalData(studyIds, patientIds, Arrays.asList(CLINICAL_ATTRIBUTE_ID_1), CLINICAL_DATA_TYPE)).thenReturn(expectedBaseMeta); BaseMeta result = clinicalDataService.fetchMetaClinicalData(studyIds, patientIds, @@ -238,7 +277,7 @@ public void fetchClinicalDataCounts() throws Exception { clinicalAttribute4.setAttrId(CLINICAL_ATTRIBUTE_ID_1); clinicalAttribute4.setPatientAttribute(false); - Mockito.when(clinicalAttributeService.getClinicalAttributesByStudyIdsAndAttributeIds( + when(clinicalAttributeService.getClinicalAttributesByStudyIdsAndAttributeIds( Arrays.asList(STUDY_ID, STUDY_ID, STUDY_ID), Arrays.asList(CLINICAL_ATTRIBUTE_ID_1, CLINICAL_ATTRIBUTE_ID_2, CLINICAL_ATTRIBUTE_ID_3))) .thenReturn( @@ -257,7 +296,7 @@ public void fetchClinicalDataCounts() throws Exception { clinicalDataCount6.setValue("value1"); clinicalDataCount6.setCount(2); - Mockito.when(clinicalDataRepository.fetchClinicalDataCounts(Arrays.asList(STUDY_ID, STUDY_ID, STUDY_ID), + when(clinicalDataRepository.fetchClinicalDataCounts(Arrays.asList(STUDY_ID, STUDY_ID, STUDY_ID), Arrays.asList(SAMPLE_ID1, SAMPLE_ID2, SAMPLE_ID3), Arrays.asList(CLINICAL_ATTRIBUTE_ID_3, CLINICAL_ATTRIBUTE_ID_1), "SAMPLE", "SUMMARY")) .thenReturn(Arrays.asList(clinicalDataCount2, clinicalDataCount5, clinicalDataCount6)); @@ -271,7 +310,7 @@ public void fetchClinicalDataCounts() throws Exception { clinicalDataCount4.setValue("value3"); clinicalDataCount4.setCount(1); - Mockito.when(clinicalDataRepository.fetchClinicalDataCounts(Arrays.asList(STUDY_ID, STUDY_ID, STUDY_ID), + when(clinicalDataRepository.fetchClinicalDataCounts(Arrays.asList(STUDY_ID, STUDY_ID, STUDY_ID), Arrays.asList(SAMPLE_ID1, SAMPLE_ID2, SAMPLE_ID3), Arrays.asList(CLINICAL_ATTRIBUTE_ID_2), "PATIENT", "SUMMARY")).thenReturn(Arrays.asList(clinicalDataCount3, clinicalDataCount4)); @@ -280,7 +319,7 @@ public void fetchClinicalDataCounts() throws Exception { clinicalDataCount1.setValue("value1"); clinicalDataCount1.setCount(2); - Mockito.when(clinicalDataRepository.fetchClinicalDataCounts(Arrays.asList(STUDY_ID, STUDY_ID, STUDY_ID), + when(clinicalDataRepository.fetchClinicalDataCounts(Arrays.asList(STUDY_ID, STUDY_ID, STUDY_ID), Arrays.asList(SAMPLE_ID1, SAMPLE_ID2, SAMPLE_ID3), Arrays.asList(CLINICAL_ATTRIBUTE_ID_1), "PATIENT", "DETAILED")).thenReturn(Arrays.asList(clinicalDataCount1)); @@ -298,7 +337,7 @@ public void fetchClinicalDataCounts() throws Exception { patient3.setCancerStudyIdentifier(STUDY_ID); patients.add(patient3); - Mockito.when(patientService.getPatientsOfSamples(Arrays.asList(STUDY_ID, STUDY_ID, STUDY_ID), + when(patientService.getPatientsOfSamples(Arrays.asList(STUDY_ID, STUDY_ID, STUDY_ID), Arrays.asList(SAMPLE_ID1, SAMPLE_ID2, SAMPLE_ID3))).thenReturn(patients); List result = clinicalDataService.fetchClinicalDataCounts( @@ -339,4 +378,53 @@ public void fetchClinicalDataCounts() throws Exception { Assert.assertEquals((Integer) 4, count1.getCount()); } + + @Test + public void fetchSampleClinicalTableHappyCase() { + + when(clinicalDataRepository.getVisibleSampleInternalIdsForClinicalTable( + sampleStudyIds, sampleIds, null, null, searchTerm, sortBy, direction + )).thenReturn(sampleInternalIdsAll); + + when(clinicalDataRepository.getSampleClinicalDataBySampleInternalIds(sampleInternalIds)).thenReturn( + List.of(datum1, datum2) + ); + when(clinicalDataRepository.getPatientClinicalDataBySampleInternalIds(sampleInternalIds)).thenReturn( + List.of(datum1, datum2) + ); + + ImmutablePair result = clinicalDataService.fetchSampleClinicalTable( + sampleStudyIds, sampleIds, pageSize, pageNumber, searchTerm, sortBy, direction + ); + SampleClinicalDataCollection clinicalDataCollection = result.getLeft(); + Integer itemCount = result.getRight(); + + Assert.assertEquals(4, (int) itemCount); + Assert.assertEquals(2, clinicalDataCollection.getByUniqueSampleKey().size()); + Assert.assertTrue(clinicalDataCollection.getByUniqueSampleKey().containsKey(uniqueKeySample1)); + Assert.assertTrue(clinicalDataCollection.getByUniqueSampleKey().containsKey(uniqueKeySample2)); + Assert.assertEquals(2, clinicalDataCollection.getByUniqueSampleKey().get(uniqueKeySample1).size()); + Assert.assertEquals(2, clinicalDataCollection.getByUniqueSampleKey().get(uniqueKeySample2).size()); + Assert.assertEquals("SampleA", clinicalDataCollection.getByUniqueSampleKey().get(uniqueKeySample1).get(0).getSampleId()); + Assert.assertEquals("Study1", clinicalDataCollection.getByUniqueSampleKey().get(uniqueKeySample1).get(0).getStudyId()); + Assert.assertEquals("SampleA", clinicalDataCollection.getByUniqueSampleKey().get(uniqueKeySample2).get(0).getSampleId()); + Assert.assertEquals("Study2", clinicalDataCollection.getByUniqueSampleKey().get(uniqueKeySample2).get(0).getStudyId()); + } + + @Test + public void fetchSampleClinicalTableEmptyIdLists() { + Assert.assertEquals(0, clinicalDataService.fetchSampleClinicalTable( + null, sampleIds, pageSize, pageNumber, searchTerm, sortBy, direction + ).getLeft().getByUniqueSampleKey().size()); + Assert.assertEquals(0, clinicalDataService.fetchSampleClinicalTable( + sampleStudyIds, null, pageSize, pageNumber, searchTerm, sortBy, direction + ).getLeft().getByUniqueSampleKey().size()); + Assert.assertEquals(0, clinicalDataService.fetchSampleClinicalTable( + new ArrayList<>(), sampleIds, pageSize, pageNumber, searchTerm, sortBy, direction + ).getLeft().getByUniqueSampleKey().size()); + Assert.assertEquals(0, clinicalDataService.fetchSampleClinicalTable( + sampleStudyIds, new ArrayList<>(), pageSize, pageNumber, searchTerm, sortBy, direction + ).getLeft().getByUniqueSampleKey().size()); + } + } diff --git a/src/test/java/org/cbioportal/web/StudyViewControllerTest.java b/src/test/java/org/cbioportal/web/StudyViewControllerTest.java index 2dd141225a8..22328b00dff 100644 --- a/src/test/java/org/cbioportal/web/StudyViewControllerTest.java +++ b/src/test/java/org/cbioportal/web/StudyViewControllerTest.java @@ -3,32 +3,16 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyList; import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.anyString; -import static org.mockito.Mockito.when; +import static org.mockito.Mockito.*; import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf; import com.fasterxml.jackson.databind.ObjectMapper; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import org.cbioportal.model.AlterationCountByGene; -import org.cbioportal.model.AlterationFilter; -import org.cbioportal.model.ClinicalAttribute; -import org.cbioportal.model.ClinicalData; -import org.cbioportal.model.ClinicalDataCount; -import org.cbioportal.model.ClinicalDataCountItem; -import org.cbioportal.model.ClinicalEventTypeCount; -import org.cbioportal.model.CopyNumberCountByGene; -import org.cbioportal.model.GenericAssayDataCount; -import org.cbioportal.model.GenericAssayDataCountItem; -import org.cbioportal.model.GenomicDataCount; -import org.cbioportal.model.GenomicDataCountItem; -import org.cbioportal.model.Sample; -import org.cbioportal.model.StructuralVariantFilterQuery; -import org.cbioportal.model.StructuralVariantSpecialValue; -import org.cbioportal.model.StudyViewStructuralVariantFilter; + +import java.util.*; + +import org.apache.commons.lang3.tuple.ImmutablePair; +import org.cbioportal.model.*; import org.cbioportal.model.util.Select; import org.cbioportal.persistence.AlterationRepository; import org.cbioportal.service.AlterationCountService; @@ -48,6 +32,8 @@ import org.cbioportal.service.ViolinPlotService; import org.cbioportal.service.util.ClinicalAttributeUtil; import org.cbioportal.service.util.MolecularProfileUtil; +import org.cbioportal.utils.Encoding; +import org.cbioportal.web.config.CustomObjectMapper; import org.cbioportal.web.config.TestConfig; import org.cbioportal.web.parameter.ClinicalDataBinCountFilter; import org.cbioportal.web.parameter.ClinicalDataBinFilter; @@ -83,6 +69,7 @@ import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; import org.springframework.test.web.servlet.result.MockMvcResultMatchers; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; import static org.mockito.ArgumentMatchers.*; @@ -125,6 +112,7 @@ public class StudyViewControllerTest { private List filteredSampleIdentifiers = new ArrayList<>(); private List clinicalData = new ArrayList<>(); + private SampleClinicalDataCollection tableClinicalData = new SampleClinicalDataCollection(); private ObjectMapper objectMapper = new ObjectMapper(); @@ -189,6 +177,8 @@ public class StudyViewControllerTest { private ArrayList filteredSamples = new ArrayList<>(); + private String uniqueKeySample1; + @Before public void setUp() throws Exception { SampleIdentifier sampleIdentifier = new SampleIdentifier(); @@ -207,6 +197,8 @@ public void setUp() throws Exception { filteredSamples.add(sample1); filteredSamples.add(sample2); + uniqueKeySample1 = Encoding.calculateBase64(TEST_SAMPLE_ID_1, TEST_STUDY_ID); + ClinicalData clinicalData1 = new ClinicalData(); clinicalData1.setAttrId(TEST_ATTRIBUTE_ID); clinicalData1.setAttrValue(TEST_CLINICAL_DATA_VALUE_1); @@ -230,6 +222,19 @@ public void setUp() throws Exception { clinicalData3.setSampleId(TEST_SAMPLE_ID_3); clinicalData3.setPatientId(TEST_PATIENT_ID_3); clinicalData.add(clinicalData3); + + Map> tableClinicalDataMap = new HashMap<>(); + tableClinicalDataMap.put(uniqueKeySample1, List.of(clinicalData1, clinicalData2, clinicalData3)); + tableClinicalData.setByUniqueSampleKey(tableClinicalDataMap); + + reset(studyViewFilterApplier); + reset(clinicalDataService); + reset(discreteCopyNumberService); + reset(sampleService); + reset(genePanelService); + reset(sampleService); + reset(clinicalAttributeService); + reset(patientService); } @Test @@ -992,14 +997,16 @@ public void fetchGenericAssayDataCounts() throws Exception { public void fetchClinicalDataClinicalTable() throws Exception { // For this sake of this test the sample clinical data and patient clinical data are identical. when(clinicalDataService.fetchSampleClinicalTable(anyList(), anyList(), - anyInt(), anyInt(), anyString(), any(), anyString())).thenReturn(clinicalData); - when(clinicalDataService.fetchClinicalData(anyList(), anyList(), - any(), anyString(), anyString())).thenReturn(clinicalData); - + anyInt(), anyInt(), anyString(), any(), anyString())).thenReturn( + new ImmutablePair<>(tableClinicalData, 100) + ); + StudyViewFilter studyViewFilter = new StudyViewFilter(); studyViewFilter.setStudyIds(Arrays.asList(TEST_STUDY_ID)); when(studyViewFilterApplier.apply(any())).thenReturn(filteredSampleIdentifiers); + + String jsonPath = "$.byUniqueSampleKey." + uniqueKeySample1; mockMvc.perform(MockMvcRequestBuilders.post("/api/clinical-data-table/fetch").with(csrf()) .accept(MediaType.APPLICATION_JSON) @@ -1007,19 +1014,13 @@ public void fetchClinicalDataClinicalTable() throws Exception { .content(objectMapper.writeValueAsString(studyViewFilter))) .andExpect(MockMvcResultMatchers.status().isOk()) .andExpect(MockMvcResultMatchers.content().contentTypeCompatibleWith(MediaType.APPLICATION_JSON)) - .andExpect(MockMvcResultMatchers.jsonPath("$.sampleClinicalData[0].clinicalAttributeId").value(TEST_ATTRIBUTE_ID)) - .andExpect(MockMvcResultMatchers.jsonPath("$.sampleClinicalData[0].sampleId").value(TEST_SAMPLE_ID_1)) - .andExpect(MockMvcResultMatchers.jsonPath("$.sampleClinicalData[1].clinicalAttributeId").value(TEST_ATTRIBUTE_ID)) - .andExpect(MockMvcResultMatchers.jsonPath("$.sampleClinicalData[1].sampleId").value(TEST_SAMPLE_ID_2)) - .andExpect(MockMvcResultMatchers.jsonPath("$.sampleClinicalData[2].clinicalAttributeId").value(TEST_ATTRIBUTE_ID)) - .andExpect(MockMvcResultMatchers.jsonPath("$.sampleClinicalData[2].sampleId").value(TEST_SAMPLE_ID_3)) - .andExpect(MockMvcResultMatchers.jsonPath("$.patientClinicalData[0].clinicalAttributeId").value(TEST_ATTRIBUTE_ID)) - .andExpect(MockMvcResultMatchers.jsonPath("$.patientClinicalData[0].sampleId").value(TEST_SAMPLE_ID_1)) - .andExpect(MockMvcResultMatchers.jsonPath("$.patientClinicalData[1].clinicalAttributeId").value(TEST_ATTRIBUTE_ID)) - .andExpect(MockMvcResultMatchers.jsonPath("$.patientClinicalData[1].sampleId").value(TEST_SAMPLE_ID_2)) - .andExpect(MockMvcResultMatchers.jsonPath("$.patientClinicalData[2].clinicalAttributeId").value(TEST_ATTRIBUTE_ID)) - .andExpect(MockMvcResultMatchers.jsonPath("$.patientClinicalData[2].sampleId").value(TEST_SAMPLE_ID_3)); - + .andExpect(MockMvcResultMatchers.jsonPath( jsonPath+"[0].clinicalAttributeId", uniqueKeySample1).value(TEST_ATTRIBUTE_ID)) + .andExpect(MockMvcResultMatchers.jsonPath(jsonPath+"[0].sampleId").value(TEST_SAMPLE_ID_1)) + .andExpect(MockMvcResultMatchers.jsonPath(jsonPath+"[1].clinicalAttributeId").value(TEST_ATTRIBUTE_ID)) + .andExpect(MockMvcResultMatchers.jsonPath(jsonPath+"[1].sampleId").value(TEST_SAMPLE_ID_2)) + .andExpect(MockMvcResultMatchers.jsonPath(jsonPath+"[2].clinicalAttributeId").value(TEST_ATTRIBUTE_ID)) + .andExpect(MockMvcResultMatchers.jsonPath(jsonPath+"[2].sampleId").value(TEST_SAMPLE_ID_3)); + } @Test diff --git a/src/test/resources/testSql.sql b/src/test/resources/testSql.sql index f7047bdbdf7..1129d1f974e 100644 --- a/src/test/resources/testSql.sql +++ b/src/test/resources/testSql.sql @@ -359,7 +359,7 @@ INSERT INTO clinical_attribute_meta (ATTR_ID,DISPLAY_NAME,DESCRIPTION,DATATYPE,P INSERT INTO clinical_attribute_meta (ATTR_ID,DISPLAY_NAME,DESCRIPTION,DATATYPE,PATIENT_ATTRIBUTE,PRIORITY,CANCER_STUDY_ID) VALUES ('OS_MONTHS','Overall Survival (Months)','Overall survival in months since initial diagonosis.','NUMBER',1,'1',1); INSERT INTO clinical_attribute_meta (ATTR_ID,DISPLAY_NAME,DESCRIPTION,DATATYPE,PATIENT_ATTRIBUTE,PRIORITY,CANCER_STUDY_ID) VALUES ('OS_STATUS','Overall Survival Status','Overall patient survival status.','STRING',1,'1',1); INSERT INTO clinical_attribute_meta (ATTR_ID,DISPLAY_NAME,DESCRIPTION,DATATYPE,PATIENT_ATTRIBUTE,PRIORITY,CANCER_STUDY_ID) VALUES ('OTHER_SAMPLE_ID','Other Sample ID','Legacy DMP sample identifier (DMPnnnn)','STRING',0,'1',1); -INSERT INTO clinical_attribute_meta (ATTR_ID,DISPLAY_NAME,DESCRIPTION,DATATYPE,PATIENT_ATTRIBUTE,PRIORITY,CANCER_STUDY_ID) VALUES ('DAYS_TO_COLLECTION','Days to Sample Collection.','Days to sample collection.','STRING',0,'1',1); +INSERT INTO clinical_attribute_meta (ATTR_ID,DISPLAY_NAME,DESCRIPTION,DATATYPE,PATIENT_ATTRIBUTE,PRIORITY,CANCER_STUDY_ID) VALUES ('DAYS_TO_COLLECTION','Days to Sample Collection.','Days to sample collection.','NUMBER',0,'1',1); INSERT INTO clinical_attribute_meta (ATTR_ID,DISPLAY_NAME,DESCRIPTION,DATATYPE,PATIENT_ATTRIBUTE,PRIORITY,CANCER_STUDY_ID) VALUES ('IS_FFPE','Is FFPE','If the sample is from FFPE','STRING',0,'1',1); INSERT INTO clinical_attribute_meta (ATTR_ID,DISPLAY_NAME,DESCRIPTION,DATATYPE,PATIENT_ATTRIBUTE,PRIORITY,CANCER_STUDY_ID) VALUES ('OCT_EMBEDDED','Oct embedded','Oct embedded','STRING',0,'1',1); INSERT INTO clinical_attribute_meta (ATTR_ID,DISPLAY_NAME,DESCRIPTION,DATATYPE,PATIENT_ATTRIBUTE,PRIORITY,CANCER_STUDY_ID) VALUES ('PATHOLOGY_REPORT_FILE_NAME','Pathology Report File Name','Pathology Report File Name','STRING',0,'1',1); @@ -373,7 +373,7 @@ INSERT INTO clinical_attribute_meta (ATTR_ID,DISPLAY_NAME,DESCRIPTION,DATATYPE,P INSERT INTO clinical_attribute_meta (ATTR_ID,DISPLAY_NAME,DESCRIPTION,DATATYPE,PATIENT_ATTRIBUTE,PRIORITY,CANCER_STUDY_ID) VALUES ('OS_MONTHS','Overall Survival (Months)','Overall survival in months since initial diagonosis.','NUMBER',1,'1',2); INSERT INTO clinical_attribute_meta (ATTR_ID,DISPLAY_NAME,DESCRIPTION,DATATYPE,PATIENT_ATTRIBUTE,PRIORITY,CANCER_STUDY_ID) VALUES ('OS_STATUS','Overall Survival Status','Overall patient survival status.','STRING',1,'1',2); INSERT INTO clinical_attribute_meta (ATTR_ID,DISPLAY_NAME,DESCRIPTION,DATATYPE,PATIENT_ATTRIBUTE,PRIORITY,CANCER_STUDY_ID) VALUES ('OTHER_SAMPLE_ID','Other Sample ID','Legacy DMP sample identifier (DMPnnnn)','STRING',0,'1',2); -INSERT INTO clinical_attribute_meta (ATTR_ID,DISPLAY_NAME,DESCRIPTION,DATATYPE,PATIENT_ATTRIBUTE,PRIORITY,CANCER_STUDY_ID) VALUES ('DAYS_TO_COLLECTION','Days to Sample Collection.','Days to sample collection.','STRING',0,'1',2); +INSERT INTO clinical_attribute_meta (ATTR_ID,DISPLAY_NAME,DESCRIPTION,DATATYPE,PATIENT_ATTRIBUTE,PRIORITY,CANCER_STUDY_ID) VALUES ('DAYS_TO_COLLECTION','Days to Sample Collection.','Days to sample collection.','NUMBER',0,'1',2); INSERT INTO clinical_attribute_meta (ATTR_ID,DISPLAY_NAME,DESCRIPTION,DATATYPE,PATIENT_ATTRIBUTE,PRIORITY,CANCER_STUDY_ID) VALUES ('IS_FFPE','Is FFPE','If the sample is from FFPE','STRING',0,'1',2); INSERT INTO clinical_attribute_meta (ATTR_ID,DISPLAY_NAME,DESCRIPTION,DATATYPE,PATIENT_ATTRIBUTE,PRIORITY,CANCER_STUDY_ID) VALUES ('OCT_EMBEDDED','Oct embedded','Oct embedded','STRING',0,'1',2); INSERT INTO clinical_attribute_meta (ATTR_ID,DISPLAY_NAME,DESCRIPTION,DATATYPE,PATIENT_ATTRIBUTE,PRIORITY,CANCER_STUDY_ID) VALUES ('PATHOLOGY_REPORT_FILE_NAME','Pathology Report File Name','Pathology Report File Name','STRING',0,'1',2);