Fix handling of filters on valueset expansions
This commit is contained in:
parent
12e047b931
commit
f1828d1ca8
|
@ -10,7 +10,7 @@ package ca.uhn.fhir.jpa.dao.dstu3;
|
|||
* 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
|
||||
* 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,
|
||||
|
@ -33,6 +33,7 @@ import org.hl7.fhir.dstu3.model.CodeSystem;
|
|||
import org.hl7.fhir.dstu3.model.CodeableConcept;
|
||||
import org.hl7.fhir.dstu3.model.Coding;
|
||||
import org.hl7.fhir.dstu3.model.Enumerations.PublicationStatus;
|
||||
import org.hl7.fhir.dstu3.model.IntegerType;
|
||||
import org.hl7.fhir.dstu3.model.UriType;
|
||||
import org.hl7.fhir.dstu3.model.ValueSet;
|
||||
import org.hl7.fhir.dstu3.model.ValueSet.ConceptSetComponent;
|
||||
|
@ -82,12 +83,12 @@ public class FhirResourceDaoValueSetDstu3 extends FhirResourceDaoDstu3<ValueSet>
|
|||
|
||||
return retVal;
|
||||
|
||||
// ValueSetExpansionComponent expansion = outcome.getValueset().getExpansion();
|
||||
// ValueSetExpansionComponent expansion = outcome.getValueset().getExpansion();
|
||||
//
|
||||
// ValueSet retVal = new ValueSet();
|
||||
// retVal.getMeta().setLastUpdated(new Date());
|
||||
// retVal.setExpansion(expansion);
|
||||
// return retVal;
|
||||
// ValueSet retVal = new ValueSet();
|
||||
// retVal.getMeta().setLastUpdated(new Date());
|
||||
// retVal.setExpansion(expansion);
|
||||
// return retVal;
|
||||
}
|
||||
|
||||
private void validateIncludes(String name, List<ConceptSetComponent> listToValidate) {
|
||||
|
@ -137,11 +138,11 @@ public class FhirResourceDaoValueSetDstu3 extends FhirResourceDaoDstu3<ValueSet>
|
|||
public ValueSet expand(ValueSet source, String theFilter) {
|
||||
ValueSet toExpand = new ValueSet();
|
||||
|
||||
// for (UriType next : source.getCompose().getInclude()) {
|
||||
// ConceptSetComponent include = toExpand.getCompose().addInclude();
|
||||
// include.setSystem(next.getValue());
|
||||
// addFilterIfPresent(theFilter, include);
|
||||
// }
|
||||
// for (UriType next : source.getCompose().getInclude()) {
|
||||
// ConceptSetComponent include = toExpand.getCompose().addInclude();
|
||||
// include.setSystem(next.getValue());
|
||||
// addFilterIfPresent(theFilter, include);
|
||||
// }
|
||||
|
||||
for (ConceptSetComponent next : source.getCompose().getInclude()) {
|
||||
toExpand.getCompose().addInclude(next);
|
||||
|
@ -155,18 +156,41 @@ public class FhirResourceDaoValueSetDstu3 extends FhirResourceDaoDstu3<ValueSet>
|
|||
toExpand.getCompose().getExclude().addAll(source.getCompose().getExclude());
|
||||
|
||||
ValueSet retVal = doExpand(toExpand);
|
||||
|
||||
if (isNotBlank(theFilter)) {
|
||||
applyFilter(retVal.getExpansion().getTotalElement(), retVal.getExpansion().getContains(), theFilter);
|
||||
}
|
||||
|
||||
return retVal;
|
||||
|
||||
}
|
||||
|
||||
private void applyFilter(IntegerType theTotalElement, List<ValueSetExpansionContainsComponent> theContains, String theFilter) {
|
||||
|
||||
for (int idx = 0; idx < theContains.size(); idx++) {
|
||||
ValueSetExpansionContainsComponent next = theContains.get(idx);
|
||||
if (isBlank(next.getDisplay()) || !org.apache.commons.lang3.StringUtils.containsIgnoreCase(next.getDisplay(), theFilter)) {
|
||||
theContains.remove(idx);
|
||||
idx--;
|
||||
if (theTotalElement.getValue() != null) {
|
||||
theTotalElement.setValue(theTotalElement.getValue() - 1);
|
||||
}
|
||||
}
|
||||
applyFilter(theTotalElement, next.getContains(), theFilter);
|
||||
}
|
||||
}
|
||||
|
||||
private void addFilterIfPresent(String theFilter, ConceptSetComponent include) {
|
||||
if (isNotBlank(theFilter)) {
|
||||
include.addFilter().setProperty("display").setOp(FilterOperator.EQUAL).setValue(theFilter);
|
||||
if (ElementUtil.isEmpty(include.getConcept())) {
|
||||
if (isNotBlank(theFilter)) {
|
||||
include.addFilter().setProperty("display").setOp(FilterOperator.EQUAL).setValue(theFilter);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ca.uhn.fhir.jpa.dao.IFhirResourceDaoValueSet.ValidateCodeResult validateCode(IPrimitiveType<String> theValueSetIdentifier, IIdType theId, IPrimitiveType<String> theCode, IPrimitiveType<String> theSystem, IPrimitiveType<String> theDisplay, Coding theCoding,
|
||||
public ca.uhn.fhir.jpa.dao.IFhirResourceDaoValueSet.ValidateCodeResult validateCode(IPrimitiveType<String> theValueSetIdentifier, IIdType theId, IPrimitiveType<String> theCode,
|
||||
IPrimitiveType<String> theSystem, IPrimitiveType<String> theDisplay, Coding theCoding,
|
||||
CodeableConcept theCodeableConcept, RequestDetails theRequestDetails) {
|
||||
|
||||
List<IIdType> valueSetIds = Collections.emptyList();
|
||||
|
@ -226,7 +250,8 @@ public class FhirResourceDaoValueSetDstu3 extends FhirResourceDaoDstu3<ValueSet>
|
|||
return thePrimitive != null ? thePrimitive.getValue() : null;
|
||||
}
|
||||
|
||||
private ca.uhn.fhir.jpa.dao.IFhirResourceDaoValueSet.ValidateCodeResult validateCodeIsInContains(List<ValueSetExpansionContainsComponent> contains, String theSystem, String theCode, Coding theCoding, CodeableConcept theCodeableConcept) {
|
||||
private ca.uhn.fhir.jpa.dao.IFhirResourceDaoValueSet.ValidateCodeResult validateCodeIsInContains(List<ValueSetExpansionContainsComponent> contains, String theSystem, String theCode,
|
||||
Coding theCoding, CodeableConcept theCodeableConcept) {
|
||||
for (ValueSetExpansionContainsComponent nextCode : contains) {
|
||||
ca.uhn.fhir.jpa.dao.IFhirResourceDaoValueSet.ValidateCodeResult result = validateCodeIsInContains(nextCode.getContains(), theSystem, theCode, theCoding, theCodeableConcept);
|
||||
if (result != null) {
|
||||
|
|
|
@ -16,6 +16,7 @@ import org.hl7.fhir.dstu3.model.AllergyIntolerance.AllergyIntoleranceCategory;
|
|||
import org.hl7.fhir.dstu3.model.AllergyIntolerance.AllergyIntoleranceClinicalStatus;
|
||||
import org.hl7.fhir.dstu3.model.CodeSystem.CodeSystemContentMode;
|
||||
import org.hl7.fhir.dstu3.model.CodeSystem.ConceptDefinitionComponent;
|
||||
import org.hl7.fhir.dstu3.model.ValueSet.ConceptReferenceComponent;
|
||||
import org.hl7.fhir.dstu3.model.ValueSet.ConceptSetComponent;
|
||||
import org.hl7.fhir.dstu3.model.ValueSet.FilterOperator;
|
||||
import org.hl7.fhir.dstu3.model.ValueSet.ValueSetComposeComponent;
|
||||
|
@ -53,6 +54,9 @@ public class FhirResourceDaoDstu3TerminologyTest extends BaseJpaDstu3Test {
|
|||
public static final String URL_MY_CODE_SYSTEM = "http://example.com/my_code_system";
|
||||
public static final String URL_MY_VALUE_SET = "http://example.com/my_value_set";
|
||||
|
||||
@Autowired
|
||||
private IHapiTerminologySvc myHapiTerminologySvc;
|
||||
|
||||
@After
|
||||
public void after() {
|
||||
myDaoConfig.setDeferIndexingForCodesystemsOfSize(new DaoConfig().getDeferIndexingForCodesystemsOfSize());
|
||||
|
@ -116,6 +120,37 @@ public class FhirResourceDaoDstu3TerminologyTest extends BaseJpaDstu3Test {
|
|||
createLocalVs(codeSystem);
|
||||
}
|
||||
|
||||
private CodeSystem createExternalCsDogs() {
|
||||
CodeSystem codeSystem = new CodeSystem();
|
||||
codeSystem.setUrl(URL_MY_CODE_SYSTEM);
|
||||
codeSystem.setContent(CodeSystemContentMode.NOTPRESENT);
|
||||
IIdType id = myCodeSystemDao.create(codeSystem, mySrd).getId().toUnqualified();
|
||||
|
||||
ResourceTable table = myResourceTableDao.findOne(id.getIdPartAsLong());
|
||||
|
||||
TermCodeSystemVersion cs = new TermCodeSystemVersion();
|
||||
cs.setResource(table);
|
||||
cs.setResourceVersionId(table.getVersion());
|
||||
|
||||
TermConcept hello = new TermConcept(cs, "hello").setDisplay("Hello");
|
||||
cs.getConcepts().add(hello);
|
||||
|
||||
TermConcept goodbye = new TermConcept(cs, "goodbye").setDisplay("Goodbye");
|
||||
cs.getConcepts().add(goodbye);
|
||||
|
||||
TermConcept dogs = new TermConcept(cs, "dogs").setDisplay("Dogs");
|
||||
cs.getConcepts().add(dogs);
|
||||
|
||||
TermConcept labrador = new TermConcept(cs, "labrador").setDisplay("Labrador");
|
||||
dogs.addChild(labrador, RelationshipTypeEnum.ISA);
|
||||
|
||||
TermConcept beagle = new TermConcept(cs, "beagle").setDisplay("Beagle");
|
||||
dogs.addChild(beagle, RelationshipTypeEnum.ISA);
|
||||
|
||||
myTermSvc.storeNewCodeSystemVersion(table.getId(), URL_MY_CODE_SYSTEM, cs);
|
||||
return codeSystem;
|
||||
}
|
||||
|
||||
private void createLocalCsAndVs() {
|
||||
//@formatter:off
|
||||
CodeSystem codeSystem = new CodeSystem();
|
||||
|
@ -144,6 +179,22 @@ public class FhirResourceDaoDstu3TerminologyTest extends BaseJpaDstu3Test {
|
|||
myValueSetDao.create(valueSet, mySrd);
|
||||
}
|
||||
|
||||
private void logAndValidateValueSet(ValueSet theResult) {
|
||||
IParser parser = myFhirCtx.newXmlParser().setPrettyPrint(true);
|
||||
String encoded = parser.encodeResourceToString(theResult);
|
||||
ourLog.info(encoded);
|
||||
|
||||
FhirValidator validator = myFhirCtx.newValidator();
|
||||
validator.setValidateAgainstStandardSchema(true);
|
||||
validator.setValidateAgainstStandardSchematron(true);
|
||||
ValidationResult result = validator.validateWithResult(theResult);
|
||||
|
||||
if (!result.isSuccessful()) {
|
||||
ourLog.info(parser.encodeResourceToString(result.toOperationOutcome()));
|
||||
fail(parser.encodeResourceToString(result.toOperationOutcome()));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCodeSystemCreateDuplicateFails() {
|
||||
CodeSystem codeSystem = new CodeSystem();
|
||||
|
@ -162,28 +213,6 @@ public class FhirResourceDaoDstu3TerminologyTest extends BaseJpaDstu3Test {
|
|||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLookupSnomed() {
|
||||
CodeSystem codeSystem = new CodeSystem();
|
||||
codeSystem.setUrl("http://snomed.info/sct");
|
||||
codeSystem.setContent(CodeSystemContentMode.NOTPRESENT);
|
||||
IIdType id = myCodeSystemDao.create(codeSystem, mySrd).getId().toUnqualified();
|
||||
|
||||
ResourceTable table = myResourceTableDao.findOne(id.getIdPartAsLong());
|
||||
|
||||
TermCodeSystemVersion cs = new TermCodeSystemVersion();
|
||||
cs.setResource(table);
|
||||
cs.setResourceVersionId(table.getVersion());
|
||||
TermConcept parentA = new TermConcept(cs, "ParentA").setDisplay("Parent A");
|
||||
cs.getConcepts().add(parentA);
|
||||
myTermSvc.storeNewCodeSystemVersion(table.getId(), "http://snomed.info/sct", cs);
|
||||
|
||||
StringType code = new StringType("ParentA");
|
||||
StringType system = new StringType("http://snomed.info/sct");
|
||||
LookupCodeResult outcome = myCodeSystemDao.lookupCode(code, system, null, mySrd);
|
||||
assertEquals(true, outcome.isFound());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCodeSystemWithDefinedCodes() {
|
||||
//@formatter:off
|
||||
|
@ -207,170 +236,6 @@ public class FhirResourceDaoDstu3TerminologyTest extends BaseJpaDstu3Test {
|
|||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExpandWithExcludeInExternalValueSet() {
|
||||
createExternalCsAndLocalVs();
|
||||
|
||||
ValueSet vs = new ValueSet();
|
||||
ConceptSetComponent include = vs.getCompose().addInclude();
|
||||
include.setSystem(URL_MY_CODE_SYSTEM);
|
||||
|
||||
ConceptSetComponent exclude = vs.getCompose().addExclude();
|
||||
exclude.setSystem(URL_MY_CODE_SYSTEM);
|
||||
exclude.addConcept().setCode("childAA");
|
||||
exclude.addConcept().setCode("childAAA");
|
||||
|
||||
ValueSet result = myValueSetDao.expand(vs, null);
|
||||
logAndValidateValueSet(result);
|
||||
|
||||
ArrayList<String> codes = toCodesContains(result.getExpansion().getContains());
|
||||
assertThat(codes, containsInAnyOrder("ParentA", "ParentB", "childAB", "childAAB", "ParentC", "childBA", "childCA"));
|
||||
}
|
||||
|
||||
private void logAndValidateValueSet(ValueSet theResult) {
|
||||
IParser parser = myFhirCtx.newXmlParser().setPrettyPrint(true);
|
||||
String encoded = parser.encodeResourceToString(theResult);
|
||||
ourLog.info(encoded);
|
||||
|
||||
FhirValidator validator = myFhirCtx.newValidator();
|
||||
validator.setValidateAgainstStandardSchema(true);
|
||||
validator.setValidateAgainstStandardSchematron(true);
|
||||
ValidationResult result = validator.validateWithResult(theResult);
|
||||
|
||||
if (!result.isSuccessful()) {
|
||||
ourLog.info(parser.encodeResourceToString(result.toOperationOutcome()));
|
||||
fail(parser.encodeResourceToString(result.toOperationOutcome()));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExpandWithInvalidExclude() {
|
||||
createExternalCsAndLocalVs();
|
||||
|
||||
ValueSet vs = new ValueSet();
|
||||
ConceptSetComponent include = vs.getCompose().addInclude();
|
||||
include.setSystem(URL_MY_CODE_SYSTEM);
|
||||
|
||||
/*
|
||||
* No system set on exclude
|
||||
*/
|
||||
ConceptSetComponent exclude = vs.getCompose().addExclude();
|
||||
exclude.addConcept().setCode("childAA");
|
||||
exclude.addConcept().setCode("childAAA");
|
||||
try {
|
||||
myValueSetDao.expand(vs, null);
|
||||
fail();
|
||||
} catch (InvalidRequestException e) {
|
||||
assertEquals("ValueSet contains exclude criteria with no system defined", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExpandWithNoResultsInLocalValueSet1() {
|
||||
createLocalCsAndVs();
|
||||
|
||||
ValueSet vs = new ValueSet();
|
||||
ConceptSetComponent include = vs.getCompose().addInclude();
|
||||
include.setSystem(URL_MY_CODE_SYSTEM);
|
||||
include.addConcept().setCode("ZZZZ");
|
||||
|
||||
try {
|
||||
myValueSetDao.expand(vs, null);
|
||||
fail();
|
||||
} catch (InvalidRequestException e) {
|
||||
assertEquals("Unable to find code 'ZZZZ' in code system http://example.com/my_code_system", e.getMessage());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReindex() {
|
||||
createLocalCsAndVs();
|
||||
|
||||
ValueSet vs = new ValueSet();
|
||||
ConceptSetComponent include = vs.getCompose().addInclude();
|
||||
include.setSystem(URL_MY_CODE_SYSTEM);
|
||||
include.addConcept().setCode("ZZZZ");
|
||||
|
||||
mySystemDao.markAllResourcesForReindexing();
|
||||
mySystemDao.performReindexingPass(null);
|
||||
myTermSvc.saveDeferred();
|
||||
mySystemDao.performReindexingPass(null);
|
||||
myTermSvc.saveDeferred();
|
||||
|
||||
// Again
|
||||
mySystemDao.markAllResourcesForReindexing();
|
||||
mySystemDao.performReindexingPass(null);
|
||||
myTermSvc.saveDeferred();
|
||||
mySystemDao.performReindexingPass(null);
|
||||
myTermSvc.saveDeferred();
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExpandWithNoResultsInLocalValueSet2() {
|
||||
createLocalCsAndVs();
|
||||
|
||||
ValueSet vs = new ValueSet();
|
||||
ConceptSetComponent include = vs.getCompose().addInclude();
|
||||
include.setSystem(URL_MY_CODE_SYSTEM + "AA");
|
||||
include.addConcept().setCode("A");
|
||||
|
||||
try {
|
||||
myValueSetDao.expand(vs, null);
|
||||
fail();
|
||||
} catch (InvalidRequestException e) {
|
||||
assertEquals("unable to find code system http://example.com/my_code_systemAA", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExpandWithIsAInExternalValueSet() {
|
||||
createExternalCsAndLocalVs();
|
||||
|
||||
ValueSet vs = new ValueSet();
|
||||
ConceptSetComponent include = vs.getCompose().addInclude();
|
||||
include.setSystem(URL_MY_CODE_SYSTEM);
|
||||
include.addFilter().setOp(FilterOperator.ISA).setValue("childAA").setProperty("concept");
|
||||
|
||||
ValueSet result = myValueSetDao.expand(vs, null);
|
||||
logAndValidateValueSet(result);
|
||||
|
||||
ArrayList<String> codes = toCodesContains(result.getExpansion().getContains());
|
||||
assertThat(codes, containsInAnyOrder("childAAA", "childAAB"));
|
||||
|
||||
}
|
||||
|
||||
@Autowired
|
||||
private IHapiTerminologySvc myHapiTerminologySvc;
|
||||
|
||||
@Test
|
||||
public void testExpandWithIsAInExternalValueSetReindex() {
|
||||
BaseHapiTerminologySvc.setForceSaveDeferredAlwaysForUnitTest(true);
|
||||
|
||||
createExternalCsAndLocalVs();
|
||||
|
||||
mySystemDao.markAllResourcesForReindexing();
|
||||
|
||||
mySystemDao.performReindexingPass(100);
|
||||
mySystemDao.performReindexingPass(100);
|
||||
myHapiTerminologySvc.saveDeferred();
|
||||
myHapiTerminologySvc.saveDeferred();
|
||||
myHapiTerminologySvc.saveDeferred();
|
||||
|
||||
ValueSet vs = new ValueSet();
|
||||
ConceptSetComponent include = vs.getCompose().addInclude();
|
||||
include.setSystem(URL_MY_CODE_SYSTEM);
|
||||
include.addFilter().setOp(FilterOperator.ISA).setValue("childAA").setProperty("concept");
|
||||
|
||||
ValueSet result = myValueSetDao.expand(vs, null);
|
||||
logAndValidateValueSet(result);
|
||||
|
||||
ArrayList<String> codes = toCodesContains(result.getExpansion().getContains());
|
||||
assertThat(codes, containsInAnyOrder("childAAA", "childAAB"));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExpandInvalid() {
|
||||
createExternalCsAndLocalVs();
|
||||
|
@ -390,43 +255,110 @@ public class FhirResourceDaoDstu3TerminologyTest extends BaseJpaDstu3Test {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testExpandWithSystemAndCodesInExternalValueSet() {
|
||||
createExternalCsAndLocalVs();
|
||||
public void testExpandWithCodesAndDisplayFilterBlank() {
|
||||
CodeSystem codeSystem = createExternalCsDogs();
|
||||
|
||||
ValueSet vs = new ValueSet();
|
||||
ConceptSetComponent include = vs.getCompose().addInclude();
|
||||
include.setSystem(URL_MY_CODE_SYSTEM);
|
||||
include.addConcept().setCode("ParentA");
|
||||
include.addConcept().setCode("childAA");
|
||||
include.addConcept().setCode("childAAA");
|
||||
ValueSet valueSet = new ValueSet();
|
||||
valueSet.setUrl(URL_MY_VALUE_SET);
|
||||
valueSet.getCompose()
|
||||
.addInclude()
|
||||
.setSystem(codeSystem.getUrl())
|
||||
.addConcept(new ConceptReferenceComponent().setCode("hello"))
|
||||
.addConcept(new ConceptReferenceComponent().setCode("goodbye"));
|
||||
valueSet.getCompose()
|
||||
.addInclude()
|
||||
.setSystem(codeSystem.getUrl())
|
||||
.addFilter()
|
||||
.setProperty("concept")
|
||||
.setOp(FilterOperator.ISA)
|
||||
.setValue("dogs");
|
||||
|
||||
myValueSetDao.create(valueSet, mySrd);
|
||||
|
||||
ValueSet result = myValueSetDao.expand(vs, null);
|
||||
ValueSet result = myValueSetDao.expand(valueSet, "");
|
||||
logAndValidateValueSet(result);
|
||||
|
||||
assertEquals(4, result.getExpansion().getTotal());
|
||||
ArrayList<String> codes = toCodesContains(result.getExpansion().getContains());
|
||||
assertThat(codes, containsInAnyOrder("ParentA", "childAA", "childAAA"));
|
||||
assertThat(codes, containsInAnyOrder("hello", "goodbye", "labrador", "beagle"));
|
||||
|
||||
int idx = codes.indexOf("childAA");
|
||||
assertEquals("childAA", result.getExpansion().getContains().get(idx).getCode());
|
||||
assertEquals("Child AA", result.getExpansion().getContains().get(idx).getDisplay());
|
||||
assertEquals(URL_MY_CODE_SYSTEM, result.getExpansion().getContains().get(idx).getSystem());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExpandWithSystemAndFilterInExternalValueSet() {
|
||||
createExternalCsAndLocalVs();
|
||||
public void testExpandWithCodesAndDisplayFilterPartialOnFilter() {
|
||||
CodeSystem codeSystem = createExternalCsDogs();
|
||||
|
||||
ValueSet vs = new ValueSet();
|
||||
ConceptSetComponent include = vs.getCompose().addInclude();
|
||||
include.setSystem(URL_MY_CODE_SYSTEM);
|
||||
ValueSet valueSet = new ValueSet();
|
||||
valueSet.setUrl(URL_MY_VALUE_SET);
|
||||
valueSet.getCompose()
|
||||
.addInclude()
|
||||
.setSystem(codeSystem.getUrl())
|
||||
.addConcept(new ConceptReferenceComponent().setCode("hello"))
|
||||
.addConcept(new ConceptReferenceComponent().setCode("goodbye"));
|
||||
valueSet.getCompose()
|
||||
.addInclude()
|
||||
.setSystem(codeSystem.getUrl())
|
||||
.addFilter()
|
||||
.setProperty("concept")
|
||||
.setOp(FilterOperator.ISA)
|
||||
.setValue("dogs");
|
||||
|
||||
myValueSetDao.create(valueSet, mySrd);
|
||||
|
||||
include.addFilter().setProperty("display").setOp(FilterOperator.EQUAL).setValue("Parent B");
|
||||
|
||||
ValueSet result = myValueSetDao.expand(vs, null);
|
||||
ValueSet result = myValueSetDao.expand(valueSet, "lab");
|
||||
logAndValidateValueSet(result);
|
||||
|
||||
assertEquals(1, result.getExpansion().getTotal());
|
||||
ArrayList<String> codes = toCodesContains(result.getExpansion().getContains());
|
||||
assertThat(codes, containsInAnyOrder("ParentB"));
|
||||
assertThat(codes, containsInAnyOrder("labrador"));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExpandWithCodesAndDisplayFilterPartialOnCodes() {
|
||||
CodeSystem codeSystem = createExternalCsDogs();
|
||||
|
||||
ValueSet valueSet = new ValueSet();
|
||||
valueSet.setUrl(URL_MY_VALUE_SET);
|
||||
valueSet.getCompose()
|
||||
.addInclude()
|
||||
.setSystem(codeSystem.getUrl())
|
||||
.addConcept(new ConceptReferenceComponent().setCode("hello"))
|
||||
.addConcept(new ConceptReferenceComponent().setCode("goodbye"));
|
||||
valueSet.getCompose()
|
||||
.addInclude()
|
||||
.setSystem(codeSystem.getUrl())
|
||||
.addFilter()
|
||||
.setProperty("concept")
|
||||
.setOp(FilterOperator.ISA)
|
||||
.setValue("dogs");
|
||||
|
||||
myValueSetDao.create(valueSet, mySrd);
|
||||
|
||||
ValueSet result = myValueSetDao.expand(valueSet, "hel");
|
||||
logAndValidateValueSet(result);
|
||||
|
||||
assertEquals(1, result.getExpansion().getTotal());
|
||||
ArrayList<String> codes = toCodesContains(result.getExpansion().getContains());
|
||||
assertThat(codes, containsInAnyOrder("hello"));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExpandWithCodesAndDisplayFilterPartialOnExpansion() {
|
||||
CodeSystem codeSystem = createExternalCsDogs();
|
||||
|
||||
ValueSet valueSet = new ValueSet();
|
||||
valueSet.setUrl(URL_MY_VALUE_SET);
|
||||
valueSet.getCompose().addInclude().setSystem(codeSystem.getUrl());
|
||||
myValueSetDao.create(valueSet, mySrd);
|
||||
|
||||
ValueSet result = myValueSetDao.expand(valueSet, "lab");
|
||||
logAndValidateValueSet(result);
|
||||
|
||||
assertEquals(1, result.getExpansion().getTotal());
|
||||
ArrayList<String> codes = toCodesContains(result.getExpansion().getContains());
|
||||
assertThat(codes, containsInAnyOrder("labrador"));
|
||||
|
||||
}
|
||||
|
||||
|
@ -463,6 +395,127 @@ public class FhirResourceDaoDstu3TerminologyTest extends BaseJpaDstu3Test {
|
|||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExpandWithExcludeInExternalValueSet() {
|
||||
createExternalCsAndLocalVs();
|
||||
|
||||
ValueSet vs = new ValueSet();
|
||||
ConceptSetComponent include = vs.getCompose().addInclude();
|
||||
include.setSystem(URL_MY_CODE_SYSTEM);
|
||||
|
||||
ConceptSetComponent exclude = vs.getCompose().addExclude();
|
||||
exclude.setSystem(URL_MY_CODE_SYSTEM);
|
||||
exclude.addConcept().setCode("childAA");
|
||||
exclude.addConcept().setCode("childAAA");
|
||||
|
||||
ValueSet result = myValueSetDao.expand(vs, null);
|
||||
logAndValidateValueSet(result);
|
||||
|
||||
ArrayList<String> codes = toCodesContains(result.getExpansion().getContains());
|
||||
assertThat(codes, containsInAnyOrder("ParentA", "ParentB", "childAB", "childAAB", "ParentC", "childBA", "childCA"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExpandWithInvalidExclude() {
|
||||
createExternalCsAndLocalVs();
|
||||
|
||||
ValueSet vs = new ValueSet();
|
||||
ConceptSetComponent include = vs.getCompose().addInclude();
|
||||
include.setSystem(URL_MY_CODE_SYSTEM);
|
||||
|
||||
/*
|
||||
* No system set on exclude
|
||||
*/
|
||||
ConceptSetComponent exclude = vs.getCompose().addExclude();
|
||||
exclude.addConcept().setCode("childAA");
|
||||
exclude.addConcept().setCode("childAAA");
|
||||
try {
|
||||
myValueSetDao.expand(vs, null);
|
||||
fail();
|
||||
} catch (InvalidRequestException e) {
|
||||
assertEquals("ValueSet contains exclude criteria with no system defined", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExpandWithIsAInExternalValueSet() {
|
||||
createExternalCsAndLocalVs();
|
||||
|
||||
ValueSet vs = new ValueSet();
|
||||
ConceptSetComponent include = vs.getCompose().addInclude();
|
||||
include.setSystem(URL_MY_CODE_SYSTEM);
|
||||
include.addFilter().setOp(FilterOperator.ISA).setValue("childAA").setProperty("concept");
|
||||
|
||||
ValueSet result = myValueSetDao.expand(vs, null);
|
||||
logAndValidateValueSet(result);
|
||||
|
||||
ArrayList<String> codes = toCodesContains(result.getExpansion().getContains());
|
||||
assertThat(codes, containsInAnyOrder("childAAA", "childAAB"));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExpandWithIsAInExternalValueSetReindex() {
|
||||
BaseHapiTerminologySvc.setForceSaveDeferredAlwaysForUnitTest(true);
|
||||
|
||||
createExternalCsAndLocalVs();
|
||||
|
||||
mySystemDao.markAllResourcesForReindexing();
|
||||
|
||||
mySystemDao.performReindexingPass(100);
|
||||
mySystemDao.performReindexingPass(100);
|
||||
myHapiTerminologySvc.saveDeferred();
|
||||
myHapiTerminologySvc.saveDeferred();
|
||||
myHapiTerminologySvc.saveDeferred();
|
||||
|
||||
ValueSet vs = new ValueSet();
|
||||
ConceptSetComponent include = vs.getCompose().addInclude();
|
||||
include.setSystem(URL_MY_CODE_SYSTEM);
|
||||
include.addFilter().setOp(FilterOperator.ISA).setValue("childAA").setProperty("concept");
|
||||
|
||||
ValueSet result = myValueSetDao.expand(vs, null);
|
||||
logAndValidateValueSet(result);
|
||||
|
||||
ArrayList<String> codes = toCodesContains(result.getExpansion().getContains());
|
||||
assertThat(codes, containsInAnyOrder("childAAA", "childAAB"));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExpandWithNoResultsInLocalValueSet1() {
|
||||
createLocalCsAndVs();
|
||||
|
||||
ValueSet vs = new ValueSet();
|
||||
ConceptSetComponent include = vs.getCompose().addInclude();
|
||||
include.setSystem(URL_MY_CODE_SYSTEM);
|
||||
include.addConcept().setCode("ZZZZ");
|
||||
|
||||
try {
|
||||
myValueSetDao.expand(vs, null);
|
||||
fail();
|
||||
} catch (InvalidRequestException e) {
|
||||
assertEquals("Unable to find code 'ZZZZ' in code system http://example.com/my_code_system", e.getMessage());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExpandWithNoResultsInLocalValueSet2() {
|
||||
createLocalCsAndVs();
|
||||
|
||||
ValueSet vs = new ValueSet();
|
||||
ConceptSetComponent include = vs.getCompose().addInclude();
|
||||
include.setSystem(URL_MY_CODE_SYSTEM + "AA");
|
||||
include.addConcept().setCode("A");
|
||||
|
||||
try {
|
||||
myValueSetDao.expand(vs, null);
|
||||
fail();
|
||||
} catch (InvalidRequestException e) {
|
||||
assertEquals("unable to find code system http://example.com/my_code_systemAA", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExpandWithSystemAndCodesAndFilterKeywordInLocalValueSet() {
|
||||
createLocalCsAndVs();
|
||||
|
@ -493,6 +546,29 @@ public class FhirResourceDaoDstu3TerminologyTest extends BaseJpaDstu3Test {
|
|||
//
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExpandWithSystemAndCodesInExternalValueSet() {
|
||||
createExternalCsAndLocalVs();
|
||||
|
||||
ValueSet vs = new ValueSet();
|
||||
ConceptSetComponent include = vs.getCompose().addInclude();
|
||||
include.setSystem(URL_MY_CODE_SYSTEM);
|
||||
include.addConcept().setCode("ParentA");
|
||||
include.addConcept().setCode("childAA");
|
||||
include.addConcept().setCode("childAAA");
|
||||
|
||||
ValueSet result = myValueSetDao.expand(vs, null);
|
||||
logAndValidateValueSet(result);
|
||||
|
||||
ArrayList<String> codes = toCodesContains(result.getExpansion().getContains());
|
||||
assertThat(codes, containsInAnyOrder("ParentA", "childAA", "childAAA"));
|
||||
|
||||
int idx = codes.indexOf("childAA");
|
||||
assertEquals("childAA", result.getExpansion().getContains().get(idx).getCode());
|
||||
assertEquals("Child AA", result.getExpansion().getContains().get(idx).getDisplay());
|
||||
assertEquals(URL_MY_CODE_SYSTEM, result.getExpansion().getContains().get(idx).getSystem());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExpandWithSystemAndCodesInLocalValueSet() {
|
||||
createLocalCsAndVs();
|
||||
|
@ -520,6 +596,43 @@ public class FhirResourceDaoDstu3TerminologyTest extends BaseJpaDstu3Test {
|
|||
//
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExpandWithSystemAndDisplayFilterBlank() {
|
||||
CodeSystem codeSystem = createExternalCsDogs();
|
||||
|
||||
ValueSet valueSet = new ValueSet();
|
||||
valueSet.setUrl(URL_MY_VALUE_SET);
|
||||
valueSet.getCompose()
|
||||
.addInclude()
|
||||
.setSystem(codeSystem.getUrl());
|
||||
|
||||
ValueSet result = myValueSetDao.expand(valueSet, "");
|
||||
logAndValidateValueSet(result);
|
||||
|
||||
assertEquals(5, result.getExpansion().getTotal());
|
||||
ArrayList<String> codes = toCodesContains(result.getExpansion().getContains());
|
||||
assertThat(codes, containsInAnyOrder("hello", "goodbye", "dogs", "labrador", "beagle"));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExpandWithSystemAndFilterInExternalValueSet() {
|
||||
createExternalCsAndLocalVs();
|
||||
|
||||
ValueSet vs = new ValueSet();
|
||||
ConceptSetComponent include = vs.getCompose().addInclude();
|
||||
include.setSystem(URL_MY_CODE_SYSTEM);
|
||||
|
||||
include.addFilter().setProperty("display").setOp(FilterOperator.EQUAL).setValue("Parent B");
|
||||
|
||||
ValueSet result = myValueSetDao.expand(vs, null);
|
||||
logAndValidateValueSet(result);
|
||||
|
||||
ArrayList<String> codes = toCodesContains(result.getExpansion().getContains());
|
||||
assertThat(codes, containsInAnyOrder("ParentB"));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIndexingIsDeferredForLargeCodeSystems() {
|
||||
myDaoConfig.setDeferIndexingForCodesystemsOfSize(1);
|
||||
|
@ -560,6 +673,28 @@ public class FhirResourceDaoDstu3TerminologyTest extends BaseJpaDstu3Test {
|
|||
assertThat(encoded, containsStringIgnoringCase("<code value=\"childAAB\"/>"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLookupSnomed() {
|
||||
CodeSystem codeSystem = new CodeSystem();
|
||||
codeSystem.setUrl("http://snomed.info/sct");
|
||||
codeSystem.setContent(CodeSystemContentMode.NOTPRESENT);
|
||||
IIdType id = myCodeSystemDao.create(codeSystem, mySrd).getId().toUnqualified();
|
||||
|
||||
ResourceTable table = myResourceTableDao.findOne(id.getIdPartAsLong());
|
||||
|
||||
TermCodeSystemVersion cs = new TermCodeSystemVersion();
|
||||
cs.setResource(table);
|
||||
cs.setResourceVersionId(table.getVersion());
|
||||
TermConcept parentA = new TermConcept(cs, "ParentA").setDisplay("Parent A");
|
||||
cs.getConcepts().add(parentA);
|
||||
myTermSvc.storeNewCodeSystemVersion(table.getId(), "http://snomed.info/sct", cs);
|
||||
|
||||
StringType code = new StringType("ParentA");
|
||||
StringType system = new StringType("http://snomed.info/sct");
|
||||
LookupCodeResult outcome = myCodeSystemDao.lookupCode(code, system, null, mySrd);
|
||||
assertEquals(true, outcome.isFound());
|
||||
}
|
||||
|
||||
/**
|
||||
* Can't currently abort costly
|
||||
*/
|
||||
|
@ -594,6 +729,30 @@ public class FhirResourceDaoDstu3TerminologyTest extends BaseJpaDstu3Test {
|
|||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReindex() {
|
||||
createLocalCsAndVs();
|
||||
|
||||
ValueSet vs = new ValueSet();
|
||||
ConceptSetComponent include = vs.getCompose().addInclude();
|
||||
include.setSystem(URL_MY_CODE_SYSTEM);
|
||||
include.addConcept().setCode("ZZZZ");
|
||||
|
||||
mySystemDao.markAllResourcesForReindexing();
|
||||
mySystemDao.performReindexingPass(null);
|
||||
myTermSvc.saveDeferred();
|
||||
mySystemDao.performReindexingPass(null);
|
||||
myTermSvc.saveDeferred();
|
||||
|
||||
// Again
|
||||
mySystemDao.markAllResourcesForReindexing();
|
||||
mySystemDao.performReindexingPass(null);
|
||||
myTermSvc.saveDeferred();
|
||||
mySystemDao.performReindexingPass(null);
|
||||
myTermSvc.saveDeferred();
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSearchCodeAboveLocalCodesystem() {
|
||||
createLocalCsAndVs();
|
||||
|
@ -636,107 +795,6 @@ public class FhirResourceDaoDstu3TerminologyTest extends BaseJpaDstu3Test {
|
|||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSearchCodeBelowLocalCodesystem() {
|
||||
createLocalCsAndVs();
|
||||
|
||||
Observation obsAA = new Observation();
|
||||
obsAA.getCode().addCoding().setSystem(URL_MY_CODE_SYSTEM).setCode("AA");
|
||||
IIdType idAA = myObservationDao.create(obsAA, mySrd).getId().toUnqualifiedVersionless();
|
||||
|
||||
Observation obsBA = new Observation();
|
||||
obsBA.getCode().addCoding().setSystem(URL_MY_CODE_SYSTEM).setCode("BA");
|
||||
IIdType idBA = myObservationDao.create(obsBA, mySrd).getId().toUnqualifiedVersionless();
|
||||
|
||||
Observation obsCA = new Observation();
|
||||
obsCA.getCode().addCoding().setSystem(URL_MY_CODE_SYSTEM).setCode("CA");
|
||||
IIdType idCA = myObservationDao.create(obsCA, mySrd).getId().toUnqualifiedVersionless();
|
||||
|
||||
SearchParameterMap params = new SearchParameterMap();
|
||||
params.add(Observation.SP_CODE, new TokenParam(URL_MY_CODE_SYSTEM, "A").setModifier(TokenParamModifier.BELOW));
|
||||
assertThat(toUnqualifiedVersionlessIdValues(myObservationDao.search(params)), containsInAnyOrder(idAA.getValue()));
|
||||
|
||||
params = new SearchParameterMap();
|
||||
params.add(Observation.SP_CODE, new TokenParam(URL_MY_CODE_SYSTEM, "AAA").setModifier(TokenParamModifier.BELOW));
|
||||
assertThat(toUnqualifiedVersionlessIdValues(myObservationDao.search(params)), empty());
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSearchCodeInBuiltInValueSet() {
|
||||
AllergyIntolerance ai1 = new AllergyIntolerance();
|
||||
ai1.setClinicalStatus(AllergyIntoleranceClinicalStatus.ACTIVE);
|
||||
String id1 = myAllergyIntoleranceDao.create(ai1, mySrd).getId().toUnqualifiedVersionless().getValue();
|
||||
|
||||
AllergyIntolerance ai2 = new AllergyIntolerance();
|
||||
ai2.setClinicalStatus(AllergyIntoleranceClinicalStatus.RESOLVED);
|
||||
String id2 = myAllergyIntoleranceDao.create(ai2, mySrd).getId().toUnqualifiedVersionless().getValue();
|
||||
|
||||
AllergyIntolerance ai3 = new AllergyIntolerance();
|
||||
ai3.setClinicalStatus(AllergyIntoleranceClinicalStatus.INACTIVE);
|
||||
String id3 = myAllergyIntoleranceDao.create(ai3, mySrd).getId().toUnqualifiedVersionless().getValue();
|
||||
|
||||
SearchParameterMap params;
|
||||
params = new SearchParameterMap();
|
||||
params.add(AllergyIntolerance.SP_CLINICAL_STATUS, new TokenParam(null, "http://hl7.org/fhir/ValueSet/allergy-clinical-status").setModifier(TokenParamModifier.IN));
|
||||
assertThat(toUnqualifiedVersionlessIdValues(myAllergyIntoleranceDao.search(params)), containsInAnyOrder(id1, id2, id3));
|
||||
|
||||
// No codes in this one
|
||||
params = new SearchParameterMap();
|
||||
params.add(AllergyIntolerance.SP_CLINICAL_STATUS, new TokenParam(null, "http://hl7.org/fhir/ValueSet/allergy-intolerance-criticality").setModifier(TokenParamModifier.IN));
|
||||
assertThat(toUnqualifiedVersionlessIdValues(myAllergyIntoleranceDao.search(params)), empty());
|
||||
|
||||
// Invalid VS
|
||||
params = new SearchParameterMap();
|
||||
params.add(AllergyIntolerance.SP_CLINICAL_STATUS, new TokenParam(null, "http://hl7.org/fhir/ValueSet/FOO").setModifier(TokenParamModifier.IN));
|
||||
try {
|
||||
myAllergyIntoleranceDao.search(params);
|
||||
} catch (InvalidRequestException e) {
|
||||
assertEquals("Unable to find imported value set http://hl7.org/fhir/ValueSet/FOO", e.getMessage());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Todo: not yet implemented
|
||||
*/
|
||||
@Test
|
||||
@Ignore
|
||||
public void testSearchCodeNotInBuiltInValueSet() {
|
||||
AllergyIntolerance ai1 = new AllergyIntolerance();
|
||||
ai1.setClinicalStatus(AllergyIntoleranceClinicalStatus.ACTIVE);
|
||||
String id1 = myAllergyIntoleranceDao.create(ai1, mySrd).getId().toUnqualifiedVersionless().getValue();
|
||||
|
||||
AllergyIntolerance ai2 = new AllergyIntolerance();
|
||||
ai2.setClinicalStatus(AllergyIntoleranceClinicalStatus.RESOLVED);
|
||||
String id2 = myAllergyIntoleranceDao.create(ai2, mySrd).getId().toUnqualifiedVersionless().getValue();
|
||||
|
||||
AllergyIntolerance ai3 = new AllergyIntolerance();
|
||||
ai3.setClinicalStatus(AllergyIntoleranceClinicalStatus.INACTIVE);
|
||||
String id3 = myAllergyIntoleranceDao.create(ai3, mySrd).getId().toUnqualifiedVersionless().getValue();
|
||||
|
||||
SearchParameterMap params;
|
||||
params = new SearchParameterMap();
|
||||
params.add(AllergyIntolerance.SP_CLINICAL_STATUS, new TokenParam(null, "http://hl7.org/fhir/ValueSet/allergy-intolerance-status").setModifier(TokenParamModifier.NOT_IN));
|
||||
assertThat(toUnqualifiedVersionlessIdValues(myAllergyIntoleranceDao.search(params)), empty());
|
||||
|
||||
// No codes in this one
|
||||
params = new SearchParameterMap();
|
||||
params.add(AllergyIntolerance.SP_CLINICAL_STATUS, new TokenParam(null, "http://hl7.org/fhir/ValueSet/allergy-intolerance-criticality").setModifier(TokenParamModifier.NOT_IN));
|
||||
assertThat(toUnqualifiedVersionlessIdValues(myAllergyIntoleranceDao.search(params)), containsInAnyOrder(id1, id2, id3));
|
||||
|
||||
// Invalid VS
|
||||
params = new SearchParameterMap();
|
||||
params.add(AllergyIntolerance.SP_CLINICAL_STATUS, new TokenParam(null, "http://hl7.org/fhir/ValueSet/FOO").setModifier(TokenParamModifier.NOT_IN));
|
||||
try {
|
||||
myAllergyIntoleranceDao.search(params);
|
||||
} catch (InvalidRequestException e) {
|
||||
assertEquals("Unable to find imported value set http://hl7.org/fhir/ValueSet/FOO", e.getMessage());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSearchCodeBelowBuiltInCodesystem() {
|
||||
AllergyIntolerance ai1 = new AllergyIntolerance();
|
||||
|
@ -824,6 +882,68 @@ public class FhirResourceDaoDstu3TerminologyTest extends BaseJpaDstu3Test {
|
|||
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testSearchCodeBelowLocalCodesystem() {
|
||||
createLocalCsAndVs();
|
||||
|
||||
Observation obsAA = new Observation();
|
||||
obsAA.getCode().addCoding().setSystem(URL_MY_CODE_SYSTEM).setCode("AA");
|
||||
IIdType idAA = myObservationDao.create(obsAA, mySrd).getId().toUnqualifiedVersionless();
|
||||
|
||||
Observation obsBA = new Observation();
|
||||
obsBA.getCode().addCoding().setSystem(URL_MY_CODE_SYSTEM).setCode("BA");
|
||||
IIdType idBA = myObservationDao.create(obsBA, mySrd).getId().toUnqualifiedVersionless();
|
||||
|
||||
Observation obsCA = new Observation();
|
||||
obsCA.getCode().addCoding().setSystem(URL_MY_CODE_SYSTEM).setCode("CA");
|
||||
IIdType idCA = myObservationDao.create(obsCA, mySrd).getId().toUnqualifiedVersionless();
|
||||
|
||||
SearchParameterMap params = new SearchParameterMap();
|
||||
params.add(Observation.SP_CODE, new TokenParam(URL_MY_CODE_SYSTEM, "A").setModifier(TokenParamModifier.BELOW));
|
||||
assertThat(toUnqualifiedVersionlessIdValues(myObservationDao.search(params)), containsInAnyOrder(idAA.getValue()));
|
||||
|
||||
params = new SearchParameterMap();
|
||||
params.add(Observation.SP_CODE, new TokenParam(URL_MY_CODE_SYSTEM, "AAA").setModifier(TokenParamModifier.BELOW));
|
||||
assertThat(toUnqualifiedVersionlessIdValues(myObservationDao.search(params)), empty());
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSearchCodeInBuiltInValueSet() {
|
||||
AllergyIntolerance ai1 = new AllergyIntolerance();
|
||||
ai1.setClinicalStatus(AllergyIntoleranceClinicalStatus.ACTIVE);
|
||||
String id1 = myAllergyIntoleranceDao.create(ai1, mySrd).getId().toUnqualifiedVersionless().getValue();
|
||||
|
||||
AllergyIntolerance ai2 = new AllergyIntolerance();
|
||||
ai2.setClinicalStatus(AllergyIntoleranceClinicalStatus.RESOLVED);
|
||||
String id2 = myAllergyIntoleranceDao.create(ai2, mySrd).getId().toUnqualifiedVersionless().getValue();
|
||||
|
||||
AllergyIntolerance ai3 = new AllergyIntolerance();
|
||||
ai3.setClinicalStatus(AllergyIntoleranceClinicalStatus.INACTIVE);
|
||||
String id3 = myAllergyIntoleranceDao.create(ai3, mySrd).getId().toUnqualifiedVersionless().getValue();
|
||||
|
||||
SearchParameterMap params;
|
||||
params = new SearchParameterMap();
|
||||
params.add(AllergyIntolerance.SP_CLINICAL_STATUS, new TokenParam(null, "http://hl7.org/fhir/ValueSet/allergy-clinical-status").setModifier(TokenParamModifier.IN));
|
||||
assertThat(toUnqualifiedVersionlessIdValues(myAllergyIntoleranceDao.search(params)), containsInAnyOrder(id1, id2, id3));
|
||||
|
||||
// No codes in this one
|
||||
params = new SearchParameterMap();
|
||||
params.add(AllergyIntolerance.SP_CLINICAL_STATUS, new TokenParam(null, "http://hl7.org/fhir/ValueSet/allergy-intolerance-criticality").setModifier(TokenParamModifier.IN));
|
||||
assertThat(toUnqualifiedVersionlessIdValues(myAllergyIntoleranceDao.search(params)), empty());
|
||||
|
||||
// Invalid VS
|
||||
params = new SearchParameterMap();
|
||||
params.add(AllergyIntolerance.SP_CLINICAL_STATUS, new TokenParam(null, "http://hl7.org/fhir/ValueSet/FOO").setModifier(TokenParamModifier.IN));
|
||||
try {
|
||||
myAllergyIntoleranceDao.search(params);
|
||||
} catch (InvalidRequestException e) {
|
||||
assertEquals("Unable to find imported value set http://hl7.org/fhir/ValueSet/FOO", e.getMessage());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSearchCodeInEmptyValueSet() {
|
||||
ValueSet valueSet = new ValueSet();
|
||||
|
@ -848,40 +968,6 @@ public class FhirResourceDaoDstu3TerminologyTest extends BaseJpaDstu3Test {
|
|||
ourLog.info("testSearchCodeInEmptyValueSet done");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSearchCodeInValueSetThatImportsInvalidCodeSystem() {
|
||||
ValueSet valueSet = new ValueSet();
|
||||
valueSet.getCompose().addInclude().addValueSet("http://non_existant_VS");
|
||||
valueSet.setUrl(URL_MY_VALUE_SET);
|
||||
IIdType vsid = myValueSetDao.create(valueSet, mySrd).getId().toUnqualifiedVersionless();
|
||||
|
||||
SearchParameterMap params;
|
||||
|
||||
ourLog.info("testSearchCodeInEmptyValueSet without status");
|
||||
|
||||
params = new SearchParameterMap();
|
||||
params.add(Observation.SP_CODE, new TokenParam(null, URL_MY_VALUE_SET).setModifier(TokenParamModifier.IN));
|
||||
try {
|
||||
myObservationDao.search(params);
|
||||
} catch(InvalidRequestException e) {
|
||||
assertEquals("Unable to expand imported value set: Unable to find imported value set http://non_existant_VS", e.getMessage());
|
||||
}
|
||||
|
||||
// Now let's update
|
||||
valueSet = new ValueSet();
|
||||
valueSet.setId(vsid);
|
||||
valueSet.getCompose().addInclude().setSystem("http://hl7.org/fhir/v3/MaritalStatus").addConcept().setCode("A");
|
||||
valueSet.setUrl(URL_MY_VALUE_SET);
|
||||
myValueSetDao.update(valueSet, mySrd).getId().toUnqualifiedVersionless();
|
||||
|
||||
params = new SearchParameterMap();
|
||||
params.add(Observation.SP_CODE, new TokenParam(null, URL_MY_VALUE_SET).setModifier(TokenParamModifier.IN));
|
||||
params.add(Observation.SP_STATUS, new TokenParam(null, "final"));
|
||||
assertThat(toUnqualifiedVersionlessIdValues(myObservationDao.search(params)), empty());
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testSearchCodeInExternalCodesystem() {
|
||||
createExternalCsAndLocalVs();
|
||||
|
@ -941,6 +1027,7 @@ public class FhirResourceDaoDstu3TerminologyTest extends BaseJpaDstu3Test {
|
|||
assertThat(toUnqualifiedVersionlessIdValues(myAuditEventDao.search(params)), empty());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testSearchCodeInLocalCodesystem() {
|
||||
createLocalCsAndVs();
|
||||
|
@ -963,6 +1050,78 @@ public class FhirResourceDaoDstu3TerminologyTest extends BaseJpaDstu3Test {
|
|||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSearchCodeInValueSetThatImportsInvalidCodeSystem() {
|
||||
ValueSet valueSet = new ValueSet();
|
||||
valueSet.getCompose().addInclude().addValueSet("http://non_existant_VS");
|
||||
valueSet.setUrl(URL_MY_VALUE_SET);
|
||||
IIdType vsid = myValueSetDao.create(valueSet, mySrd).getId().toUnqualifiedVersionless();
|
||||
|
||||
SearchParameterMap params;
|
||||
|
||||
ourLog.info("testSearchCodeInEmptyValueSet without status");
|
||||
|
||||
params = new SearchParameterMap();
|
||||
params.add(Observation.SP_CODE, new TokenParam(null, URL_MY_VALUE_SET).setModifier(TokenParamModifier.IN));
|
||||
try {
|
||||
myObservationDao.search(params);
|
||||
} catch(InvalidRequestException e) {
|
||||
assertEquals("Unable to expand imported value set: Unable to find imported value set http://non_existant_VS", e.getMessage());
|
||||
}
|
||||
|
||||
// Now let's update
|
||||
valueSet = new ValueSet();
|
||||
valueSet.setId(vsid);
|
||||
valueSet.getCompose().addInclude().setSystem("http://hl7.org/fhir/v3/MaritalStatus").addConcept().setCode("A");
|
||||
valueSet.setUrl(URL_MY_VALUE_SET);
|
||||
myValueSetDao.update(valueSet, mySrd).getId().toUnqualifiedVersionless();
|
||||
|
||||
params = new SearchParameterMap();
|
||||
params.add(Observation.SP_CODE, new TokenParam(null, URL_MY_VALUE_SET).setModifier(TokenParamModifier.IN));
|
||||
params.add(Observation.SP_STATUS, new TokenParam(null, "final"));
|
||||
assertThat(toUnqualifiedVersionlessIdValues(myObservationDao.search(params)), empty());
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Todo: not yet implemented
|
||||
*/
|
||||
@Test
|
||||
@Ignore
|
||||
public void testSearchCodeNotInBuiltInValueSet() {
|
||||
AllergyIntolerance ai1 = new AllergyIntolerance();
|
||||
ai1.setClinicalStatus(AllergyIntoleranceClinicalStatus.ACTIVE);
|
||||
String id1 = myAllergyIntoleranceDao.create(ai1, mySrd).getId().toUnqualifiedVersionless().getValue();
|
||||
|
||||
AllergyIntolerance ai2 = new AllergyIntolerance();
|
||||
ai2.setClinicalStatus(AllergyIntoleranceClinicalStatus.RESOLVED);
|
||||
String id2 = myAllergyIntoleranceDao.create(ai2, mySrd).getId().toUnqualifiedVersionless().getValue();
|
||||
|
||||
AllergyIntolerance ai3 = new AllergyIntolerance();
|
||||
ai3.setClinicalStatus(AllergyIntoleranceClinicalStatus.INACTIVE);
|
||||
String id3 = myAllergyIntoleranceDao.create(ai3, mySrd).getId().toUnqualifiedVersionless().getValue();
|
||||
|
||||
SearchParameterMap params;
|
||||
params = new SearchParameterMap();
|
||||
params.add(AllergyIntolerance.SP_CLINICAL_STATUS, new TokenParam(null, "http://hl7.org/fhir/ValueSet/allergy-intolerance-status").setModifier(TokenParamModifier.NOT_IN));
|
||||
assertThat(toUnqualifiedVersionlessIdValues(myAllergyIntoleranceDao.search(params)), empty());
|
||||
|
||||
// No codes in this one
|
||||
params = new SearchParameterMap();
|
||||
params.add(AllergyIntolerance.SP_CLINICAL_STATUS, new TokenParam(null, "http://hl7.org/fhir/ValueSet/allergy-intolerance-criticality").setModifier(TokenParamModifier.NOT_IN));
|
||||
assertThat(toUnqualifiedVersionlessIdValues(myAllergyIntoleranceDao.search(params)), containsInAnyOrder(id1, id2, id3));
|
||||
|
||||
// Invalid VS
|
||||
params = new SearchParameterMap();
|
||||
params.add(AllergyIntolerance.SP_CLINICAL_STATUS, new TokenParam(null, "http://hl7.org/fhir/ValueSet/FOO").setModifier(TokenParamModifier.NOT_IN));
|
||||
try {
|
||||
myAllergyIntoleranceDao.search(params);
|
||||
} catch (InvalidRequestException e) {
|
||||
assertEquals("Unable to find imported value set http://hl7.org/fhir/ValueSet/FOO", e.getMessage());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private ArrayList<String> toCodesContains(List<ValueSetExpansionContainsComponent> theContains) {
|
||||
ArrayList<String> retVal = new ArrayList<String>();
|
||||
for (ValueSetExpansionContainsComponent next : theContains) {
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
[*.java]
|
||||
charset = utf-8
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
|
|
@ -6,33 +6,33 @@ import java.io.FileNotFoundException;
|
|||
import java.io.IOException;
|
||||
|
||||
/*
|
||||
Copyright (c) 2011+, HL7, Inc
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
* Neither the name of HL7 nor the names of its contributors may be used to
|
||||
endorse or promote products derived from this software without specific
|
||||
prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
* Copyright (c) 2011+, HL7, Inc
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met:
|
||||
*
|
||||
* Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* Neither the name of HL7 nor the names of its contributors may be used to
|
||||
* endorse or promote products derived from this software without specific
|
||||
* prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
|
@ -72,66 +72,67 @@ import org.hl7.fhir.utilities.Utilities;
|
|||
|
||||
public class ValueSetExpanderSimple implements ValueSetExpander {
|
||||
|
||||
private List<ValueSetExpansionContainsComponent> codes = new ArrayList<ValueSet.ValueSetExpansionContainsComponent>();
|
||||
private List<ValueSetExpansionContainsComponent> codes = new ArrayList<ValueSet.ValueSetExpansionContainsComponent>();
|
||||
private List<ValueSetExpansionContainsComponent> roots = new ArrayList<ValueSet.ValueSetExpansionContainsComponent>();
|
||||
private Map<String, ValueSetExpansionContainsComponent> map = new HashMap<String, ValueSet.ValueSetExpansionContainsComponent>();
|
||||
private IWorkerContext context;
|
||||
private IWorkerContext context;
|
||||
private boolean canBeHeirarchy = true;
|
||||
private Set<String> excludeKeys = new HashSet<String>();
|
||||
private Set<String> excludeKeys = new HashSet<String>();
|
||||
private Set<String> excludeSystems = new HashSet<String>();
|
||||
private ValueSetExpanderFactory factory;
|
||||
private ValueSet focus;
|
||||
private int maxExpansionSize = 500;
|
||||
private ValueSetExpanderFactory factory;
|
||||
private ValueSet focus;
|
||||
private int maxExpansionSize = 500;
|
||||
|
||||
private int total;
|
||||
private int total;
|
||||
|
||||
public ValueSetExpanderSimple(IWorkerContext context, ValueSetExpanderFactory factory) {
|
||||
super();
|
||||
this.context = context;
|
||||
this.factory = factory;
|
||||
}
|
||||
public ValueSetExpanderSimple(IWorkerContext context, ValueSetExpanderFactory factory) {
|
||||
super();
|
||||
this.context = context;
|
||||
this.factory = factory;
|
||||
}
|
||||
|
||||
public void setMaxExpansionSize(int theMaxExpansionSize) {
|
||||
maxExpansionSize = theMaxExpansionSize;
|
||||
}
|
||||
public void setMaxExpansionSize(int theMaxExpansionSize) {
|
||||
maxExpansionSize = theMaxExpansionSize;
|
||||
}
|
||||
|
||||
|
||||
private ValueSetExpansionContainsComponent addCode(String system, String code, String display, ValueSetExpansionContainsComponent parent, List<ConceptDefinitionDesignationComponent> designations, ExpansionProfile profile, boolean isAbstract, boolean inactive, List<ValueSet> filters) {
|
||||
private ValueSetExpansionContainsComponent addCode(String system, String code, String display, ValueSetExpansionContainsComponent parent, List<ConceptDefinitionDesignationComponent> designations,
|
||||
ExpansionProfile profile, boolean isAbstract, boolean inactive, List<ValueSet> filters) {
|
||||
if (filters != null && !filters.isEmpty() && !filterContainsCode(filters, system, code))
|
||||
return null;
|
||||
ValueSetExpansionContainsComponent n = new ValueSet.ValueSetExpansionContainsComponent();
|
||||
n.setSystem(system);
|
||||
n.setCode(code);
|
||||
if (isAbstract)
|
||||
n.setSystem(system);
|
||||
n.setCode(code);
|
||||
if (isAbstract)
|
||||
n.setAbstract(true);
|
||||
if (inactive)
|
||||
n.setInactive(true);
|
||||
|
||||
|
||||
if (profile.getIncludeDesignations() && designations != null) {
|
||||
for (ConceptDefinitionDesignationComponent t : designations) {
|
||||
ToolingExtensions.addLanguageTranslation(n, t.getLanguage(), t.getValue());
|
||||
ToolingExtensions.addLanguageTranslation(n, t.getLanguage(), t.getValue());
|
||||
}
|
||||
}
|
||||
ConceptDefinitionDesignationComponent t = profile.hasLanguage() ? getMatchingLang(designations, profile.getLanguage()) : null;
|
||||
if (t == null)
|
||||
n.setDisplay(display);
|
||||
n.setDisplay(display);
|
||||
else
|
||||
n.setDisplay(t.getValue());
|
||||
|
||||
String s = key(n);
|
||||
if (map.containsKey(s) || excludeKeys.contains(s)) {
|
||||
canBeHeirarchy = false;
|
||||
} else {
|
||||
codes.add(n);
|
||||
map.put(s, n);
|
||||
}
|
||||
if (canBeHeirarchy && parent != null) {
|
||||
parent.getContains().add(n);
|
||||
} else {
|
||||
roots.add(n);
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
String s = key(n);
|
||||
if (map.containsKey(s) || excludeKeys.contains(s)) {
|
||||
canBeHeirarchy = false;
|
||||
} else {
|
||||
codes.add(n);
|
||||
map.put(s, n);
|
||||
total++;
|
||||
}
|
||||
if (canBeHeirarchy && parent != null) {
|
||||
parent.getContains().add(n);
|
||||
} else {
|
||||
roots.add(n);
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
private boolean filterContainsCode(List<ValueSet> filters, String system, String code) {
|
||||
for (ValueSet vse : filters)
|
||||
|
@ -160,93 +161,92 @@ public class ValueSetExpanderSimple implements ValueSetExpander {
|
|||
return null;
|
||||
}
|
||||
|
||||
private void addCodeAndDescendents(CodeSystem cs, String system, ConceptDefinitionComponent def, ValueSetExpansionContainsComponent parent, ExpansionProfile profile, List<ValueSet> filters) throws FHIRException {
|
||||
if (!CodeSystemUtilities.isDeprecated(cs, def)) {
|
||||
ValueSetExpansionContainsComponent np = null;
|
||||
private void addCodeAndDescendents(CodeSystem cs, String system, ConceptDefinitionComponent def, ValueSetExpansionContainsComponent parent, ExpansionProfile profile, List<ValueSet> filters)
|
||||
throws FHIRException {
|
||||
if (!CodeSystemUtilities.isDeprecated(cs, def)) {
|
||||
ValueSetExpansionContainsComponent np = null;
|
||||
boolean abs = CodeSystemUtilities.isNotSelectable(cs, def);
|
||||
boolean inc = CodeSystemUtilities.isInactive(cs, def);
|
||||
boolean inc = CodeSystemUtilities.isInactive(cs, def);
|
||||
if (canBeHeirarchy || !abs)
|
||||
np = addCode(system, def.getCode(), def.getDisplay(), parent, def.getDesignation(), profile, abs, inc, filters);
|
||||
for (ConceptDefinitionComponent c : def.getConcept())
|
||||
addCodeAndDescendents(cs, system, c, np, profile, filters);
|
||||
} else
|
||||
for (ConceptDefinitionComponent c : def.getConcept())
|
||||
addCodeAndDescendents(cs, system, c, null, profile, filters);
|
||||
} else
|
||||
for (ConceptDefinitionComponent c : def.getConcept())
|
||||
addCodeAndDescendents(cs, system, c, null, profile, filters);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private void addCodes(ValueSetExpansionComponent expand, List<ValueSetExpansionParameterComponent> params, ExpansionProfile profile, List<ValueSet> filters) throws ETooCostly {
|
||||
if (expand.getContains().size() > maxExpansionSize)
|
||||
throw new ETooCostly("Too many codes to display (>" + Integer.toString(expand.getContains().size()) + ")");
|
||||
for (ValueSetExpansionParameterComponent p : expand.getParameter()) {
|
||||
if (!existsInParams(params, p.getName(), p.getValue()))
|
||||
params.add(p);
|
||||
}
|
||||
if (expand.getContains().size() > maxExpansionSize)
|
||||
throw new ETooCostly("Too many codes to display (>" + Integer.toString(expand.getContains().size()) + ")");
|
||||
for (ValueSetExpansionParameterComponent p : expand.getParameter()) {
|
||||
if (!existsInParams(params, p.getName(), p.getValue()))
|
||||
params.add(p);
|
||||
}
|
||||
|
||||
copyImportContains(expand.getContains(), null, profile, filters);
|
||||
|
||||
total = expand.getTotal();
|
||||
}
|
||||
}
|
||||
|
||||
private void excludeCode(String theSystem, String theCode) {
|
||||
ValueSetExpansionContainsComponent n = new ValueSet.ValueSetExpansionContainsComponent();
|
||||
n.setSystem(theSystem);
|
||||
n.setCode(theCode);
|
||||
String s = key(n);
|
||||
excludeKeys.add(s);
|
||||
}
|
||||
private void excludeCode(String theSystem, String theCode) {
|
||||
ValueSetExpansionContainsComponent n = new ValueSet.ValueSetExpansionContainsComponent();
|
||||
n.setSystem(theSystem);
|
||||
n.setCode(theCode);
|
||||
String s = key(n);
|
||||
excludeKeys.add(s);
|
||||
}
|
||||
|
||||
private void excludeCodes(ConceptSetComponent exc, List<ValueSetExpansionParameterComponent> params) throws TerminologyServiceException {
|
||||
if (exc.hasSystem() && exc.getConcept().size() == 0 && exc.getFilter().size() == 0) {
|
||||
excludeSystems.add(exc.getSystem());
|
||||
}
|
||||
private void excludeCodes(ConceptSetComponent exc, List<ValueSetExpansionParameterComponent> params) throws TerminologyServiceException {
|
||||
if (exc.hasSystem() && exc.getConcept().size() == 0 && exc.getFilter().size() == 0) {
|
||||
excludeSystems.add(exc.getSystem());
|
||||
}
|
||||
|
||||
if (exc.hasValueSet())
|
||||
throw new Error("Processing Value set references in exclude is not yet done");
|
||||
// importValueSet(imp.getValue(), params, profile);
|
||||
// importValueSet(imp.getValue(), params, profile);
|
||||
|
||||
CodeSystem cs = context.fetchCodeSystem(exc.getSystem());
|
||||
if ((cs == null || cs.getContent() != CodeSystemContentMode.COMPLETE) && context.supportsSystem(exc.getSystem())) {
|
||||
excludeCodes(context.expandVS(exc, false), params);
|
||||
return;
|
||||
}
|
||||
CodeSystem cs = context.fetchCodeSystem(exc.getSystem());
|
||||
if ((cs == null || cs.getContent() != CodeSystemContentMode.COMPLETE) && context.supportsSystem(exc.getSystem())) {
|
||||
excludeCodes(context.expandVS(exc, false), params);
|
||||
return;
|
||||
}
|
||||
|
||||
for (ConceptReferenceComponent c : exc.getConcept()) {
|
||||
excludeCode(exc.getSystem(), c.getCode());
|
||||
}
|
||||
|
||||
if (exc.getFilter().size() > 0)
|
||||
throw new NotImplementedException("not done yet");
|
||||
}
|
||||
for (ConceptReferenceComponent c : exc.getConcept()) {
|
||||
excludeCode(exc.getSystem(), c.getCode());
|
||||
}
|
||||
|
||||
private void excludeCodes(ValueSetExpansionComponent expand, List<ValueSetExpansionParameterComponent> params) {
|
||||
for (ValueSetExpansionContainsComponent c : expand.getContains()) {
|
||||
excludeCode(c.getSystem(), c.getCode());
|
||||
}
|
||||
}
|
||||
if (exc.getFilter().size() > 0)
|
||||
throw new NotImplementedException("not done yet");
|
||||
}
|
||||
|
||||
private boolean existsInParams(List<ValueSetExpansionParameterComponent> params, String name, Type value) {
|
||||
for (ValueSetExpansionParameterComponent p : params) {
|
||||
if (p.getName().equals(name) && PrimitiveType.compareDeep(p.getValue(), value, false))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
private void excludeCodes(ValueSetExpansionComponent expand, List<ValueSetExpansionParameterComponent> params) {
|
||||
for (ValueSetExpansionContainsComponent c : expand.getContains()) {
|
||||
excludeCode(c.getSystem(), c.getCode());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
private boolean existsInParams(List<ValueSetExpansionParameterComponent> params, String name, Type value) {
|
||||
for (ValueSetExpansionParameterComponent p : params) {
|
||||
if (p.getName().equals(name) && PrimitiveType.compareDeep(p.getValue(), value, false))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ValueSetExpansionOutcome expand(ValueSet source, ExpansionProfile profile) {
|
||||
|
||||
if (profile == null)
|
||||
profile = makeDefaultExpansion();
|
||||
try {
|
||||
focus = source.copy();
|
||||
focus.setExpansion(new ValueSet.ValueSetExpansionComponent());
|
||||
focus.getExpansion().setTimestampElement(DateTimeType.now());
|
||||
focus.getExpansion().setIdentifier(Factory.createUUID());
|
||||
try {
|
||||
focus = source.copy();
|
||||
focus.setExpansion(new ValueSet.ValueSetExpansionComponent());
|
||||
focus.getExpansion().setTimestampElement(DateTimeType.now());
|
||||
focus.getExpansion().setIdentifier(Factory.createUUID());
|
||||
if (!profile.getUrl().startsWith("urn:uuid:"))
|
||||
focus.getExpansion().addParameter().setName("profile").setValue(new UriType(profile.getUrl()));
|
||||
|
||||
if (source.hasCompose())
|
||||
if (source.hasCompose())
|
||||
handleCompose(source.getCompose(), focus.getExpansion().getParameter(), profile);
|
||||
|
||||
if (canBeHeirarchy) {
|
||||
|
@ -254,38 +254,38 @@ public class ValueSetExpanderSimple implements ValueSetExpander {
|
|||
focus.getExpansion().getContains().add(c);
|
||||
}
|
||||
} else {
|
||||
for (ValueSetExpansionContainsComponent c : codes) {
|
||||
for (ValueSetExpansionContainsComponent c : codes) {
|
||||
if (map.containsKey(key(c)) && !c.getAbstract()) { // we may have added abstract codes earlier while we still thought it might be heirarchical, but later we gave up, so now ignore them
|
||||
focus.getExpansion().getContains().add(c);
|
||||
focus.getExpansion().getContains().add(c);
|
||||
c.getContains().clear(); // make sure any heirarchy is wiped
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (total > 0) {
|
||||
focus.getExpansion().setTotal(total);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if (total > 0) {
|
||||
focus.getExpansion().setTotal(total);
|
||||
}
|
||||
|
||||
return new ValueSetExpansionOutcome(focus);
|
||||
} catch (RuntimeException e) {
|
||||
// TODO: we should put something more specific instead of just Exception below, since
|
||||
// it swallows bugs.. what would be expected to be caught there?
|
||||
throw e;
|
||||
} catch (RuntimeException e) {
|
||||
// TODO: we should put something more specific instead of just Exception below, since
|
||||
// it swallows bugs.. what would be expected to be caught there?
|
||||
throw e;
|
||||
} catch (NoTerminologyServiceException e) {
|
||||
// well, we couldn't expand, so we'll return an interface to a checker that can check membership of the set
|
||||
// that might fail too, but it might not, later.
|
||||
return new ValueSetExpansionOutcome(new ValueSetCheckerSimple(source, factory, context), e.getMessage(), TerminologyServiceErrorClass.NOSERVICE);
|
||||
} catch (Exception e) {
|
||||
// well, we couldn't expand, so we'll return an interface to a checker that can check membership of the set
|
||||
// that might fail too, but it might not, later.
|
||||
return new ValueSetExpansionOutcome(new ValueSetCheckerSimple(source, factory, context), e.getMessage(), TerminologyServiceErrorClass.UNKNOWN);
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// well, we couldn't expand, so we'll return an interface to a checker that can check membership of the set
|
||||
// that might fail too, but it might not, later.
|
||||
return new ValueSetExpansionOutcome(new ValueSetCheckerSimple(source, factory, context), e.getMessage(), TerminologyServiceErrorClass.UNKNOWN);
|
||||
}
|
||||
}
|
||||
|
||||
private ExpansionProfile makeDefaultExpansion() {
|
||||
ExpansionProfile res = new ExpansionProfile();
|
||||
res.setUrl("urn:uuid:"+UUID.randomUUID().toString().toLowerCase());
|
||||
res.setExcludeNested(true);
|
||||
private ExpansionProfile makeDefaultExpansion() {
|
||||
ExpansionProfile res = new ExpansionProfile();
|
||||
res.setUrl("urn:uuid:" + UUID.randomUUID().toString().toLowerCase());
|
||||
res.setExcludeNested(true);
|
||||
res.setIncludeDesignations(false);
|
||||
return res;
|
||||
}
|
||||
|
@ -296,68 +296,70 @@ public class ValueSetExpanderSimple implements ValueSetExpander {
|
|||
}
|
||||
}
|
||||
|
||||
private String getCodeDisplay(CodeSystem cs, String code) throws TerminologyServiceException {
|
||||
ConceptDefinitionComponent def = getConceptForCode(cs.getConcept(), code);
|
||||
if (def == null)
|
||||
throw new TerminologyServiceException("Unable to find code '" + code + "' in code system " + cs.getUrl());
|
||||
return def.getDisplay();
|
||||
}
|
||||
private String getCodeDisplay(CodeSystem cs, String code) throws TerminologyServiceException {
|
||||
ConceptDefinitionComponent def = getConceptForCode(cs.getConcept(), code);
|
||||
if (def == null)
|
||||
throw new TerminologyServiceException("Unable to find code '" + code + "' in code system " + cs.getUrl());
|
||||
return def.getDisplay();
|
||||
}
|
||||
|
||||
private ConceptDefinitionComponent getConceptForCode(List<ConceptDefinitionComponent> clist, String code) {
|
||||
for (ConceptDefinitionComponent c : clist) {
|
||||
if (code.equals(c.getCode()))
|
||||
return c;
|
||||
ConceptDefinitionComponent v = getConceptForCode(c.getConcept(), code);
|
||||
if (v != null)
|
||||
return v;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
private ConceptDefinitionComponent getConceptForCode(List<ConceptDefinitionComponent> clist, String code) {
|
||||
for (ConceptDefinitionComponent c : clist) {
|
||||
if (code.equals(c.getCode()))
|
||||
return c;
|
||||
ConceptDefinitionComponent v = getConceptForCode(c.getConcept(), code);
|
||||
if (v != null)
|
||||
return v;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private void handleCompose(ValueSetComposeComponent compose, List<ValueSetExpansionParameterComponent> params, ExpansionProfile profile) throws ETooCostly, FileNotFoundException, IOException, FHIRException {
|
||||
// Exclude comes first because we build up a map of things to exclude
|
||||
for (ConceptSetComponent inc : compose.getExclude())
|
||||
excludeCodes(inc, params);
|
||||
private void handleCompose(ValueSetComposeComponent compose, List<ValueSetExpansionParameterComponent> params, ExpansionProfile profile)
|
||||
throws ETooCostly, FileNotFoundException, IOException, FHIRException {
|
||||
// Exclude comes first because we build up a map of things to exclude
|
||||
for (ConceptSetComponent inc : compose.getExclude())
|
||||
excludeCodes(inc, params);
|
||||
canBeHeirarchy = !profile.getExcludeNested() && excludeKeys.isEmpty() && excludeSystems.isEmpty();
|
||||
boolean first = true;
|
||||
for (ConceptSetComponent inc : compose.getInclude()) {
|
||||
if (first == true)
|
||||
first = false;
|
||||
else
|
||||
canBeHeirarchy = false;
|
||||
boolean first = true;
|
||||
for (ConceptSetComponent inc : compose.getInclude()) {
|
||||
if (first == true)
|
||||
first = false;
|
||||
else
|
||||
canBeHeirarchy = false;
|
||||
includeCodes(inc, params, profile);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private ValueSet importValueSet(String value, List<ValueSetExpansionParameterComponent> params, ExpansionProfile profile) throws ETooCostly, TerminologyServiceException, FileNotFoundException, IOException {
|
||||
if (value == null)
|
||||
throw new TerminologyServiceException("unable to find value set with no identity");
|
||||
ValueSet vs = context.fetchResource(ValueSet.class, value);
|
||||
if (vs == null)
|
||||
throw new TerminologyServiceException("Unable to find imported value set " + value);
|
||||
ValueSetExpansionOutcome vso = factory.getExpander().expand(vs, profile);
|
||||
private ValueSet importValueSet(String value, List<ValueSetExpansionParameterComponent> params, ExpansionProfile profile)
|
||||
throws ETooCostly, TerminologyServiceException, FileNotFoundException, IOException {
|
||||
if (value == null)
|
||||
throw new TerminologyServiceException("unable to find value set with no identity");
|
||||
ValueSet vs = context.fetchResource(ValueSet.class, value);
|
||||
if (vs == null)
|
||||
throw new TerminologyServiceException("Unable to find imported value set " + value);
|
||||
ValueSetExpansionOutcome vso = factory.getExpander().expand(vs, profile);
|
||||
if (vso.getError() != null)
|
||||
throw new TerminologyServiceException("Unable to expand imported value set: "+vso.getError());
|
||||
if (vso.getService() != null)
|
||||
throw new TerminologyServiceException("Unable to expand imported value set "+value);
|
||||
if (vs.hasVersion())
|
||||
if (!existsInParams(params, "version", new UriType(vs.getUrl()+"|"+vs.getVersion())))
|
||||
params.add(new ValueSetExpansionParameterComponent().setName("version").setValue(new UriType(vs.getUrl()+"|"+vs.getVersion())));
|
||||
for (ValueSetExpansionParameterComponent p : vso.getValueset().getExpansion().getParameter()) {
|
||||
if (!existsInParams(params, p.getName(), p.getValue()))
|
||||
params.add(p);
|
||||
}
|
||||
throw new TerminologyServiceException("Unable to expand imported value set: " + vso.getError());
|
||||
if (vso.getService() != null)
|
||||
throw new TerminologyServiceException("Unable to expand imported value set " + value);
|
||||
if (vs.hasVersion())
|
||||
if (!existsInParams(params, "version", new UriType(vs.getUrl() + "|" + vs.getVersion())))
|
||||
params.add(new ValueSetExpansionParameterComponent().setName("version").setValue(new UriType(vs.getUrl() + "|" + vs.getVersion())));
|
||||
for (ValueSetExpansionParameterComponent p : vso.getValueset().getExpansion().getParameter()) {
|
||||
if (!existsInParams(params, p.getName(), p.getValue()))
|
||||
params.add(p);
|
||||
}
|
||||
canBeHeirarchy = false; // if we're importing a value set, we have to be combining, so we won't try for a heirarchy
|
||||
return vso.getValueset();
|
||||
return vso.getValueset();
|
||||
}
|
||||
|
||||
private void copyImportContains(List<ValueSetExpansionContainsComponent> list, ValueSetExpansionContainsComponent parent, ExpansionProfile profile, List<ValueSet> filter) {
|
||||
for (ValueSetExpansionContainsComponent c : list) {
|
||||
ValueSetExpansionContainsComponent np = addCode(c.getSystem(), c.getCode(), c.getDisplay(), parent, null, profile, c.getAbstract(), c.getInactive(), filter);
|
||||
copyImportContains(c.getContains(), np, profile, filter);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void includeCodes(ConceptSetComponent inc, List<ValueSetExpansionParameterComponent> params, ExpansionProfile profile) throws ETooCostly, FileNotFoundException, IOException, FHIRException {
|
||||
List<ValueSet> imports = new ArrayList<ValueSet>();
|
||||
|
@ -367,9 +369,9 @@ public class ValueSetExpanderSimple implements ValueSetExpander {
|
|||
if (!inc.hasSystem()) {
|
||||
if (imports.isEmpty()) // though this is not supposed to be the case
|
||||
return;
|
||||
ValueSet base = imports.get(0);
|
||||
ValueSet base = imports.get(0);
|
||||
imports.remove(0);
|
||||
copyImportContains(base.getExpansion().getContains(), null, profile, imports);
|
||||
copyImportContains(base.getExpansion().getContains(), null, profile, imports);
|
||||
} else {
|
||||
CodeSystem cs = context.fetchCodeSystem(inc.getSystem());
|
||||
if ((cs == null || cs.getContent() != CodeSystemContentMode.COMPLETE) && context.supportsSystem(inc.getSystem())) {
|
||||
|
@ -379,15 +381,15 @@ public class ValueSetExpanderSimple implements ValueSetExpander {
|
|||
|
||||
if (cs == null) {
|
||||
if (context.isNoTerminologyServer())
|
||||
throw new NoTerminologyServiceException("unable to find code system "+inc.getSystem().toString());
|
||||
throw new NoTerminologyServiceException("unable to find code system " + inc.getSystem().toString());
|
||||
else
|
||||
throw new TerminologyServiceException("unable to find code system "+inc.getSystem().toString());
|
||||
throw new TerminologyServiceException("unable to find code system " + inc.getSystem().toString());
|
||||
}
|
||||
if (cs.getContent() != CodeSystemContentMode.COMPLETE)
|
||||
throw new TerminologyServiceException("Code system "+inc.getSystem().toString()+" is incomplete");
|
||||
throw new TerminologyServiceException("Code system " + inc.getSystem().toString() + " is incomplete");
|
||||
if (cs.hasVersion())
|
||||
if (!existsInParams(params, "version", new UriType(cs.getUrl()+"|"+cs.getVersion())))
|
||||
params.add(new ValueSetExpansionParameterComponent().setName("version").setValue(new UriType(cs.getUrl()+"|"+cs.getVersion())));
|
||||
if (!existsInParams(params, "version", new UriType(cs.getUrl() + "|" + cs.getVersion())))
|
||||
params.add(new ValueSetExpansionParameterComponent().setName("version").setValue(new UriType(cs.getUrl() + "|" + cs.getVersion())));
|
||||
|
||||
if (inc.getConcept().size() == 0 && inc.getFilter().size() == 0) {
|
||||
// special case - add all the code system
|
||||
|
@ -399,7 +401,8 @@ public class ValueSetExpanderSimple implements ValueSetExpander {
|
|||
if (!inc.getConcept().isEmpty()) {
|
||||
canBeHeirarchy = false;
|
||||
for (ConceptReferenceComponent c : inc.getConcept()) {
|
||||
addCode(inc.getSystem(), c.getCode(), Utilities.noString(c.getDisplay()) ? getCodeDisplay(cs, c.getCode()) : c.getDisplay(), null, convertDesignations(c.getDesignation()), profile, false, CodeSystemUtilities.isInactive(cs, c.getCode()), imports);
|
||||
addCode(inc.getSystem(), c.getCode(), Utilities.noString(c.getDisplay()) ? getCodeDisplay(cs, c.getCode()) : c.getDisplay(), null, convertDesignations(c.getDesignation()), profile, false,
|
||||
CodeSystemUtilities.isInactive(cs, c.getCode()), imports);
|
||||
}
|
||||
}
|
||||
if (inc.getFilter().size() > 1) {
|
||||
|
@ -412,13 +415,13 @@ public class ValueSetExpanderSimple implements ValueSetExpander {
|
|||
// special: all codes in the target code system under the value
|
||||
ConceptDefinitionComponent def = getConceptForCode(cs.getConcept(), fc.getValue());
|
||||
if (def == null)
|
||||
throw new TerminologyServiceException("Code '"+fc.getValue()+"' not found in system '"+inc.getSystem()+"'");
|
||||
throw new TerminologyServiceException("Code '" + fc.getValue() + "' not found in system '" + inc.getSystem() + "'");
|
||||
addCodeAndDescendents(cs, inc.getSystem(), def, null, profile, imports);
|
||||
} else if ("concept".equals(fc.getProperty()) && fc.getOp() == FilterOperator.DESCENDENTOF) {
|
||||
// special: all codes in the target code system under the value
|
||||
ConceptDefinitionComponent def = getConceptForCode(cs.getConcept(), fc.getValue());
|
||||
if (def == null)
|
||||
throw new TerminologyServiceException("Code '"+fc.getValue()+"' not found in system '"+inc.getSystem()+"'");
|
||||
throw new TerminologyServiceException("Code '" + fc.getValue() + "' not found in system '" + inc.getSystem() + "'");
|
||||
for (ConceptDefinitionComponent c : def.getConcept())
|
||||
addCodeAndDescendents(cs, inc.getSystem(), c, null, profile, imports);
|
||||
} else if ("display".equals(fc.getProperty()) && fc.getOp() == FilterOperator.EQUAL) {
|
||||
|
@ -428,7 +431,8 @@ public class ValueSetExpanderSimple implements ValueSetExpander {
|
|||
if (def != null) {
|
||||
if (isNotBlank(def.getDisplay()) && isNotBlank(fc.getValue())) {
|
||||
if (def.getDisplay().contains(fc.getValue())) {
|
||||
addCode(inc.getSystem(), def.getCode(), def.getDisplay(), null, def.getDesignation(), profile, CodeSystemUtilities.isNotSelectable(cs, def), CodeSystemUtilities.isInactive(cs, def), imports);
|
||||
addCode(inc.getSystem(), def.getCode(), def.getDisplay(), null, def.getDesignation(), profile, CodeSystemUtilities.isNotSelectable(cs, def), CodeSystemUtilities.isInactive(cs, def),
|
||||
imports);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -449,12 +453,12 @@ public class ValueSetExpanderSimple implements ValueSetExpander {
|
|||
return res;
|
||||
}
|
||||
|
||||
private String key(String uri, String code) {
|
||||
return "{" + uri + "}" + code;
|
||||
}
|
||||
private String key(String uri, String code) {
|
||||
return "{" + uri + "}" + code;
|
||||
}
|
||||
|
||||
private String key(ValueSetExpansionContainsComponent c) {
|
||||
return key(c.getSystem(), c.getCode());
|
||||
}
|
||||
private String key(ValueSetExpansionContainsComponent c) {
|
||||
return key(c.getSystem(), c.getCode());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -145,6 +145,12 @@
|
|||
<![CDATA[<code>IBundleProvider</code> called <code>getUuid()</code>]]>. This
|
||||
method may return <![CDATA[<code>null</code>]]> in any current cases.
|
||||
</action>
|
||||
<action type="fix">
|
||||
Expanding a ValueSet in JPA server did not correctly apply
|
||||
<![CDATA[<code>?filter=</code>]]> parameter when the ValueSet
|
||||
being expanded had codes included explicitly (i.e. not by
|
||||
is-a relationship). Thanks to David Hay for reporting!
|
||||
</action>
|
||||
</release>
|
||||
<release version="2.2" date="2016-12-20">
|
||||
<action type="add">
|
||||
|
|
Loading…
Reference in New Issue