$translate operation implementation for remote terminology (#3552)

This commit is contained in:
seanmikalson-smilecdr 2022-04-25 12:37:15 -07:00 committed by GitHub
parent f7a31287b6
commit 68c8523046
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 555 additions and 54 deletions

View File

@ -29,6 +29,7 @@ import org.apache.commons.lang3.Validate;
import org.apache.commons.lang3.builder.EqualsBuilder; import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder; import org.apache.commons.lang3.builder.HashCodeBuilder;
import org.hl7.fhir.instance.model.api.IBase; import org.hl7.fhir.instance.model.api.IBase;
import org.hl7.fhir.instance.model.api.IBaseCoding;
import org.hl7.fhir.instance.model.api.IBaseParameters; import org.hl7.fhir.instance.model.api.IBaseParameters;
import org.hl7.fhir.instance.model.api.IBaseResource; import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.instance.model.api.IPrimitiveType; import org.hl7.fhir.instance.model.api.IPrimitiveType;
@ -806,21 +807,43 @@ public interface IValidationSupport {
class TranslateCodeRequest { class TranslateCodeRequest {
private final String mySourceSystemUrl; private List<IBaseCoding> myCodings;
private final String mySourceCode;
private final String myTargetSystemUrl; private final String myTargetSystemUrl;
private final int myHashCode; private final String myConceptMapUrl;
private final String myConceptMapVersion;
private final String mySourceValueSetUrl;
private final String myTargetValueSetUrl;
private final Long myResourcePid;
private final boolean myReverse;
public TranslateCodeRequest(String theSourceSystemUrl, String theSourceCode, String theTargetSystemUrl) { public TranslateCodeRequest(List<IBaseCoding> theCodings, String theTargetSystemUrl) {
mySourceSystemUrl = theSourceSystemUrl; myCodings = theCodings;
mySourceCode = theSourceCode;
myTargetSystemUrl = theTargetSystemUrl; myTargetSystemUrl = theTargetSystemUrl;
myConceptMapUrl = null;
myConceptMapVersion = null;
mySourceValueSetUrl = null;
myTargetValueSetUrl = null;
myResourcePid = null;
myReverse = false;
}
myHashCode = new HashCodeBuilder(17, 37) public TranslateCodeRequest(
.append(mySourceSystemUrl) List<IBaseCoding> theCodings,
.append(mySourceCode) String theTargetSystemUrl,
.append(myTargetSystemUrl) String theConceptMapUrl,
.toHashCode(); String theConceptMapVersion,
String theSourceValueSetUrl,
String theTargetValueSetUrl,
Long theResourcePid,
boolean theReverse) {
myCodings = theCodings;
myTargetSystemUrl = theTargetSystemUrl;
myConceptMapUrl = theConceptMapUrl;
myConceptMapVersion = theConceptMapVersion;
mySourceValueSetUrl = theSourceValueSetUrl;
myTargetValueSetUrl = theTargetValueSetUrl;
myResourcePid = theResourcePid;
myReverse = theReverse;
} }
@Override @Override
@ -836,28 +859,62 @@ public interface IValidationSupport {
TranslateCodeRequest that = (TranslateCodeRequest) theO; TranslateCodeRequest that = (TranslateCodeRequest) theO;
return new EqualsBuilder() return new EqualsBuilder()
.append(mySourceSystemUrl, that.mySourceSystemUrl) .append(myCodings, that.myCodings)
.append(mySourceCode, that.mySourceCode)
.append(myTargetSystemUrl, that.myTargetSystemUrl) .append(myTargetSystemUrl, that.myTargetSystemUrl)
.append(myConceptMapUrl, that.myConceptMapUrl)
.append(myConceptMapVersion, that.myConceptMapVersion)
.append(mySourceValueSetUrl, that.mySourceValueSetUrl)
.append(myTargetValueSetUrl, that.myTargetValueSetUrl)
.append(myResourcePid, that.myResourcePid)
.append(myReverse, that.myReverse)
.isEquals(); .isEquals();
} }
@Override @Override
public int hashCode() { public int hashCode() {
return myHashCode; return new HashCodeBuilder(17, 37)
.append(myCodings)
.append(myTargetSystemUrl)
.append(myConceptMapUrl)
.append(myConceptMapVersion)
.append(mySourceValueSetUrl)
.append(myTargetValueSetUrl)
.append(myResourcePid)
.append(myReverse)
.toHashCode();
} }
public String getSourceSystemUrl() { public List<IBaseCoding> getCodings() {
return mySourceSystemUrl; return myCodings;
}
public String getSourceCode() {
return mySourceCode;
} }
public String getTargetSystemUrl() { public String getTargetSystemUrl() {
return myTargetSystemUrl; return myTargetSystemUrl;
} }
public String getConceptMapUrl() {
return myConceptMapUrl;
}
public String getConceptMapVersion() {
return myConceptMapVersion;
}
public String getSourceValueSetUrl() {
return mySourceValueSetUrl;
}
public String getTargetValueSetUrl() {
return myTargetValueSetUrl;
}
public Long getResourcePid() {
return myResourcePid;
}
public boolean isReverse() {
return myReverse;
}
} }

View File

@ -0,0 +1,3 @@
type: add
issue: 3442
title: "Provided a Remote Terminology Service implementation for the $translate operation."

View File

@ -20,6 +20,7 @@ package ca.uhn.fhir.jpa.dao.dstu3;
* #L% * #L%
*/ */
import ca.uhn.fhir.context.support.IValidationSupport;
import ca.uhn.fhir.i18n.Msg; import ca.uhn.fhir.i18n.Msg;
import ca.uhn.fhir.context.support.TranslateConceptResults; import ca.uhn.fhir.context.support.TranslateConceptResults;
import ca.uhn.fhir.jpa.api.dao.IFhirResourceDaoConceptMap; import ca.uhn.fhir.jpa.api.dao.IFhirResourceDaoConceptMap;
@ -38,19 +39,19 @@ import org.hl7.fhir.exceptions.FHIRException;
import org.hl7.fhir.instance.model.api.IBaseResource; import org.hl7.fhir.instance.model.api.IBaseResource;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import java.util.Collections;
import java.util.Date; import java.util.Date;
public class FhirResourceDaoConceptMapDstu3 extends BaseHapiFhirResourceDao<ConceptMap> implements IFhirResourceDaoConceptMap<ConceptMap> { public class FhirResourceDaoConceptMapDstu3 extends BaseHapiFhirResourceDao<ConceptMap> implements IFhirResourceDaoConceptMap<ConceptMap> {
@Autowired @Autowired
private ITermConceptMappingSvc myTermConceptMappingSvc; private ITermConceptMappingSvc myTermConceptMappingSvc;
@Autowired
private IValidationSupport myValidationSupport;
@Override @Override
public TranslateConceptResults translate(TranslationRequest theTranslationRequest, RequestDetails theRequestDetails) { public TranslateConceptResults translate(TranslationRequest theTranslationRequest, RequestDetails theRequestDetails) {
if (theTranslationRequest.hasReverse() && theTranslationRequest.getReverseAsBoolean()) { IValidationSupport.TranslateCodeRequest translateCodeRequest = theTranslationRequest.asTranslateCodeRequest();
return myTermConceptMappingSvc.translateWithReverse(theTranslationRequest); return myValidationSupport.translateConcept(translateCodeRequest);
}
return myTermConceptMappingSvc.translate(theTranslationRequest);
} }

View File

@ -20,6 +20,7 @@ package ca.uhn.fhir.jpa.dao.r4;
* #L% * #L%
*/ */
import ca.uhn.fhir.context.support.IValidationSupport;
import ca.uhn.fhir.context.support.TranslateConceptResults; import ca.uhn.fhir.context.support.TranslateConceptResults;
import ca.uhn.fhir.jpa.api.dao.IFhirResourceDaoConceptMap; import ca.uhn.fhir.jpa.api.dao.IFhirResourceDaoConceptMap;
import ca.uhn.fhir.jpa.api.model.TranslationRequest; import ca.uhn.fhir.jpa.api.model.TranslationRequest;
@ -29,23 +30,28 @@ import ca.uhn.fhir.jpa.model.entity.ResourceTable;
import ca.uhn.fhir.jpa.term.api.ITermConceptMappingSvc; import ca.uhn.fhir.jpa.term.api.ITermConceptMappingSvc;
import ca.uhn.fhir.rest.api.server.RequestDetails; import ca.uhn.fhir.rest.api.server.RequestDetails;
import ca.uhn.fhir.rest.api.server.storage.TransactionDetails; import ca.uhn.fhir.rest.api.server.storage.TransactionDetails;
import org.hl7.fhir.instance.model.api.IBase;
import org.hl7.fhir.instance.model.api.IBaseCoding;
import org.hl7.fhir.instance.model.api.IBaseResource; import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.r4.model.CodeableConcept;
import org.hl7.fhir.r4.model.Coding;
import org.hl7.fhir.r4.model.ConceptMap; import org.hl7.fhir.r4.model.ConceptMap;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import java.util.Collections;
import java.util.Date; import java.util.Date;
import java.util.List;
public class FhirResourceDaoConceptMapR4 extends BaseHapiFhirResourceDao<ConceptMap> implements IFhirResourceDaoConceptMap<ConceptMap> { public class FhirResourceDaoConceptMapR4 extends BaseHapiFhirResourceDao<ConceptMap> implements IFhirResourceDaoConceptMap<ConceptMap> {
@Autowired @Autowired
private ITermConceptMappingSvc myTermConceptMappingSvc; private ITermConceptMappingSvc myTermConceptMappingSvc;
@Autowired
private IValidationSupport myValidationSupport;
@Override @Override
public TranslateConceptResults translate(TranslationRequest theTranslationRequest, RequestDetails theRequestDetails) { public TranslateConceptResults translate(TranslationRequest theTranslationRequest, RequestDetails theRequestDetails) {
if (theTranslationRequest.hasReverse() && theTranslationRequest.getReverseAsBoolean()) { IValidationSupport.TranslateCodeRequest translateCodeRequest = theTranslationRequest.asTranslateCodeRequest();
return myTermConceptMappingSvc.translateWithReverse(theTranslationRequest); return myValidationSupport.translateConcept(translateCodeRequest);
}
return myTermConceptMappingSvc.translate(theTranslationRequest);
} }
@Override @Override

View File

@ -20,6 +20,7 @@ package ca.uhn.fhir.jpa.dao.r5;
* #L% * #L%
*/ */
import ca.uhn.fhir.context.support.IValidationSupport;
import ca.uhn.fhir.context.support.TranslateConceptResults; import ca.uhn.fhir.context.support.TranslateConceptResults;
import ca.uhn.fhir.jpa.api.dao.IFhirResourceDaoConceptMap; import ca.uhn.fhir.jpa.api.dao.IFhirResourceDaoConceptMap;
import ca.uhn.fhir.jpa.api.model.TranslationRequest; import ca.uhn.fhir.jpa.api.model.TranslationRequest;
@ -35,19 +36,19 @@ import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.r5.model.ConceptMap; import org.hl7.fhir.r5.model.ConceptMap;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import java.util.Collections;
import java.util.Date; import java.util.Date;
public class FhirResourceDaoConceptMapR5 extends BaseHapiFhirResourceDao<ConceptMap> implements IFhirResourceDaoConceptMap<ConceptMap> { public class FhirResourceDaoConceptMapR5 extends BaseHapiFhirResourceDao<ConceptMap> implements IFhirResourceDaoConceptMap<ConceptMap> {
@Autowired @Autowired
private ITermConceptMappingSvc myTermConceptMappingSvc; private ITermConceptMappingSvc myTermConceptMappingSvc;
@Autowired
private IValidationSupport myValidationSupport;
@Override @Override
public TranslateConceptResults translate(TranslationRequest theTranslationRequest, RequestDetails theRequestDetails) { public TranslateConceptResults translate(TranslationRequest theTranslationRequest, RequestDetails theRequestDetails) {
if (theTranslationRequest.hasReverse() && theTranslationRequest.getReverseAsBoolean()) { IValidationSupport.TranslateCodeRequest translateCodeRequest = theTranslationRequest.asTranslateCodeRequest();
return myTermConceptMappingSvc.translateWithReverse(theTranslationRequest); return myValidationSupport.translateConcept(translateCodeRequest);
}
return myTermConceptMappingSvc.translate(theTranslationRequest);
} }
@Override @Override

View File

@ -47,6 +47,8 @@ import org.apache.commons.lang3.StringUtils;
import org.hibernate.ScrollMode; import org.hibernate.ScrollMode;
import org.hibernate.ScrollableResults; import org.hibernate.ScrollableResults;
import org.hl7.fhir.exceptions.FHIRException; import org.hl7.fhir.exceptions.FHIRException;
import org.hl7.fhir.instance.model.api.IBase;
import org.hl7.fhir.instance.model.api.IBaseCoding;
import org.hl7.fhir.r4.model.BooleanType; import org.hl7.fhir.r4.model.BooleanType;
import org.hl7.fhir.r4.model.CodeType; import org.hl7.fhir.r4.model.CodeType;
import org.hl7.fhir.r4.model.CodeableConcept; import org.hl7.fhir.r4.model.CodeableConcept;
@ -118,16 +120,10 @@ public class TermConceptMappingSvcImpl implements ITermConceptMappingSvc {
@Override @Override
@Transactional @Transactional
public TranslateConceptResults translateConcept(TranslateCodeRequest theRequest) { public TranslateConceptResults translateConcept(TranslateCodeRequest theRequest) {
TranslationRequest request = TranslationRequest.fromTranslateCodeRequest(theRequest);
CodeableConcept sourceCodeableConcept = new CodeableConcept(); if (request.hasReverse() && request.getReverseAsBoolean()) {
sourceCodeableConcept return translateWithReverse(request);
.addCoding() }
.setSystem(theRequest.getSourceSystemUrl())
.setCode(theRequest.getSourceCode());
TranslationRequest request = new TranslationRequest();
request.setCodeableConcept(sourceCodeableConcept);
request.setTargetSystem(new UriType(theRequest.getTargetSystemUrl()));
return translate(request); return translate(request);
} }

View File

@ -12,6 +12,7 @@ import ca.uhn.fhir.jpa.test.BaseJpaR4Test;
import org.hl7.fhir.instance.model.api.IIdType; import org.hl7.fhir.instance.model.api.IIdType;
import org.hl7.fhir.r4.model.CanonicalType; import org.hl7.fhir.r4.model.CanonicalType;
import org.hl7.fhir.r4.model.CodeableConcept; import org.hl7.fhir.r4.model.CodeableConcept;
import org.hl7.fhir.r4.model.Coding;
import org.hl7.fhir.r4.model.ConceptMap; import org.hl7.fhir.r4.model.ConceptMap;
import org.hl7.fhir.r4.model.Enumerations.ConceptMapEquivalence; import org.hl7.fhir.r4.model.Enumerations.ConceptMapEquivalence;
import org.hl7.fhir.r4.model.Enumerations.PublicationStatus; import org.hl7.fhir.r4.model.Enumerations.PublicationStatus;
@ -30,6 +31,7 @@ import org.springframework.transaction.support.TransactionTemplate;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import java.io.IOException; import java.io.IOException;
import java.util.Collections;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
@ -1139,7 +1141,9 @@ public class FhirResourceDaoR4ConceptMapTest extends BaseJpaR4Test {
}); });
List<TranslateConceptResult> translationResults = myValidationSupport.translateConcept(new IValidationSupport.TranslateCodeRequest("http://source", "source1", "http://target")).getResults(); CodeableConcept sourceCodeableConcept = new CodeableConcept();
sourceCodeableConcept.addCoding(new Coding("http://source", "source1", null));
List<TranslateConceptResult> translationResults = myValidationSupport.translateConcept(new IValidationSupport.TranslateCodeRequest(Collections.unmodifiableList(sourceCodeableConcept.getCoding()), "http://target")).getResults();
assertThat(translationResults.toString(), translationResults, hasItem( assertThat(translationResults.toString(), translationResults, hasItem(
new TranslateConceptResult() new TranslateConceptResult()
.setSystem("http://target") .setSystem("http://target")

View File

@ -1,5 +1,6 @@
package ca.uhn.fhir.jpa.term; package ca.uhn.fhir.jpa.term;
import ca.uhn.fhir.context.support.IValidationSupport;
import ca.uhn.fhir.context.support.TranslateConceptResult; import ca.uhn.fhir.context.support.TranslateConceptResult;
import ca.uhn.fhir.context.support.TranslateConceptResults; import ca.uhn.fhir.context.support.TranslateConceptResults;
import ca.uhn.fhir.i18n.Msg; import ca.uhn.fhir.i18n.Msg;
@ -8,14 +9,19 @@ import ca.uhn.fhir.jpa.entity.TermConceptMap;
import ca.uhn.fhir.jpa.entity.TermConceptMapGroup; import ca.uhn.fhir.jpa.entity.TermConceptMapGroup;
import ca.uhn.fhir.jpa.entity.TermConceptMapGroupElement; import ca.uhn.fhir.jpa.entity.TermConceptMapGroupElement;
import ca.uhn.fhir.jpa.entity.TermConceptMapGroupElementTarget; import ca.uhn.fhir.jpa.entity.TermConceptMapGroupElementTarget;
import ca.uhn.fhir.jpa.term.api.ITermConceptMappingSvc;
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException; import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
import org.hl7.fhir.instance.model.api.IIdType; import org.hl7.fhir.instance.model.api.IIdType;
import org.hl7.fhir.r4.model.CanonicalType; import org.hl7.fhir.r4.model.CanonicalType;
import org.hl7.fhir.r4.model.CodeableConcept;
import org.hl7.fhir.r4.model.Coding;
import org.hl7.fhir.r4.model.ConceptMap; import org.hl7.fhir.r4.model.ConceptMap;
import org.hl7.fhir.r4.model.Enumerations; import org.hl7.fhir.r4.model.Enumerations;
import org.hl7.fhir.r4.model.StringType;
import org.hl7.fhir.r4.model.UriType; import org.hl7.fhir.r4.model.UriType;
import org.hl7.fhir.r4.model.codesystems.HttpVerb; import org.hl7.fhir.r4.model.codesystems.HttpVerb;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.mockito.ArgumentCaptor;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.PageRequest;
@ -25,6 +31,7 @@ import org.springframework.transaction.support.TransactionCallbackWithoutResult;
import org.springframework.transaction.support.TransactionTemplate; import org.springframework.transaction.support.TransactionTemplate;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import java.util.Collections;
import java.util.List; import java.util.List;
import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
@ -32,6 +39,11 @@ import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.fail; import static org.junit.jupiter.api.Assertions.fail;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
public class TermConceptMappingSvcImplTest extends BaseTermR4Test { public class TermConceptMappingSvcImplTest extends BaseTermR4Test {
private static final Logger ourLog = LoggerFactory.getLogger(TermConceptMappingSvcImplTest.class); private static final Logger ourLog = LoggerFactory.getLogger(TermConceptMappingSvcImplTest.class);
@ -1547,6 +1559,100 @@ public class TermConceptMappingSvcImplTest extends BaseTermR4Test {
}); });
} }
@Test
public void testTranslateCodeRequestToTranslationRequestMapping() {
CodeableConcept codeableConcept = new CodeableConcept();
Coding coding = new Coding("theSourceSystemUrl", "theSourceCode", null);
codeableConcept.addCoding(coding);
IValidationSupport.TranslateCodeRequest theRequest = new IValidationSupport.TranslateCodeRequest(
Collections.unmodifiableList(codeableConcept.getCoding()),
"theTargetSystemUrl",
"theConceptMapUrl",
"theConceptMapVersion",
"theSourceValueSetUrl",
"theTargetValueSetUrl",
0L,
false
);
CodeableConcept sourceCodeableConcept = new CodeableConcept();
sourceCodeableConcept
.addCoding()
.setSystem(coding.getSystem())
.setCode(coding.getCode());
TranslationRequest expected = new TranslationRequest();
expected.setCodeableConcept(sourceCodeableConcept);
expected.setConceptMapVersion(new StringType(theRequest.getConceptMapVersion()));
expected.setUrl(new UriType(theRequest.getConceptMapUrl()));
expected.setSource(new UriType(theRequest.getSourceValueSetUrl()));
expected.setTarget(new UriType(theRequest.getTargetValueSetUrl()));
expected.setTargetSystem(new UriType(theRequest.getTargetSystemUrl()));
expected.setResourceId(theRequest.getResourcePid());
expected.setReverse(theRequest.isReverse());
ITermConceptMappingSvc mock = mock(TermConceptMappingSvcImpl.class);
ArgumentCaptor<TranslationRequest> argument = ArgumentCaptor.forClass(TranslationRequest.class);
when(mock.translate(expected)).thenReturn(new TranslateConceptResults());
when(mock.translateConcept(theRequest)).thenCallRealMethod();
mock.translateConcept(theRequest);
verify(mock).translate(argument.capture());
assertSameTranslationRequest(expected, argument.getValue());
}
@Test
public void testTranslateCodeRequestWithReverseToTranslationRequestMapping() {
CodeableConcept codeableConcept = new CodeableConcept();
Coding coding = new Coding("theSourceSystemUrl", "theSourceCode", null);
codeableConcept.addCoding(coding);
IValidationSupport.TranslateCodeRequest theRequest = new IValidationSupport.TranslateCodeRequest(
Collections.unmodifiableList(codeableConcept.getCoding()),
"theTargetSystemUrl",
"theConceptMapUrl",
"theConceptMapVersion",
"theSourceValueSetUrl",
"theTargetValueSetUrl",
0L,
true
);
CodeableConcept sourceCodeableConcept = new CodeableConcept();
sourceCodeableConcept
.addCoding()
.setSystem(coding.getSystem())
.setCode(coding.getCode());
TranslationRequest expected = new TranslationRequest();
expected.setCodeableConcept(sourceCodeableConcept);
expected.setConceptMapVersion(new StringType(theRequest.getConceptMapVersion()));
expected.setUrl(new UriType(theRequest.getConceptMapUrl()));
expected.setSource(new UriType(theRequest.getSourceValueSetUrl()));
expected.setTarget(new UriType(theRequest.getTargetValueSetUrl()));
expected.setTargetSystem(new UriType(theRequest.getTargetSystemUrl()));
expected.setResourceId(theRequest.getResourcePid());
expected.setReverse(theRequest.isReverse());
ITermConceptMappingSvc mock = mock(TermConceptMappingSvcImpl.class);
ArgumentCaptor<TranslationRequest> argument = ArgumentCaptor.forClass(TranslationRequest.class);
when(mock.translate(expected)).thenReturn(new TranslateConceptResults());
when(mock.translateConcept(theRequest)).thenCallRealMethod();
mock.translateConcept(theRequest);
verify(mock).translateWithReverse(argument.capture());
assertSameTranslationRequest(expected, argument.getValue());
}
private static void assertSameTranslationRequest(TranslationRequest expected, TranslationRequest actual) {
assertTrue(expected.getCodeableConcept().equalsDeep(actual.getCodeableConcept()));
assertEquals(expected.getConceptMapVersion().asStringValue(), actual.getConceptMapVersion().asStringValue());
assertEquals(expected.getUrl().asStringValue(), actual.getUrl().asStringValue());
assertEquals(expected.getSource().asStringValue(), actual.getSource().asStringValue());
assertEquals(expected.getTarget().asStringValue(), actual.getTarget().asStringValue());
assertEquals(expected.getTargetSystem().asStringValue(), actual.getTargetSystem().asStringValue());
assertEquals(expected.getResourceId(), actual.getResourceId());
assertEquals(expected.getReverseAsBoolean(), actual.getReverseAsBoolean());
}
private void createAndPersistConceptMap() { private void createAndPersistConceptMap() {
ConceptMap conceptMap = createConceptMap(); ConceptMap conceptMap = createConceptMap();

View File

@ -36,9 +36,11 @@ import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Multimap; import com.google.common.collect.Multimap;
import org.apache.commons.lang3.Validate; import org.apache.commons.lang3.Validate;
import org.hl7.fhir.instance.model.api.IBase; import org.hl7.fhir.instance.model.api.IBase;
import org.hl7.fhir.instance.model.api.IBaseCoding;
import org.hl7.fhir.instance.model.api.IBaseResource; import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.instance.model.api.IPrimitiveType; import org.hl7.fhir.instance.model.api.IPrimitiveType;
import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -153,12 +155,17 @@ public class ResponseTerminologyTranslationInterceptor extends BaseResponseTermi
if (!foundSystemsToCodes.containsKey(wantTargetSystem)) { if (!foundSystemsToCodes.containsKey(wantTargetSystem)) {
for (String code : foundSystemsToCodes.get(nextSourceSystem)) { for (String code : foundSystemsToCodes.get(nextSourceSystem)) {
TranslateConceptResults translateConceptResults = myValidationSupport.translateConcept(new IValidationSupport.TranslateCodeRequest(nextSourceSystem, code, wantTargetSystem)); List<IBaseCoding> codings = new ArrayList<IBaseCoding>();
codings.add(createCodingFromPrimitives(nextSourceSystem, code, null));
TranslateConceptResults translateConceptResults = myValidationSupport.translateConcept(new IValidationSupport.TranslateCodeRequest(codings, wantTargetSystem));
if (translateConceptResults != null) { if (translateConceptResults != null) {
List<TranslateConceptResult> mappings = translateConceptResults.getResults(); List<TranslateConceptResult> mappings = translateConceptResults.getResults();
for (TranslateConceptResult nextMapping : mappings) { for (TranslateConceptResult nextMapping : mappings) {
IBase newCoding = createCodingFromMappingTarget(nextMapping); IBase newCoding = createCodingFromPrimitives(
nextMapping.getSystem(),
nextMapping.getCode(),
nextMapping.getDisplay());
// Add coding to existing CodeableConcept // Add coding to existing CodeableConcept
myCodeableConceptCodingChild.getMutator().addValue(theElement, newCoding); myCodeableConceptCodingChild.getMutator().addValue(theElement, newCoding);
@ -174,14 +181,14 @@ public class ResponseTerminologyTranslationInterceptor extends BaseResponseTermi
} }
private IBase createCodingFromMappingTarget(TranslateConceptResult nextMapping) { private IBaseCoding createCodingFromPrimitives(String system, String code, String display) {
IBase newCoding = myCodingDefinitition.newInstance(); IBaseCoding newCoding = (IBaseCoding) myCodingDefinitition.newInstance();
IPrimitiveType<?> newSystem = myUriDefinition.newInstance(nextMapping.getSystem()); IPrimitiveType<?> newSystem = myUriDefinition.newInstance(system);
myCodingSystemChild.getMutator().addValue(newCoding, newSystem); myCodingSystemChild.getMutator().addValue(newCoding, newSystem);
IPrimitiveType<?> newCode = myCodeDefinition.newInstance(nextMapping.getCode()); IPrimitiveType<?> newCode = myCodeDefinition.newInstance(code);
myCodingCodeChild.getMutator().addValue(newCoding, newCode); myCodingCodeChild.getMutator().addValue(newCoding, newCode);
if (isNotBlank(nextMapping.getDisplay())) { if (isNotBlank(display)) {
IPrimitiveType<?> newDisplay = myStringDefinition.newInstance(nextMapping.getDisplay()); IPrimitiveType<?> newDisplay = myStringDefinition.newInstance(display);
myCodingDisplayChild.getMutator().addValue(newCoding, newDisplay); myCodingDisplayChild.getMutator().addValue(newCoding, newDisplay);
} }
return newCoding; return newCoding;

View File

@ -20,7 +20,9 @@ package ca.uhn.fhir.jpa.api.model;
* #L% * #L%
*/ */
import ca.uhn.fhir.context.support.IValidationSupport;
import org.apache.commons.lang3.Validate; import org.apache.commons.lang3.Validate;
import org.hl7.fhir.instance.model.api.IBaseCoding;
import org.hl7.fhir.r4.model.BooleanType; import org.hl7.fhir.r4.model.BooleanType;
import org.hl7.fhir.r4.model.CodeableConcept; import org.hl7.fhir.r4.model.CodeableConcept;
import org.hl7.fhir.r4.model.Coding; import org.hl7.fhir.r4.model.Coding;
@ -28,6 +30,7 @@ import org.hl7.fhir.r4.model.StringType;
import org.hl7.fhir.r4.model.UriType; import org.hl7.fhir.r4.model.UriType;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.List; import java.util.List;
public class TranslationRequest { public class TranslationRequest {
@ -208,4 +211,40 @@ public class TranslationRequest {
public boolean hasTargetSystem() { public boolean hasTargetSystem() {
return myTargetSystem != null && myTargetSystem.hasValue(); return myTargetSystem != null && myTargetSystem.hasValue();
} }
public IValidationSupport.TranslateCodeRequest asTranslateCodeRequest() {
return new IValidationSupport.TranslateCodeRequest(
Collections.unmodifiableList(this.getCodeableConcept().getCoding()),
this.getTargetSystem() != null ? this.getTargetSystem().asStringValue() : null,
this.getUrl() != null ? this.getUrl().asStringValue() : null,
this.getConceptMapVersion() != null ? this.getConceptMapVersion().asStringValue() : null,
this.getSource() != null ? this.getSource().asStringValue() : null,
this.getTarget() != null ? this.getTarget().asStringValue() : null,
this.getResourceId(),
this.getReverseAsBoolean()
);
}
public static TranslationRequest fromTranslateCodeRequest(IValidationSupport.TranslateCodeRequest theRequest) {
CodeableConcept sourceCodeableConcept = new CodeableConcept();
for (IBaseCoding aCoding : theRequest.getCodings()) {
sourceCodeableConcept
.addCoding()
.setSystem(aCoding.getSystem())
.setCode(aCoding.getCode())
.setVersion(((Coding) aCoding).getVersion());
}
TranslationRequest translationRequest = new TranslationRequest();
translationRequest.setCodeableConcept(sourceCodeableConcept);
translationRequest.setConceptMapVersion(new StringType(theRequest.getConceptMapVersion()));
translationRequest.setUrl(new UriType(theRequest.getConceptMapUrl()));
translationRequest.setSource(new UriType(theRequest.getSourceValueSetUrl()));
translationRequest.setTarget(new UriType(theRequest.getTargetValueSetUrl()));
translationRequest.setTargetSystem(new UriType(theRequest.getTargetSystemUrl()));
translationRequest.setResourceId(theRequest.getResourcePid());
translationRequest.setReverse(theRequest.isReverse());
return translationRequest;
}
} }

View File

@ -1,5 +1,11 @@
package org.hl7.fhir.common.hapi.validation.support; package org.hl7.fhir.common.hapi.validation.support;
import ca.uhn.fhir.context.BaseRuntimeChildDefinition;
import ca.uhn.fhir.context.BaseRuntimeElementCompositeDefinition;
import ca.uhn.fhir.context.BaseRuntimeElementDefinition;
import ca.uhn.fhir.context.RuntimePrimitiveDatatypeDefinition;
import ca.uhn.fhir.context.support.TranslateConceptResult;
import ca.uhn.fhir.context.support.TranslateConceptResults;
import ca.uhn.fhir.i18n.Msg; import ca.uhn.fhir.i18n.Msg;
import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.context.FhirVersionEnum; import ca.uhn.fhir.context.FhirVersionEnum;
@ -11,20 +17,29 @@ import ca.uhn.fhir.rest.client.api.IGenericClient;
import ca.uhn.fhir.util.BundleUtil; import ca.uhn.fhir.util.BundleUtil;
import ca.uhn.fhir.util.JsonUtil; import ca.uhn.fhir.util.JsonUtil;
import ca.uhn.fhir.util.ParametersUtil; import ca.uhn.fhir.util.ParametersUtil;
import ca.uhn.fhir.util.StringUtil;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.Validate; import org.apache.commons.lang3.Validate;
import org.hl7.fhir.instance.model.api.IBase;
import org.hl7.fhir.instance.model.api.IBaseBundle; import org.hl7.fhir.instance.model.api.IBaseBundle;
import org.hl7.fhir.instance.model.api.IBaseCoding;
import org.hl7.fhir.instance.model.api.IBaseParameters; import org.hl7.fhir.instance.model.api.IBaseParameters;
import org.hl7.fhir.instance.model.api.IBaseResource; import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.instance.model.api.IPrimitiveType;
import org.hl7.fhir.r4.model.CodeSystem; import org.hl7.fhir.r4.model.CodeSystem;
import org.hl7.fhir.r4.model.Coding;
import org.hl7.fhir.r4.model.Parameters;
import org.hl7.fhir.r4.model.ValueSet; import org.hl7.fhir.r4.model.ValueSet;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import java.io.IOException; import java.io.IOException;
import java.sql.Array;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Objects;
import java.util.Optional;
import static org.apache.commons.lang3.StringUtils.isBlank; import static org.apache.commons.lang3.StringUtils.isBlank;
import static org.apache.commons.lang3.StringUtils.isNotBlank; import static org.apache.commons.lang3.StringUtils.isNotBlank;
@ -331,6 +346,23 @@ public class RemoteTerminologyServiceValidationSupport extends BaseValidationSup
return fetchValueSet(theValueSetUrl) != null; return fetchValueSet(theValueSetUrl) != null;
} }
@Override
public TranslateConceptResults translateConcept(TranslateCodeRequest theRequest) {
IGenericClient client = provideClient();
FhirContext fhirContext = client.getFhirContext();
IBaseParameters params = buildTranslateInputParameters(fhirContext, theRequest);
IBaseParameters outcome = client
.operation()
.onType("ConceptMap")
.named("$translate")
.withParameters(params)
.execute();
return translateOutcomeToResults(fhirContext, outcome);
}
private IGenericClient provideClient() { private IGenericClient provideClient() {
IGenericClient retVal = myCtx.newRestfulGenericClient(myBaseUrl); IGenericClient retVal = myCtx.newRestfulGenericClient(myBaseUrl);
for (Object next : myClientInterceptors) { for (Object next : myClientInterceptors) {
@ -442,4 +474,103 @@ public class RemoteTerminologyServiceValidationSupport extends BaseValidationSup
myClientInterceptors.add(theClientInterceptor); myClientInterceptors.add(theClientInterceptor);
} }
private IBaseParameters buildTranslateInputParameters(FhirContext fhirContext, TranslateCodeRequest theRequest) {
IBaseParameters params = ParametersUtil.newInstance(fhirContext);
if (!StringUtils.isEmpty(theRequest.getConceptMapUrl())) {
ParametersUtil.addParameterToParametersUri(fhirContext, params, "url", theRequest.getConceptMapUrl());
}
if (!StringUtils.isEmpty(theRequest.getConceptMapVersion())) {
ParametersUtil.addParameterToParametersString(fhirContext, params, "conceptMapVersion", theRequest.getConceptMapVersion());
}
if (theRequest.getCodings() != null) {
addCodingsToTranslateParameters(fhirContext, theRequest.getCodings(), params);
}
if (!StringUtils.isEmpty(theRequest.getSourceValueSetUrl())) {
ParametersUtil.addParameterToParametersUri(fhirContext, params, "source", theRequest.getSourceValueSetUrl());
}
if (!StringUtils.isEmpty(theRequest.getTargetValueSetUrl())) {
ParametersUtil.addParameterToParametersUri(fhirContext, params, "target", theRequest.getTargetValueSetUrl());
}
if (!StringUtils.isEmpty(theRequest.getTargetSystemUrl())) {
ParametersUtil.addParameterToParametersUri(fhirContext, params, "targetsystem", theRequest.getTargetSystemUrl());
}
if (theRequest.isReverse()) {
ParametersUtil.addParameterToParametersBoolean(fhirContext, params, "reverse", theRequest.isReverse());
}
return params;
}
private void addCodingsToTranslateParameters(FhirContext fhirContext, List<IBaseCoding> theCodings, IBaseParameters theParams) {
BaseRuntimeElementCompositeDefinition<?> codeableConceptDef = (BaseRuntimeElementCompositeDefinition<?>) Objects.requireNonNull(fhirContext.getElementDefinition("CodeableConcept"));
BaseRuntimeChildDefinition codings = codeableConceptDef.getChildByName("coding");
BaseRuntimeElementCompositeDefinition<?> codingDef = (BaseRuntimeElementCompositeDefinition<?>) Objects.requireNonNull(fhirContext.getElementDefinition("Coding"));
BaseRuntimeChildDefinition codingSystemChild = codingDef.getChildByName("system");
BaseRuntimeChildDefinition codingCodeChild = codingDef.getChildByName("code");
BaseRuntimeElementDefinition<IPrimitiveType<?>> systemDef = (RuntimePrimitiveDatatypeDefinition) fhirContext.getElementDefinition("uri");
BaseRuntimeElementDefinition<IPrimitiveType<?>> codeDef = (RuntimePrimitiveDatatypeDefinition) fhirContext.getElementDefinition("code");
IBase codeableConcept = codeableConceptDef.newInstance();
for (IBaseCoding aCoding : theCodings) {
IBaseCoding newCoding = (IBaseCoding) codingDef.newInstance();
IPrimitiveType<?> newSystem = systemDef.newInstance(aCoding.getSystem());
codingSystemChild.getMutator().addValue(newCoding, newSystem);
IPrimitiveType<?> newCode = codeDef.newInstance(aCoding.getCode());
codingCodeChild.getMutator().addValue(newCoding, newCode);
codings.getMutator().addValue(codeableConcept, newCoding);
}
ParametersUtil.addParameterToParameters(fhirContext, theParams, "codeableConcept", codeableConcept);
}
private TranslateConceptResults translateOutcomeToResults(FhirContext fhirContext, IBaseParameters outcome) {
Optional<String> result = ParametersUtil.getNamedParameterValueAsString(fhirContext, outcome, "result");
Optional<String> message = ParametersUtil.getNamedParameterValueAsString(fhirContext, outcome, "message");
List<IBase> matches = ParametersUtil.getNamedParameters(fhirContext, outcome, "match");
TranslateConceptResults retVal = new TranslateConceptResults();
if (result.isPresent()) {
retVal.setResult(Boolean.parseBoolean(result.get()));
}
if (message.isPresent()) {
retVal.setMessage(message.get());
}
if (!matches.isEmpty()) {
retVal.setResults(matchesToTranslateConceptResults(fhirContext, matches));
}
return retVal;
}
private List<TranslateConceptResult> matchesToTranslateConceptResults(FhirContext fhirContext, List<IBase> theMatches) {
List<TranslateConceptResult> resultList = new ArrayList();
for (IBase m : theMatches) {
TranslateConceptResult match = new TranslateConceptResult();
String equivalence = ParametersUtil.getParameterPartValueAsString(fhirContext, m, "equivalence");
Optional<IBase> concept = ParametersUtil.getParameterPartValue(fhirContext, m, "concept");
String source = ParametersUtil.getParameterPartValueAsString(fhirContext, m, "source");
if (StringUtils.isNotBlank(equivalence)) {
match.setEquivalence(equivalence);
}
if (concept.isPresent()) {
IBaseCoding matchedCoding = (IBaseCoding) concept.get();
match.setSystem(matchedCoding.getSystem());
match.setCode(matchedCoding.getCode());
match.setDisplay(matchedCoding.getDisplay());
if (StringUtils.isNotBlank(source)) {
match.setConceptMapUrl(source);
}
resultList.add(match);
}
}
return resultList;
}
} }

View File

@ -3,6 +3,8 @@ package org.hl7.fhir.common.hapi.validation.support;
import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.context.support.ConceptValidationOptions; import ca.uhn.fhir.context.support.ConceptValidationOptions;
import ca.uhn.fhir.context.support.IValidationSupport; import ca.uhn.fhir.context.support.IValidationSupport;
import ca.uhn.fhir.context.support.TranslateConceptResult;
import ca.uhn.fhir.context.support.TranslateConceptResults;
import ca.uhn.fhir.jpa.model.util.JpaConstants; import ca.uhn.fhir.jpa.model.util.JpaConstants;
import ca.uhn.fhir.parser.IJsonLikeParser; import ca.uhn.fhir.parser.IJsonLikeParser;
import ca.uhn.fhir.rest.annotation.IdParam; import ca.uhn.fhir.rest.annotation.IdParam;
@ -20,11 +22,14 @@ import ca.uhn.fhir.rest.server.IResourceProvider;
import ca.uhn.fhir.test.utilities.server.RestfulServerExtension; import ca.uhn.fhir.test.utilities.server.RestfulServerExtension;
import ca.uhn.fhir.util.ParametersUtil; import ca.uhn.fhir.util.ParametersUtil;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import org.hl7.fhir.instance.model.api.IBaseCoding;
import org.hl7.fhir.instance.model.api.IBaseResource; import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.r4.model.BooleanType; import org.hl7.fhir.r4.model.BooleanType;
import org.hl7.fhir.r4.model.CodeSystem; import org.hl7.fhir.r4.model.CodeSystem;
import org.hl7.fhir.r4.model.CodeType; import org.hl7.fhir.r4.model.CodeType;
import org.hl7.fhir.r4.model.CodeableConcept;
import org.hl7.fhir.r4.model.Coding; import org.hl7.fhir.r4.model.Coding;
import org.hl7.fhir.r4.model.ConceptMap;
import org.hl7.fhir.r4.model.IdType; import org.hl7.fhir.r4.model.IdType;
import org.hl7.fhir.r4.model.Parameters; import org.hl7.fhir.r4.model.Parameters;
import org.hl7.fhir.r4.model.StringType; import org.hl7.fhir.r4.model.StringType;
@ -58,7 +63,18 @@ public class RemoteTerminologyServiceValidationSupportTest {
private static final String CODE_SYSTEM_VERSION_AS_TEXT = "v2.1.12"; private static final String CODE_SYSTEM_VERSION_AS_TEXT = "v2.1.12";
private static final String CODE = "CODE"; private static final String CODE = "CODE";
private static final String VALUE_SET_URL = "http://value.set/url"; private static final String VALUE_SET_URL = "http://value.set/url";
private static final String TARGET_SYSTEM = "http://target.system/url";
private static final String CONCEPT_MAP_URL = "http://concept.map/url";
private static final String CONCEPT_MAP_VERSION = "2.1";
private static final String SOURCE_VALUE_SET_URL = "http://source.vs.system/url";
private static final String TARGET_VALUE_SET_URL = "http://target.vs.system/url";
private static final String TARGET_CODE = "CODE";
private static final String TARGET_CODE_DISPLAY = "code";
private static final boolean REVERSE = true;
private static final String EQUIVALENCE_CODE = "equivalent";
private static final String ERROR_MESSAGE = "This is an error message"; private static final String ERROR_MESSAGE = "This is an error message";
private static final String SUCCESS_MESSAGE = "This is a success message";
private static FhirContext ourCtx = FhirContext.forR4Cached(); private static FhirContext ourCtx = FhirContext.forR4Cached();
@ -68,6 +84,7 @@ public class RemoteTerminologyServiceValidationSupportTest {
private MyValueSetProvider myValueSetProvider; private MyValueSetProvider myValueSetProvider;
private RemoteTerminologyServiceValidationSupport mySvc; private RemoteTerminologyServiceValidationSupport mySvc;
private MyCodeSystemProvider myCodeSystemProvider; private MyCodeSystemProvider myCodeSystemProvider;
private MyConceptMapProvider myConceptMapProvider;
@BeforeEach @BeforeEach
public void before() { public void before() {
@ -77,6 +94,9 @@ public class RemoteTerminologyServiceValidationSupportTest {
myCodeSystemProvider = new MyCodeSystemProvider(); myCodeSystemProvider = new MyCodeSystemProvider();
myRestfulServerExtension.getRestfulServer().registerProvider(myCodeSystemProvider); myRestfulServerExtension.getRestfulServer().registerProvider(myCodeSystemProvider);
myConceptMapProvider = new MyConceptMapProvider();
myRestfulServerExtension.getRestfulServer().registerProvider(myConceptMapProvider);
String baseUrl = "http://localhost:" + myRestfulServerExtension.getPort(); String baseUrl = "http://localhost:" + myRestfulServerExtension.getPort();
mySvc = new RemoteTerminologyServiceValidationSupport(ourCtx); mySvc = new RemoteTerminologyServiceValidationSupport(ourCtx);
@ -277,6 +297,91 @@ public class RemoteTerminologyServiceValidationSupportTest {
assertEquals(null, outcome); assertEquals(null, outcome);
} }
@Test
public void testTranslateCode_AllInParams_AllOutParams() {
myConceptMapProvider.myNextReturnParams = new Parameters();
myConceptMapProvider.myNextReturnParams.addParameter("result", true);
myConceptMapProvider.myNextReturnParams.addParameter("message", ERROR_MESSAGE);
TranslateConceptResults expectedResults = new TranslateConceptResults();
expectedResults.setResult(true);
// Add 2 matches
addMatchToTranslateRequest(myConceptMapProvider.myNextReturnParams);
addMatchToTranslateRequest(myConceptMapProvider.myNextReturnParams);
List<TranslateConceptResult> translateResults = new ArrayList<>();
TranslateConceptResult singleResult = new TranslateConceptResult();
singleResult
.setEquivalence(EQUIVALENCE_CODE)
.setSystem(TARGET_SYSTEM)
.setCode(TARGET_CODE)
.setConceptMapUrl(CONCEPT_MAP_URL)
.setDisplay(TARGET_CODE_DISPLAY);
translateResults.add(singleResult);
translateResults.add(singleResult);
expectedResults.setResults(translateResults);
CodeableConcept codeableConcept = new CodeableConcept();
codeableConcept.addCoding(new Coding(CODE_SYSTEM, CODE, null));
IValidationSupport.TranslateCodeRequest request = new IValidationSupport.TranslateCodeRequest(
Collections.unmodifiableList(codeableConcept.getCoding()),
TARGET_SYSTEM,
CONCEPT_MAP_URL,
CONCEPT_MAP_VERSION,
SOURCE_VALUE_SET_URL,
TARGET_VALUE_SET_URL,
null,
REVERSE);
TranslateConceptResults results = mySvc.translateConcept(request);
assertEquals(results.getResult(), true);
assertEquals(results.getResults().size(), 2);
for(TranslateConceptResult result : results.getResults()) {
assertEquals(singleResult, result);
}
assertTrue(codeableConcept.equalsDeep(myConceptMapProvider.myLastCodeableConcept));
assertEquals(TARGET_SYSTEM, myConceptMapProvider.myLastTargetCodeSystem.getValue());
assertEquals(CONCEPT_MAP_URL, myConceptMapProvider.myLastConceptMapUrl.getValue());
assertEquals(CONCEPT_MAP_VERSION, myConceptMapProvider.myLastConceptMapVersion.getValue());
assertEquals(SOURCE_VALUE_SET_URL, myConceptMapProvider.myLastSourceValueSet.getValue());
assertEquals(TARGET_VALUE_SET_URL, myConceptMapProvider.myLastTargetValueSet.getValue());
assertEquals(REVERSE, myConceptMapProvider.myLastReverse.getValue());
}
@Test
public void testTranslateCode_NoInParams_NoOutParams() {
myConceptMapProvider.myNextReturnParams = new Parameters();
List<IBaseCoding> codings = new ArrayList<>();
codings.add(new Coding(null, null, null));
IValidationSupport.TranslateCodeRequest request = new IValidationSupport.TranslateCodeRequest(codings, null);
TranslateConceptResults results = mySvc.translateConcept(request);
assertEquals(results.getResult(), false);
assertEquals(results.getResults().size(), 0);
assertNull(myConceptMapProvider.myLastCodeableConcept);
assertNull(myConceptMapProvider.myLastTargetCodeSystem);
assertNull(myConceptMapProvider.myLastConceptMapUrl);
assertNull(myConceptMapProvider.myLastConceptMapVersion);
assertNull(myConceptMapProvider.myLastSourceValueSet);
assertNull(myConceptMapProvider.myLastTargetValueSet);
assertNull(myConceptMapProvider.myLastReverse);
}
private void addMatchToTranslateRequest(Parameters params) {
Parameters.ParametersParameterComponent matchParam = params.addParameter().setName("match");
matchParam.addPart().setName("equivalence").setValue(new CodeType(EQUIVALENCE_CODE));
Coding value = new Coding(TARGET_SYSTEM, TARGET_CODE, TARGET_CODE_DISPLAY);
matchParam.addPart().setName("concept").setValue(value);
matchParam.addPart().setName("source").setValue(new UriType(CONCEPT_MAP_URL));
}
/** /**
* Remote terminology services can be used to validate codes when code system is present, * Remote terminology services can be used to validate codes when code system is present,
* even when inferSystem is true * even when inferSystem is true
@ -636,5 +741,50 @@ public class RemoteTerminologyServiceValidationSupportTest {
} }
private static class MyConceptMapProvider implements IResourceProvider {
private UriType myLastConceptMapUrl;
private StringType myLastConceptMapVersion;
private CodeableConcept myLastCodeableConcept;
private UriType myLastSourceValueSet;
private UriType myLastTargetValueSet;
private UriType myLastTargetCodeSystem;
private BooleanType myLastReverse;
private int myInvocationCount;
private Parameters myNextReturnParams;
@Operation(name = JpaConstants.OPERATION_TRANSLATE, idempotent = true, returnParameters = {
@OperationParam(name = "result", type = BooleanType.class, min = 1, max = 1),
@OperationParam(name = "message", type = StringType.class, min = 0, max = 1),
})
public Parameters translate(
HttpServletRequest theServletRequest,
@IdParam(optional = true) IdType theId,
@OperationParam(name = "url", min = 0, max = 1) UriType theConceptMapUrl,
@OperationParam(name = "conceptMapVersion", min = 0, max = 1) StringType theConceptMapVersion,
@OperationParam(name = "codeableConcept", min = 0, max = 1) CodeableConcept theSourceCodeableConcept,
@OperationParam(name = "source", min = 0, max = 1) UriType theSourceValueSet,
@OperationParam(name = "target", min = 0, max = 1) UriType theTargetValueSet,
@OperationParam(name = "targetsystem", min = 0, max = 1) UriType theTargetCodeSystem,
@OperationParam(name = "reverse", min = 0, max = 1) BooleanType theReverse,
RequestDetails theRequestDetails
) {
myInvocationCount++;
myLastConceptMapUrl = theConceptMapUrl;
myLastConceptMapVersion = theConceptMapVersion;
myLastCodeableConcept = theSourceCodeableConcept;
myLastSourceValueSet = theSourceValueSet;
myLastTargetValueSet = theTargetValueSet;
myLastTargetCodeSystem = theTargetCodeSystem;
myLastReverse = theReverse;
return myNextReturnParams;
}
@Override
public Class<? extends IBaseResource> getResourceType() {
return ConceptMap.class;
}
}
} }