diff --git a/model/src/main/java/org/mskcc/smile/model/SmilePatient.java b/model/src/main/java/org/mskcc/smile/model/SmilePatient.java index 1cc9df43..00240def 100644 --- a/model/src/main/java/org/mskcc/smile/model/SmilePatient.java +++ b/model/src/main/java/org/mskcc/smile/model/SmilePatient.java @@ -30,6 +30,11 @@ public class SmilePatient implements Serializable { public SmilePatient() {} + public SmilePatient(String aliasValue, String aliasNamespace) { + this.patientAliases = new ArrayList<>(); + patientAliases.add(new PatientAlias(aliasValue, aliasNamespace)); + } + public UUID getSmilePatientId() { return smilePatientId; } diff --git a/persistence/src/main/java/org/mskcc/smile/persistence/neo4j/SmileSampleRepository.java b/persistence/src/main/java/org/mskcc/smile/persistence/neo4j/SmileSampleRepository.java index a932e4c5..383dea6a 100644 --- a/persistence/src/main/java/org/mskcc/smile/persistence/neo4j/SmileSampleRepository.java +++ b/persistence/src/main/java/org/mskcc/smile/persistence/neo4j/SmileSampleRepository.java @@ -105,4 +105,10 @@ void updateSamplePatientRelationship(@Param("smileSampleId") UUID smileSampleId, + "OR sm.cmoSampleName = $inputId " + "RETURN s;") SmileSample findSampleByInputId(@Param("inputId") String inputId); + + @Query("MATCH (s: Sample {smileSampleId: $smileSampleId}) " + + "MATCH (s)<-[r:HAS_SAMPLE]-(p: Patient {smilePatientId: $smilePatientId}) " + + "DELETE r") + void removeSamplePatientRelationship(@Param("smileSampleId") UUID smileSampleId, + @Param("smilePatientId") UUID smilePatientId); } diff --git a/pom.xml b/pom.xml index cffd1890..cafa15a5 100644 --- a/pom.xml +++ b/pom.xml @@ -48,10 +48,10 @@ 1.16.0 com.github.mskcc - 1.3.3.RELEASE + 1.3.4.RELEASE com.github.mskcc - 1.3.3.RELEASE + 1.3.4.RELEASE v2.2 diff --git a/service/src/main/java/org/mskcc/smile/service/SmileSampleService.java b/service/src/main/java/org/mskcc/smile/service/SmileSampleService.java index b6860eae..e2bec1eb 100644 --- a/service/src/main/java/org/mskcc/smile/service/SmileSampleService.java +++ b/service/src/main/java/org/mskcc/smile/service/SmileSampleService.java @@ -10,7 +10,7 @@ public interface SmileSampleService { SmileSample saveSmileSample(SmileSample smileSample) throws Exception; - SmileSample fetchAndLoadSampleDetails(SmileSample smileSample) throws Exception; + SmileSample fetchAndLoadPatientDetails(SmileSample smileSample) throws Exception; Boolean updateSampleMetadata(SampleMetadata sampleMetadata) throws Exception; List getMatchedNormalsBySample(SmileSample smileSample) throws Exception; @@ -19,7 +19,8 @@ List getMatchedNormalsBySample(SmileSample smileSample) SmileSample getResearchSampleByRequestAndIgoId(String requestId, String igoId) throws Exception; List getResearchSamplesByRequestId(String requestId) throws Exception; List getResearchSampleMetadataHistoryByIgoId(String igoId) throws Exception; - Boolean sampleHasMetadataUpdates(SampleMetadata existingSampleMetadata, SampleMetadata sampleMetadata) + Boolean sampleHasMetadataUpdates(SampleMetadata existingSampleMetadata, + SampleMetadata sampleMetadata, Boolean isResearchSample) throws Exception; PublishedSmileSample getPublishedSmileSample(UUID smileSampleId) throws Exception; List getPublishedSmileSamplesByCmoPatientId(String cmoPatientId) diff --git a/service/src/main/java/org/mskcc/smile/service/impl/ClinicalMessageHandlingServiceImpl.java b/service/src/main/java/org/mskcc/smile/service/impl/ClinicalMessageHandlingServiceImpl.java index 394bbc9c..d0020e49 100644 --- a/service/src/main/java/org/mskcc/smile/service/impl/ClinicalMessageHandlingServiceImpl.java +++ b/service/src/main/java/org/mskcc/smile/service/impl/ClinicalMessageHandlingServiceImpl.java @@ -126,7 +126,7 @@ public void run() { mapper.writeValueAsString(smileSample)); } else if (sampleService.sampleHasMetadataUpdates( existingSample.getLatestSampleMetadata(), - smileSample.getLatestSampleMetadata())) { + smileSample.getLatestSampleMetadata(), Boolean.FALSE)) { LOG.info("Found updates for sample - persisting to database: " + smileSample.getPrimarySampleAlias()); existingSample.updateSampleMetadata(smileSample.getLatestSampleMetadata()); @@ -180,7 +180,7 @@ public void run() { mapper.writeValueAsString(smileSample)); } else if (sampleService.sampleHasMetadataUpdates( existingSample.getLatestSampleMetadata(), - smileSample.getLatestSampleMetadata())) { + smileSample.getLatestSampleMetadata(), Boolean.FALSE)) { LOG.info("Found updates for sample - persisting to database: " + smileSample.getPrimarySampleAlias()); existingSample.updateSampleMetadata(smileSample.getLatestSampleMetadata()); @@ -244,6 +244,11 @@ public void onMessage(Message msg, Object message) { DmpSampleMetadata.class); String cmoPatientId = crdbMappingService.getCmoPatientIdbyDmpId( dmpSample.getDmpPatientId()); + if (cmoPatientId == null) { + LOG.error("Could not resolve cmoPatientId from dmpId: " + + dmpSample.getDmpPatientId()); + return; + } SmileSample sample = SampleDataFactory.buildNewClinicalSampleFromMetadata( cmoPatientId, dmpSample); clinicalMessageHandlingService.newClinicalSampleHandler(sample); @@ -268,6 +273,11 @@ public void onMessage(Message msg, Object message) { DmpSampleMetadata.class); String cmoPatientId = crdbMappingService.getCmoPatientIdbyDmpId( dmpSample.getDmpPatientId()); + if (cmoPatientId == null) { + LOG.error("Could not resolve cmoPatientId from dmpId: " + + dmpSample.getDmpPatientId()); + return; + } SmileSample sample = SampleDataFactory.buildNewClinicalSampleFromMetadata( cmoPatientId, dmpSample); clinicalMessageHandlingService.clinicalSampleUpdateHandler(sample); diff --git a/service/src/main/java/org/mskcc/smile/service/impl/RequestServiceImpl.java b/service/src/main/java/org/mskcc/smile/service/impl/RequestServiceImpl.java index f232cd16..845745de 100644 --- a/service/src/main/java/org/mskcc/smile/service/impl/RequestServiceImpl.java +++ b/service/src/main/java/org/mskcc/smile/service/impl/RequestServiceImpl.java @@ -206,27 +206,15 @@ private Boolean timestampWithin24Hours(Date referenceTimestamp, Date newTimestam @Override public Boolean requestHasUpdates(SmileRequest existingRequest, SmileRequest request) throws Exception { - try { - jsonComparator.isConsistent(mapper.writeValueAsString(existingRequest), - mapper.writeValueAsString(request)); - } catch (AssertionError e) { - LOG.warn("Found discrepancies between JSONs:\n" + e.getLocalizedMessage()); - return Boolean.TRUE; - } - return Boolean.FALSE; + return !(jsonComparator.isConsistent(mapper.writeValueAsString(existingRequest), + mapper.writeValueAsString(request))); } @Override public Boolean requestHasMetadataUpdates(RequestMetadata existingRequestMetadata, RequestMetadata requestMetadata) throws Exception { - try { - jsonComparator.isConsistent(existingRequestMetadata.getRequestMetadataJson(), - requestMetadata.getRequestMetadataJson()); - } catch (AssertionError e) { - LOG.warn("Found discrepancies between JSONs:\n" + e.getLocalizedMessage()); - return Boolean.TRUE; - } - return Boolean.FALSE; + return !(jsonComparator.isConsistent(existingRequestMetadata.getRequestMetadataJson(), + requestMetadata.getRequestMetadataJson())); } @Override @@ -240,14 +228,10 @@ public List getRequestSamplesWithUpdates(SmileRequest request) thro if (existingSample == null) { continue; } - // compare sample metadata from current request and the saved request - String latestMetadata = mapper.writeValueAsString(existingSample.getLatestSampleMetadata()); - String currentMetadata = mapper.writeValueAsString(sample.getLatestSampleMetadata()); - - try { - jsonComparator.isConsistent(latestMetadata, currentMetadata); - } catch (AssertionError e) { - LOG.warn("Found discrepancies between JSONs:\n" + e.getLocalizedMessage()); + Boolean sampleHasUpdates = + sampleService.sampleHasMetadataUpdates(existingSample.getLatestSampleMetadata(), + sample.getLatestSampleMetadata(), Boolean.TRUE); + if (sampleHasUpdates) { existingSample.updateSampleMetadata(sample.getLatestSampleMetadata()); updatedSamples.add(existingSample); } diff --git a/service/src/main/java/org/mskcc/smile/service/impl/ResearchMessageHandlingServiceImpl.java b/service/src/main/java/org/mskcc/smile/service/impl/ResearchMessageHandlingServiceImpl.java index 0ca73f21..efbecf93 100644 --- a/service/src/main/java/org/mskcc/smile/service/impl/ResearchMessageHandlingServiceImpl.java +++ b/service/src/main/java/org/mskcc/smile/service/impl/ResearchMessageHandlingServiceImpl.java @@ -53,6 +53,9 @@ public class ResearchMessageHandlingServiceImpl implements ResearchMessageHandli @Value("${smile.cmo_sample_update_topic}") private String CMO_SAMPLE_UPDATE_TOPIC; + @Value("${request_reply.cmo_label_generator_topic}") + private String CMO_LABEL_GENERATOR_REQREPLY_TOPIC; + @Value("${num.new_request_handler_threads}") private int NUM_NEW_REQUEST_HANDLERS; @@ -123,10 +126,10 @@ public void run() { requestService.saveRequest(request); } else { // request-service and sample-service methods will check for updates and persist - // them if applicable + // them if applicable (including patient swapping) requestService.updateRequestMetadata(request.getLatestRequestMetadata()); for (SmileSample sample : request.getSmileSampleList()) { - sampleService.updateSampleMetadata(sample.getLatestSampleMetadata()); + sampleService.saveSmileSample(sample); } } // publish updated/saved request to consistency checker or promoted request topic diff --git a/service/src/main/java/org/mskcc/smile/service/impl/SampleServiceImpl.java b/service/src/main/java/org/mskcc/smile/service/impl/SampleServiceImpl.java index 929956f6..6c8e0a06 100644 --- a/service/src/main/java/org/mskcc/smile/service/impl/SampleServiceImpl.java +++ b/service/src/main/java/org/mskcc/smile/service/impl/SampleServiceImpl.java @@ -47,7 +47,7 @@ public class SampleServiceImpl implements SmileSampleService { @Transactional(rollbackFor = {Exception.class}) public SmileSample saveSmileSample(SmileSample sample) throws Exception { - fetchAndLoadSampleDetails(sample); + fetchAndLoadPatientDetails(sample); SmileSample existingSample = sampleRepository.findSampleByPrimaryId(sample.getPrimarySampleAlias()); if (existingSample == null) { @@ -55,37 +55,129 @@ public SmileSample saveSmileSample(SmileSample sample.setSmileSampleId(newSampleId); return sample; } else { - existingSample.updateSampleMetadata(sample.getLatestSampleMetadata()); + // populate existing sample details and check if there are actual updates to persist + getDetailedSmileSample(existingSample); + SampleMetadata existingMetadata = existingSample.getLatestSampleMetadata(); + SampleMetadata sampleMetadata = sample.getLatestSampleMetadata(); + if (sampleHasMetadataUpdates(existingMetadata, sampleMetadata, + sample.getSampleCategory().equals("research"))) { + LOG.info("Found updates to persist for sample: " + existingSample.getPrimarySampleAlias()); + existingSample.updateSampleMetadata(sample.getLatestSampleMetadata()); + + // determine where a patient swap is required also + if (!sample.getPatient().getSmilePatientId().equals( + existingSample.getPatient().getSmilePatientId())) { + LOG.info("Updating sample-to-patient relationship and removing connection to patient: " + + existingSample.getPatient().getSmilePatientId()); + sampleRepository.removeSamplePatientRelationship(existingSample.getSmileSampleId(), + existingSample.getPatient().getSmilePatientId()); + existingSample.setPatient(sample.getPatient()); + } + existingSample.setPatient(sample.getPatient()); + } sampleRepository.save(existingSample); return existingSample; } } + /** + * Fetching and loading patient details explained. + * + *

Scenario #1: new sample, new patient + * --> new sample and patient are persisted to the database + * + *

Scenario #2: existing sample with updates and patient swap + * a) patient by cmo id in the incoming metadata updates does not already exist and does not match + * the patient linked to the existing sample: + * --> patient by the new id is persisted to the database, sample-to-patient relationship + * is updated to match the newly persisted patient and the former sample-to-patient relationship + * is removed + * b) patient by cmo id in the incoming metadata updates already exists but does not match + * the patient linked to the existing sample: + * --> sample-to-patient relationship is updated to match the patient referenced in the incoming + * sample updates and the former sample-to-patient relationship is removed + * + *

Scenario #3: special case where new sample is added to database but there's a mismatch + * between the patient that the canonical sample is pointing to and the patient referenced in the + * latest sample metadata + * a) cmo patient ids do not match + * --> construct and persist a new patient node with the cmo id from the latest metadata + * b) cmo patient ids match + * --> persist patient from sample.getPatient() to database + * + *

Scenario #4: new sample where sample.getPatient() is null and cmo patient id in latest + * metadata is not null and exists in the database + * --> throws exception, this is a case that should never happen and would result from malformed data + * @param sample + * @return SmileSample + * @throws Exception + */ @Override - public SmileSample fetchAndLoadSampleDetails(SmileSample sample) throws Exception { + public SmileSample fetchAndLoadPatientDetails(SmileSample sample) throws Exception { SampleMetadata sampleMetadata = sample.getLatestSampleMetadata(); SmilePatient patient = sample.getPatient(); - // find or save new patient for sample - SmilePatient existingPatient = patientService.getPatientByCmoPatientId( - sampleMetadata.getCmoPatientId()); - if (existingPatient == null) { + // handle the scenario where a patient node does not already exist in the database + // to prevent any null pointer exceptions (a situation that had arose in some test dmp sample cases) + if (patientService.getPatientByCmoPatientId( + sample.getPatient().getCmoPatientId().getValue()) == null) { patientService.savePatientMetadata(patient); sample.setPatient(patient); - } else { + } + + // get patient by cmo id from latest sample metadata + SmilePatient patientByLatestCmoId = patientService.getPatientByCmoPatientId( + sampleMetadata.getCmoPatientId()); + + // again this is something that should never happen and would arise from some error + // in the data construction/parsing + if (patient == null) { + throw new IllegalStateException("Patient object assigned to the sample is null " + + "- confirm whether data construction and parsing is being handled correctly"); + } + + // scenario that requires a patient swap and updating the sample-to-patient relationship + // in the database and removing the former sample-to-patient relationship + if (patientByLatestCmoId == null) { + SmilePatient newPatient = new SmilePatient(sampleMetadata.getCmoPatientId(), "cmoId"); + patientService.savePatientMetadata(newPatient); + sample.setPatient(newPatient); + // remove sample-to-patient relationship from former patient node + sampleRepository.removeSamplePatientRelationship(sample.getSmileSampleId(), + patient.getSmilePatientId()); + return sample; + } + + // scenario where we are checking for an update to the existing patient, which is the same + // that already existing and is linked to the sample in the database but may contain updates + // (i.e., a new patient alias) + if (patient.getCmoPatientId().getValue().equals(sampleMetadata.getCmoPatientId())) { // go through the new patient aliases and indicator for whether a // new patient alias was added to the existing patient Boolean patientUpdated = Boolean.FALSE; for (PatientAlias pa : patient.getPatientAliases()) { - if (!existingPatient.hasPatientAlias(pa)) { - existingPatient.addPatientAlias(pa); + if (!patientByLatestCmoId.hasPatientAlias(pa)) { + patientByLatestCmoId.addPatientAlias(pa); patientUpdated = Boolean.TRUE; } } if (patientUpdated) { - patientService.savePatientMetadata(existingPatient); + sample.setPatient(patientService.savePatientMetadata(patientByLatestCmoId)); + } else { + sample.setPatient(patientByLatestCmoId); } - sample.setPatient(existingPatient); + return sample; + } + + // scenario where the patient that the sample-to-patient relationship points to in the database + // does not match the cmo patient id referenced in the latest sample metadata updates + // and the former sample-to-patient relationship needs to be removed + if (!patient.getCmoPatientId().getValue().equals(sampleMetadata.getCmoPatientId())) { + sample.setPatient(patientByLatestCmoId); + sampleRepository.removeSamplePatientRelationship(sample.getSmileSampleId(), + patient.getSmilePatientId()); + return sample; + } return sample; } @@ -105,11 +197,13 @@ public Boolean updateSampleMetadata(SampleMetadata sampleMetadata) throws Except } // save updates to sample if applicable SampleMetadata existingMetadata = existingSample.getLatestSampleMetadata(); - if (sampleHasMetadataUpdates(existingMetadata, sampleMetadata) + + Boolean isResearchSample = existingSample.getSampleCategory().equals("research"); + if (sampleHasMetadataUpdates(existingMetadata, sampleMetadata, isResearchSample) || (!sampleHasMetadataUpdates( - existingMetadata, sampleMetadata)) + existingMetadata, sampleMetadata, isResearchSample) && !existingMetadata.getCmoSampleName() - .equals(sampleMetadata.getCmoSampleName())) { + .equals(sampleMetadata.getCmoSampleName()))) { LOG.info("Persisting updates for sample: " + sampleMetadata.getPrimaryId()); existingSample.updateSampleMetadata(sampleMetadata); saveSmileSample(existingSample); @@ -173,12 +267,22 @@ public List getResearchSampleMetadataHistoryByIgoId(String igoId @Override public Boolean sampleHasMetadataUpdates(SampleMetadata existingSampleMetadata, - SampleMetadata sampleMetadata) throws Exception { + SampleMetadata sampleMetadata, Boolean isResearchSample) throws Exception { String existingMetadata = mapper.writeValueAsString(existingSampleMetadata); String currentMetadata = mapper.writeValueAsString(sampleMetadata); - try { - jsonComparator.isConsistent(currentMetadata, existingMetadata); - } catch (AssertionError e) { + Boolean isConsistent = jsonComparator.isConsistent(currentMetadata, existingMetadata); + // if not consistent then return true since changes were detected + if (!isConsistent) { + return Boolean.TRUE; + } + // if there is a change to the cmo sample label.. + if (isResearchSample && !existingSampleMetadata.getCmoSampleName() + .equals(sampleMetadata.getCmoSampleName())) { + return Boolean.TRUE; + } + // if there needs to be a patient swap.. + if (!existingSampleMetadata.getCmoPatientId() + .equals(sampleMetadata.getCmoPatientId())) { return Boolean.TRUE; } return Boolean.FALSE; diff --git a/service/src/main/java/org/mskcc/smile/service/util/SampleDataFactory.java b/service/src/main/java/org/mskcc/smile/service/util/SampleDataFactory.java index 8ec64ffa..350f0e65 100644 --- a/service/src/main/java/org/mskcc/smile/service/util/SampleDataFactory.java +++ b/service/src/main/java/org/mskcc/smile/service/util/SampleDataFactory.java @@ -47,7 +47,9 @@ private static Map initDmpClinicalMetastasisValuesMap() { public static SmileSample buildNewResearchSampleFromMetadata(String requestId, SampleMetadata sampleMetadata) { sampleMetadata.setIgoRequestId(requestId); - sampleMetadata.setImportDate(LocalDateTime.now().format(DateTimeFormatter.ISO_LOCAL_DATE)); + if (sampleMetadata.getImportDate() == null) { + sampleMetadata.setImportDate(LocalDateTime.now().format(DateTimeFormatter.ISO_LOCAL_DATE)); + } SmileSample sample = new SmileSample(); sample.addSampleMetadata(sampleMetadata); diff --git a/service/src/test/java/org/mskcc/smile/service/SampleServiceTest.java b/service/src/test/java/org/mskcc/smile/service/SampleServiceTest.java index 587da6d3..9187ab43 100644 --- a/service/src/test/java/org/mskcc/smile/service/SampleServiceTest.java +++ b/service/src/test/java/org/mskcc/smile/service/SampleServiceTest.java @@ -214,7 +214,7 @@ public void testSampleHasMetadataUpdates() throws Exception { SmileSample updatedSample = updatedRequest.getSmileSampleList().get(0); Boolean hasUpdates = sampleService.sampleHasMetadataUpdates(sample.getLatestSampleMetadata(), - updatedSample.getLatestSampleMetadata()); + updatedSample.getLatestSampleMetadata(), Boolean.TRUE); Assertions.assertThat(hasUpdates).isEqualTo(Boolean.TRUE); } @@ -232,9 +232,11 @@ public void testSampleHistoryAfterUpdate() throws Exception { .get("mockIncomingRequest1UpdatedJsonDataWith2T2N"); SmileRequest updatedRequest = RequestDataFactory.buildNewLimsRequestFromJson( updatedRequestData.getJsonString()); - SmileSample updatedSample = updatedRequest.getSmileSampleList().get(1); - sampleService.saveSmileSample(updatedSample); - + for (SmileSample updatedSample : updatedRequest.getSmileSampleList()) { + if (updatedSample.getLatestSampleMetadata().getPrimaryId().equals(igoId)) { + sampleService.saveSmileSample(updatedSample); + } + } List sampleMetadataHistory = sampleService .getResearchSampleMetadataHistoryByIgoId(igoId); Assertions.assertThat(sampleMetadataHistory.size()).isEqualTo(2); @@ -297,29 +299,46 @@ public void testFindSamplesByDate() throws Exception { String requestId = "MOCKREQUEST1_B"; String igoId = "MOCKREQUEST1_B_2"; + // fetch sample from db and insert an older version of its metadata SmileSample sample = sampleService.getResearchSampleByRequestAndIgoId(requestId, igoId); - sample.getLatestSampleMetadata().setCmoSampleName("C-LATESTLABEL-T02-d002"); - SampleMetadata updatedMetadata = new SampleMetadata(); updatedMetadata.setImportDate("2000-06-10"); - updatedMetadata.setPrimaryId(igoId); + updatedMetadata.setPrimaryId(sample.getPrimarySampleAlias()); + updatedMetadata.setBaitSet("DIFFERENTBAITSET"); updatedMetadata.setCmoSampleName("C-OLDSAMPLELABEL-T11"); - sample.updateSampleMetadata(updatedMetadata); - sampleService.saveSmileSample(sample); + sample.addSampleMetadata(updatedMetadata); - // confirm that new sample metadata was persisted - List sampleMetadataHistory = sampleService + // assert that the metadata history size is equal to 1 before any updates are made + List sampleMetadataHistoryBeforeUpdate = sampleService .getResearchSampleMetadataHistoryByIgoId(igoId); - Assertions.assertThat(sampleMetadataHistory.size()).isEqualTo(3); + Assertions.assertThat(sampleMetadataHistoryBeforeUpdate.size()).isEqualTo(1); + // persist updates for sample and confirm that the metadata history size increased + sampleService.updateSampleMetadata(updatedMetadata); + List sampleMetadataHistoryAfterUpdate = sampleService + .getResearchSampleMetadataHistoryByIgoId(igoId); + Assertions.assertThat(sampleMetadataHistoryAfterUpdate.size()).isEqualTo(2); + + // confirm that new sample metadata was persisted and that there is an older sample + // metadata with the date '2000-06-10' that we basically inserted into the + // history for this sample + Boolean hasMockOldMetadata = Boolean.FALSE; + for (SampleMetadata sm : sampleMetadataHistoryAfterUpdate) { + if (sm.getImportDate().equals("2000-06-10")) { + hasMockOldMetadata = Boolean.TRUE; + break; + } + } + Assertions.assertThat(hasMockOldMetadata).isTrue(); // confirms that both methods return the same latest metadata and // same cmo sample label corresponding to it + // the most up-to-date cmo label is C-MP789JR-N001-d based on mocked test data SmileSample updatedSample = sampleService.getResearchSampleByRequestAndIgoId(requestId, igoId); Assertions.assertThat(updatedSample.getLatestSampleMetadata().getCmoSampleName()) - .isEqualTo("C-LATESTLABEL-T02-d002"); + .isEqualTo("C-MP789JR-N001-d"); SampleMetadata latestMetadata = sampleRepository.findLatestSampleMetadataBySmileId(updatedSample.getSmileSampleId()); - Assertions.assertThat(latestMetadata.getCmoSampleName()).isEqualTo("C-LATESTLABEL-T02-d002"); + Assertions.assertThat(latestMetadata.getCmoSampleName()).isEqualTo("C-MP789JR-N001-d"); } /** @@ -356,17 +375,89 @@ public void testFindSampleByInvalidInputId() throws Exception { */ @Test public void testUpdateSampleMetadata() throws Exception { + MockJsonTestData updatedRequestData = mockDataUtils.mockedRequestJsonDataMap + .get("mockIncomingRequest1UpdatedJsonDataWith2T2N"); + SmileRequest updatedRequest = RequestDataFactory.buildNewLimsRequestFromJson( + updatedRequestData.getJsonString()); + // get the updated sample data from the mocked updated request String igoId = "MOCKREQUEST1_B_2"; + SmileSample updatedSample = null; + for (SmileSample s : updatedRequest.getSmileSampleList()) { + if (s.getLatestSampleMetadata().getPrimaryId().equals(igoId)) { + updatedSample = s; + break; + } + } + Assertions.assertThat(updatedSample).isNotNull(); + SampleMetadata updatedMetadata = updatedSample.getLatestSampleMetadata(); + updatedMetadata.setImportDate("2000-10-15"); + updatedMetadata.setBaitSet("NEW BAIT SET"); + updatedMetadata.setGenePanel("NEW GENE PANEL"); + updatedSample.addSampleMetadata(updatedMetadata); + sampleService.saveSmileSample(updatedSample); + // confirm that the sample metadata history size increases + List sampleMetadataHistory = sampleService + .getResearchSampleMetadataHistoryByIgoId(igoId); + Assertions.assertThat(sampleMetadataHistory.size()).isEqualTo(2); + } + + + /** + * Tests if sampleMetadata with updates that includes a patient swap is being persisted correctly + * @throws Exception + */ + @Test + public void testUpdateSampleMetadataWithPatientSwap() throws Exception { MockJsonTestData updatedRequestData = mockDataUtils.mockedRequestJsonDataMap .get("mockIncomingRequest1UpdatedJsonDataWith2T2N"); SmileRequest updatedRequest = RequestDataFactory.buildNewLimsRequestFromJson( updatedRequestData.getJsonString()); - SmileSample updatedSample = updatedRequest.getSmileSampleList().get(1); - sampleService.updateSampleMetadata(updatedSample.getLatestSampleMetadata()); + // get the updated sample data from the mocked updated request + String igoId = "MOCKREQUEST1_B_2"; + SmileSample updatedSample = null; + for (SmileSample s : updatedRequest.getSmileSampleList()) { + if (s.getLatestSampleMetadata().getPrimaryId().equals(igoId)) { + updatedSample = s; + break; + } + } + Assertions.assertThat(updatedSample).isNotNull(); + SampleMetadata updatedMetadata = updatedSample.getLatestSampleMetadata(); + + // do a quick string replacement for the current cmo sample label and persist update + String currentCmoPtId = updatedMetadata.getCmoPatientId(); + String swappedCmoPtId = "C-123456H"; + + // first confirm that there arent any samples by the swapped cmo pt id + List samplesBeforeUpdateForCurrentPt = + sampleService.getSamplesByCmoPatientId(currentCmoPtId); + Assertions.assertThat(samplesBeforeUpdateForCurrentPt.size()).isEqualTo(4); + List samplesBeforeUpdate = + sampleService.getSamplesByCmoPatientId(swappedCmoPtId); + Assertions.assertThat(samplesBeforeUpdate).isEmpty(); + + // perform update on the metadata and save to db + String updatedLabel = updatedMetadata.getCmoSampleName().replace(currentCmoPtId, swappedCmoPtId); + updatedMetadata.setCmoPatientId(swappedCmoPtId); + updatedMetadata.setCmoSampleName(updatedLabel); + updatedSample.updateSampleMetadata(updatedMetadata); + sampleService.saveSmileSample(updatedSample); + // confirm that the sample metadata history size increases List sampleMetadataHistory = sampleService .getResearchSampleMetadataHistoryByIgoId(igoId); Assertions.assertThat(sampleMetadataHistory.size()).isEqualTo(2); + + // confirm that the patient linked to the sample after the update matches the swapped id + // first confirm that there arent any samples by the swapped cmo pt id + List samplesAfterUpdate = + sampleService.getSamplesByCmoPatientId(swappedCmoPtId); + Assertions.assertThat(samplesAfterUpdate.size()).isEqualTo(1); + List samplesStillLinkedToOldPt = + sampleService.getSamplesByCmoPatientId(currentCmoPtId); + Assertions.assertThat(samplesStillLinkedToOldPt.size()) + .isEqualTo(samplesBeforeUpdateForCurrentPt.size() - 1); + } }