Merge branch 'master' of github.com:jamesagnew/hapi-fhir

This commit is contained in:
James Agnew 2019-09-16 15:55:49 -04:00
commit 882e0853df
6 changed files with 1002 additions and 129 deletions

View File

@ -62,6 +62,7 @@ public class TermConceptProperty implements Serializable {
@Column(name = "PROP_KEY", nullable = false, length = MAX_LENGTH) @Column(name = "PROP_KEY", nullable = false, length = MAX_LENGTH)
@NotBlank @NotBlank
private String myKey; private String myKey;
// FIXME: DM 2019-09-13 - We presently truncate down to 500. The longest value for EXTERNAL_COPYRIGHT_NOTICE is 2,597 so we should use a LOB instead of a String.
@Column(name = "PROP_VAL", nullable = true, length = MAX_LENGTH) @Column(name = "PROP_VAL", nullable = true, length = MAX_LENGTH)
private String myValue; private String myValue;
@Column(name = "PROP_TYPE", nullable = false, length = MAX_PROPTYPE_ENUM_LENGTH) @Column(name = "PROP_TYPE", nullable = false, length = MAX_PROPTYPE_ENUM_LENGTH)

View File

@ -691,11 +691,11 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc,
/** /**
* @return Returns true if there are potentially more results to process. * @return Returns true if there are potentially more results to process.
*/ */
private Boolean expandValueSetHandleIncludeOrExclude(IValueSetConceptAccumulator theValueSetCodeAccumulator, Set<String> theAddedCodes, ValueSet.ConceptSetComponent theInclude, boolean theAdd, AtomicInteger theCodeCounter, int theQueryIndex) { private Boolean expandValueSetHandleIncludeOrExclude(IValueSetConceptAccumulator theValueSetCodeAccumulator, Set<String> theAddedCodes, ValueSet.ConceptSetComponent theIncludeOrExclude, boolean theAdd, AtomicInteger theCodeCounter, int theQueryIndex) {
String system = theInclude.getSystem(); String system = theIncludeOrExclude.getSystem();
boolean hasSystem = isNotBlank(system); boolean hasSystem = isNotBlank(system);
boolean hasValueSet = theInclude.getValueSet().size() > 0; boolean hasValueSet = theIncludeOrExclude.getValueSet().size() > 0;
if (hasSystem) { if (hasSystem) {
ourLog.info("Starting {} expansion around CodeSystem: {}", (theAdd ? "inclusion" : "exclusion"), system); ourLog.info("Starting {} expansion around CodeSystem: {}", (theAdd ? "inclusion" : "exclusion"), system);
@ -711,7 +711,7 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc,
* since we're going to do it without the database. * since we're going to do it without the database.
*/ */
if (myFulltextSearchSvc == null) { if (myFulltextSearchSvc == null) {
expandWithoutHibernateSearch(theValueSetCodeAccumulator, theAddedCodes, theInclude, system, theAdd, theCodeCounter); expandWithoutHibernateSearch(theValueSetCodeAccumulator, theAddedCodes, theIncludeOrExclude, system, theAdd, theCodeCounter);
return false; return false;
} }
@ -726,85 +726,14 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc,
/* /*
* Filters * Filters
*/ */
handleFilters(bool, system, qb, theIncludeOrExclude);
if (theInclude.getFilter().size() > 0) {
for (ValueSet.ConceptSetFilterComponent nextFilter : theInclude.getFilter()) {
if (isBlank(nextFilter.getValue()) && nextFilter.getOp() == null && isBlank(nextFilter.getProperty())) {
continue;
}
if (isBlank(nextFilter.getValue()) || nextFilter.getOp() == null || isBlank(nextFilter.getProperty())) {
throw new InvalidRequestException("Invalid filter, must have fields populated: property op value");
}
if (nextFilter.getProperty().equals("display:exact") && nextFilter.getOp() == ValueSet.FilterOperator.EQUAL) {
addDisplayFilterExact(qb, bool, nextFilter);
} else if ("display".equals(nextFilter.getProperty()) && nextFilter.getOp() == ValueSet.FilterOperator.EQUAL) {
if (nextFilter.getValue().trim().contains(" ")) {
addDisplayFilterExact(qb, bool, nextFilter);
} else {
addDisplayFilterInexact(qb, bool, nextFilter);
}
} else if (nextFilter.getProperty().equals("concept") || nextFilter.getProperty().equals("code")) {
TermConcept code = findCode(system, nextFilter.getValue())
.orElseThrow(() -> new InvalidRequestException("Invalid filter criteria - code does not exist: {" + system + "}" + nextFilter.getValue()));
if (nextFilter.getOp() == ValueSet.FilterOperator.ISA) {
ourLog.info(" * Filtering on codes with a parent of {}/{}/{}", code.getId(), code.getCode(), code.getDisplay());
bool.must(qb.keyword().onField("myParentPids").matching("" + code.getId()).createQuery());
} else {
throw new InvalidRequestException("Don't know how to handle op=" + nextFilter.getOp() + " on property " + nextFilter.getProperty());
}
} else {
if (nextFilter.getOp() == ValueSet.FilterOperator.REGEX) {
/*
* We treat the regex filter as a match on the regex
* anywhere in the property string. The spec does not
* say whether or not this is the right behaviour, but
* there are examples that seem to suggest that it is.
*/
String value = nextFilter.getValue();
if (value.endsWith("$")) {
value = value.substring(0, value.length() - 1);
} else if (!value.endsWith(".*")) {
value = value + ".*";
}
if (!value.startsWith("^") && !value.startsWith(".*")) {
value = ".*" + value;
} else if (value.startsWith("^")) {
value = value.substring(1);
}
Term term = new Term(TermConceptPropertyFieldBridge.CONCEPT_FIELD_PROPERTY_PREFIX + nextFilter.getProperty(), value);
RegexpQuery query = new RegexpQuery(term);
bool.must(query);
} else {
String value = nextFilter.getValue();
Term term = new Term(TermConceptPropertyFieldBridge.CONCEPT_FIELD_PROPERTY_PREFIX + nextFilter.getProperty(), value);
bool.must(new TermsQuery(term));
}
}
}
}
Query luceneQuery = bool.createQuery(); Query luceneQuery = bool.createQuery();
/* /*
* Include Concepts * Include/Exclude Concepts
*/ */
List<Term> codes = theIncludeOrExclude
List<Term> codes = theInclude
.getConcept() .getConcept()
.stream() .stream()
.filter(Objects::nonNull) .filter(Objects::nonNull)
@ -824,8 +753,8 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc,
/* /*
* Execute the query * Execute the query
*/ */
FullTextQuery jpaQuery = em.createFullTextQuery(luceneQuery, TermConcept.class); FullTextQuery jpaQuery = em.createFullTextQuery(luceneQuery, TermConcept.class);
/* /*
* DM 2019-08-21 - Processing slows after any ValueSets with many codes explicitly identified. This might * DM 2019-08-21 - Processing slows after any ValueSets with many codes explicitly identified. This might
* be due to the dark arts that is memory management. Will monitor but not do anything about this right now. * be due to the dark arts that is memory management. Will monitor but not do anything about this right now.
@ -864,15 +793,15 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc,
} }
} else { } else {
// No codesystem matching the URL found in the database // No CodeSystem matching the URL found in the database.
CodeSystem codeSystemFromContext = getCodeSystemFromContext(system); CodeSystem codeSystemFromContext = getCodeSystemFromContext(system);
if (codeSystemFromContext == null) { if (codeSystemFromContext == null) {
throw new InvalidRequestException("Unknown code system: " + system); throw new InvalidRequestException("Unknown code system: " + system);
} }
if (!theInclude.getConcept().isEmpty()) { if (!theIncludeOrExclude.getConcept().isEmpty()) {
for (ValueSet.ConceptReferenceComponent next : theInclude.getConcept()) { for (ValueSet.ConceptReferenceComponent next : theIncludeOrExclude.getConcept()) {
String nextCode = next.getCode(); String nextCode = next.getCode();
if (isNoneBlank(system, nextCode) && !theAddedCodes.contains(system + "|" + nextCode)) { if (isNoneBlank(system, nextCode) && !theAddedCodes.contains(system + "|" + nextCode)) {
CodeSystem.ConceptDefinitionComponent code = findCode(codeSystemFromContext.getConcept(), nextCode); CodeSystem.ConceptDefinitionComponent code = findCode(codeSystemFromContext.getConcept(), nextCode);
@ -895,7 +824,7 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc,
} }
} else if (hasValueSet) { } else if (hasValueSet) {
for (CanonicalType nextValueSet : theInclude.getValueSet()) { for (CanonicalType nextValueSet : theIncludeOrExclude.getValueSet()) {
ourLog.info("Starting {} expansion around ValueSet: {}", (theAdd ? "inclusion" : "exclusion"), nextValueSet.getValueAsString()); ourLog.info("Starting {} expansion around ValueSet: {}", (theAdd ? "inclusion" : "exclusion"), nextValueSet.getValueAsString());
List<VersionIndependentConcept> expanded = expandValueSet(nextValueSet.getValueAsString()); List<VersionIndependentConcept> expanded = expandValueSet(nextValueSet.getValueAsString());
@ -925,6 +854,191 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc,
} }
private void handleFilters(BooleanJunction<?> theBool, String theSystem, QueryBuilder theQb, ValueSet.ConceptSetComponent theIncludeOrExclude) {
if (theIncludeOrExclude.getFilter().size() > 0) {
for (ValueSet.ConceptSetFilterComponent nextFilter : theIncludeOrExclude.getFilter()) {
handleFilter(theSystem, theQb, theBool, nextFilter);
}
}
}
private void handleFilter(String theSystem, QueryBuilder theQb, BooleanJunction<?> theBool, ValueSet.ConceptSetFilterComponent theFilter) {
if (isBlank(theFilter.getValue()) && theFilter.getOp() == null && isBlank(theFilter.getProperty())) {
return;
}
if (isBlank(theFilter.getValue()) || theFilter.getOp() == null || isBlank(theFilter.getProperty())) {
throw new InvalidRequestException("Invalid filter, must have fields populated: property op value");
}
switch (theFilter.getProperty()) {
case "display:exact":
case "display":
handleFilterDisplay(theQb, theBool, theFilter);
break;
case "concept":
case "code":
handleFilterConceptAndCode(theSystem, theQb, theBool, theFilter);
break;
case "parent":
case "child":
if (isCodeSystemLoinc(theSystem)) {
handleFilterLoincParentChild(theQb, theBool, theFilter);
} else {
throw new InvalidRequestException("Invalid filter, property " + theFilter.getProperty() + " is LOINC-specific and cannot be used with system: " + theSystem);
}
break;
case "copyright":
if (isCodeSystemLoinc(theSystem)) {
handleFilterLoincCopyright(theQb, theBool, theFilter);
} else {
throw new InvalidRequestException("Invalid filter, property " + theFilter.getProperty() + " is LOINC-specific and cannot be used with system: " + theSystem);
}
break;
default:
handleFilterRegex(theBool, theFilter);
break;
}
}
private boolean isCodeSystemLoinc(String theSystem) {
return IHapiTerminologyLoaderSvc.LOINC_URI.equals(theSystem);
}
private void handleFilterDisplay(QueryBuilder theQb, BooleanJunction<?> theBool, ValueSet.ConceptSetFilterComponent theFilter) {
if (theFilter.getProperty().equals("display:exact") && theFilter.getOp() == ValueSet.FilterOperator.EQUAL) {
addDisplayFilterExact(theQb, theBool, theFilter);
} else if (theFilter.getProperty().equals("display") && theFilter.getOp() == ValueSet.FilterOperator.EQUAL) {
if (theFilter.getValue().trim().contains(" ")) {
addDisplayFilterExact(theQb, theBool, theFilter);
} else {
addDisplayFilterInexact(theQb, theBool, theFilter);
}
}
}
private void handleFilterConceptAndCode(String theSystem, QueryBuilder theQb, BooleanJunction<?> theBool, ValueSet.ConceptSetFilterComponent theFilter) {
TermConcept code = findCode(theSystem, theFilter.getValue())
.orElseThrow(() -> new InvalidRequestException("Invalid filter criteria - code does not exist: {" + theSystem + "}" + theFilter.getValue()));
if (theFilter.getOp() == ValueSet.FilterOperator.ISA) {
ourLog.info(" * Filtering on codes with a parent of {}/{}/{}", code.getId(), code.getCode(), code.getDisplay());
theBool.must(theQb.keyword().onField("myParentPids").matching("" + code.getId()).createQuery());
} else {
throw new InvalidRequestException("Don't know how to handle op=" + theFilter.getOp() + " on property " + theFilter.getProperty());
}
}
private void handleFilterLoincParentChild(QueryBuilder theQb, BooleanJunction<?> theBool, ValueSet.ConceptSetFilterComponent theFilter) {
if (theFilter.getOp() == ValueSet.FilterOperator.EQUAL) {
addLoincFilterParentChildEqual(theBool, theFilter.getProperty(), theFilter.getValue());
} else if (theFilter.getOp() == ValueSet.FilterOperator.IN) {
addLoincFilterParentChildIn(theBool, theFilter);
} else {
throw new InvalidRequestException("Don't know how to handle op=" + theFilter.getOp() + " on property " + theFilter.getProperty());
}
}
private void addLoincFilterParentChildEqual(BooleanJunction<?> theBool, String theProperty, String theValue) {
logFilteringValueOnProperty(theValue, theProperty);
theBool.must(new TermsQuery(getPropertyTerm(theProperty, theValue)));
}
private void addLoincFilterParentChildIn(BooleanJunction<?> theBool, ValueSet.ConceptSetFilterComponent theFilter) {
String[] values = theFilter.getValue().split(",");
List<Term> terms = new ArrayList<>();
for (String value : values) {
logFilteringValueOnProperty(value, theFilter.getProperty());
terms.add(getPropertyTerm(theFilter.getProperty(), value));
}
theBool.must(new TermsQuery(terms));
}
private Term getPropertyTerm(String theProperty, String theValue) {
return new Term(TermConceptPropertyFieldBridge.CONCEPT_FIELD_PROPERTY_PREFIX + theProperty, theValue);
}
private void handleFilterLoincCopyright(QueryBuilder theQb, BooleanJunction<?> theBool, ValueSet.ConceptSetFilterComponent theFilter) {
if (theFilter.getOp() == ValueSet.FilterOperator.EQUAL) {
String copyrightFilterValue = defaultString(theFilter.getValue()).toLowerCase();
switch (copyrightFilterValue) {
case "3rdparty":
logFilteringValueOnProperty(theFilter.getValue(), theFilter.getProperty());
addFilterLoincCopyright3rdParty(theBool);
break;
case "loinc":
logFilteringValueOnProperty(theFilter.getValue(), theFilter.getProperty());
addFilterLoincCopyrightLoinc(theBool);
break;
default:
throwInvalidRequestForValueOnProperty(theFilter.getValue(), theFilter.getProperty());
}
} else {
throwInvalidRequestForOpOnProperty(theFilter.getOp(), theFilter.getProperty());
}
}
private void addFilterLoincCopyright3rdParty(BooleanJunction<?> theBool) {
theBool.must(getRegexQueryForFilterLoincCopyright());
}
private void addFilterLoincCopyrightLoinc(BooleanJunction<?> theBool) {
theBool.must(getRegexQueryForFilterLoincCopyright()).not();
}
private RegexpQuery getRegexQueryForFilterLoincCopyright() {
Term term = new Term(TermConceptPropertyFieldBridge.CONCEPT_FIELD_PROPERTY_PREFIX + "EXTERNAL_COPYRIGHT_NOTICE", ".*");
return new RegexpQuery(term);
}
private void logFilteringValueOnProperty(String theValue, String theProperty) {
ourLog.info(" * Filtering with value={} on property {}", theValue, theProperty);
}
private void throwInvalidRequestForOpOnProperty(ValueSet.FilterOperator theOp, String theProperty) {
throw new InvalidRequestException("Don't know how to handle op=" + theOp + " on property " + theProperty);
}
private void throwInvalidRequestForValueOnProperty(String theValue, String theProperty) {
throw new InvalidRequestException("Don't know how to handle value=" + theValue + " on property " + theProperty);
}
private void handleFilterRegex(BooleanJunction<?> theBool, ValueSet.ConceptSetFilterComponent theFilter) {
if (theFilter.getOp() == ValueSet.FilterOperator.REGEX) {
/*
* We treat the regex filter as a match on the regex
* anywhere in the property string. The spec does not
* say whether or not this is the right behaviour, but
* there are examples that seem to suggest that it is.
*/
String value = theFilter.getValue();
if (value.endsWith("$")) {
value = value.substring(0, value.length() - 1);
} else if (!value.endsWith(".*")) {
value = value + ".*";
}
if (!value.startsWith("^") && !value.startsWith(".*")) {
value = ".*" + value;
} else if (value.startsWith("^")) {
value = value.substring(1);
}
Term term = new Term(TermConceptPropertyFieldBridge.CONCEPT_FIELD_PROPERTY_PREFIX + theFilter.getProperty(), value);
RegexpQuery query = new RegexpQuery(term);
theBool.must(query);
} else {
String value = theFilter.getValue();
Term term = new Term(TermConceptPropertyFieldBridge.CONCEPT_FIELD_PROPERTY_PREFIX + theFilter.getProperty(), value);
theBool.must(new TermsQuery(term));
}
}
private void expandWithoutHibernateSearch(IValueSetConceptAccumulator theValueSetCodeAccumulator, Set<String> theAddedCodes, ValueSet.ConceptSetComponent theInclude, String theSystem, boolean theAdd, AtomicInteger theCodeCounter) { private void expandWithoutHibernateSearch(IValueSetConceptAccumulator theValueSetCodeAccumulator, Set<String> theAddedCodes, ValueSet.ConceptSetComponent theInclude, String theSystem, boolean theAdd, AtomicInteger theCodeCounter) {
ourLog.trace("Hibernate search is not enabled"); ourLog.trace("Hibernate search is not enabled");
if (theValueSetCodeAccumulator instanceof ValueSetExpansionComponentWithConceptAccumulator) { if (theValueSetCodeAccumulator instanceof ValueSetExpansionComponentWithConceptAccumulator) {

View File

@ -480,6 +480,13 @@ public class TerminologyLoaderSvcImpl implements IHapiTerminologyLoaderSvc {
} }
} }
// FIXME: DM 2019-09-13 - Manually add EXTERNAL_COPYRIGHT_NOTICE property until Regenstrief adds this to loinc.xml
if (!propertyNamesToTypes.containsKey("EXTERNAL_COPYRIGHT_NOTICE")) {
String externalCopyRightNoticeCode = "EXTERNAL_COPYRIGHT_NOTICE";
CodeSystem.PropertyType externalCopyRightNoticeType = CodeSystem.PropertyType.STRING;
propertyNamesToTypes.put(externalCopyRightNoticeCode, externalCopyRightNoticeType);
}
IRecordHandler handler; IRecordHandler handler;
// Part // Part

View File

@ -68,7 +68,7 @@ public class TerminologyLoaderSvcLoincTest extends BaseLoaderTest {
ValueSet vs; ValueSet vs;
ConceptMap.ConceptMapGroupComponent group; ConceptMap.ConceptMapGroupComponent group;
// Normal loinc code // Normal LOINC code
code = concepts.get("10013-1"); code = concepts.get("10013-1");
assertEquals("10013-1", code.getCode()); assertEquals("10013-1", code.getCode());
assertEquals(IHapiTerminologyLoaderSvc.LOINC_URI, code.getCodingProperties("PROPERTY").get(0).getSystem()); assertEquals(IHapiTerminologyLoaderSvc.LOINC_URI, code.getCodingProperties("PROPERTY").get(0).getSystem());
@ -84,10 +84,17 @@ public class TerminologyLoaderSvcLoincTest extends BaseLoaderTest {
assertEquals("http://loinc.org", code.getCodingProperties("COMPONENT").get(0).getSystem()); assertEquals("http://loinc.org", code.getCodingProperties("COMPONENT").get(0).getSystem());
assertEquals("LP19258-0", code.getCodingProperties("COMPONENT").get(0).getCode()); assertEquals("LP19258-0", code.getCodingProperties("COMPONENT").get(0).getCode());
// Loinc code with answer // LOINC code with answer
code = concepts.get("61438-8"); code = concepts.get("61438-8");
assertThat(code.getStringProperties("answer-list"), contains("LL1000-0")); assertThat(code.getStringProperties("answer-list"), contains("LL1000-0"));
// LOINC code with 3rd party copyright
code = concepts.get("47239-9");
// FIXME: DM 2019-09-13 - We presently truncate down to 500. The longest value for EXTERNAL_COPYRIGHT_NOTICE is 2,597 so we should use a LOB instead of a String.
// String expectedExternalCopyrightNotice = "Copyright © 2006 World Health Organization. Used with permission. Publications of the World Health Organization can be obtained from WHO Press, World Health Organization, 20 Avenue Appia, 1211 Geneva 27, Switzerland (tel: +41 22 791 2476; fax: +41 22 791 4857; email: bookorders@who.int). Requests for permission to reproduce or translate WHO publications whether for sale or for noncommercial distribution should be addressed to WHO Press, at the above address (fax: +41 22 791 4806; email: permissions@who.int). The designations employed and the presentation of the material in this publication do not imply the expression of any opinion whatsoever on the part of the World Health Organization concerning the legal status of any country, territory, city or area or of its authorities, or concerning the delimitation of its frontiers or boundaries. Dotted lines on maps represent approximate border lines for which there may not yet be full agreement. The mention of specific companies or of certain manufacturers products does not imply that they are endorsed or recommended by the World Health Organization in preference to others of a similar nature that are not mentioned. Errors and omissions excepted, the names of proprietary products are distinguished by initial capital letters. All reasonable precautions have been taken by WHO to verify the information contained in this publication. However, the published material is being distributed without warranty of any kind, either express or implied. The responsibility for the interpretation and use of the material lies with the reader. In no event shall the World Health Organization be liable for damages arising from its use.";
String expectedExternalCopyrightNotice = "Copyright © 2006 World Health Organization. Used with permission. Publications of the World Health Organization can be obtained from WHO Press, World Health Organization, 20 Avenue Appia, 1211 Geneva 27, Switzerland (tel: +41 22 791 2476; fax: +41 22 791 4857; email: bookorders@who.int). Requests for permission to reproduce or translate WHO publications whether for sale or for noncommercial distribution should be addressed to WHO Press, at the above address (fax: +41 22 791 4806; email: perm";
assertEquals(expectedExternalCopyrightNotice, code.getStringProperty("EXTERNAL_COPYRIGHT_NOTICE"));
// Answer list // Answer list
code = concepts.get("LL1001-8"); code = concepts.get("LL1001-8");
assertEquals("LL1001-8", code.getCode()); assertEquals("LL1001-8", code.getCode());
@ -330,7 +337,7 @@ public class TerminologyLoaderSvcLoincTest extends BaseLoaderTest {
Map<String, ValueSet> valueSets = extractValueSets(); Map<String, ValueSet> valueSets = extractValueSets();
Map<String, ConceptMap> conceptMaps = extractConceptMaps(); Map<String, ConceptMap> conceptMaps = extractConceptMaps();
// Normal loinc code // Normal LOINC code
TermConcept code = concepts.get("10013-1"); TermConcept code = concepts.get("10013-1");
assertEquals("10013-1", code.getCode()); assertEquals("10013-1", code.getCode());
@ -394,7 +401,7 @@ public class TerminologyLoaderSvcLoincTest extends BaseLoaderTest {
ValueSet vs; ValueSet vs;
ConceptMap.ConceptMapGroupComponent group; ConceptMap.ConceptMapGroupComponent group;
// Normal loinc code // Normal LOINC code
code = concepts.get("10013-1"); code = concepts.get("10013-1");
assertEquals("10013-1", code.getCode()); assertEquals("10013-1", code.getCode());
assertEquals(IHapiTerminologyLoaderSvc.LOINC_URI, code.getCodingProperties("PROPERTY").get(0).getSystem()); assertEquals(IHapiTerminologyLoaderSvc.LOINC_URI, code.getCodingProperties("PROPERTY").get(0).getSystem());

View File

@ -31,6 +31,7 @@ import java.util.List;
import java.util.Set; import java.util.Set;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import static ca.uhn.fhir.jpa.term.IHapiTerminologyLoaderSvc.LOINC_URI;
import static org.hamcrest.Matchers.*; import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*; import static org.junit.Assert.*;
@ -124,7 +125,7 @@ public class TerminologySvcImplDstu3Test extends BaseJpaDstu3Test {
public void createLoincSystemWithSomeCodes() { public void createLoincSystemWithSomeCodes() {
runInTransaction(() -> { runInTransaction(() -> {
CodeSystem codeSystem = new CodeSystem(); CodeSystem codeSystem = new CodeSystem();
codeSystem.setUrl(CS_URL); codeSystem.setUrl(LOINC_URI);
codeSystem.setContent(CodeSystemContentMode.NOTPRESENT); codeSystem.setContent(CodeSystemContentMode.NOTPRESENT);
IIdType id = myCodeSystemDao.create(codeSystem, mySrd).getId().toUnqualified(); IIdType id = myCodeSystemDao.create(codeSystem, mySrd).getId().toUnqualified();
@ -133,22 +134,57 @@ public class TerminologySvcImplDstu3Test extends BaseJpaDstu3Test {
TermCodeSystemVersion cs = new TermCodeSystemVersion(); TermCodeSystemVersion cs = new TermCodeSystemVersion();
cs.setResource(table); cs.setResource(table);
TermConcept code; TermConcept code1 = new TermConcept(cs, "50015-7");
code = new TermConcept(cs, "50015-7"); TermConcept code2 = new TermConcept(cs, "43343-3");
code.addPropertyString("SYSTEM", "Bld/Bone mar^Donor"); TermConcept code3 = new TermConcept(cs, "43343-4");
cs.getConcepts().add(code); TermConcept code4 = new TermConcept(cs, "47239-9");
code = new TermConcept(cs, "43343-3"); code1.addPropertyString("SYSTEM", "Bld/Bone mar^Donor");
code.addPropertyString("SYSTEM", "Ser"); code1.addPropertyCoding(
code.addPropertyString("HELLO", "12345-1"); "child",
cs.getConcepts().add(code); LOINC_URI,
code2.getCode(),
code2.getDisplay());
cs.getConcepts().add(code1);
code = new TermConcept(cs, "43343-4"); code2.addPropertyString("SYSTEM", "Ser");
code.addPropertyString("SYSTEM", "Ser"); code2.addPropertyString("HELLO", "12345-1");
code.addPropertyString("HELLO", "12345-2"); code2.addPropertyCoding(
cs.getConcepts().add(code); "parent",
LOINC_URI,
code1.getCode(),
code1.getDisplay());
code2.addPropertyCoding(
"child",
LOINC_URI,
code3.getCode(),
code3.getDisplay());
code2.addPropertyCoding(
"child",
LOINC_URI,
code4.getCode(),
code4.getDisplay());
cs.getConcepts().add(code2);
myTermSvc.storeNewCodeSystemVersion(table.getId(), CS_URL, "SYSTEM NAME", "SYSTEM VERSION" , cs); code3.addPropertyString("SYSTEM", "Ser");
code3.addPropertyString("HELLO", "12345-2");
code3.addPropertyCoding(
"parent",
LOINC_URI,
code2.getCode(),
code2.getDisplay());
cs.getConcepts().add(code3);
code4.addPropertyString("SYSTEM", "^Patient");
code4.addPropertyString("EXTERNAL_COPYRIGHT_NOTICE", "Copyright © 2006 World Health Organization...");
code4.addPropertyCoding(
"parent",
LOINC_URI,
code2.getCode(),
code2.getDisplay());
cs.getConcepts().add(code4);
myTermSvc.storeNewCodeSystemVersion(table.getId(), LOINC_URI, "SYSTEM NAME", "SYSTEM VERSION" , cs);
}); });
} }
@ -273,6 +309,714 @@ public class TerminologySvcImplDstu3Test extends BaseJpaDstu3Test {
} }
@Test
public void testExpandValueSetPropertyFilterLoincCopyrightWithExclude3rdParty() {
createLoincSystemWithSomeCodes();
List<String> codes;
ValueSet vs;
ValueSet outcome;
ValueSet.ConceptSetComponent exclude;
// Include
vs = new ValueSet();
vs.getCompose()
.addInclude()
.setSystem(LOINC_URI);
// Exclude
exclude = vs.getCompose().addExclude();
exclude.setSystem(LOINC_URI);
exclude
.addFilter()
.setProperty("copyright")
.setOp(ValueSet.FilterOperator.EQUAL)
.setValue("3rdParty");
outcome = myTermSvc.expandValueSet(vs);
codes = toCodesContains(outcome.getExpansion().getContains());
assertThat(codes, containsInAnyOrder("50015-7", "43343-3", "43343-4"));
// Include
vs = new ValueSet();
vs.getCompose()
.addInclude()
.setSystem(LOINC_URI);
// Exclude
exclude = vs.getCompose().addExclude();
exclude.setSystem(LOINC_URI);
exclude
.addFilter()
.setProperty("copyright")
.setOp(ValueSet.FilterOperator.EQUAL)
.setValue("3rdparty");
outcome = myTermSvc.expandValueSet(vs);
codes = toCodesContains(outcome.getExpansion().getContains());
assertThat(codes, containsInAnyOrder("50015-7", "43343-3", "43343-4"));
}
@Test
public void testExpandValueSetPropertyFilterLoincCopyrightWithExcludeLoinc() {
createLoincSystemWithSomeCodes();
List<String> codes;
ValueSet vs;
ValueSet outcome;
ValueSet.ConceptSetComponent exclude;
// Include
vs = new ValueSet();
vs.getCompose()
.addInclude()
.setSystem(LOINC_URI);
// Exclude
exclude = vs.getCompose().addExclude();
exclude.setSystem(LOINC_URI);
exclude
.addFilter()
.setProperty("copyright")
.setOp(ValueSet.FilterOperator.EQUAL)
.setValue("LOINC");
outcome = myTermSvc.expandValueSet(vs);
codes = toCodesContains(outcome.getExpansion().getContains());
assertThat(codes, containsInAnyOrder("47239-9"));
// Include
vs = new ValueSet();
vs.getCompose()
.addInclude()
.setSystem(LOINC_URI);
// Exclude
exclude = vs.getCompose().addExclude();
exclude.setSystem(LOINC_URI);
exclude
.addFilter()
.setProperty("copyright")
.setOp(ValueSet.FilterOperator.EQUAL)
.setValue("loinc");
outcome = myTermSvc.expandValueSet(vs);
codes = toCodesContains(outcome.getExpansion().getContains());
assertThat(codes, containsInAnyOrder("47239-9"));
}
@Test
public void testExpandValueSetPropertyFilterLoincCopyrightWithInclude3rdParty() {
createLoincSystemWithSomeCodes();
List<String> codes;
ValueSet vs;
ValueSet outcome;
ValueSet.ConceptSetComponent include;
// Include
vs = new ValueSet();
include = vs.getCompose().addInclude();
include.setSystem(LOINC_URI);
include
.addFilter()
.setProperty("copyright")
.setOp(ValueSet.FilterOperator.EQUAL)
.setValue("3rdParty");
outcome = myTermSvc.expandValueSet(vs);
codes = toCodesContains(outcome.getExpansion().getContains());
assertThat(codes, containsInAnyOrder("47239-9"));
// Include
vs = new ValueSet();
include = vs.getCompose().addInclude();
include.setSystem(LOINC_URI);
include
.addFilter()
.setProperty("copyright")
.setOp(ValueSet.FilterOperator.EQUAL)
.setValue("3rdparty");
outcome = myTermSvc.expandValueSet(vs);
codes = toCodesContains(outcome.getExpansion().getContains());
assertThat(codes, containsInAnyOrder("47239-9"));
}
@Test
public void testExpandValueSetPropertyFilterLoincCopyrightWithIncludeLoinc() {
createLoincSystemWithSomeCodes();
List<String> codes;
ValueSet vs;
ValueSet outcome;
ValueSet.ConceptSetComponent include;
// Include
vs = new ValueSet();
include = vs.getCompose().addInclude();
include.setSystem(LOINC_URI);
include
.addFilter()
.setProperty("copyright")
.setOp(ValueSet.FilterOperator.EQUAL)
.setValue("LOINC");
outcome = myTermSvc.expandValueSet(vs);
codes = toCodesContains(outcome.getExpansion().getContains());
assertThat(codes, containsInAnyOrder("50015-7", "43343-3", "43343-4"));
// Include
vs = new ValueSet();
include = vs.getCompose().addInclude();
include.setSystem(LOINC_URI);
include
.addFilter()
.setProperty("copyright")
.setOp(ValueSet.FilterOperator.EQUAL)
.setValue("loinc");
outcome = myTermSvc.expandValueSet(vs);
codes = toCodesContains(outcome.getExpansion().getContains());
assertThat(codes, containsInAnyOrder("50015-7", "43343-3", "43343-4"));
}
@Test
public void testExpandValueSetPropertyFilterLoincCopyrightWithUnsupportedOp() {
createLoincSystemWithSomeCodes();
ValueSet vs;
ValueSet.ConceptSetComponent include;
// Include
vs = new ValueSet();
include = vs.getCompose().addInclude();
include.setSystem(LOINC_URI);
include
.addFilter()
.setProperty("copyright")
.setOp(ValueSet.FilterOperator.ISA)
.setValue("LOINC");
try {
myTermSvc.expandValueSet(vs);
} catch (InvalidRequestException e) {
assertEquals(400, e.getStatusCode());
assertEquals("Don't know how to handle op=ISA on property copyright", e.getMessage());
}
}
@Test
public void testExpandValueSetPropertyFilterLoincCopyrightWithUnsupportedSystem() {
createCodeSystem();
createLoincSystemWithSomeCodes();
ValueSet vs;
ValueSet.ConceptSetComponent include;
// Include
vs = new ValueSet();
include = vs.getCompose().addInclude();
include.setSystem(LOINC_URI);
include
.addFilter()
.setProperty("copyright")
.setOp(ValueSet.FilterOperator.EQUAL)
.setValue("LOINC");
try {
myTermSvc.expandValueSet(vs);
} catch (InvalidRequestException e) {
assertEquals(400, e.getStatusCode());
assertEquals("Invalid filter, property copyright is LOINC-specific and cannot be used with system: http://example.com/my_code_system", e.getMessage());
}
}
@Test
public void testExpandValueSetPropertyFilterLoincCopyrightWithUnsupportedValue() {
createLoincSystemWithSomeCodes();
ValueSet vs;
ValueSet.ConceptSetComponent include;
// Include
vs = new ValueSet();
include = vs.getCompose().addInclude();
include.setSystem(LOINC_URI);
include
.addFilter()
.setProperty("copyright")
.setOp(ValueSet.FilterOperator.EQUAL)
.setValue("bogus");
try {
myTermSvc.expandValueSet(vs);
} catch (InvalidRequestException e) {
assertEquals(400, e.getStatusCode());
assertEquals("Don't know how to handle value=bogus on property copyright", e.getMessage());
}
}
@Test
public void testExpandValueSetPropertyFilterLoincChildWithExcludeAndEqual() {
createLoincSystemWithSomeCodes();
List<String> codes;
ValueSet vs;
ValueSet outcome;
ValueSet.ConceptSetComponent exclude;
// Include
vs = new ValueSet();
vs.getCompose()
.addInclude()
.setSystem(LOINC_URI);
// Exclude
exclude = vs.getCompose().addExclude();
exclude.setSystem(LOINC_URI);
exclude
.addFilter()
.setProperty("child")
.setOp(ValueSet.FilterOperator.EQUAL)
.setValue("50015-7");
outcome = myTermSvc.expandValueSet(vs);
codes = toCodesContains(outcome.getExpansion().getContains());
assertThat(codes, containsInAnyOrder("50015-7", "43343-3", "43343-4", "47239-9"));
// Include
vs = new ValueSet();
vs.getCompose()
.addInclude()
.setSystem(LOINC_URI);
// Exclude
exclude = vs.getCompose().addExclude();
exclude.setSystem(LOINC_URI);
exclude
.addFilter()
.setProperty("child")
.setOp(ValueSet.FilterOperator.EQUAL)
.setValue("43343-3");
outcome = myTermSvc.expandValueSet(vs);
codes = toCodesContains(outcome.getExpansion().getContains());
assertThat(codes, containsInAnyOrder("43343-3", "43343-4", "47239-9"));
// Include
vs = new ValueSet();
vs.getCompose()
.addInclude()
.setSystem(LOINC_URI);
// Exclude
exclude = vs.getCompose().addExclude();
exclude.setSystem(LOINC_URI);
exclude
.addFilter()
.setProperty("child")
.setOp(ValueSet.FilterOperator.EQUAL)
.setValue("43343-4");
outcome = myTermSvc.expandValueSet(vs);
codes = toCodesContains(outcome.getExpansion().getContains());
assertThat(codes, containsInAnyOrder("50015-7", "43343-4", "47239-9"));
// Include
vs = new ValueSet();
vs.getCompose()
.addInclude()
.setSystem(LOINC_URI);
// Exclude
exclude = vs.getCompose().addExclude();
exclude.setSystem(LOINC_URI);
exclude
.addFilter()
.setProperty("child")
.setOp(ValueSet.FilterOperator.EQUAL)
.setValue("47239-9");
outcome = myTermSvc.expandValueSet(vs);
codes = toCodesContains(outcome.getExpansion().getContains());
assertThat(codes, containsInAnyOrder("50015-7", "43343-4", "47239-9"));
}
@Test
public void testExpandValueSetPropertyFilterLoincChildWithExcludeAndIn() {
createLoincSystemWithSomeCodes();
List<String> codes;
ValueSet vs;
ValueSet outcome;
ValueSet.ConceptSetComponent exclude;
// Include
vs = new ValueSet();
vs.getCompose()
.addInclude()
.setSystem(LOINC_URI);
// Exclude
exclude = vs.getCompose().addExclude();
exclude.setSystem(LOINC_URI);
exclude
.addFilter()
.setProperty("child")
.setOp(ValueSet.FilterOperator.IN)
.setValue("50015-7,43343-3,43343-4,47239-9");
outcome = myTermSvc.expandValueSet(vs);
codes = toCodesContains(outcome.getExpansion().getContains());
assertThat(codes, containsInAnyOrder("43343-4", "47239-9"));
}
@Test
public void testExpandValueSetPropertyFilterLoincChildWithIncludeAndEqual() {
createLoincSystemWithSomeCodes();
List<String> codes;
ValueSet vs;
ValueSet outcome;
ValueSet.ConceptSetComponent include;
// Include
vs = new ValueSet();
include = vs.getCompose().addInclude();
include.setSystem(LOINC_URI);
include
.addFilter()
.setProperty("child")
.setOp(ValueSet.FilterOperator.EQUAL)
.setValue("50015-7");
outcome = myTermSvc.expandValueSet(vs);
assertEquals(0, outcome.getExpansion().getContains().size());
// Include
vs = new ValueSet();
include = vs.getCompose().addInclude();
include.setSystem(LOINC_URI);
include
.addFilter()
.setProperty("child")
.setOp(ValueSet.FilterOperator.EQUAL)
.setValue("43343-3");
outcome = myTermSvc.expandValueSet(vs);
codes = toCodesContains(outcome.getExpansion().getContains());
assertThat(codes, containsInAnyOrder("50015-7"));
// Include
vs = new ValueSet();
include = vs.getCompose().addInclude();
include.setSystem(LOINC_URI);
include
.addFilter()
.setProperty("child")
.setOp(ValueSet.FilterOperator.EQUAL)
.setValue("43343-4");
outcome = myTermSvc.expandValueSet(vs);
codes = toCodesContains(outcome.getExpansion().getContains());
assertThat(codes, containsInAnyOrder("43343-3"));
// Include
vs = new ValueSet();
include = vs.getCompose().addInclude();
include.setSystem(LOINC_URI);
include
.addFilter()
.setProperty("child")
.setOp(ValueSet.FilterOperator.EQUAL)
.setValue("47239-9");
outcome = myTermSvc.expandValueSet(vs);
codes = toCodesContains(outcome.getExpansion().getContains());
assertThat(codes, containsInAnyOrder("43343-3"));
}
@Test
public void testExpandValueSetPropertyFilterLoincChildWithIncludeAndIn() {
createLoincSystemWithSomeCodes();
List<String> codes;
ValueSet vs;
ValueSet outcome;
ValueSet.ConceptSetComponent include;
// Include
vs = new ValueSet();
include = vs.getCompose().addInclude();
include.setSystem(LOINC_URI);
include
.addFilter()
.setProperty("child")
.setOp(ValueSet.FilterOperator.IN)
.setValue("50015-7,43343-3,43343-4,47239-9");
outcome = myTermSvc.expandValueSet(vs);
codes = toCodesContains(outcome.getExpansion().getContains());
assertThat(codes, containsInAnyOrder("50015-7", "43343-3"));
}
@Test
public void testExpandValueSetPropertyFilterLoincChildWithUnsupportedOp() {
createLoincSystemWithSomeCodes();
ValueSet vs;
ValueSet.ConceptSetComponent include;
// Include
vs = new ValueSet();
include = vs.getCompose().addInclude();
include.setSystem(LOINC_URI);
include
.addFilter()
.setProperty("child")
.setOp(ValueSet.FilterOperator.ISA)
.setValue("50015-7");
try {
myTermSvc.expandValueSet(vs);
} catch (InvalidRequestException e) {
assertEquals(400, e.getStatusCode());
assertEquals("Don't know how to handle op=ISA on property child", e.getMessage());
}
}
@Test
public void testExpandValueSetPropertyFilterLoincChildWithUnsupportedSystem() {
createCodeSystem();
createLoincSystemWithSomeCodes();
ValueSet vs;
ValueSet.ConceptSetComponent include;
// Include
vs = new ValueSet();
include = vs.getCompose().addInclude();
include.setSystem(CS_URL);
include
.addFilter()
.setProperty("child")
.setOp(ValueSet.FilterOperator.EQUAL)
.setValue("50015-7");
try {
myTermSvc.expandValueSet(vs);
} catch (InvalidRequestException e) {
assertEquals(400, e.getStatusCode());
assertEquals("Invalid filter, property child is LOINC-specific and cannot be used with system: http://example.com/my_code_system", e.getMessage());
}
}
@Test
public void testExpandValueSetPropertyFilterLoincParentWithExcludeAndEqual() {
createLoincSystemWithSomeCodes();
List<String> codes;
ValueSet vs;
ValueSet outcome;
ValueSet.ConceptSetComponent exclude;
// Include
vs = new ValueSet();
vs.getCompose()
.addInclude()
.setSystem(LOINC_URI);
// Exclude
exclude = vs.getCompose().addExclude();
exclude.setSystem(LOINC_URI);
exclude
.addFilter()
.setProperty("parent")
.setOp(ValueSet.FilterOperator.EQUAL)
.setValue("50015-7");
outcome = myTermSvc.expandValueSet(vs);
codes = toCodesContains(outcome.getExpansion().getContains());
assertThat(codes, containsInAnyOrder("50015-7", "43343-4", "47239-9"));
// Include
vs = new ValueSet();
vs.getCompose()
.addInclude()
.setSystem(LOINC_URI);
// Exclude
exclude = vs.getCompose().addExclude();
exclude.setSystem(LOINC_URI);
exclude
.addFilter()
.setProperty("parent")
.setOp(ValueSet.FilterOperator.EQUAL)
.setValue("43343-3");
outcome = myTermSvc.expandValueSet(vs);
codes = toCodesContains(outcome.getExpansion().getContains());
assertThat(codes, containsInAnyOrder("50015-7", "43343-3"));
// Include
vs = new ValueSet();
vs.getCompose()
.addInclude()
.setSystem(LOINC_URI);
// Exclude
exclude = vs.getCompose().addExclude();
exclude.setSystem(LOINC_URI);
exclude
.addFilter()
.setProperty("parent")
.setOp(ValueSet.FilterOperator.EQUAL)
.setValue("43343-4");
outcome = myTermSvc.expandValueSet(vs);
codes = toCodesContains(outcome.getExpansion().getContains());
assertThat(codes, containsInAnyOrder("50015-7", "43343-3", "43343-4", "47239-9"));
// Include
vs = new ValueSet();
vs.getCompose()
.addInclude()
.setSystem(LOINC_URI);
// Exclude
exclude = vs.getCompose().addExclude();
exclude.setSystem(LOINC_URI);
exclude
.addFilter()
.setProperty("parent")
.setOp(ValueSet.FilterOperator.EQUAL)
.setValue("47239-9");
outcome = myTermSvc.expandValueSet(vs);
codes = toCodesContains(outcome.getExpansion().getContains());
assertThat(codes, containsInAnyOrder("50015-7", "43343-3", "43343-4", "47239-9"));
}
@Test
public void testExpandValueSetPropertyFilterLoincParentWithExcludeAndIn() {
createLoincSystemWithSomeCodes();
List<String> codes;
ValueSet vs;
ValueSet outcome;
ValueSet.ConceptSetComponent exclude;
// Include
vs = new ValueSet();
vs.getCompose()
.addInclude()
.setSystem(LOINC_URI);
// Exclude
exclude = vs.getCompose().addExclude();
exclude.setSystem(LOINC_URI);
exclude
.addFilter()
.setProperty("parent")
.setOp(ValueSet.FilterOperator.IN)
.setValue("50015-7,43343-3,43343-4,47239-9");
outcome = myTermSvc.expandValueSet(vs);
codes = toCodesContains(outcome.getExpansion().getContains());
assertThat(codes, containsInAnyOrder("50015-7"));
}
@Test
public void testExpandValueSetPropertyFilterLoincParentWithIncludeAndEqual() {
createLoincSystemWithSomeCodes();
List<String> codes;
ValueSet vs;
ValueSet outcome;
ValueSet.ConceptSetComponent include;
// Include
vs = new ValueSet();
include = vs.getCompose().addInclude();
include.setSystem(LOINC_URI);
include
.addFilter()
.setProperty("parent")
.setOp(ValueSet.FilterOperator.EQUAL)
.setValue("50015-7");
outcome = myTermSvc.expandValueSet(vs);
codes = toCodesContains(outcome.getExpansion().getContains());
assertThat(codes, containsInAnyOrder("43343-3"));
// Include
vs = new ValueSet();
include = vs.getCompose().addInclude();
include.setSystem(LOINC_URI);
include
.addFilter()
.setProperty("parent")
.setOp(ValueSet.FilterOperator.EQUAL)
.setValue("43343-3");
outcome = myTermSvc.expandValueSet(vs);
codes = toCodesContains(outcome.getExpansion().getContains());
assertThat(codes, containsInAnyOrder("43343-4", "47239-9"));
// Include
vs = new ValueSet();
include = vs.getCompose().addInclude();
include.setSystem(LOINC_URI);
include
.addFilter()
.setProperty("parent")
.setOp(ValueSet.FilterOperator.EQUAL)
.setValue("43343-4");
outcome = myTermSvc.expandValueSet(vs);
assertEquals(0, outcome.getExpansion().getContains().size());
// Include
vs = new ValueSet();
include = vs.getCompose().addInclude();
include.setSystem(LOINC_URI);
include
.addFilter()
.setProperty("parent")
.setOp(ValueSet.FilterOperator.EQUAL)
.setValue("47239-9");
outcome = myTermSvc.expandValueSet(vs);
assertEquals(0, outcome.getExpansion().getContains().size());
}
@Test
public void testExpandValueSetPropertyFilterLoincParentWithIncludeAndIn() {
createLoincSystemWithSomeCodes();
List<String> codes;
ValueSet vs;
ValueSet outcome;
ValueSet.ConceptSetComponent include;
// Include
vs = new ValueSet();
include = vs.getCompose().addInclude();
include.setSystem(LOINC_URI);
include
.addFilter()
.setProperty("parent")
.setOp(ValueSet.FilterOperator.IN)
.setValue("50015-7,43343-3,43343-4,47239-9");
outcome = myTermSvc.expandValueSet(vs);
codes = toCodesContains(outcome.getExpansion().getContains());
assertThat(codes, containsInAnyOrder("43343-3", "43343-4", "47239-9"));
}
@Test
public void testExpandValueSetPropertyFilterLoincParentWithUnsupportedOp() {
createLoincSystemWithSomeCodes();
ValueSet vs;
ValueSet.ConceptSetComponent include;
// Include
vs = new ValueSet();
include = vs.getCompose().addInclude();
include.setSystem(LOINC_URI);
include
.addFilter()
.setProperty("parent")
.setOp(ValueSet.FilterOperator.ISA)
.setValue("50015-7");
try {
myTermSvc.expandValueSet(vs);
} catch (InvalidRequestException e) {
assertEquals(400, e.getStatusCode());
assertEquals("Don't know how to handle op=ISA on property parent", e.getMessage());
}
}
@Test
public void testExpandValueSetPropertyFilterLoincParentWithUnsupportedSystem() {
createCodeSystem();
createLoincSystemWithSomeCodes();
ValueSet vs;
ValueSet.ConceptSetComponent include;
// Include
vs = new ValueSet();
include = vs.getCompose().addInclude();
include.setSystem(CS_URL);
include
.addFilter()
.setProperty("parent")
.setOp(ValueSet.FilterOperator.EQUAL)
.setValue("50015-7");
try {
myTermSvc.expandValueSet(vs);
} catch (InvalidRequestException e) {
assertEquals(400, e.getStatusCode());
assertEquals("Invalid filter, property parent is LOINC-specific and cannot be used with system: http://example.com/my_code_system", e.getMessage());
}
}
@Test @Test
public void testExpandValueSetPropertySearchWithRegexExclude() { public void testExpandValueSetPropertySearchWithRegexExclude() {
createLoincSystemWithSomeCodes(); createLoincSystemWithSomeCodes();
@ -286,10 +1030,10 @@ public class TerminologySvcImplDstu3Test extends BaseJpaDstu3Test {
vs = new ValueSet(); vs = new ValueSet();
vs.getCompose() vs.getCompose()
.addInclude() .addInclude()
.setSystem(CS_URL); .setSystem(LOINC_URI);
exclude = vs.getCompose().addExclude(); exclude = vs.getCompose().addExclude();
exclude.setSystem(CS_URL); exclude.setSystem(LOINC_URI);
exclude exclude
.addFilter() .addFilter()
.setProperty("SYSTEM") .setProperty("SYSTEM")
@ -297,7 +1041,7 @@ public class TerminologySvcImplDstu3Test extends BaseJpaDstu3Test {
.setValue(".*\\^Donor$"); .setValue(".*\\^Donor$");
outcome = myTermSvc.expandValueSet(vs); outcome = myTermSvc.expandValueSet(vs);
codes = toCodesContains(outcome.getExpansion().getContains()); codes = toCodesContains(outcome.getExpansion().getContains());
assertThat(codes, containsInAnyOrder("43343-3", "43343-4")); assertThat(codes, containsInAnyOrder("43343-3", "43343-4", "47239-9"));
} }
@Test @Test
@ -313,10 +1057,10 @@ public class TerminologySvcImplDstu3Test extends BaseJpaDstu3Test {
vs = new ValueSet(); vs = new ValueSet();
vs.getCompose() vs.getCompose()
.addInclude() .addInclude()
.setSystem(CS_URL); .setSystem(LOINC_URI);
exclude = vs.getCompose().addExclude(); exclude = vs.getCompose().addExclude();
exclude.setSystem(CS_URL); exclude.setSystem(LOINC_URI);
exclude exclude
.addFilter() .addFilter()
.setProperty("HELLO") .setProperty("HELLO")
@ -324,12 +1068,11 @@ public class TerminologySvcImplDstu3Test extends BaseJpaDstu3Test {
.setValue("12345-1|12345-2"); .setValue("12345-1|12345-2");
outcome = myTermSvc.expandValueSet(vs); outcome = myTermSvc.expandValueSet(vs);
codes = toCodesContains(outcome.getExpansion().getContains()); codes = toCodesContains(outcome.getExpansion().getContains());
assertThat(codes, containsInAnyOrder("50015-7")); assertThat(codes, containsInAnyOrder("50015-7", "47239-9"));
} }
@Test @Test
public void testExpandValueSetPropertySearchWithRegexInclude() { public void testExpandValueSetPropertySearchWithRegexInclude() {
// create codes with "SYSTEM" property "Bld/Bone mar^Donor" and "Ser"
createLoincSystemWithSomeCodes(); createLoincSystemWithSomeCodes();
List<String> codes; List<String> codes;
@ -340,7 +1083,7 @@ public class TerminologySvcImplDstu3Test extends BaseJpaDstu3Test {
// Include // Include
vs = new ValueSet(); vs = new ValueSet();
include = vs.getCompose().addInclude(); include = vs.getCompose().addInclude();
include.setSystem(CS_URL); include.setSystem(LOINC_URI);
include include
.addFilter() .addFilter()
.setProperty("SYSTEM") .setProperty("SYSTEM")
@ -353,7 +1096,7 @@ public class TerminologySvcImplDstu3Test extends BaseJpaDstu3Test {
// Include // Include
vs = new ValueSet(); vs = new ValueSet();
include = vs.getCompose().addInclude(); include = vs.getCompose().addInclude();
include.setSystem(CS_URL); include.setSystem(LOINC_URI);
include include
.addFilter() .addFilter()
.setProperty("SYSTEM") .setProperty("SYSTEM")
@ -366,7 +1109,7 @@ public class TerminologySvcImplDstu3Test extends BaseJpaDstu3Test {
// Include // Include
vs = new ValueSet(); vs = new ValueSet();
include = vs.getCompose().addInclude(); include = vs.getCompose().addInclude();
include.setSystem(CS_URL); include.setSystem(LOINC_URI);
include include
.addFilter() .addFilter()
.setProperty("SYSTEM") .setProperty("SYSTEM")
@ -379,7 +1122,7 @@ public class TerminologySvcImplDstu3Test extends BaseJpaDstu3Test {
// Include // Include
vs = new ValueSet(); vs = new ValueSet();
include = vs.getCompose().addInclude(); include = vs.getCompose().addInclude();
include.setSystem(CS_URL); include.setSystem(LOINC_URI);
include include
.addFilter() .addFilter()
.setProperty("SYSTEM") .setProperty("SYSTEM")
@ -392,7 +1135,7 @@ public class TerminologySvcImplDstu3Test extends BaseJpaDstu3Test {
// Include // Include
vs = new ValueSet(); vs = new ValueSet();
include = vs.getCompose().addInclude(); include = vs.getCompose().addInclude();
include.setSystem(CS_URL); include.setSystem(LOINC_URI);
include include
.addFilter() .addFilter()
.setProperty("SYSTEM") .setProperty("SYSTEM")
@ -405,7 +1148,7 @@ public class TerminologySvcImplDstu3Test extends BaseJpaDstu3Test {
// Include // Include
vs = new ValueSet(); vs = new ValueSet();
include = vs.getCompose().addInclude(); include = vs.getCompose().addInclude();
include.setSystem(CS_URL); include.setSystem(LOINC_URI);
include include
.addFilter() .addFilter()
.setProperty("SYSTEM") .setProperty("SYSTEM")

View File

@ -13,3 +13,4 @@
"17787-3" ,"Study report" ,"Find" ,"Pt" ,"Neck>Thyroid gland","Doc" ,"NM" ,"RAD" ,"2.61" ,"MIN" , ,"ACTIVE", ,2 , , , , , , , ,"Document; Finding; Findings; Imaging; Point in time; Radiology; Random; Study report; Thy" ,"NM Thyroid Study report" ,"Both" , , , , ,"NM Thyroid gland Study report" , , , , , , ,"Changed System from ""Thyroid"" for conformance with the LOINC/RadLex unified model.; Method of ""Radnuc"" was changed to ""NM"". The LOINC/RadLex Committee agreed to use a subset of the two-letter DICOM modality codes as the primary modality identifier." ,0 ,0 ,0 ,"IG exists" , , , ,"81220-6;72230-6" ,"1.0l" , "17787-3" ,"Study report" ,"Find" ,"Pt" ,"Neck>Thyroid gland","Doc" ,"NM" ,"RAD" ,"2.61" ,"MIN" , ,"ACTIVE", ,2 , , , , , , , ,"Document; Finding; Findings; Imaging; Point in time; Radiology; Random; Study report; Thy" ,"NM Thyroid Study report" ,"Both" , , , , ,"NM Thyroid gland Study report" , , , , , , ,"Changed System from ""Thyroid"" for conformance with the LOINC/RadLex unified model.; Method of ""Radnuc"" was changed to ""NM"". The LOINC/RadLex Committee agreed to use a subset of the two-letter DICOM modality codes as the primary modality identifier." ,0 ,0 ,0 ,"IG exists" , , , ,"81220-6;72230-6" ,"1.0l" ,
"17788-1" ,"Large unstained cells/100 leukocytes" ,"NFr" ,"Pt" ,"Bld" ,"Qn" ,"Automated count","HEM/BC" ,"2.50" ,"MIN" ,"Part of auto diff output of Bayer H*3S; peroxidase negative cells too large to be classified as lymph or basophil" ,"ACTIVE", ,1 , , , , , ,"Y" ,"%" ,"100WBC; Auto; Automated detection; Blood; Cell; Cellularity; Elec; Elect; Electr; HEMATOLOGY/CELL COUNTS; Leuc; Leuk; Leukocyte; Lkcs; LUC; Number Fraction; Percent; Point in time; QNT; Quan; Quant; Quantitative; Random; WB; WBC; WBCs; White blood cell; White blood cells; Whole blood" ,"LUC/leuk NFr Bld Auto" ,"Observation", , , ,"%" ,"Large unstained cells/100 leukocytes in Blood by Automated count" , , ,"%" , , , , ,1894 ,0 ,1894 , , , , , ,"1.0l" , "17788-1" ,"Large unstained cells/100 leukocytes" ,"NFr" ,"Pt" ,"Bld" ,"Qn" ,"Automated count","HEM/BC" ,"2.50" ,"MIN" ,"Part of auto diff output of Bayer H*3S; peroxidase negative cells too large to be classified as lymph or basophil" ,"ACTIVE", ,1 , , , , , ,"Y" ,"%" ,"100WBC; Auto; Automated detection; Blood; Cell; Cellularity; Elec; Elect; Electr; HEMATOLOGY/CELL COUNTS; Leuc; Leuk; Leukocyte; Lkcs; LUC; Number Fraction; Percent; Point in time; QNT; Quan; Quant; Quantitative; Random; WB; WBC; WBCs; White blood cell; White blood cells; Whole blood" ,"LUC/leuk NFr Bld Auto" ,"Observation", , , ,"%" ,"Large unstained cells/100 leukocytes in Blood by Automated count" , , ,"%" , , , , ,1894 ,0 ,1894 , , , , , ,"1.0l" ,
"11488-4" ,"Consultation note" ,"Find" ,"Pt" ,"{Setting}" ,"Doc" ,"{Role}" ,"DOC.ONTOLOGY","2.63" ,"MIN" , ,"ACTIVE", ,2 , , , , , , , ,"Consult note; DOC.ONT; Document; Encounter; Evaluation and management; Evaluation and management note; Finding; Findings; notes; Point in time; Random; Visit note" ,"Consult note" ,"Both" , , , , ,"Consult note" , , , , , , ,"Edit made because this term is conformant to the Document Ontology axis values and therefore are being placed in this class.; Based on Clinical LOINC Committee decision during the September 2014 meeting, {Provider} was changed to {Author Type} to emphasize a greater breadth of potential document authors. At the September 2015 Clinical LOINC Committee meeting, the Committee decided to change {Author Type} to {Role} to align with the 'Role' axis name in the LOINC Document Ontology.; Because it is too difficult to maintain and because the distinction between documents and sections is not clear-cut nor necessary in most cases, the DOCUMENT_SECTION field has been deemed to have little value. The field has been set to null in the December 2017 release in preparation for removal in the December 2018 release. These changes were approved by the Clinical LOINC Committee.",0 ,0 ,0 ,"IG exists" , , , ,"81222-2;72231-4;81243-8","1.0j-a" ,"Y" "11488-4" ,"Consultation note" ,"Find" ,"Pt" ,"{Setting}" ,"Doc" ,"{Role}" ,"DOC.ONTOLOGY","2.63" ,"MIN" , ,"ACTIVE", ,2 , , , , , , , ,"Consult note; DOC.ONT; Document; Encounter; Evaluation and management; Evaluation and management note; Finding; Findings; notes; Point in time; Random; Visit note" ,"Consult note" ,"Both" , , , , ,"Consult note" , , , , , , ,"Edit made because this term is conformant to the Document Ontology axis values and therefore are being placed in this class.; Based on Clinical LOINC Committee decision during the September 2014 meeting, {Provider} was changed to {Author Type} to emphasize a greater breadth of potential document authors. At the September 2015 Clinical LOINC Committee meeting, the Committee decided to change {Author Type} to {Role} to align with the 'Role' axis name in the LOINC Document Ontology.; Because it is too difficult to maintain and because the distinction between documents and sections is not clear-cut nor necessary in most cases, the DOCUMENT_SECTION field has been deemed to have little value. The field has been set to null in the December 2017 release in preparation for removal in the December 2018 release. These changes were approved by the Clinical LOINC Committee.",0 ,0 ,0 ,"IG exists" , , , ,"81222-2;72231-4;81243-8","1.0j-a" ,"Y"
"47239-9" ,"Reason for stopping HIV Rx" ,"Type" ,"Pt" ,"^Patient" ,"Nom" ,"Reported" ,"ART" ,"2.50" ,"MIN" ,"Reason for stopping antiretroviral therapy" ,"ACTIVE", ,2 , , , , , ,"N" , ,"AIDS; Anti-retroviral therapy; ART; Human immunodeficiency virus; Nominal; Point in time; Random; Treatment; Typ" ,"Reason for stopping HIV Rx" ,"Observation", , ,"Copyright © 2006 World Health Organization. Used with permission. Publications of the World Health Organization can be obtained from WHO Press, World Health Organization, 20 Avenue Appia, 1211 Geneva 27, Switzerland (tel: +41 22 791 2476; fax: +41 22 791 4857; email: bookorders@who.int). Requests for permission to reproduce or translate WHO publications whether for sale or for noncommercial distribution should be addressed to WHO Press, at the above address (fax: +41 22 791 4806; email: permissions@who.int). The designations employed and the presentation of the material in this publication do not imply the expression of any opinion whatsoever on the part of the World Health Organization concerning the legal status of any country, territory, city or area or of its authorities, or concerning the delimitation of its frontiers or boundaries. Dotted lines on maps represent approximate border lines for which there may not yet be full agreement. The mention of specific companies or of certain manufacturers products does not imply that they are endorsed or recommended by the World Health Organization in preference to others of a similar nature that are not mentioned. Errors and omissions excepted, the names of proprietary products are distinguished by initial capital letters. All reasonable precautions have been taken by WHO to verify the information contained in this publication. However, the published material is being distributed without warranty of any kind, either express or implied. The responsibility for the interpretation and use of the material lies with the reader. In no event shall the World Health Organization be liable for damages arising from its use.", ,"Reason for stopping HIV treatment" , , , , , , , ,0 ,0 ,0 , ,"WHO_HIV" , , , ,"2.22" ,

Can't render this file because it contains an unexpected character in line 1 and column 23.