Make sure a loinc CodeSystem always has a ForcedId

This commit is contained in:
juan.marchionatto 2021-09-20 08:51:51 -04:00
parent 18e3ed68eb
commit d372371f36
6 changed files with 49 additions and 11 deletions

View File

@ -51,7 +51,6 @@ import ca.uhn.fhir.jpa.partition.SystemRequestDetails;
import ca.uhn.fhir.jpa.patch.FhirPatch; import ca.uhn.fhir.jpa.patch.FhirPatch;
import ca.uhn.fhir.jpa.patch.JsonPatchUtils; import ca.uhn.fhir.jpa.patch.JsonPatchUtils;
import ca.uhn.fhir.jpa.patch.XmlPatchUtils; import ca.uhn.fhir.jpa.patch.XmlPatchUtils;
import ca.uhn.fhir.jpa.search.DatabaseBackedPagingProvider;
import ca.uhn.fhir.jpa.search.PersistedJpaBundleProvider; import ca.uhn.fhir.jpa.search.PersistedJpaBundleProvider;
import ca.uhn.fhir.jpa.search.cache.SearchCacheStatusEnum; import ca.uhn.fhir.jpa.search.cache.SearchCacheStatusEnum;
import ca.uhn.fhir.jpa.search.reindex.IResourceReindexingSvc; import ca.uhn.fhir.jpa.search.reindex.IResourceReindexingSvc;
@ -169,7 +168,7 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
@Autowired @Autowired
private IRequestPartitionHelperSvc myRequestPartitionHelperService; private IRequestPartitionHelperSvc myRequestPartitionHelperService;
@Autowired @Autowired
private HapiTransactionService myTransactionService; protected HapiTransactionService myTransactionService;
@Autowired @Autowired
private MatchUrlService myMatchUrlService; private MatchUrlService myMatchUrlService;
@Autowired @Autowired
@ -221,7 +220,7 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
/** /**
* Called for FHIR create (POST) operations * Called for FHIR create (POST) operations
*/ */
private DaoMethodOutcome doCreateForPost(T theResource, String theIfNoneExist, boolean thePerformIndexing, TransactionDetails theTransactionDetails, RequestDetails theRequestDetails) { protected DaoMethodOutcome doCreateForPost(T theResource, String theIfNoneExist, boolean thePerformIndexing, TransactionDetails theTransactionDetails, RequestDetails theRequestDetails) {
if (theResource == null) { if (theResource == null) {
String msg = getContext().getLocalizer().getMessage(BaseHapiFhirResourceDao.class, "missingBody"); String msg = getContext().getLocalizer().getMessage(BaseHapiFhirResourceDao.class, "missingBody");
throw new InvalidRequestException(msg); throw new InvalidRequestException(msg);

View File

@ -109,8 +109,10 @@ public class JpaPersistedResourceValidationSupport implements IValidationSupport
public IBaseResource fetchCodeSystem(String theSystem) { public IBaseResource fetchCodeSystem(String theSystem) {
if (myTermReadSvc.isLoincNotGenericUnversionedCodeSystem(theSystem)) { if (myTermReadSvc.isLoincNotGenericUnversionedCodeSystem(theSystem)) {
Optional<IBaseResource> currentCSOpt = getCodeSystemCurrentVersion(new UriType(theSystem)); Optional<IBaseResource> currentCSOpt = getCodeSystemCurrentVersion(new UriType(theSystem));
return currentCSOpt.orElseThrow(() -> new ResourceNotFoundException( if (! currentCSOpt.isPresent()) {
"Couldn't find current version CodeSystem for url: " + theSystem)); ourLog.info("Couldn't find current version of CodeSystem: " + theSystem);
}
return currentCSOpt.orElse(null);
} }
return fetchResource(myCodeSystemType, theSystem); return fetchResource(myCodeSystemType, theSystem);
@ -125,7 +127,16 @@ public class JpaPersistedResourceValidationSupport implements IValidationSupport
IFhirResourceDao<? extends IBaseResource> valueSetResourceDao = myDaoRegistry.getResourceDao(myCodeSystemType); IFhirResourceDao<? extends IBaseResource> valueSetResourceDao = myDaoRegistry.getResourceDao(myCodeSystemType);
String forcedId = "loinc"; String forcedId = "loinc";
IBaseResource codeSystem = valueSetResourceDao.read(new IdDt("CodeSystem", forcedId));
// try/catch ignores exception because we need code to fall back to other options
IBaseResource codeSystem;
try {
codeSystem = valueSetResourceDao.read(new IdDt("CodeSystem", forcedId));
} catch (Exception theE) {
return Optional.empty();
}
return Optional.ofNullable(codeSystem); return Optional.ofNullable(codeSystem);
} }

View File

@ -25,6 +25,7 @@ import ca.uhn.fhir.context.support.IValidationSupport;
import ca.uhn.fhir.context.support.IValidationSupport.CodeValidationResult; import ca.uhn.fhir.context.support.IValidationSupport.CodeValidationResult;
import ca.uhn.fhir.context.support.ValidationSupportContext; import ca.uhn.fhir.context.support.ValidationSupportContext;
import ca.uhn.fhir.jpa.api.dao.IFhirResourceDaoCodeSystem; import ca.uhn.fhir.jpa.api.dao.IFhirResourceDaoCodeSystem;
import ca.uhn.fhir.jpa.api.model.DaoMethodOutcome;
import ca.uhn.fhir.jpa.dao.BaseHapiFhirResourceDao; import ca.uhn.fhir.jpa.dao.BaseHapiFhirResourceDao;
import ca.uhn.fhir.jpa.model.cross.IBasePersistedResource; import ca.uhn.fhir.jpa.model.cross.IBasePersistedResource;
import ca.uhn.fhir.jpa.model.entity.ResourceTable; import ca.uhn.fhir.jpa.model.entity.ResourceTable;
@ -46,12 +47,14 @@ import org.hl7.fhir.r4.model.Coding;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import java.security.InvalidParameterException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
import static ca.uhn.fhir.jpa.dao.FhirResourceDaoValueSetDstu2.toStringOrNull; import static ca.uhn.fhir.jpa.dao.FhirResourceDaoValueSetDstu2.toStringOrNull;
import static org.apache.commons.lang3.StringUtils.isBlank;
import static org.apache.commons.lang3.StringUtils.isNotBlank; import static org.apache.commons.lang3.StringUtils.isNotBlank;
public class FhirResourceDaoCodeSystemR4 extends BaseHapiFhirResourceDao<CodeSystem> implements IFhirResourceDaoCodeSystem<CodeSystem, Coding, CodeableConcept> { public class FhirResourceDaoCodeSystemR4 extends BaseHapiFhirResourceDao<CodeSystem> implements IFhirResourceDaoCodeSystem<CodeSystem, Coding, CodeableConcept> {
@ -173,4 +176,17 @@ public class FhirResourceDaoCodeSystemR4 extends BaseHapiFhirResourceDao<CodeSys
} }
@Override
public DaoMethodOutcome create(CodeSystem theResource, String theIfNoneExist, boolean thePerformIndexing,
@Nonnull TransactionDetails theTransactionDetails, RequestDetails theRequestDetails) {
// loinc CodeSystem must have an ID
if (isNotBlank(theResource.getUrl()) && theResource.getUrl().contains("loinc")
&& isBlank(theResource.getIdElement().getIdPart())) {
throw new InvalidParameterException("'loinc' CodeSystem must have an ID");
}
return myTransactionService.execute(theRequestDetails, theTransactionDetails,
tx -> doCreateForPost(theResource, theIfNoneExist, thePerformIndexing, theTransactionDetails, theRequestDetails));
}
} }

View File

@ -86,6 +86,7 @@ import java.util.UUID;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import static org.apache.commons.lang3.StringUtils.isBlank;
import static org.apache.commons.lang3.StringUtils.isNotBlank; import static org.apache.commons.lang3.StringUtils.isNotBlank;
public class TermCodeSystemStorageSvcImpl implements ITermCodeSystemStorageSvc { public class TermCodeSystemStorageSvcImpl implements ITermCodeSystemStorageSvc {
@ -139,6 +140,9 @@ public class TermCodeSystemStorageSvcImpl implements ITermCodeSystemStorageSvc {
CodeSystem codeSystemResource = new CodeSystem(); CodeSystem codeSystemResource = new CodeSystem();
codeSystemResource.setUrl(theSystem); codeSystemResource.setUrl(theSystem);
codeSystemResource.setContent(CodeSystem.CodeSystemContentMode.NOTPRESENT); codeSystemResource.setContent(CodeSystem.CodeSystemContentMode.NOTPRESENT);
if (isBlank(codeSystemResource.getIdElement().getIdPart()) && theSystem.contains("loinc")) {
codeSystemResource.setId("loinc");
}
myTerminologyVersionAdapterSvc.createOrUpdateCodeSystem(codeSystemResource); myTerminologyVersionAdapterSvc.createOrUpdateCodeSystem(codeSystemResource);
cs = myCodeSystemDao.findByCodeSystemUri(theSystem); cs = myCodeSystemDao.findByCodeSystemUri(theSystem);

View File

@ -33,6 +33,8 @@ import org.springframework.context.ApplicationContext;
import org.springframework.context.event.ContextRefreshedEvent; import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.context.event.EventListener; import org.springframework.context.event.EventListener;
import java.security.InvalidParameterException;
import static org.apache.commons.lang3.StringUtils.isBlank; import static org.apache.commons.lang3.StringUtils.isBlank;
public class TermVersionAdapterSvcR4 extends BaseTermVersionAdapterSvcImpl implements ITermVersionAdapterSvc { public class TermVersionAdapterSvcR4 extends BaseTermVersionAdapterSvcImpl implements ITermVersionAdapterSvc {
@ -63,6 +65,9 @@ public class TermVersionAdapterSvcR4 extends BaseTermVersionAdapterSvcImpl imple
public IIdType createOrUpdateCodeSystem(org.hl7.fhir.r4.model.CodeSystem theCodeSystemResource, RequestDetails theRequestDetails) { public IIdType createOrUpdateCodeSystem(org.hl7.fhir.r4.model.CodeSystem theCodeSystemResource, RequestDetails theRequestDetails) {
validateCodeSystemForStorage(theCodeSystemResource); validateCodeSystemForStorage(theCodeSystemResource);
if (isBlank(theCodeSystemResource.getIdElement().getIdPart())) { if (isBlank(theCodeSystemResource.getIdElement().getIdPart())) {
if (theCodeSystemResource.getUrl().contains("loinc")) {
throw new InvalidParameterException("LOINC CodeSystem must have an 'ID' element");
}
String matchUrl = "CodeSystem?url=" + UrlUtil.escapeUrlParam(theCodeSystemResource.getUrl()); String matchUrl = "CodeSystem?url=" + UrlUtil.escapeUrlParam(theCodeSystemResource.getUrl());
return myCodeSystemResourceDao.update(theCodeSystemResource, matchUrl, theRequestDetails).getId(); return myCodeSystemResourceDao.update(theCodeSystemResource, matchUrl, theRequestDetails).getId();
} else { } else {

View File

@ -501,7 +501,8 @@ public class FhirResourceDaoR4ValidateTest extends BaseJpaR4Test {
cs.setContent(CodeSystem.CodeSystemContentMode.COMPLETE); cs.setContent(CodeSystem.CodeSystemContentMode.COMPLETE);
cs.setUrl("http://loinc.org"); cs.setUrl("http://loinc.org");
cs.addConcept().setCode("123-4").setDisplay("Code 123 4"); cs.addConcept().setCode("123-4").setDisplay("Code 123 4");
myCodeSystemDao.create(cs); cs.setId("loinc");
myCodeSystemDao.update(cs);
Group group = new Group(); Group group = new Group();
group.setId("ABC"); group.setId("ABC");
@ -567,8 +568,8 @@ public class FhirResourceDaoR4ValidateTest extends BaseJpaR4Test {
CodeSystem cs = new CodeSystem(); CodeSystem cs = new CodeSystem();
cs.setContent(CodeSystem.CodeSystemContentMode.COMPLETE); cs.setContent(CodeSystem.CodeSystemContentMode.COMPLETE);
cs.setUrl("http://loinc.org"); cs.setUrl("http://loinc.org");
cs.addConcept().setCode("123-4").setDisplay("Code 123 4"); cs.addConcept().setCode("123-4").setDisplay("Code 123 4").setId("loinc");
myCodeSystemDao.create(cs); myCodeSystemDao.update(cs);
Group group = new Group(); Group group = new Group();
group.setId("ABC"); group.setId("ABC");
@ -628,14 +629,15 @@ public class FhirResourceDaoR4ValidateTest extends BaseJpaR4Test {
ValueSet vs = new ValueSet(); ValueSet vs = new ValueSet();
vs.setUrl("http://example.com/fhir/ValueSet/observation-vitalsignresult"); vs.setUrl("http://example.com/fhir/ValueSet/observation-vitalsignresult");
vs.getCompose().addInclude().setSystem("http://loinc.org"); vs.getCompose().addInclude().setSystem("http://loinc.org").setId("loinc");
myValueSetDao.create(vs); myValueSetDao.create(vs);
CodeSystem cs = new CodeSystem(); CodeSystem cs = new CodeSystem();
cs.setContent(CodeSystem.CodeSystemContentMode.COMPLETE); cs.setContent(CodeSystem.CodeSystemContentMode.COMPLETE);
cs.setUrl("http://loinc.org"); cs.setUrl("http://loinc.org");
cs.addConcept().setCode("123-4").setDisplay("Code 123 4"); cs.addConcept().setCode("123-4").setDisplay("Code 123 4");
myCodeSystemDao.create(cs); cs.setId("loinc");
myCodeSystemDao.update(cs);
Group group = new Group(); Group group = new Group();
group.setId("ABC"); group.setId("ABC");
@ -936,6 +938,7 @@ public class FhirResourceDaoR4ValidateTest extends BaseJpaR4Test {
// Valid code // Valid code
obs.getText().setStatus(Narrative.NarrativeStatus.GENERATED); obs.getText().setStatus(Narrative.NarrativeStatus.GENERATED);
obs.getCode().getCodingFirstRep().setSystem("http://loinc.org").setCode("CODE3").setDisplay("Display 3"); obs.getCode().getCodingFirstRep().setSystem("http://loinc.org").setCode("CODE3").setDisplay("Display 3");
obs.getCode().getCodingFirstRep().setId("loinc");
oo = validateAndReturnOutcome(obs); oo = validateAndReturnOutcome(obs);
assertEquals("No issues detected during validation", oo.getIssueFirstRep().getDiagnostics(), encode(oo)); assertEquals("No issues detected during validation", oo.getIssueFirstRep().getDiagnostics(), encode(oo));