Make sure the validator can get at codes defined in notpresent
codesystems
This commit is contained in:
parent
94f87e7282
commit
cc0df9850c
|
@ -108,9 +108,13 @@ public class OperationOutcomeUtil {
|
|||
if (theOutcome == null) {
|
||||
return false;
|
||||
}
|
||||
return getIssueCount(theCtx, theOutcome) > 0;
|
||||
}
|
||||
|
||||
public static int getIssueCount(FhirContext theCtx, IBaseOperationOutcome theOutcome) {
|
||||
RuntimeResourceDefinition ooDef = theCtx.getResourceDefinition(theOutcome);
|
||||
BaseRuntimeChildDefinition issueChild = ooDef.getChildByName("issue");
|
||||
return issueChild.getAccessor().getValues(theOutcome).size() > 0;
|
||||
return issueChild.getAccessor().getValues(theOutcome).size();
|
||||
}
|
||||
|
||||
public static IBaseOperationOutcome newInstance(FhirContext theCtx) {
|
||||
|
@ -152,5 +156,4 @@ public class OperationOutcomeUtil {
|
|||
locationChild.getMutator().addValue(theIssue, locationElem);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -173,4 +173,11 @@ public class TermCodeSystemVersion implements Serializable {
|
|||
"Version ID exceeds maximum length (" + MAX_VERSION_LENGTH + "): " + length(theCodeSystemDisplayName));
|
||||
myCodeSystemDisplayName = theCodeSystemDisplayName;
|
||||
}
|
||||
|
||||
public TermConcept addConcept() {
|
||||
TermConcept concept = new TermConcept();
|
||||
concept.setCodeSystemVersion(this);
|
||||
getConcepts().add(concept);
|
||||
return concept;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,10 +5,6 @@ import ca.uhn.fhir.jpa.dao.IFhirResourceDao;
|
|||
import ca.uhn.fhir.jpa.dao.IFhirResourceDaoValueSet.ValidateCodeResult;
|
||||
import ca.uhn.fhir.jpa.entity.TermConcept;
|
||||
import ca.uhn.fhir.jpa.model.entity.ResourceTable;
|
||||
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
||||
import ca.uhn.fhir.rest.api.server.IBundleProvider;
|
||||
import ca.uhn.fhir.rest.param.StringParam;
|
||||
import ca.uhn.fhir.rest.param.UriParam;
|
||||
import ca.uhn.fhir.util.CoverageIgnore;
|
||||
import ca.uhn.fhir.util.UrlUtil;
|
||||
import org.hl7.fhir.instance.model.api.IBaseDatatype;
|
||||
|
@ -174,13 +170,6 @@ public class HapiTerminologySvcR4 extends BaseHapiTerminologySvcImpl implements
|
|||
@CoverageIgnore
|
||||
@Override
|
||||
public CodeSystem fetchCodeSystem(FhirContext theContext, String theSystem) {
|
||||
SearchParameterMap map = new SearchParameterMap();
|
||||
map.add(CodeSystem.SP_URL, new UriParam(theSystem));
|
||||
map.setLoadSynchronousUpTo(1);
|
||||
IBundleProvider outcome = myCodeSystemResourceDao.search(map);
|
||||
if (outcome.size() > 0) {
|
||||
return (CodeSystem) outcome.getResources(0, 1).get(0);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
|
|
@ -5,10 +5,6 @@ import ca.uhn.fhir.jpa.dao.IFhirResourceDao;
|
|||
import ca.uhn.fhir.jpa.dao.IFhirResourceDaoValueSet.ValidateCodeResult;
|
||||
import ca.uhn.fhir.jpa.entity.TermConcept;
|
||||
import ca.uhn.fhir.jpa.model.entity.ResourceTable;
|
||||
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
||||
import ca.uhn.fhir.rest.api.server.IBundleProvider;
|
||||
import ca.uhn.fhir.rest.param.StringParam;
|
||||
import ca.uhn.fhir.rest.param.UriParam;
|
||||
import ca.uhn.fhir.util.CoverageIgnore;
|
||||
import ca.uhn.fhir.util.UrlUtil;
|
||||
import ca.uhn.fhir.util.ValidateUtil;
|
||||
|
@ -185,13 +181,6 @@ public class HapiTerminologySvcR5 extends BaseHapiTerminologySvcImpl implements
|
|||
@CoverageIgnore
|
||||
@Override
|
||||
public CodeSystem fetchCodeSystem(FhirContext theContext, String theSystem) {
|
||||
SearchParameterMap map = new SearchParameterMap();
|
||||
map.add(org.hl7.fhir.r5.model.CodeSystem.SP_URL, new UriParam(theSystem));
|
||||
map.setLoadSynchronousUpTo(1);
|
||||
IBundleProvider outcome = myCodeSystemResourceDao.search(map);
|
||||
if (outcome.size() > 0) {
|
||||
return (org.hl7.fhir.r5.model.CodeSystem) outcome.getResources(0, 1).get(0);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -281,7 +270,7 @@ public class HapiTerminologySvcR5 extends BaseHapiTerminologySvcImpl implements
|
|||
public IValidationSupport.CodeValidationResult validateCode(FhirContext theContext, String theCodeSystem, String theCode, String theDisplay) {
|
||||
TransactionTemplate txTemplate = new TransactionTemplate(myTransactionManager);
|
||||
txTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
|
||||
return txTemplate.execute(t-> {
|
||||
return txTemplate.execute(t -> {
|
||||
Optional<TermConcept> codeOpt = findCode(theCodeSystem, theCode);
|
||||
if (codeOpt.isPresent()) {
|
||||
TermConcept code = codeOpt.get();
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
package ca.uhn.fhir.jpa.dao.r4;
|
||||
|
||||
import ca.uhn.fhir.jpa.dao.DaoConfig;
|
||||
import ca.uhn.fhir.jpa.entity.TermCodeSystemVersion;
|
||||
import ca.uhn.fhir.jpa.term.IHapiTerminologySvc;
|
||||
import ca.uhn.fhir.rest.api.EncodingEnum;
|
||||
import ca.uhn.fhir.rest.api.MethodOutcome;
|
||||
import ca.uhn.fhir.rest.api.ValidationModeEnum;
|
||||
|
@ -8,10 +10,12 @@ import ca.uhn.fhir.rest.server.exceptions.PreconditionFailedException;
|
|||
import ca.uhn.fhir.rest.server.exceptions.ResourceGoneException;
|
||||
import ca.uhn.fhir.rest.server.exceptions.ResourceVersionConflictException;
|
||||
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
|
||||
import ca.uhn.fhir.util.OperationOutcomeUtil;
|
||||
import ca.uhn.fhir.util.StopWatch;
|
||||
import ca.uhn.fhir.util.TestUtil;
|
||||
import ca.uhn.fhir.validation.IValidatorModule;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.hl7.fhir.instance.model.api.IBaseOperationOutcome;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.hl7.fhir.instance.model.api.IIdType;
|
||||
import org.hl7.fhir.r4.hapi.validation.FhirInstanceValidator;
|
||||
|
@ -28,16 +32,18 @@ import org.springframework.test.util.AopTestUtils;
|
|||
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Collections;
|
||||
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.hamcrest.Matchers.not;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.junit.Assert.fail;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
public class FhirResourceDaoR4ValidateTest extends BaseJpaR4Test {
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(FhirResourceDaoR4ValidateTest.class);
|
||||
@Autowired
|
||||
private IValidatorModule myValidatorModule;
|
||||
@Autowired
|
||||
private IHapiTerminologySvc myTerminologySvc;
|
||||
|
||||
@Test
|
||||
public void testValidateStructureDefinition() throws Exception {
|
||||
|
@ -106,6 +112,43 @@ public class FhirResourceDaoR4ValidateTest extends BaseJpaR4Test {
|
|||
assertThat(ooString, containsString("Element '/f:Observation.device': minimum required = 1, but only found 0"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testValidateUsingExternallyDefinedCode() {
|
||||
CodeSystem codeSystem = new CodeSystem();
|
||||
codeSystem.setUrl("http://foo");
|
||||
codeSystem.setContent(CodeSystem.CodeSystemContentMode.NOTPRESENT);
|
||||
IIdType csId = myCodeSystemDao.create(codeSystem).getId();
|
||||
|
||||
TermCodeSystemVersion csv = new TermCodeSystemVersion();
|
||||
csv.addConcept().setCode("bar").setDisplay("Bar Code");
|
||||
myTerminologySvc.storeNewCodeSystemVersion(codeSystem, csv, mySrd, Collections.emptyList(), Collections.emptyList());
|
||||
|
||||
// Validate a resource containing this codesystem in a field with an extendable binding
|
||||
Patient patient = new Patient();
|
||||
patient.getText().setStatus(Narrative.NarrativeStatus.GENERATED).setDivAsString("<div>hello</div>");
|
||||
patient
|
||||
.addIdentifier()
|
||||
.setSystem("http://example.com")
|
||||
.setValue("12345")
|
||||
.getType()
|
||||
.addCoding()
|
||||
.setSystem("http://foo")
|
||||
.setCode("bar");
|
||||
MethodOutcome outcome = myPatientDao.validate(patient, null, encode(patient), EncodingEnum.JSON, ValidationModeEnum.CREATE, null, mySrd);
|
||||
IBaseOperationOutcome oo = outcome.getOperationOutcome();
|
||||
ourLog.info(myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(oo));
|
||||
|
||||
// It would be ok for this to produce 0 issues, or just an information message too
|
||||
assertEquals(1, OperationOutcomeUtil.getIssueCount(myFhirCtx, oo));
|
||||
assertEquals("None of the codes provided are in the value set http://hl7.org/fhir/ValueSet/identifier-type (http://hl7.org/fhir/ValueSet/identifier-type, and a code should come from this value set unless it has no suitable code) (codes = http://foo#bar)", OperationOutcomeUtil.getFirstIssueDetails(myFhirCtx, oo));
|
||||
|
||||
}
|
||||
|
||||
private String encode(Patient thePatient) {
|
||||
return myFhirCtx.newJsonParser().encodeResourceToString(thePatient);
|
||||
}
|
||||
|
||||
|
||||
private OperationOutcome doTestValidateResourceContainingProfileDeclaration(String methodName, EncodingEnum enc) throws IOException {
|
||||
Bundle vss = loadResourceFromClasspath(Bundle.class, "/org/hl7/fhir/r4/model/valueset/valuesets.xml");
|
||||
myValueSetDao.update((ValueSet) findResourceByIdInBundle(vss, "observation-status"), mySrd);
|
||||
|
|
|
@ -98,11 +98,9 @@ public class ValidationSupportChain implements IValidationSupport {
|
|||
@Override
|
||||
public CodeSystem fetchCodeSystem(FhirContext theCtx, String theSystem) {
|
||||
for (IValidationSupport next : myChain) {
|
||||
if (next.isCodeSystemSupported(theCtx, theSystem)) {
|
||||
CodeSystem retVal = next.fetchCodeSystem(theCtx, theSystem);
|
||||
if (retVal != null) {
|
||||
return retVal;
|
||||
}
|
||||
CodeSystem retVal = next.fetchCodeSystem(theCtx, theSystem);
|
||||
if (retVal != null) {
|
||||
return retVal;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
|
|
|
@ -77,11 +77,9 @@ public class ValidationSupportChain implements IValidationSupport {
|
|||
@Override
|
||||
public CodeSystem fetchCodeSystem(FhirContext theCtx, String theSystem) {
|
||||
for (IValidationSupport next : myChain) {
|
||||
if (next.isCodeSystemSupported(theCtx, theSystem)) {
|
||||
CodeSystem retVal = next.fetchCodeSystem(theCtx, theSystem);
|
||||
if (retVal != null) {
|
||||
return retVal;
|
||||
}
|
||||
CodeSystem retVal = next.fetchCodeSystem(theCtx, theSystem);
|
||||
if (retVal != null) {
|
||||
return retVal;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
|
|
|
@ -75,11 +75,9 @@ public class ValidationSupportChain implements IValidationSupport {
|
|||
@Override
|
||||
public CodeSystem fetchCodeSystem(FhirContext theCtx, String theSystem) {
|
||||
for (IValidationSupport next : myChain) {
|
||||
if (next.isCodeSystemSupported(theCtx, theSystem)) {
|
||||
CodeSystem retVal = next.fetchCodeSystem(theCtx, theSystem);
|
||||
if (retVal != null) {
|
||||
return retVal;
|
||||
}
|
||||
CodeSystem retVal = next.fetchCodeSystem(theCtx, theSystem);
|
||||
if (retVal != null) {
|
||||
return retVal;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
|
|
|
@ -218,6 +218,10 @@
|
|||
handled by method implementations that did not have any <![CDATA[<code>@IncludeParam</code>]]> defined. This
|
||||
is now corrected. Thanks to Tuomo Ala-Vannesluoma for reporting and providing a test case!
|
||||
</action>
|
||||
<action type="fix">
|
||||
The JPA server failed to find codes defined in not-present codesystems in some cases, and reported
|
||||
that the CodeSystem did not exist. This has been corrected.
|
||||
</action>
|
||||
</release>
|
||||
<release version="4.0.3" date="2019-09-03" description="Igloo (Point Release)">
|
||||
<action type="fix">
|
||||
|
|
Loading…
Reference in New Issue