From b05c5f3f711b078515c026e9cd09e0abb1f9e733 Mon Sep 17 00:00:00 2001 From: Diederik Muylwyk Date: Sun, 15 Sep 2019 21:52:33 -0400 Subject: [PATCH] Implement the parent and child filters for LOINC. #1453 --- .../jpa/term/BaseHapiTerminologySvcImpl.java | 213 +++++--- .../jpa/term/TerminologySvcImplDstu3Test.java | 505 ++++++++++++++++-- 2 files changed, 597 insertions(+), 121 deletions(-) diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/BaseHapiTerminologySvcImpl.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/BaseHapiTerminologySvcImpl.java index 3e63cae7937..a2c3c866756 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/BaseHapiTerminologySvcImpl.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/BaseHapiTerminologySvcImpl.java @@ -199,20 +199,6 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc, } } - private void addCopyrightFilter3rdParty(BooleanJunction bool) { - // FIXME: DM 2019-09-13 - This feels hacky but it works until we have a better way for filtering TermConcept based on TermConceptProperty. - Term term = new Term(TermConceptPropertyFieldBridge.CONCEPT_FIELD_PROPERTY_PREFIX + "EXTERNAL_COPYRIGHT_NOTICE", ".*"); - RegexpQuery query = new RegexpQuery(term); - bool.must(query); - } - - private void addCopyrightFilterLoinc(BooleanJunction bool) { - // FIXME: DM 2019-09-13 - This feels hacky but it works until we have a better way for filtering TermConcept based on TermConceptProperty. - Term term = new Term(TermConceptPropertyFieldBridge.CONCEPT_FIELD_PROPERTY_PREFIX + "EXTERNAL_COPYRIGHT_NOTICE", ".*"); - RegexpQuery query = new RegexpQuery(term); - bool.must(query).not(); - } - private void addDisplayFilterExact(QueryBuilder qb, BooleanJunction bool, ValueSet.ConceptSetFilterComponent nextFilter) { bool.must(qb.phrase().onField("myDisplay").sentence(nextFilter.getValue()).createQuery()); } @@ -705,11 +691,11 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc, /** * @return Returns true if there are potentially more results to process. */ - private Boolean expandValueSetHandleIncludeOrExclude(IValueSetConceptAccumulator theValueSetCodeAccumulator, Set theAddedCodes, ValueSet.ConceptSetComponent theInclude, boolean theAdd, AtomicInteger theCodeCounter, int theQueryIndex) { + private Boolean expandValueSetHandleIncludeOrExclude(IValueSetConceptAccumulator theValueSetCodeAccumulator, Set theAddedCodes, ValueSet.ConceptSetComponent theIncludeOrExclude, boolean theAdd, AtomicInteger theCodeCounter, int theQueryIndex) { - String system = theInclude.getSystem(); + String system = theIncludeOrExclude.getSystem(); boolean hasSystem = isNotBlank(system); - boolean hasValueSet = theInclude.getValueSet().size() > 0; + boolean hasValueSet = theIncludeOrExclude.getValueSet().size() > 0; if (hasSystem) { ourLog.info("Starting {} expansion around CodeSystem: {}", (theAdd ? "inclusion" : "exclusion"), system); @@ -725,7 +711,7 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc, * since we're going to do it without the database. */ if (myFulltextSearchSvc == null) { - expandWithoutHibernateSearch(theValueSetCodeAccumulator, theAddedCodes, theInclude, system, theAdd, theCodeCounter); + expandWithoutHibernateSearch(theValueSetCodeAccumulator, theAddedCodes, theIncludeOrExclude, system, theAdd, theCodeCounter); return false; } @@ -740,20 +726,14 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc, /* * Filters */ - - if (theInclude.getFilter().size() > 0) { - for (ValueSet.ConceptSetFilterComponent nextFilter : theInclude.getFilter()) { - handleFilter(system, qb, bool, nextFilter); - } - } + handleFilters(bool, system, qb, theIncludeOrExclude); Query luceneQuery = bool.createQuery(); /* - * Include Concepts + * Include/Exclude Concepts */ - - List codes = theInclude + List codes = theIncludeOrExclude .getConcept() .stream() .filter(Objects::nonNull) @@ -773,8 +753,8 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc, /* * Execute the query */ - FullTextQuery jpaQuery = em.createFullTextQuery(luceneQuery, TermConcept.class); + /* * 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. @@ -813,15 +793,15 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc, } } else { - // No codesystem matching the URL found in the database + // No CodeSystem matching the URL found in the database. CodeSystem codeSystemFromContext = getCodeSystemFromContext(system); if (codeSystemFromContext == null) { throw new InvalidRequestException("Unknown code system: " + system); } - if (!theInclude.getConcept().isEmpty()) { - for (ValueSet.ConceptReferenceComponent next : theInclude.getConcept()) { + if (!theIncludeOrExclude.getConcept().isEmpty()) { + for (ValueSet.ConceptReferenceComponent next : theIncludeOrExclude.getConcept()) { String nextCode = next.getCode(); if (isNoneBlank(system, nextCode) && !theAddedCodes.contains(system + "|" + nextCode)) { CodeSystem.ConceptDefinitionComponent code = findCode(codeSystemFromContext.getConcept(), nextCode); @@ -844,7 +824,7 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc, } } else if (hasValueSet) { - for (CanonicalType nextValueSet : theInclude.getValueSet()) { + for (CanonicalType nextValueSet : theIncludeOrExclude.getValueSet()) { ourLog.info("Starting {} expansion around ValueSet: {}", (theAdd ? "inclusion" : "exclusion"), nextValueSet.getValueAsString()); List expanded = expandValueSet(nextValueSet.getValueAsString()); @@ -874,74 +854,163 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc, } - private void handleFilter(String theSystem, QueryBuilder theQb, BooleanJunction theBool, ValueSet.ConceptSetFilterComponent nextFilter) { - if (isBlank(nextFilter.getValue()) && nextFilter.getOp() == null && isBlank(nextFilter.getProperty())) { + 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(nextFilter.getValue()) || nextFilter.getOp() == null || isBlank(nextFilter.getProperty())) { + if (isBlank(theFilter.getValue()) || theFilter.getOp() == null || isBlank(theFilter.getProperty())) { throw new InvalidRequestException("Invalid filter, must have fields populated: property op value"); } - if (nextFilter.getProperty().equals("display:exact") || nextFilter.getProperty().equals("display")) { - handleDisplayFilter(theQb, theBool, nextFilter); - } else if (nextFilter.getProperty().equals("concept") || nextFilter.getProperty().equals("code")) { - handleConceptAndCodeFilter(theSystem, theQb, theBool, nextFilter); - } else if (nextFilter.getProperty().equals("copyright")) { - handleLoincCopyrightFilter(theQb, theBool, nextFilter); - } else { - handleRegexFilter(theBool, nextFilter); + 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": + handleFilterLoincParentChild(theSystem, theQb, theBool, theFilter); + break; + case "copyright": + handleFilterLoincCopyright(theSystem, theQb, theBool, theFilter); + break; + default: + handleFilterRegex(theBool, theFilter); + break; } } - private void handleDisplayFilter(QueryBuilder theQb, BooleanJunction theBool, ValueSet.ConceptSetFilterComponent nextFilter) { - if (nextFilter.getProperty().equals("display:exact") && nextFilter.getOp() == ValueSet.FilterOperator.EQUAL) { - addDisplayFilterExact(theQb, theBool, nextFilter); - } else if (nextFilter.getProperty().equals("display") && nextFilter.getOp() == ValueSet.FilterOperator.EQUAL) { - if (nextFilter.getValue().trim().contains(" ")) { - addDisplayFilterExact(theQb, theBool, nextFilter); + 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, nextFilter); + addDisplayFilterInexact(theQb, theBool, theFilter); } } } - private void handleConceptAndCodeFilter(String theSystem, QueryBuilder theQb, BooleanJunction theBool, ValueSet.ConceptSetFilterComponent nextFilter) { - TermConcept code = findCode(theSystem, nextFilter.getValue()) - .orElseThrow(() -> new InvalidRequestException("Invalid filter criteria - code does not exist: {" + theSystem + "}" + nextFilter.getValue())); + 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 (nextFilter.getOp() == ValueSet.FilterOperator.ISA) { + 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=" + nextFilter.getOp() + " on property " + nextFilter.getProperty()); + throw new InvalidRequestException("Don't know how to handle op=" + theFilter.getOp() + " on property " + theFilter.getProperty()); } } - private void handleLoincCopyrightFilter(QueryBuilder theQb, BooleanJunction theBool, ValueSet.ConceptSetFilterComponent nextFilter) { - if (nextFilter.getOp() == ValueSet.FilterOperator.EQUAL) { + private void handleFilterLoincParentChild(String theSystem, QueryBuilder theQb, BooleanJunction theBool, ValueSet.ConceptSetFilterComponent theFilter) { + if (isNotCodeSystemLoinc(theSystem)) { + return; + } - String copyrightFilterValue = defaultString(nextFilter.getValue()).toLowerCase(); + 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 boolean isCodeSystemLoinc(String theSystem) { + return IHapiTerminologyLoaderSvc.LOINC_URI.equals(theSystem); + } + + private boolean isNotCodeSystemLoinc(String theSystem) { + return !isCodeSystemLoinc(theSystem); + } + + 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 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(String theSystem, QueryBuilder theQb, BooleanJunction theBool, ValueSet.ConceptSetFilterComponent theFilter) { + if (isNotCodeSystemLoinc(theSystem)) { + return; + } + + if (theFilter.getOp() == ValueSet.FilterOperator.EQUAL) { + + String copyrightFilterValue = defaultString(theFilter.getValue()).toLowerCase(); switch (copyrightFilterValue) { - case "loinc": - ourLog.info(" * Filtering with value=" + nextFilter.getValue() + " on property " + nextFilter.getProperty()); - addCopyrightFilterLoinc(theBool); - break; case "3rdparty": - ourLog.info(" * Filtering with value=" + nextFilter.getValue() + " on property " + nextFilter.getProperty()); - addCopyrightFilter3rdParty(theBool); + logFilteringValueOnProperty(theFilter.getValue(), theFilter.getProperty()); + addFilterLoincCopyright3rdParty(theBool); + break; + case "loinc": + logFilteringValueOnProperty(theFilter.getValue(), theFilter.getProperty()); + addFilterLoincCopyrightLoinc(theBool); break; default: - throw new InvalidRequestException("Don't know how to handle value=" + nextFilter.getValue() + " on property " + nextFilter.getProperty()); + throwInvalidRequestForValueOnProperty(theFilter.getValue(), theFilter.getProperty()); } } else { - throw new InvalidRequestException("Don't know how to handle op=" + nextFilter.getOp() + " on property " + nextFilter.getProperty()); + throwInvalidRequestForOpOnProperty(theFilter.getOp(), theFilter.getProperty()); } } - private void handleRegexFilter(BooleanJunction theBool, ValueSet.ConceptSetFilterComponent nextFilter) { - if (nextFilter.getOp() == ValueSet.FilterOperator.REGEX) { + 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 @@ -949,7 +1018,7 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc, * say whether or not this is the right behaviour, but * there are examples that seem to suggest that it is. */ - String value = nextFilter.getValue(); + String value = theFilter.getValue(); if (value.endsWith("$")) { value = value.substring(0, value.length() - 1); } else if (!value.endsWith(".*")) { @@ -961,14 +1030,14 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc, value = value.substring(1); } - Term term = new Term(TermConceptPropertyFieldBridge.CONCEPT_FIELD_PROPERTY_PREFIX + nextFilter.getProperty(), value); + Term term = new Term(TermConceptPropertyFieldBridge.CONCEPT_FIELD_PROPERTY_PREFIX + theFilter.getProperty(), value); RegexpQuery query = new RegexpQuery(term); theBool.must(query); } else { - String value = nextFilter.getValue(); - Term term = new Term(TermConceptPropertyFieldBridge.CONCEPT_FIELD_PROPERTY_PREFIX + nextFilter.getProperty(), value); + String value = theFilter.getValue(); + Term term = new Term(TermConceptPropertyFieldBridge.CONCEPT_FIELD_PROPERTY_PREFIX + theFilter.getProperty(), value); theBool.must(new TermsQuery(term)); } diff --git a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/term/TerminologySvcImplDstu3Test.java b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/term/TerminologySvcImplDstu3Test.java index 809f887945b..b034c74ae37 100644 --- a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/term/TerminologySvcImplDstu3Test.java +++ b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/term/TerminologySvcImplDstu3Test.java @@ -31,6 +31,7 @@ import java.util.List; import java.util.Set; import java.util.stream.Collectors; +import static ca.uhn.fhir.jpa.term.IHapiTerminologyLoaderSvc.LOINC_URI; import static org.hamcrest.Matchers.*; import static org.junit.Assert.*; @@ -124,7 +125,7 @@ public class TerminologySvcImplDstu3Test extends BaseJpaDstu3Test { public void createLoincSystemWithSomeCodes() { runInTransaction(() -> { CodeSystem codeSystem = new CodeSystem(); - codeSystem.setUrl(CS_URL); + codeSystem.setUrl(LOINC_URI); codeSystem.setContent(CodeSystemContentMode.NOTPRESENT); IIdType id = myCodeSystemDao.create(codeSystem, mySrd).getId().toUnqualified(); @@ -133,27 +134,57 @@ public class TerminologySvcImplDstu3Test extends BaseJpaDstu3Test { TermCodeSystemVersion cs = new TermCodeSystemVersion(); cs.setResource(table); - TermConcept code; - code = new TermConcept(cs, "50015-7"); - code.addPropertyString("SYSTEM", "Bld/Bone mar^Donor"); - cs.getConcepts().add(code); + TermConcept code1 = new TermConcept(cs, "50015-7"); + TermConcept code2 = new TermConcept(cs, "43343-3"); + TermConcept code3 = new TermConcept(cs, "43343-4"); + TermConcept code4 = new TermConcept(cs, "47239-9"); - code = new TermConcept(cs, "43343-3"); - code.addPropertyString("SYSTEM", "Ser"); - code.addPropertyString("HELLO", "12345-1"); - cs.getConcepts().add(code); + code1.addPropertyString("SYSTEM", "Bld/Bone mar^Donor"); + code1.addPropertyCoding( + "child", + LOINC_URI, + code2.getCode(), + code2.getDisplay()); + cs.getConcepts().add(code1); - code = new TermConcept(cs, "43343-4"); - code.addPropertyString("SYSTEM", "Ser"); - code.addPropertyString("HELLO", "12345-2"); - cs.getConcepts().add(code); + code2.addPropertyString("SYSTEM", "Ser"); + code2.addPropertyString("HELLO", "12345-1"); + code2.addPropertyCoding( + "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); - code = new TermConcept(cs, "47239-9"); - code.addPropertyString("SYSTEM", "^Patient"); - code.addPropertyString("EXTERNAL_COPYRIGHT_NOTICE", "Copyright © 2006 World Health Organization..."); - cs.getConcepts().add(code); + code3.addPropertyString("SYSTEM", "Ser"); + code3.addPropertyString("HELLO", "12345-2"); + code3.addPropertyCoding( + "parent", + LOINC_URI, + code2.getCode(), + code2.getDisplay()); + cs.getConcepts().add(code3); - myTermSvc.storeNewCodeSystemVersion(table.getId(), CS_URL, "SYSTEM NAME", "SYSTEM VERSION" , cs); + 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); }); } @@ -279,7 +310,7 @@ public class TerminologySvcImplDstu3Test extends BaseJpaDstu3Test { } @Test - public void testExpandValueSetPropertyFilterCopyrightWithExclude3rdParty() { + public void testExpandValueSetPropertyFilterLoincCopyrightWithExclude3rdParty() { createLoincSystemWithSomeCodes(); List codes; @@ -291,10 +322,10 @@ public class TerminologySvcImplDstu3Test extends BaseJpaDstu3Test { vs = new ValueSet(); vs.getCompose() .addInclude() - .setSystem(CS_URL); + .setSystem(LOINC_URI); // Exclude exclude = vs.getCompose().addExclude(); - exclude.setSystem(CS_URL); + exclude.setSystem(LOINC_URI); exclude .addFilter() .setProperty("copyright") @@ -308,10 +339,10 @@ public class TerminologySvcImplDstu3Test extends BaseJpaDstu3Test { vs = new ValueSet(); vs.getCompose() .addInclude() - .setSystem(CS_URL); + .setSystem(LOINC_URI); // Exclude exclude = vs.getCompose().addExclude(); - exclude.setSystem(CS_URL); + exclude.setSystem(LOINC_URI); exclude .addFilter() .setProperty("copyright") @@ -323,7 +354,7 @@ public class TerminologySvcImplDstu3Test extends BaseJpaDstu3Test { } @Test - public void testExpandValueSetPropertyFilterCopyrightWithExcludeLoinc() { + public void testExpandValueSetPropertyFilterLoincCopyrightWithExcludeLoinc() { createLoincSystemWithSomeCodes(); List codes; @@ -335,10 +366,10 @@ public class TerminologySvcImplDstu3Test extends BaseJpaDstu3Test { vs = new ValueSet(); vs.getCompose() .addInclude() - .setSystem(CS_URL); + .setSystem(LOINC_URI); // Exclude exclude = vs.getCompose().addExclude(); - exclude.setSystem(CS_URL); + exclude.setSystem(LOINC_URI); exclude .addFilter() .setProperty("copyright") @@ -352,10 +383,10 @@ public class TerminologySvcImplDstu3Test extends BaseJpaDstu3Test { vs = new ValueSet(); vs.getCompose() .addInclude() - .setSystem(CS_URL); + .setSystem(LOINC_URI); // Exclude exclude = vs.getCompose().addExclude(); - exclude.setSystem(CS_URL); + exclude.setSystem(LOINC_URI); exclude .addFilter() .setProperty("copyright") @@ -367,7 +398,7 @@ public class TerminologySvcImplDstu3Test extends BaseJpaDstu3Test { } @Test - public void testExpandValueSetPropertyFilterCopyrightWithInclude3rdParty() { + public void testExpandValueSetPropertyFilterLoincCopyrightWithInclude3rdParty() { createLoincSystemWithSomeCodes(); List codes; @@ -378,7 +409,7 @@ public class TerminologySvcImplDstu3Test extends BaseJpaDstu3Test { // Include vs = new ValueSet(); include = vs.getCompose().addInclude(); - include.setSystem(CS_URL); + include.setSystem(LOINC_URI); include .addFilter() .setProperty("copyright") @@ -391,7 +422,7 @@ public class TerminologySvcImplDstu3Test extends BaseJpaDstu3Test { // Include vs = new ValueSet(); include = vs.getCompose().addInclude(); - include.setSystem(CS_URL); + include.setSystem(LOINC_URI); include .addFilter() .setProperty("copyright") @@ -403,7 +434,7 @@ public class TerminologySvcImplDstu3Test extends BaseJpaDstu3Test { } @Test - public void testExpandValueSetPropertyFilterCopyrightWithIncludeLoinc() { + public void testExpandValueSetPropertyFilterLoincCopyrightWithIncludeLoinc() { createLoincSystemWithSomeCodes(); List codes; @@ -414,7 +445,7 @@ public class TerminologySvcImplDstu3Test extends BaseJpaDstu3Test { // Include vs = new ValueSet(); include = vs.getCompose().addInclude(); - include.setSystem(CS_URL); + include.setSystem(LOINC_URI); include .addFilter() .setProperty("copyright") @@ -427,7 +458,7 @@ public class TerminologySvcImplDstu3Test extends BaseJpaDstu3Test { // Include vs = new ValueSet(); include = vs.getCompose().addInclude(); - include.setSystem(CS_URL); + include.setSystem(LOINC_URI); include .addFilter() .setProperty("copyright") @@ -439,7 +470,7 @@ public class TerminologySvcImplDstu3Test extends BaseJpaDstu3Test { } @Test - public void testExpandValueSetPropertyFilterCopyrightWithUnsupportedOp() { + public void testExpandValueSetPropertyFilterLoincCopyrightWithUnsupportedOp() { createLoincSystemWithSomeCodes(); List codes; @@ -450,7 +481,7 @@ public class TerminologySvcImplDstu3Test extends BaseJpaDstu3Test { // Include vs = new ValueSet(); include = vs.getCompose().addInclude(); - include.setSystem(CS_URL); + include.setSystem(LOINC_URI); include .addFilter() .setProperty("copyright") @@ -465,7 +496,7 @@ public class TerminologySvcImplDstu3Test extends BaseJpaDstu3Test { } @Test - public void testExpandValueSetPropertyFilterCopyrightWithUnsupportedValue() { + public void testExpandValueSetPropertyFilterLoincCopyrightWithUnsupportedValue() { createLoincSystemWithSomeCodes(); List codes; @@ -476,7 +507,7 @@ public class TerminologySvcImplDstu3Test extends BaseJpaDstu3Test { // Include vs = new ValueSet(); include = vs.getCompose().addInclude(); - include.setSystem(CS_URL); + include.setSystem(LOINC_URI); include .addFilter() .setProperty("copyright") @@ -490,6 +521,383 @@ public class TerminologySvcImplDstu3Test extends BaseJpaDstu3Test { } } + @Test + public void testExpandValueSetPropertyFilterLoincChildWithExcludeAndEqual() { + createLoincSystemWithSomeCodes(); + + List 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 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 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 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 testExpandValueSetPropertyFilterLoincParentWithExcludeAndEqual() { + createLoincSystemWithSomeCodes(); + + List 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 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 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 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 testExpandValueSetPropertySearchWithRegexExclude() { createLoincSystemWithSomeCodes(); @@ -503,10 +911,10 @@ public class TerminologySvcImplDstu3Test extends BaseJpaDstu3Test { vs = new ValueSet(); vs.getCompose() .addInclude() - .setSystem(CS_URL); + .setSystem(LOINC_URI); exclude = vs.getCompose().addExclude(); - exclude.setSystem(CS_URL); + exclude.setSystem(LOINC_URI); exclude .addFilter() .setProperty("SYSTEM") @@ -530,10 +938,10 @@ public class TerminologySvcImplDstu3Test extends BaseJpaDstu3Test { vs = new ValueSet(); vs.getCompose() .addInclude() - .setSystem(CS_URL); + .setSystem(LOINC_URI); exclude = vs.getCompose().addExclude(); - exclude.setSystem(CS_URL); + exclude.setSystem(LOINC_URI); exclude .addFilter() .setProperty("HELLO") @@ -546,7 +954,6 @@ public class TerminologySvcImplDstu3Test extends BaseJpaDstu3Test { @Test public void testExpandValueSetPropertySearchWithRegexInclude() { - // create codes with "SYSTEM" property "Bld/Bone mar^Donor" and "Ser" createLoincSystemWithSomeCodes(); List codes; @@ -557,7 +964,7 @@ public class TerminologySvcImplDstu3Test extends BaseJpaDstu3Test { // Include vs = new ValueSet(); include = vs.getCompose().addInclude(); - include.setSystem(CS_URL); + include.setSystem(LOINC_URI); include .addFilter() .setProperty("SYSTEM") @@ -570,7 +977,7 @@ public class TerminologySvcImplDstu3Test extends BaseJpaDstu3Test { // Include vs = new ValueSet(); include = vs.getCompose().addInclude(); - include.setSystem(CS_URL); + include.setSystem(LOINC_URI); include .addFilter() .setProperty("SYSTEM") @@ -583,7 +990,7 @@ public class TerminologySvcImplDstu3Test extends BaseJpaDstu3Test { // Include vs = new ValueSet(); include = vs.getCompose().addInclude(); - include.setSystem(CS_URL); + include.setSystem(LOINC_URI); include .addFilter() .setProperty("SYSTEM") @@ -596,7 +1003,7 @@ public class TerminologySvcImplDstu3Test extends BaseJpaDstu3Test { // Include vs = new ValueSet(); include = vs.getCompose().addInclude(); - include.setSystem(CS_URL); + include.setSystem(LOINC_URI); include .addFilter() .setProperty("SYSTEM") @@ -609,7 +1016,7 @@ public class TerminologySvcImplDstu3Test extends BaseJpaDstu3Test { // Include vs = new ValueSet(); include = vs.getCompose().addInclude(); - include.setSystem(CS_URL); + include.setSystem(LOINC_URI); include .addFilter() .setProperty("SYSTEM") @@ -622,7 +1029,7 @@ public class TerminologySvcImplDstu3Test extends BaseJpaDstu3Test { // Include vs = new ValueSet(); include = vs.getCompose().addInclude(); - include.setSystem(CS_URL); + include.setSystem(LOINC_URI); include .addFilter() .setProperty("SYSTEM")