Force _summary=false when fetching CodeSystems and ValueSets with remote terminology (#5372)

Force _summary=false when fetching CodeSystems and ValueSets with remote terminology
This commit is contained in:
michaelabuckley 2023-10-19 09:18:01 -04:00 committed by GitHub
parent 25ce7d0b8f
commit e2ca967fd9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 93 additions and 14 deletions

View File

@ -0,0 +1,4 @@
---
type: change
issue: 5371
title: "Remote terminology operations that fetch ValueSets or CodeSystems now force _summary=false to allow local validation."

View File

@ -8,7 +8,9 @@ import ca.uhn.fhir.context.support.IValidationSupport;
import ca.uhn.fhir.context.support.TranslateConceptResults; import ca.uhn.fhir.context.support.TranslateConceptResults;
import ca.uhn.fhir.context.support.ValidationSupportContext; import ca.uhn.fhir.context.support.ValidationSupportContext;
import ca.uhn.fhir.i18n.Msg; import ca.uhn.fhir.i18n.Msg;
import ca.uhn.fhir.rest.api.SummaryEnum;
import ca.uhn.fhir.rest.client.api.IGenericClient; import ca.uhn.fhir.rest.client.api.IGenericClient;
import ca.uhn.fhir.rest.gclient.IQuery;
import ca.uhn.fhir.util.BundleUtil; import ca.uhn.fhir.util.BundleUtil;
import ca.uhn.fhir.util.ParametersUtil; import ca.uhn.fhir.util.ParametersUtil;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
@ -24,6 +26,7 @@ import org.slf4j.LoggerFactory;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import static org.apache.commons.lang3.StringUtils.isBlank; import static org.apache.commons.lang3.StringUtils.isBlank;
import static org.apache.commons.lang3.StringUtils.isNotBlank; import static org.apache.commons.lang3.StringUtils.isNotBlank;
@ -141,16 +144,32 @@ public class RemoteTerminologyServiceValidationSupport extends BaseValidationSup
@Override @Override
public IBaseResource fetchCodeSystem(String theSystem) { public IBaseResource fetchCodeSystem(String theSystem) {
// callers of this want the whole resource.
return fetchCodeSystem(theSystem, SummaryEnum.FALSE);
}
/**
* Fetch the code system, possibly a summary.
* @param theSystem the canonical url
* @param theSummaryParam to force a summary mode - or null to allow server default.
* @return the CodeSystem
*/
@Nullable
private IBaseResource fetchCodeSystem(String theSystem, @Nullable SummaryEnum theSummaryParam) {
IGenericClient client = provideClient(); IGenericClient client = provideClient();
Class<? extends IBaseBundle> bundleType = Class<? extends IBaseBundle> bundleType =
myCtx.getResourceDefinition("Bundle").getImplementingClass(IBaseBundle.class); myCtx.getResourceDefinition("Bundle").getImplementingClass(IBaseBundle.class);
IBaseBundle results = client.search() IQuery<IBaseBundle> codeSystemQuery = client.search()
.forResource("CodeSystem") .forResource("CodeSystem")
.where(CodeSystem.URL.matches().value(theSystem)) .where(CodeSystem.URL.matches().value(theSystem));
.returnBundle(bundleType)
.execute(); if (theSummaryParam != null) {
codeSystemQuery.summaryMode(theSummaryParam);
}
IBaseBundle results = codeSystemQuery.returnBundle(bundleType).execute();
List<IBaseResource> resultsList = BundleUtil.toListOfResources(myCtx, results); List<IBaseResource> resultsList = BundleUtil.toListOfResources(myCtx, results);
if (resultsList.size() > 0) { if (!resultsList.isEmpty()) {
return resultsList.get(0); return resultsList.get(0);
} }
@ -388,16 +407,36 @@ public class RemoteTerminologyServiceValidationSupport extends BaseValidationSup
@Override @Override
public IBaseResource fetchValueSet(String theValueSetUrl) { public IBaseResource fetchValueSet(String theValueSetUrl) {
// force the remote server to send the whole resource.
SummaryEnum summaryParam = SummaryEnum.FALSE;
return fetchValueSet(theValueSetUrl, summaryParam);
}
/**
* Search for a ValueSet by canonical url via IGenericClient.
*
* @param theValueSetUrl the canonical url of the ValueSet
* @param theSummaryParam force a summary mode - null allows server default
* @return the ValueSet or null if none match the url
*/
@Nullable
private IBaseResource fetchValueSet(String theValueSetUrl, SummaryEnum theSummaryParam) {
IGenericClient client = provideClient(); IGenericClient client = provideClient();
Class<? extends IBaseBundle> bundleType = Class<? extends IBaseBundle> bundleType =
myCtx.getResourceDefinition("Bundle").getImplementingClass(IBaseBundle.class); myCtx.getResourceDefinition("Bundle").getImplementingClass(IBaseBundle.class);
IBaseBundle results = client.search()
IQuery<IBaseBundle> valueSetQuery = client.search()
.forResource("ValueSet") .forResource("ValueSet")
.where(CodeSystem.URL.matches().value(theValueSetUrl)) .where(CodeSystem.URL.matches().value(theValueSetUrl));
.returnBundle(bundleType)
.execute(); if (theSummaryParam != null) {
valueSetQuery.summaryMode(theSummaryParam);
}
IBaseBundle results = valueSetQuery.returnBundle(bundleType).execute();
List<IBaseResource> resultsList = BundleUtil.toListOfResources(myCtx, results); List<IBaseResource> resultsList = BundleUtil.toListOfResources(myCtx, results);
if (resultsList.size() > 0) { if (!resultsList.isEmpty()) {
return resultsList.get(0); return resultsList.get(0);
} }
@ -406,12 +445,18 @@ public class RemoteTerminologyServiceValidationSupport extends BaseValidationSup
@Override @Override
public boolean isCodeSystemSupported(ValidationSupportContext theValidationSupportContext, String theSystem) { public boolean isCodeSystemSupported(ValidationSupportContext theValidationSupportContext, String theSystem) {
return fetchCodeSystem(theSystem) != null; // a summary is ok if we are just checking the presence.
SummaryEnum summaryParam = null;
return fetchCodeSystem(theSystem, summaryParam) != null;
} }
@Override @Override
public boolean isValueSetSupported(ValidationSupportContext theValidationSupportContext, String theValueSetUrl) { public boolean isValueSetSupported(ValidationSupportContext theValidationSupportContext, String theValueSetUrl) {
return fetchValueSet(theValueSetUrl) != null; // a summary is ok if we are just checking the presence.
SummaryEnum summaryParam = null;
return fetchValueSet(theValueSetUrl, summaryParam) != null;
} }
@Override @Override

View File

@ -12,6 +12,7 @@ import ca.uhn.fhir.rest.annotation.Operation;
import ca.uhn.fhir.rest.annotation.OperationParam; import ca.uhn.fhir.rest.annotation.OperationParam;
import ca.uhn.fhir.rest.annotation.RequiredParam; import ca.uhn.fhir.rest.annotation.RequiredParam;
import ca.uhn.fhir.rest.annotation.Search; import ca.uhn.fhir.rest.annotation.Search;
import ca.uhn.fhir.rest.api.SummaryEnum;
import ca.uhn.fhir.rest.api.server.RequestDetails; import ca.uhn.fhir.rest.api.server.RequestDetails;
import ca.uhn.fhir.rest.client.api.IClientInterceptor; import ca.uhn.fhir.rest.client.api.IClientInterceptor;
import ca.uhn.fhir.rest.client.api.IHttpRequest; import ca.uhn.fhir.rest.client.api.IHttpRequest;
@ -175,6 +176,18 @@ public class RemoteTerminologyServiceValidationSupportTest {
assertEquals(null, myValueSetProvider.myLastValueSet); assertEquals(null, myValueSetProvider.myLastValueSet);
} }
@Test
void testFetchValueSet_forcesSummaryFalse() {
// given
myValueSetProvider.myNextReturnValueSets = new ArrayList<>();
// when
IBaseResource valueSet = mySvc.fetchValueSet(VALUE_SET_URL);
// then
assertEquals(SummaryEnum.FALSE, myValueSetProvider.myLastSummaryParam);
}
@Test @Test
public void testValidateCodeWithAllParams_CodeSystem_Success() { public void testValidateCodeWithAllParams_CodeSystem_Success() {
createNextCodeSystemReturnParameters(true, DISPLAY, null); createNextCodeSystemReturnParameters(true, DISPLAY, null);
@ -374,6 +387,19 @@ public class RemoteTerminologyServiceValidationSupportTest {
assertNull(myConceptMapProvider.myLastReverse); assertNull(myConceptMapProvider.myLastReverse);
} }
@Test
void testFetchCodeSystem_forcesSummaryFalse() {
// given
myCodeSystemProvider.myNextReturnCodeSystems = new ArrayList<>();
// when
IBaseResource codeSystem = mySvc.fetchCodeSystem("http://loinc.org");
// then
assertEquals(SummaryEnum.FALSE, myCodeSystemProvider.myLastSummaryParam);
}
private void addMatchToTranslateRequest(Parameters params) { private void addMatchToTranslateRequest(Parameters params) {
Parameters.ParametersParameterComponent matchParam = params.addParameter().setName("match"); Parameters.ParametersParameterComponent matchParam = params.addParameter().setName("match");
matchParam.addPart().setName("equivalence").setValue(new CodeType(EQUIVALENCE_CODE)); matchParam.addPart().setName("equivalence").setValue(new CodeType(EQUIVALENCE_CODE));
@ -626,6 +652,7 @@ public class RemoteTerminologyServiceValidationSupportTest {
private static class MyCodeSystemProvider implements IResourceProvider { private static class MyCodeSystemProvider implements IResourceProvider {
private SummaryEnum myLastSummaryParam;
private UriParam myLastUrlParam; private UriParam myLastUrlParam;
private List<CodeSystem> myNextReturnCodeSystems; private List<CodeSystem> myNextReturnCodeSystems;
private int myInvocationCount; private int myInvocationCount;
@ -680,8 +707,9 @@ public class RemoteTerminologyServiceValidationSupportTest {
} }
@Search @Search
public List<CodeSystem> find(@RequiredParam(name = "url") UriParam theUrlParam) { public List<CodeSystem> find(@RequiredParam(name = "url") UriParam theUrlParam, SummaryEnum theSummaryParam) {
myLastUrlParam = theUrlParam; myLastUrlParam = theUrlParam;
myLastSummaryParam = theSummaryParam;
assert myNextReturnCodeSystems != null; assert myNextReturnCodeSystems != null;
return myNextReturnCodeSystems; return myNextReturnCodeSystems;
} }
@ -703,6 +731,7 @@ public class RemoteTerminologyServiceValidationSupportTest {
private StringType myLastDisplay; private StringType myLastDisplay;
private ValueSet myLastValueSet; private ValueSet myLastValueSet;
private UriParam myLastUrlParam; private UriParam myLastUrlParam;
private SummaryEnum myLastSummaryParam;
@Operation(name = "validate-code", idempotent = true, returnParameters = { @Operation(name = "validate-code", idempotent = true, returnParameters = {
@OperationParam(name = "result", type = BooleanType.class, min = 1), @OperationParam(name = "result", type = BooleanType.class, min = 1),
@ -728,8 +757,9 @@ public class RemoteTerminologyServiceValidationSupportTest {
} }
@Search @Search
public List<ValueSet> find(@RequiredParam(name = "url") UriParam theUrlParam) { public List<ValueSet> find(@RequiredParam(name = "url") UriParam theUrlParam, SummaryEnum theSummaryParam) {
myLastUrlParam = theUrlParam; myLastUrlParam = theUrlParam;
myLastSummaryParam = theSummaryParam;
assert myNextReturnValueSets != null; assert myNextReturnValueSets != null;
return myNextReturnValueSets; return myNextReturnValueSets;
} }