Skip to content

Commit

Permalink
Support ALT ID's (#1374)
Browse files Browse the repository at this point in the history
* Add alt (#1362)

* Init commit - add alt ID to data models

Signed-off-by: Angelica Ochoa <[email protected]>

* Support searching by alt ID in persistence and service layers

Signed-off-by: Angelica Ochoa <[email protected]>

---------

Signed-off-by: Angelica Ochoa <[email protected]>

* Add request-reply handler for fetching samples by alt ID (#1363)

* Add a message handler for alt ID

* Create a mocked incoming request for the alt id test

* Create a mocked outgoing request for the alt id test

* Add test for the alt id handler

* Rename 'altId' to 'altid' in the incoming mocked request to match IGO casing

---------

Signed-off-by: Angelica Ochoa <[email protected]>
Co-authored-by: Quan Nguyen <[email protected]>
  • Loading branch information
ao508 and qu8n authored Jan 15, 2025
1 parent 9588cae commit b889029
Show file tree
Hide file tree
Showing 12 changed files with 520 additions and 3 deletions.
5 changes: 5 additions & 0 deletions model/src/main/java/org/mskcc/smile/model/SampleMetadata.java
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ public SampleMetadata(IgoSampleManifest igoSampleManifest) throws JsonProcessing
this.qcReports = igoSampleManifest.getQcReports();
this.libraries = igoSampleManifest.getLibraries();
this.cmoSampleIdFields = igoSampleManifest.getCmoSampleIdFields();
addAdditionalProperty("altId", igoSampleManifest.getAltid());
}

/**
Expand Down Expand Up @@ -380,6 +381,10 @@ public void addAdditionalProperty(String property, String value) {
this.additionalProperties.put(property, value);
}

public String getAdditionalProperty(String property) {
return additionalProperties.get(property);
}

public Status getStatus() {
return status;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ public class IgoSampleManifest {
private String cmoPatientId;
private String cmoSampleName;
private String sampleName;
private String altid;
private String baitSet;
private String cfDNA2dBarcode;
private String cmoInfoIgoId;
Expand Down Expand Up @@ -70,6 +71,14 @@ public void setSampleName(String sampleName) {
this.sampleName = sampleName;
}

public String getAltid() {
return altid;
}

public void setAltid(String altid) {
this.altid = altid;
}

public String getBaitSet() {
return baitSet;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,18 @@ public interface SmileSampleRepository extends Neo4jRepository<SmileSample, UUID
SmileSample findSampleBySampleSmileId(@Param("smileSampleId") UUID smileSampleId);

@Query("MATCH (s: Sample)-[:HAS_METADATA]->(sm: SampleMetadata {primaryId: $primaryId}) "
+ "RETURN s")
+ "RETURN DISTINCT s")
SmileSample findSampleByPrimaryId(@Param("primaryId") String primaryId);

@Query("MATCH (s: Sample)-[:HAS_METADATA]->(sm: SampleMetadata {cmoSampleName: $cmoSampleName}) "
+ "RETURN s")
+ "RETURN DISTINCT s")
List<SmileSample> findSamplesByCmoSampleName(@Param("cmoSampleName") String cmoSampleName);

@Query("MATCH (s: Sample)-[:HAS_METADATA]->(sm: SampleMetadata) "
+ "WHERE sm.additionalProperties CONTAINS $altId "
+ "RETURN DISTINCT s")
List<SmileSample> findSamplesByAltId(@Param("altId") String altId);

@Query("MATCH (s: Sample {smileSampleId: $smileSampleId})-[:HAS_METADATA]->(sm: SampleMetadata) "
+ "OPTIONAL MATCH (sm)-[hs:HAS_STATUS]->(ss: Status) "
+ "RETURN sm, hs, ss")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ public interface RequestReplyHandlingService {
void initialize(Gateway gateway) throws Exception;
void patientSamplesHandler(String patientId, String replyTo) throws Exception;
void samplesByCmoLabelHandler(String cmoLabel, String replyTo) throws Exception;
void samplesByAltIdHandler(String cmoLabel, String replyTo) throws Exception;
void crdbMappingHandler(String inputId, String replyTo) throws Exception;
void shutdown() throws Exception;
}
Original file line number Diff line number Diff line change
Expand Up @@ -36,4 +36,5 @@ List<SmileSample> getSamplesByCategoryAndCmoPatientId(String cmoPatientId,
Boolean sampleExistsByInputId(String primaryId);
List<SmileSample> getSamplesByCohortId(String cohortId) throws Exception;
List<SmileSample> getSamplesByCmoSampleName(String cmoSampleName) throws Exception;
List<SmileSample> getSamplesByAltId(String altId) throws Exception;
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@ public class RequestReplyHandlingServiceImpl implements RequestReplyHandlingServ
@Value("${request_reply.samples_by_cmo_label_topic}")
private String SAMPLES_BY_CMO_LABEL_REQREPLY_TOPIC;

@Value("${request_reply.samples_by_alt_id_topic}")
private String SAMPLES_BY_ALT_ID_REQREPLY_TOPIC;

@Value("${request_reply.crdb_mapping_topic}")
private String CRDB_MAPPING_REQREPLY_TOPIC;

Expand All @@ -54,10 +57,13 @@ public class RequestReplyHandlingServiceImpl implements RequestReplyHandlingServ
new LinkedBlockingQueue<ReplyInfo>();
private static final BlockingQueue<ReplyInfo> samplesByCmoLabelReqReplyQueue =
new LinkedBlockingQueue<ReplyInfo>();
private static final BlockingQueue<ReplyInfo> samplesByAltIdReqReplyQueue =
new LinkedBlockingQueue<ReplyInfo>();
private static final BlockingQueue<ReplyInfo> crdbMappingReqReplyQueue =
new LinkedBlockingQueue<ReplyInfo>();
private static CountDownLatch patientSamplesHandlerShutdownLatch;
private static CountDownLatch samplesByCmoLabelHandlerShutdownLatch;
private static CountDownLatch samplesByAltIdHandlerShutdownLatch;
private static CountDownLatch crdbMappingHandlerShutdownLatch;
private static Gateway messagingGateway;

Expand Down Expand Up @@ -160,6 +166,45 @@ public void run() {
}
}

private class SamplesByAltIdReqReplyHandler implements Runnable {

final Phaser phaser;
boolean interrupted = false;

SamplesByAltIdReqReplyHandler(Phaser phaser) {
this.phaser = phaser;
}

@Override
public void run() {
phaser.arrive();
while (true) {
try {
// reply info request message contains cmo sample label
ReplyInfo replyInfo = samplesByAltIdReqReplyQueue.poll(100, TimeUnit.MILLISECONDS);
if (replyInfo != null) {
List<SmileSample> matchingSamples =
sampleService.getSamplesByAltId(replyInfo.getRequestMessage());
List<SampleMetadata> sampleMetadataList = new ArrayList<>();
for (SmileSample sample : matchingSamples) {
sampleMetadataList.add(sample.getLatestSampleMetadata());
}
messagingGateway.replyPublish(replyInfo.getReplyTo(),
mapper.writeValueAsString(sampleMetadataList));
}
if (interrupted && samplesByAltIdReqReplyQueue.isEmpty()) {
break;
}
} catch (InterruptedException e) {
interrupted = true;
} catch (Exception e) {
LOG.error("Error during request handling", e);
}
}
samplesByAltIdHandlerShutdownLatch.countDown();
}
}

private class CrdbMappingReqReplyHandler implements Runnable {

final Phaser phaser;
Expand Down Expand Up @@ -205,6 +250,7 @@ public void initialize(Gateway gateway) throws Exception {
messagingGateway = gateway;
setupPatientSamplesHandler(messagingGateway, this);
setupSamplesByCmoLabelHandler(messagingGateway, this);
setupSamplesByAltIdHandler(messagingGateway, this);
setupCrdbMappingHandler(messagingGateway, this);
initializeRequestReplyHandlers();
initialized = true;
Expand Down Expand Up @@ -239,6 +285,19 @@ public void samplesByCmoLabelHandler(String cmoLabel, String replyTo) throws Exc
}
}

@Override
public void samplesByAltIdHandler(String altId, String replyTo) throws Exception {
if (!initialized) {
throw new IllegalStateException("Message Handling Service has not been initialized");
}
if (!shutdownInitiated) {
samplesByAltIdReqReplyQueue.put(new ReplyInfo(altId, replyTo));
} else {
LOG.error("Shutdown initiated, not accepting alt ID req-reply: " + altId);
throw new IllegalStateException("Shutdown initiated, not handling any more alt IDs");
}
}

@Override
public void crdbMappingHandler(String inputId, String replyTo) throws Exception {
if (!initialized) {
Expand Down Expand Up @@ -308,6 +367,28 @@ public void onMessage(Message msg, Object message) {
});
}

private void setupSamplesByAltIdHandler(Gateway gateway,
RequestReplyHandlingServiceImpl requestReplyHandlingServiceImpl)
throws Exception {
gateway.replySub(SAMPLES_BY_ALT_ID_REQREPLY_TOPIC, new MessageConsumer() {
@Override
public void onMessage(Message msg, Object message) {
LOG.info("Received message on topic: " + SAMPLES_BY_ALT_ID_REQREPLY_TOPIC);
try {
if (StringUtils.isBlank(new String(msg.getData()))) {
LOG.error("Expected an alt ID but message received is empty: " + msg
+ " - message will not be added to request-reply queue");
} else {
requestReplyHandlingServiceImpl.samplesByAltIdHandler(
new String(msg.getData()), msg.getReplyTo());
}
} catch (Exception e) {
e.printStackTrace();
}
}
});
}

private void setupCrdbMappingHandler(Gateway gateway,
RequestReplyHandlingServiceImpl requestReplyHandlingServiceImpl)
throws Exception {
Expand Down Expand Up @@ -344,6 +425,15 @@ private void initializeRequestReplyHandlers() throws Exception {
}
samplesByCmoLabelPhaser.arriveAndAwaitAdvance();

samplesByAltIdHandlerShutdownLatch = new CountDownLatch(NUM_NEW_REQUEST_HANDLERS);
final Phaser samplesByAltIdPhaser = new Phaser();
samplesByAltIdPhaser.register();
for (int lc = 0; lc < NUM_NEW_REQUEST_HANDLERS; lc++) {
samplesByAltIdPhaser.register();
exec.execute(new SamplesByAltIdReqReplyHandler(samplesByAltIdPhaser));
}
samplesByAltIdPhaser.arriveAndAwaitAdvance();

crdbMappingHandlerShutdownLatch = new CountDownLatch(NUM_NEW_REQUEST_HANDLERS);
final Phaser crdbMappingPhaser = new Phaser();
crdbMappingPhaser.register();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -501,4 +501,26 @@ public List<SmileSample> getSamplesByCmoSampleName(String cmoSampleName) throws
}
return toReturn;
}

@Override
public List<SmileSample> getSamplesByAltId(String altId) throws Exception {
// alt id is stored in the sample metadata 'additionalProperties' map which
// is stored in the database as a string so the query needs to specify the
// altId property name as well: "altId":"<altId>"
String altIdSearchTerm = new StringBuilder("\"altId\":\"")
.append(altId)
.append("\"").toString();

List<SmileSample> samples = sampleRepository.findSamplesByAltId(altIdSearchTerm);
if (samples == null) {
return new ArrayList<>();
}

List<SmileSample> toReturn = new ArrayList<>();
for (SmileSample s : samples) {
SmileSample detailedSample = getSmileSample(s.getSmileSampleId());
toReturn.add(detailedSample);
}
return toReturn;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,12 @@ public void initializeMockDatabase() throws Exception {
SmileRequest request8 = RequestDataFactory.buildNewLimsRequestFromJson(request8Data.getJsonString());
requestService.saveRequest(request8);

// mock request id: MOCKREQUEST9_D
MockJsonTestData request9Data = mockDataUtils.mockedRequestJsonDataMap
.get("mockIncomingRequest9DupAltIds");
SmileRequest request9 = RequestDataFactory.buildNewLimsRequestFromJson(request9Data.getJsonString());
requestService.saveRequest(request9);

//persist all mocked clinical data
for (MockJsonTestData mockJsonTestData : mockDataUtils.mockedDmpMetadataMap.values()) {
DmpSampleMetadata dmpSample = mapper.readValue(mockJsonTestData.getJsonString(),
Expand Down Expand Up @@ -713,5 +719,12 @@ public void testDuplicateCmoSampleLabels() throws Exception {
List<SmileSample> samplesMatchingLabels = sampleService.getSamplesByCmoSampleName(cmoLabel);
Assertions.assertEquals(2, samplesMatchingLabels.size());
}
}

@Test
@Order(24)
public void testDuplicateAltIds() throws Exception {
String altId = "AB9-ABC";
List<SmileSample> samplesMatchingAltIds = sampleService.getSamplesByAltId(altId);
Assertions.assertEquals(2, samplesMatchingAltIds.size());
}
}
Loading

0 comments on commit b889029

Please sign in to comment.