4115 Combining 'indexMissingFields' and 'advancedHSearchIndexing' functionalities will prevent creating a resource (#4122)

* Added Test

* Added Integration Test

* Made changes based on comments

* Implemented solution

* Implemented solution

* Debug

* Changelog

* Changes made based on comments

* Changelog

* Made changes based on comments

* Made changes based on comments

Co-authored-by: Karneet Kaur <karneet.kaur@smilecdr.com>
This commit is contained in:
Etienne Poirier 2022-10-12 12:16:44 -04:00 committed by GitHub
parent 2de9b5aa03
commit 4cebcfb766
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 93 additions and 9 deletions

View File

@ -0,0 +1,7 @@
---
type: fix
issue: 4115
title: "Previously, enabling 'indexMissingFields' and 'advancedHSearchIndexing'
functionalities would cause creating a Patient resource to return HTTP 500.
Upon further investigation, the same happened for creating an Observation.
This has been fixed."

View File

@ -87,18 +87,25 @@ public class ExtendedHSearchIndexExtractor {
// wipmb mb add a flag ot DaoConfig to suppress this // wipmb mb add a flag ot DaoConfig to suppress this
extractAutocompleteTokens(theResource, retVal); extractAutocompleteTokens(theResource, retVal);
theNewParams.myStringParams.forEach(nextParam -> theNewParams.myStringParams.stream()
retVal.addStringIndexData(nextParam.getParamName(), nextParam.getValueExact())); .filter(nextParam -> !nextParam.isMissing())
.forEach(nextParam -> retVal.addStringIndexData(nextParam.getParamName(), nextParam.getValueExact()));
theNewParams.myTokenParams.forEach(nextParam -> theNewParams.myTokenParams.stream()
retVal.addTokenIndexDataIfNotPresent(nextParam.getParamName(), nextParam.getSystem(), nextParam.getValue())); .filter(nextParam -> !nextParam.isMissing())
.forEach(nextParam -> retVal.addTokenIndexDataIfNotPresent(nextParam.getParamName(), nextParam.getSystem(), nextParam.getValue()));
theNewParams.myNumberParams.forEach(nextParam -> theNewParams.myNumberParams.stream()
retVal.addNumberIndexDataIfNotPresent(nextParam.getParamName(), nextParam.getValue())); .filter(nextParam -> !nextParam.isMissing())
.forEach(nextParam -> retVal.addNumberIndexDataIfNotPresent(nextParam.getParamName(), nextParam.getValue()));
theNewParams.myDateParams.forEach(nextParam -> retVal.addDateIndexData(nextParam.getParamName(), convertDate(nextParam))); theNewParams.myDateParams.stream()
.filter(nextParam -> !nextParam.isMissing())
.forEach(nextParam -> retVal.addDateIndexData(nextParam.getParamName(), convertDate(nextParam)));
theNewParams.myQuantityParams.forEach(nextParam -> retVal.addQuantityIndexData(nextParam.getParamName(), convertQuantity(nextParam))); theNewParams.myQuantityParams.stream()
.filter(nextParam -> !nextParam.isMissing())
.forEach(nextParam -> retVal.addQuantityIndexData(nextParam.getParamName(), convertQuantity(nextParam)));
theResource.getMeta().getTag().forEach(tag -> theResource.getMeta().getTag().forEach(tag ->
retVal.addTokenIndexData("_tag", tag)); retVal.addTokenIndexData("_tag", tag));

View File

@ -40,6 +40,7 @@ import com.google.common.collect.Sets;
import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.BooleanUtils; import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import static ca.uhn.fhir.rest.api.Constants.PARAMQUALIFIER_MISSING;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
@ -127,7 +128,12 @@ public class ExtendedHSearchSearchBuilder {
return modifier.equals(EMPTY_MODIFIER); return modifier.equals(EMPTY_MODIFIER);
} else if (param instanceof CompositeParam) { } else if (param instanceof CompositeParam) {
switch(modifier) {
case PARAMQUALIFIER_MISSING:
return false;
default:
return true; return true;
}
} else if (param instanceof ReferenceParam) { } else if (param instanceof ReferenceParam) {
//We cannot search by chain. //We cannot search by chain.

View File

@ -141,6 +141,8 @@ public class ExtendedHSearchIndexData {
mySearchParamDates.put(theSpName, value); mySearchParamDates.put(theSpName, value);
} }
public SetMultimap<String, DateSearchIndexData> getDateIndexData() { return mySearchParamDates; }
public void addNumberIndexDataIfNotPresent(String theParamName, BigDecimal theValue) { public void addNumberIndexDataIfNotPresent(String theParamName, BigDecimal theValue) {
mySearchParamNumbers.put(theParamName, theValue); mySearchParamNumbers.put(theParamName, theValue);
} }
@ -149,6 +151,8 @@ public class ExtendedHSearchIndexData {
mySearchParamQuantities.put(theSpName, value); mySearchParamQuantities.put(theSpName, value);
} }
public SetMultimap<String,QuantitySearchIndexData> getQuantityIndexData () {return mySearchParamQuantities;}
public void setForcedId(String theForcedId) { public void setForcedId(String theForcedId) {
myForcedId = theForcedId; myForcedId = theForcedId;
} }

View File

@ -240,6 +240,7 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test {
myDaoConfig.setSearchPreFetchThresholds(new DaoConfig().getSearchPreFetchThresholds()); myDaoConfig.setSearchPreFetchThresholds(new DaoConfig().getSearchPreFetchThresholds());
myDaoConfig.setAllowContainsSearches(new DaoConfig().isAllowContainsSearches()); myDaoConfig.setAllowContainsSearches(new DaoConfig().isAllowContainsSearches());
myDaoConfig.setIndexMissingFields(new DaoConfig().getIndexMissingFields()); myDaoConfig.setIndexMissingFields(new DaoConfig().getIndexMissingFields());
myDaoConfig.setAdvancedHSearchIndexing(new DaoConfig().isAdvancedHSearchIndexing());
mySearchCoordinatorSvcRaw.setLoadingThrottleForUnitTests(null); mySearchCoordinatorSvcRaw.setLoadingThrottleForUnitTests(null);
mySearchCoordinatorSvcRaw.setSyncSizeForUnitTests(QueryParameterUtils.DEFAULT_SYNC_SIZE); mySearchCoordinatorSvcRaw.setSyncSizeForUnitTests(QueryParameterUtils.DEFAULT_SYNC_SIZE);
@ -6167,6 +6168,34 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test {
} }
} }
@Test
public void testCreateResourcesWithAdvancedHSearchIndexingAndIndexMissingFieldsEnableSucceeds() throws Exception {
myDaoConfig.setIndexMissingFields(DaoConfig.IndexEnabledEnum.ENABLED);
myDaoConfig.setAdvancedHSearchIndexing(true);
String identifierValue = "someValue";
String searchPatientURIWithMissingBirthdate = "Patient?birthdate:missing=true";
String searchObsURIWithMissingValueQuantity = "Observation?value-quantity:missing=true";
//create patient
Patient patient = new Patient();
patient.addIdentifier().setSystem("urn:system").setValue(identifierValue);
MethodOutcome outcome = myClient.create().resource(patient).execute();
assertTrue(outcome.getCreated());
//create observation
Observation obs = new Observation();
obs.addIdentifier().setSystem("urn:system").setValue(identifierValue);
outcome = myClient.create().resource(obs).execute();
assertTrue(outcome.getCreated());
// search
Bundle patientsWithMissingBirthdate = myClient.search().byUrl(searchPatientURIWithMissingBirthdate).returnBundle(Bundle.class).execute();
assertEquals(1, patientsWithMissingBirthdate.getTotal());
Bundle obsWithMissingValueQuantity = myClient.search().byUrl(searchObsURIWithMissingValueQuantity).returnBundle(Bundle.class).execute();
assertEquals(1, obsWithMissingValueQuantity.getTotal());
}
@Test @Test
public void testTryToCreateResourceWithReferenceThatDoesntExist() { public void testTryToCreateResourceWithReferenceThatDoesntExist() {
Patient p1 = new Patient(); Patient p1 = new Patient();

View File

@ -5,9 +5,13 @@ import ca.uhn.fhir.jpa.api.config.DaoConfig;
import ca.uhn.fhir.jpa.model.config.PartitionSettings; import ca.uhn.fhir.jpa.model.config.PartitionSettings;
import ca.uhn.fhir.jpa.model.entity.BaseResourceIndexedSearchParam; import ca.uhn.fhir.jpa.model.entity.BaseResourceIndexedSearchParam;
import ca.uhn.fhir.jpa.model.entity.ModelConfig; import ca.uhn.fhir.jpa.model.entity.ModelConfig;
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamDate;
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamQuantity;
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamToken; import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamToken;
import ca.uhn.fhir.jpa.model.search.CompositeSearchIndexData; import ca.uhn.fhir.jpa.model.search.CompositeSearchIndexData;
import ca.uhn.fhir.jpa.model.search.DateSearchIndexData;
import ca.uhn.fhir.jpa.model.search.ExtendedHSearchIndexData; import ca.uhn.fhir.jpa.model.search.ExtendedHSearchIndexData;
import ca.uhn.fhir.jpa.model.search.QuantitySearchIndexData;
import ca.uhn.fhir.jpa.searchparam.extractor.ISearchParamExtractor; import ca.uhn.fhir.jpa.searchparam.extractor.ISearchParamExtractor;
import ca.uhn.fhir.jpa.searchparam.extractor.ResourceIndexedSearchParamComposite; import ca.uhn.fhir.jpa.searchparam.extractor.ResourceIndexedSearchParamComposite;
import ca.uhn.fhir.jpa.searchparam.extractor.ResourceIndexedSearchParams; import ca.uhn.fhir.jpa.searchparam.extractor.ResourceIndexedSearchParams;
@ -17,6 +21,7 @@ import ca.uhn.fhir.rest.server.util.FhirContextSearchParamRegistry;
import ca.uhn.fhir.rest.server.util.ResourceSearchParams; import ca.uhn.fhir.rest.server.util.ResourceSearchParams;
import ca.uhn.fhir.test.utilities.ITestDataBuilder; import ca.uhn.fhir.test.utilities.ITestDataBuilder;
import org.hl7.fhir.r4.model.Observation; import org.hl7.fhir.r4.model.Observation;
import org.hl7.fhir.r4.model.SearchParameter;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import java.util.Set; import java.util.Set;
@ -59,6 +64,32 @@ class ExtendedHSearchIndexExtractorTest implements ITestDataBuilder.WithSupport
assertThat(spIndexData, hasSize(1)); assertThat(spIndexData, hasSize(1));
} }
@Test
void testExtract_withParamMarkedAsMissing_willBeIgnored() {
//setup
ResourceIndexedSearchParams searchParams = new ResourceIndexedSearchParams();
ResourceIndexedSearchParamDate searchParamDate = new ResourceIndexedSearchParamDate(new PartitionSettings(), "SearchParameter", "Date", null, null, null, null, null);
searchParamDate.setMissing(true);
searchParams.myDateParams.add(searchParamDate);
ResourceIndexedSearchParamQuantity searchParamQuantity = new ResourceIndexedSearchParamQuantity(new PartitionSettings(), "SearchParameter","Quantity", null, null,null);
searchParamQuantity.setMissing(true);
searchParams.myQuantityParams.add(searchParamQuantity);
// run: now translate to HSearch
ResourceSearchParams activeSearchParams = mySearchParamRegistry.getActiveSearchParams("Patient");
ExtendedHSearchIndexExtractor extractor = new ExtendedHSearchIndexExtractor(
myDaoConfig, myFhirContext, activeSearchParams, mySearchParamExtractor, myModelConfig);
ExtendedHSearchIndexData indexData = extractor.extract(new SearchParameter(), searchParams);
// validate
Set<DateSearchIndexData> dIndexData = indexData.getDateIndexData().get("Date");
assertThat(dIndexData, hasSize(0));
Set<QuantitySearchIndexData> qIndexData = indexData.getQuantityIndexData().get("Quantity");
assertThat(qIndexData, hasSize(0));
}
@Override @Override
public Support getTestDataBuilderSupport() { public Support getTestDataBuilderSupport() {
return new SupportNoDao(myFhirContext); return new SupportNoDao(myFhirContext);