Allow storing ConceptMap with StructureDefinition as a source or target

This commit is contained in:
James Agnew 2019-01-13 12:24:51 -06:00
parent 93bf2788ec
commit 63b8a70e8a
3 changed files with 86 additions and 41 deletions

View File

@ -9,9 +9,9 @@ package ca.uhn.fhir.jpa.term;
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -25,9 +25,9 @@ import ca.uhn.fhir.jpa.dao.BaseHapiFhirDao;
import ca.uhn.fhir.jpa.dao.DaoConfig;
import ca.uhn.fhir.jpa.dao.IFhirResourceDaoCodeSystem;
import ca.uhn.fhir.jpa.dao.data.*;
import ca.uhn.fhir.jpa.model.entity.*;
import ca.uhn.fhir.jpa.entity.*;
import ca.uhn.fhir.jpa.entity.TermConceptParentChildLink.RelationshipTypeEnum;
import ca.uhn.fhir.jpa.model.entity.ResourceTable;
import ca.uhn.fhir.jpa.util.ScrollableResultsIterator;
import ca.uhn.fhir.rest.api.server.RequestDetails;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
@ -137,6 +137,8 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc,
private int myFetchSize = DEFAULT_FETCH_SIZE;
private ApplicationContext myApplicationContext;
private TransactionTemplate myTxTemplate;
@Autowired
private PlatformTransactionManager myTransactionManager;
/**
* @param theAdd If true, add the code. If false, remove the code.
@ -368,9 +370,6 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc,
}
}
@Autowired
private PlatformTransactionManager myTransactionManager;
@Override
@Transactional
public void deleteConceptMapAndChildren(ResourceTable theResourceTable) {
@ -391,7 +390,7 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc,
TransactionTemplate txTemplate = new TransactionTemplate(myTransactionManager);
txTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
txTemplate.execute(t->{
txTemplate.execute(t -> {
theDao.deleteInBatch(link);
return null;
});
@ -1190,6 +1189,22 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc,
termConceptMap.setResource(theResourceTable);
termConceptMap.setUrl(theConceptMap.getUrl());
String source = theConceptMap.hasSourceUriType() ? theConceptMap.getSourceUriType().getValueAsString() : null;
String target = theConceptMap.hasTargetUriType() ? theConceptMap.getTargetUriType().getValueAsString() : null;
/*
* If this is a mapping between "resources" instead of purely between
* "concepts" (this is a weird concept that is technically possible, at least as of
* FHIR R4), don't try to store the mappings.
*
* See here for a description of what that is:
* http://hl7.org/fhir/conceptmap.html#bnr
*/
if ("StructureDefinition".equals(new IdType(source).getResourceType()) ||
"StructureDefinition".equals(new IdType(target).getResourceType())) {
return;
}
/*
* For now we always delete old versions. At some point, it would be nice to allow configuration to keep old versions.
*/
@ -1202,11 +1217,9 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc,
Optional<TermConceptMap> optionalExistingTermConceptMapByUrl = myConceptMapDao.findTermConceptMapByUrl(conceptMapUrl);
if (!optionalExistingTermConceptMapByUrl.isPresent()) {
try {
String source = theConceptMap.hasSourceUriType() ? theConceptMap.getSourceUriType().getValueAsString() : null;
if (isNotBlank(source)) {
termConceptMap.setSource(source);
}
String target = theConceptMap.hasTargetUriType() ? theConceptMap.getTargetUriType().getValueAsString() : null;
if (isNotBlank(target)) {
termConceptMap.setTarget(target);
}
@ -1244,12 +1257,12 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc,
if (element.hasTarget()) {
TermConceptMapGroupElementTarget termConceptMapGroupElementTarget;
for (ConceptMap.TargetElementComponent target : element.getTarget()) {
for (ConceptMap.TargetElementComponent elementTarget : element.getTarget()) {
termConceptMapGroupElementTarget = new TermConceptMapGroupElementTarget();
termConceptMapGroupElementTarget.setConceptMapGroupElement(termConceptMapGroupElement);
termConceptMapGroupElementTarget.setCode(target.getCode());
termConceptMapGroupElementTarget.setDisplay(target.getDisplay());
termConceptMapGroupElementTarget.setEquivalence(target.getEquivalence());
termConceptMapGroupElementTarget.setCode(elementTarget.getCode());
termConceptMapGroupElementTarget.setDisplay(elementTarget.getDisplay());
termConceptMapGroupElementTarget.setEquivalence(elementTarget.getEquivalence());
myConceptMapGroupElementTargetDao.save(termConceptMapGroupElementTarget);
if (codesSaved++ % 250 == 0) {

View File

@ -1,5 +1,6 @@
package ca.uhn.fhir.jpa.term;
import ca.uhn.fhir.jpa.dao.DaoConfig;
import ca.uhn.fhir.jpa.dao.r4.BaseJpaR4Test;
import ca.uhn.fhir.jpa.entity.TermConceptMap;
import ca.uhn.fhir.jpa.entity.TermConceptMapGroup;
@ -8,12 +9,11 @@ import ca.uhn.fhir.jpa.entity.TermConceptMapGroupElementTarget;
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
import ca.uhn.fhir.util.TestUtil;
import org.hl7.fhir.instance.model.api.IIdType;
import org.hl7.fhir.r4.model.CanonicalType;
import org.hl7.fhir.r4.model.ConceptMap;
import org.hl7.fhir.r4.model.Enumerations.ConceptMapEquivalence;
import org.hl7.fhir.r4.model.UriType;
import org.junit.AfterClass;
import org.junit.Rule;
import org.junit.Test;
import org.junit.*;
import org.junit.rules.ExpectedException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -32,11 +32,26 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test {
public final ExpectedException expectedException = ExpectedException.none();
private IIdType myConceptMapId;
private void persistConceptMap() {
@Before
public void before() {
myDaoConfig.setAllowExternalReferences(true);
}
@After
public void after() {
myDaoConfig.setAllowExternalReferences(new DaoConfig().isAllowExternalReferences());
}
private void createAndPersistConceptMap() {
ConceptMap conceptMap = createConceptMap();
persistConceptMap(conceptMap);
}
private void persistConceptMap(ConceptMap theConceptMap) {
new TransactionTemplate(myTxManager).execute(new TransactionCallbackWithoutResult() {
@Override
protected void doInTransactionWithoutResult(TransactionStatus theStatus) {
myConceptMapId = myConceptMapDao.create(createConceptMap(), mySrd).getId().toUnqualifiedVersionless();
myConceptMapId = myConceptMapDao.create(theConceptMap, mySrd).getId().toUnqualifiedVersionless();
}
});
}
@ -63,6 +78,17 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test {
}
@Test
public void testCreateConceptMapWithVirtualSourceSystem() {
ConceptMap conceptMap = createConceptMap();
conceptMap.getGroup().forEach(t->t.setSource(null));
conceptMap.setSource(new CanonicalType("http://hl7.org/fhir/uv/livd/StructureDefinition/loinc-livd"));
persistConceptMap(conceptMap);
}
@Test
public void testCreateConceptMapWithMissingTargetSystems() {
@ -113,17 +139,17 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test {
@Test
public void testDuplicateConceptMapUrls() {
persistConceptMap();
createAndPersistConceptMap();
expectedException.expect(UnprocessableEntityException.class);
expectedException.expectMessage("Can not create multiple ConceptMap resources with ConceptMap.url \"http://example.com/my_concept_map\", already have one with resource ID: ConceptMap/" + myConceptMapId.getIdPart());
persistConceptMap();
createAndPersistConceptMap();
}
@Test
public void testStoreTermConceptMapAndChildren() {
persistConceptMap();
createAndPersistConceptMap();
ConceptMap conceptMap = myConceptMapDao.read(myConceptMapId);
ourLog.info("ConceptMap:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(conceptMap));
@ -301,7 +327,7 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test {
@Test
public void testTranslateByCodeSystemsAndSourceCodeOneToMany() {
persistConceptMap();
createAndPersistConceptMap();
ConceptMap conceptMap = myConceptMapDao.read(myConceptMapId);
ourLog.info("ConceptMap:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(conceptMap));
@ -355,7 +381,7 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test {
@Test
public void testTranslateByCodeSystemsAndSourceCodeOneToOne() {
persistConceptMap();
createAndPersistConceptMap();
ConceptMap conceptMap = myConceptMapDao.read(myConceptMapId);
ourLog.info("ConceptMap:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(conceptMap));
@ -429,7 +455,7 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test {
@Test
public void testTranslateByCodeSystemsAndSourceCodeUnmapped() {
persistConceptMap();
createAndPersistConceptMap();
ConceptMap conceptMap = myConceptMapDao.read(myConceptMapId);
ourLog.info("ConceptMap:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(conceptMap));
@ -482,7 +508,7 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test {
@Test
public void testTranslateUsingPredicatesWithCodeOnly() {
persistConceptMap();
createAndPersistConceptMap();
ConceptMap conceptMap = myConceptMapDao.read(myConceptMapId);
ourLog.info("ConceptMap:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(conceptMap));
@ -550,7 +576,7 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test {
@Test
public void testTranslateUsingPredicatesWithSourceAndTargetSystem2() {
persistConceptMap();
createAndPersistConceptMap();
ConceptMap conceptMap = myConceptMapDao.read(myConceptMapId);
ourLog.info("ConceptMap:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(conceptMap));
@ -598,7 +624,7 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test {
@Test
public void testTranslateUsingPredicatesWithSourceAndTargetSystem3() {
persistConceptMap();
createAndPersistConceptMap();
ConceptMap conceptMap = myConceptMapDao.read(myConceptMapId);
ourLog.info("ConceptMap:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(conceptMap));
@ -658,7 +684,7 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test {
@Test
public void testTranslateUsingPredicatesWithSourceSystem() {
persistConceptMap();
createAndPersistConceptMap();
ConceptMap conceptMap = myConceptMapDao.read(myConceptMapId);
ourLog.info("ConceptMap:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(conceptMap));
@ -728,7 +754,7 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test {
@Test
public void testTranslateUsingPredicatesWithSourceSystemAndVersion1() {
persistConceptMap();
createAndPersistConceptMap();
ConceptMap conceptMap = myConceptMapDao.read(myConceptMapId);
ourLog.info("ConceptMap:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(conceptMap));
@ -776,7 +802,7 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test {
@Test
public void testTranslateUsingPredicatesWithSourceSystemAndVersion3() {
persistConceptMap();
createAndPersistConceptMap();
ConceptMap conceptMap = myConceptMapDao.read(myConceptMapId);
ourLog.info("ConceptMap:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(conceptMap));
@ -836,7 +862,7 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test {
@Test
public void testTranslateUsingPredicatesWithSourceValueSet() {
persistConceptMap();
createAndPersistConceptMap();
ConceptMap conceptMap = myConceptMapDao.read(myConceptMapId);
ourLog.info("ConceptMap:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(conceptMap));
@ -906,7 +932,7 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test {
@Test
public void testTranslateUsingPredicatesWithTargetValueSet() {
persistConceptMap();
createAndPersistConceptMap();
ConceptMap conceptMap = myConceptMapDao.read(myConceptMapId);
ourLog.info("ConceptMap:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(conceptMap));
@ -976,7 +1002,7 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test {
@Test
public void testTranslateWithReverse() {
persistConceptMap();
createAndPersistConceptMap();
ConceptMap conceptMap = myConceptMapDao.read(myConceptMapId);
ourLog.info("ConceptMap:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(conceptMap));
@ -1025,7 +1051,7 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test {
@Test
public void testTranslateWithReverseByCodeSystemsAndSourceCodeUnmapped() {
persistConceptMap();
createAndPersistConceptMap();
ConceptMap conceptMap = myConceptMapDao.read(myConceptMapId);
ourLog.info("ConceptMap:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(conceptMap));
@ -1048,7 +1074,7 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test {
@Test
public void testTranslateWithReverseUsingPredicatesWithCodeOnly() {
persistConceptMap();
createAndPersistConceptMap();
ConceptMap conceptMap = myConceptMapDao.read(myConceptMapId);
ourLog.info("ConceptMap:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(conceptMap));
@ -1104,7 +1130,7 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test {
@Test
public void testTranslateWithReverseUsingPredicatesWithSourceAndTargetSystem1() {
persistConceptMap();
createAndPersistConceptMap();
ConceptMap conceptMap = myConceptMapDao.read(myConceptMapId);
ourLog.info("ConceptMap:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(conceptMap));
@ -1153,7 +1179,7 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test {
@Test
public void testTranslateWithReverseUsingPredicatesWithSourceAndTargetSystem4() {
persistConceptMap();
createAndPersistConceptMap();
ConceptMap conceptMap = myConceptMapDao.read(myConceptMapId);
ourLog.info("ConceptMap:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(conceptMap));
@ -1202,7 +1228,7 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test {
@Test
public void testTranslateWithReverseUsingPredicatesWithSourceSystem() {
persistConceptMap();
createAndPersistConceptMap();
ConceptMap conceptMap = myConceptMapDao.read(myConceptMapId);
ourLog.info("ConceptMap:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(conceptMap));
@ -1260,7 +1286,7 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test {
@Test
public void testTranslateWithReverseUsingPredicatesWithSourceSystemAndVersion() {
persistConceptMap();
createAndPersistConceptMap();
ConceptMap conceptMap = myConceptMapDao.read(myConceptMapId);
ourLog.info("ConceptMap:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(conceptMap));
@ -1320,7 +1346,7 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test {
@Test
public void testTranslateWithReverseUsingPredicatesWithSourceValueSet() {
persistConceptMap();
createAndPersistConceptMap();
ConceptMap conceptMap = myConceptMapDao.read(myConceptMapId);
ourLog.info("ConceptMap:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(conceptMap));
@ -1378,7 +1404,7 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test {
@Test
public void testTranslateWithReverseUsingPredicatesWithTargetValueSet() {
persistConceptMap();
createAndPersistConceptMap();
ConceptMap conceptMap = myConceptMapDao.read(myConceptMapId);
ourLog.info("ConceptMap:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(conceptMap));

View File

@ -289,6 +289,12 @@
an exception with a misleading error about the Conformance resource not existing. This
has been corrected. Thanks to Shayaan Munshi for reporting and providing a test case!
</action>
<action type="fix">
It is now possible to upload a ConceptMap to the JPA server containing mappings where the
source or target is a StructureDefinition canonical URI. This was previously blocked, as the
system could not apply these mappings. It is now permitted to be stored, although
the system will still not apply these mappings.
</action>
</release>
<release version="3.6.0" date="2018-11-12" description="Food">
<action type="add">