add `displayLanguage` to the `ValueSet/$expand` (#3619)

* add `displayLanguage` to the `ValueSet/$expand`

* fix tests

* fix tests
This commit is contained in:
Gjergj Sheldija 2022-07-12 21:54:29 +02:00 committed by GitHub
parent f0decbf8c8
commit 4684dde6a6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 87 additions and 10 deletions

View File

@ -35,6 +35,8 @@ public class ValueSetExpansionOptions {
private boolean myIncludeHierarchy; private boolean myIncludeHierarchy;
private String myFilter; private String myFilter;
private String myDisplayLanguage;
public String getFilter() { public String getFilter() {
return myFilter; return myFilter;
} }
@ -118,4 +120,13 @@ public class ValueSetExpansionOptions {
.setOffset(theOffset) .setOffset(theOffset)
.setCount(theCount); .setCount(theCount);
} }
public String getTheDisplayLanguage() {
return myDisplayLanguage;
}
public ValueSetExpansionOptions setTheDisplayLanguage(String theDisplayLanguage) {
myDisplayLanguage = theDisplayLanguage;
return this;
}
} }

View File

@ -50,11 +50,13 @@ import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.instance.model.api.ICompositeType; import org.hl7.fhir.instance.model.api.ICompositeType;
import org.hl7.fhir.instance.model.api.IIdType; import org.hl7.fhir.instance.model.api.IIdType;
import org.hl7.fhir.instance.model.api.IPrimitiveType; import org.hl7.fhir.instance.model.api.IPrimitiveType;
import org.hl7.fhir.r4.model.CodeType;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.annotation.Qualifier;
import javax.annotation.Nullable;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import static org.apache.commons.lang3.StringUtils.isNotBlank; import static org.apache.commons.lang3.StringUtils.isNotBlank;
@ -108,6 +110,7 @@ public class ValueSetOperationProvider extends BaseJpaProvider {
@OperationParam(name = "contextDirection", min = 0, max = 1, typeName = "string") IPrimitiveType<String> theContextDirection, @OperationParam(name = "contextDirection", min = 0, max = 1, typeName = "string") IPrimitiveType<String> theContextDirection,
@OperationParam(name = "offset", min = 0, max = 1, typeName = "integer") IPrimitiveType<Integer> theOffset, @OperationParam(name = "offset", min = 0, max = 1, typeName = "integer") IPrimitiveType<Integer> theOffset,
@OperationParam(name = "count", min = 0, max = 1, typeName = "integer") IPrimitiveType<Integer> theCount, @OperationParam(name = "count", min = 0, max = 1, typeName = "integer") IPrimitiveType<Integer> theCount,
@OperationParam(name = JpaConstants.OPERATION_EXPAND_PARAM_DISPLAY_LANGUAGE, min = 0, max = 1, typeName = "code") IPrimitiveType<String> theDisplayLanguage,
@OperationParam(name = JpaConstants.OPERATION_EXPAND_PARAM_INCLUDE_HIERARCHY, min = 0, max = 1, typeName = "boolean") IPrimitiveType<Boolean> theIncludeHierarchy, @OperationParam(name = JpaConstants.OPERATION_EXPAND_PARAM_INCLUDE_HIERARCHY, min = 0, max = 1, typeName = "boolean") IPrimitiveType<Boolean> theIncludeHierarchy,
RequestDetails theRequestDetails) { RequestDetails theRequestDetails) {
@ -143,7 +146,7 @@ public class ValueSetOperationProvider extends BaseJpaProvider {
throw new InvalidRequestException(Msg.code(1134) + "$expand must EITHER be invoked at the instance level, or have a url specified, or have a ValueSet specified. Can not combine these options."); throw new InvalidRequestException(Msg.code(1134) + "$expand must EITHER be invoked at the instance level, or have a url specified, or have a ValueSet specified. Can not combine these options.");
} }
ValueSetExpansionOptions options = createValueSetExpansionOptions(myDaoConfig, theOffset, theCount, theIncludeHierarchy, theFilter); ValueSetExpansionOptions options = createValueSetExpansionOptions(myDaoConfig, theOffset, theCount, theIncludeHierarchy, theFilter, theDisplayLanguage);
startRequest(theServletRequest); startRequest(theServletRequest);
try { try {
@ -265,7 +268,7 @@ public class ValueSetOperationProvider extends BaseJpaProvider {
} }
public static ValueSetExpansionOptions createValueSetExpansionOptions(DaoConfig theDaoConfig, IPrimitiveType<Integer> theOffset, IPrimitiveType<Integer> theCount, IPrimitiveType<Boolean> theIncludeHierarchy, IPrimitiveType<String> theFilter) { public static ValueSetExpansionOptions createValueSetExpansionOptions(DaoConfig theDaoConfig, IPrimitiveType<Integer> theOffset, IPrimitiveType<Integer> theCount, IPrimitiveType<Boolean> theIncludeHierarchy, IPrimitiveType<String> theFilter, IPrimitiveType<String> theDisplayLanguage) {
int offset = theDaoConfig.getPreExpandValueSetsDefaultOffset(); int offset = theDaoConfig.getPreExpandValueSetsDefaultOffset();
if (theOffset != null && theOffset.hasValue()) { if (theOffset != null && theOffset.hasValue()) {
if (theOffset.getValue() >= 0) { if (theOffset.getValue() >= 0) {
@ -299,6 +302,10 @@ public class ValueSetOperationProvider extends BaseJpaProvider {
options.setFilter(theFilter.getValue()); options.setFilter(theFilter.getValue());
} }
if( theDisplayLanguage != null ) {
options.setTheDisplayLanguage(theDisplayLanguage.getValue());
}
return options; return options;
} }

View File

@ -308,6 +308,7 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc {
.collect(joining(" ")); .collect(joining(" "));
} }
Collection<TermConceptDesignation> designations = theConcept.getDesignations(); Collection<TermConceptDesignation> designations = theConcept.getDesignations();
if (StringUtils.isNotEmpty(theValueSetIncludeVersion)) { if (StringUtils.isNotEmpty(theValueSetIncludeVersion)) {
return addCodeIfNotAlreadyAdded(theValueSetCodeAccumulator, theAddedCodes, designations, theAdd, codeSystem + "|" + theValueSetIncludeVersion, code, display, sourceConceptPid, directParentPids, codeSystemVersion); return addCodeIfNotAlreadyAdded(theValueSetCodeAccumulator, theAddedCodes, designations, theAdd, codeSystem + "|" + theValueSetIncludeVersion, code, display, sourceConceptPid, directParentPids, codeSystemVersion);
@ -526,7 +527,7 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc {
String expansionTimestamp = toHumanReadableExpansionTimestamp(termValueSet); String expansionTimestamp = toHumanReadableExpansionTimestamp(termValueSet);
String msg = myContext.getLocalizer().getMessage(BaseTermReadSvcImpl.class, "valueSetExpandedUsingPreExpansion", expansionTimestamp); String msg = myContext.getLocalizer().getMessage(BaseTermReadSvcImpl.class, "valueSetExpandedUsingPreExpansion", expansionTimestamp);
theAccumulator.addMessage(msg); theAccumulator.addMessage(msg);
expandConcepts(theAccumulator, termValueSet, theFilter, theAdd, isOracleDialect()); expandConcepts(theExpansionOptions, theAccumulator, termValueSet, theFilter, theAdd, isOracleDialect());
} }
@Nonnull @Nonnull
@ -543,7 +544,7 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc {
return myHibernatePropertiesProvider.getDialect() instanceof org.hibernate.dialect.Oracle12cDialect; return myHibernatePropertiesProvider.getDialect() instanceof org.hibernate.dialect.Oracle12cDialect;
} }
private void expandConcepts(IValueSetConceptAccumulator theAccumulator, TermValueSet theTermValueSet, ExpansionFilter theFilter, boolean theAdd, boolean theOracle) { private void expandConcepts(ValueSetExpansionOptions theExpansionOptions, IValueSetConceptAccumulator theAccumulator, TermValueSet theTermValueSet, ExpansionFilter theFilter, boolean theAdd, boolean theOracle) {
// NOTE: if you modifiy the logic here, look to `expandConceptsOracle` and see if your new code applies to its copy pasted sibling // NOTE: if you modifiy the logic here, look to `expandConceptsOracle` and see if your new code applies to its copy pasted sibling
Integer offset = theAccumulator.getSkipCountRemaining(); Integer offset = theAccumulator.getSkipCountRemaining();
offset = ObjectUtils.defaultIfNull(offset, 0); offset = ObjectUtils.defaultIfNull(offset, 0);
@ -612,12 +613,15 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc {
// TODO: DM 2019-08-17 - Implement includeDesignations parameter for $expand operation to designations optional. // TODO: DM 2019-08-17 - Implement includeDesignations parameter for $expand operation to designations optional.
if (conceptView.getDesignationPid() != null) { if (conceptView.getDesignationPid() != null) {
TermConceptDesignation designation = new TermConceptDesignation(); TermConceptDesignation designation = new TermConceptDesignation();
designation.setUseSystem(conceptView.getDesignationUseSystem());
designation.setUseCode(conceptView.getDesignationUseCode()); if(isValueSetDisplayLanguageMatch(theExpansionOptions, conceptView.getDesignationLang() )) {
designation.setUseDisplay(conceptView.getDesignationUseDisplay()); designation.setUseSystem(conceptView.getDesignationUseSystem());
designation.setValue(conceptView.getDesignationVal()); designation.setUseCode(conceptView.getDesignationUseCode());
designation.setLanguage(conceptView.getDesignationLang()); designation.setUseDisplay(conceptView.getDesignationUseDisplay());
pidToDesignations.put(conceptPid, designation); designation.setValue(conceptView.getDesignationVal());
designation.setLanguage(conceptView.getDesignationLang());
pidToDesignations.put(conceptPid, designation);
}
if (++designationsExpanded % 250 == 0) { if (++designationsExpanded % 250 == 0) {
logDesignationsExpanded("Expansion of designations in progress. ", theTermValueSet, designationsExpanded); logDesignationsExpanded("Expansion of designations in progress. ", theTermValueSet, designationsExpanded);
@ -668,6 +672,19 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc {
logConceptsExpanded("Finished expanding concepts. ", theTermValueSet, conceptsExpanded); logConceptsExpanded("Finished expanding concepts. ", theTermValueSet, conceptsExpanded);
} }
static boolean isValueSetDisplayLanguageMatch(ValueSetExpansionOptions theExpansionOptions, String theStoredLang){
if( theExpansionOptions == null) {
return true;
}
if(theExpansionOptions.getTheDisplayLanguage() == null || theStoredLang == null) {
return true;
}
return theExpansionOptions.getTheDisplayLanguage().equalsIgnoreCase(theStoredLang);
}
private void logConceptsExpanded(String theLogDescriptionPrefix, TermValueSet theTermValueSet, int theConceptsExpanded) { private void logConceptsExpanded(String theLogDescriptionPrefix, TermValueSet theTermValueSet, int theConceptsExpanded) {
if (theConceptsExpanded > 0) { if (theConceptsExpanded > 0) {
ourLog.debug("{}Have expanded {} concepts in ValueSet[{}]", theLogDescriptionPrefix, theConceptsExpanded, theTermValueSet.getUrl()); ourLog.debug("{}Have expanded {} concepts in ValueSet[{}]", theLogDescriptionPrefix, theConceptsExpanded, theTermValueSet.getUrl());

View File

@ -257,9 +257,11 @@ public class JpaConstants {
* Parameter for the $expand operation * Parameter for the $expand operation
*/ */
public static final String OPERATION_EXPAND_PARAM_INCLUDE_HIERARCHY = "includeHierarchy"; public static final String OPERATION_EXPAND_PARAM_INCLUDE_HIERARCHY = "includeHierarchy";
public static final String OPERATION_EXPAND_PARAM_DISPLAY_LANGUAGE = "displayLanguage";
public static final String HEADER_UPSERT_EXISTENCE_CHECK = "X-Upsert-Extistence-Check"; public static final String HEADER_UPSERT_EXISTENCE_CHECK = "X-Upsert-Extistence-Check";
public static final String HEADER_UPSERT_EXISTENCE_CHECK_DISABLED = "disabled"; public static final String HEADER_UPSERT_EXISTENCE_CHECK_DISABLED = "disabled";
/** /**
* Parameters for the rewrite history operation * Parameters for the rewrite history operation
*/ */

View File

@ -630,6 +630,46 @@ public class ValueSetExpansionR4Test extends BaseTermR4Test {
assertExpandedValueSetContainsConcept(expandedValueSet, "http://acme.org", "8492-1", "Systolic blood pressure 8 hour minimum", 0); assertExpandedValueSetContainsConcept(expandedValueSet, "http://acme.org", "8492-1", "Systolic blood pressure 8 hour minimum", 0);
} }
@Test
public void testExpandTermValueSetAndChildrenWithCountWithDisplayLanguage() throws Exception {
myDaoConfig.setPreExpandValueSets(true);
loadAndPersistCodeSystemAndValueSetWithDesignations(HttpVerb.POST);
CodeSystem codeSystem = myCodeSystemDao.read(myExtensionalCsId);
ourLog.info("CodeSystem:\n" + myFhirContext.newJsonParser().setPrettyPrint(true).encodeResourceToString(codeSystem));
ValueSet valueSet = myValueSetDao.read(myExtensionalVsId);
ourLog.info("ValueSet:\n" + myFhirContext.newJsonParser().setPrettyPrint(true).encodeResourceToString(valueSet));
myTermSvc.preExpandDeferredValueSetsToTerminologyTables();
List<String> expandedConceptCodes = getExpandedConceptsByValueSetUrl("http://www.healthintersections.com.au/fhir/ValueSet/extensional-case-2");
ValueSetExpansionOptions options = new ValueSetExpansionOptions()
.setOffset(0)
.setCount(23)
.setTheDisplayLanguage("nl");
ValueSet expandedValueSet = myTermSvc.expandValueSet(options, valueSet);
ourLog.info("Expanded ValueSet:\n" + myFhirContext.newJsonParser().setPrettyPrint(true).encodeResourceToString(expandedValueSet));
assertEquals(codeSystem.getConcept().size(), expandedValueSet.getExpansion().getTotal());
assertEquals(myDaoConfig.getPreExpandValueSetsDefaultOffset(), expandedValueSet.getExpansion().getOffset());
assertEquals(2, expandedValueSet.getExpansion().getParameter().size());
assertEquals("offset", expandedValueSet.getExpansion().getParameter().get(0).getName());
assertEquals(0, expandedValueSet.getExpansion().getParameter().get(0).getValueIntegerType().getValue().intValue());
assertEquals("count", expandedValueSet.getExpansion().getParameter().get(1).getName());
assertEquals(23, expandedValueSet.getExpansion().getParameter().get(1).getValueIntegerType().getValue().intValue());
assertEquals(23, expandedValueSet.getExpansion().getContains().size());
ValueSet.ValueSetExpansionContainsComponent concept = assertExpandedValueSetContainsConcept(expandedValueSet, "http://acme.org", "8450-9", "Systolic blood pressure--expiration", 1);
assertThat(concept.getDesignation().size() , is(equalTo(1)));
assertConceptContainsDesignation(concept, "nl", "http://snomed.info/sct", "900000000000013009", "Synonym", "Systolische bloeddruk - expiratie");
//It is enough to test that the sublist returned is the correct one.
assertThat(ValueSetTestUtil.toCodes(expandedValueSet), is(equalTo(expandedConceptCodes.subList(0, 23))));
}
@Test @Test
public void testExpandTermValueSetAndChildrenWithCount() throws Exception { public void testExpandTermValueSetAndChildrenWithCount() throws Exception {
myDaoConfig.setPreExpandValueSets(true); myDaoConfig.setPreExpandValueSets(true);