Re-enable contains searches on the public HAPI FHIR server and improve

message formatting in HapiLocalizer
This commit is contained in:
James Agnew 2019-03-14 13:19:26 -04:00
parent ed4da7c414
commit a8c76450e5
12 changed files with 129 additions and 5 deletions

View File

@ -101,13 +101,36 @@ public class HapiLocalizer {
String formatString = getFormatString(theQualifiedKey);
format = new MessageFormat(formatString.trim());
format = newMessageFormat(formatString);
myKeyToMessageFormat.put(theQualifiedKey, format);
return format.format(theParameters);
}
return getFormatString(theQualifiedKey);
}
MessageFormat newMessageFormat(String theFormatString) {
StringBuilder pattern = new StringBuilder(theFormatString.trim());
for (int i = 0; i < (pattern.length()-1); i++) {
if (pattern.charAt(i) == '{') {
char nextChar = pattern.charAt(i+1);
if (nextChar >= '0' && nextChar <= '9') {
continue;
}
pattern.replace(i, i+1, "'{'");
int closeBraceIndex = pattern.indexOf("}", i);
if (closeBraceIndex > 0) {
i = closeBraceIndex;
pattern.replace(i, i+1, "'}'");
}
}
}
return new MessageFormat(pattern.toString());
}
protected void init() {
for (String nextName : myBundleNames) {
myBundle.add(ResourceBundle.getBundle(nextName));

View File

@ -2,6 +2,7 @@ package ca.uhn.fhir.i18n;
import static org.hamcrest.Matchers.empty;
import static org.hamcrest.Matchers.not;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThat;
import java.util.Set;
@ -10,6 +11,15 @@ import org.junit.Test;
public class HapiLocalizerTest {
@Test
public void testEscapePatterns() {
HapiLocalizer loc = new HapiLocalizer();
assertEquals("some message", loc.newMessageFormat("some message").format(new Object[]{}));
assertEquals("var1 {var2} var3 {var4}", loc.newMessageFormat("var1 {var2} var3 {var4}").format(new Object[]{}));
assertEquals("var1 A var3 B", loc.newMessageFormat("var1 {0} var3 {1}").format(new Object[]{ "A", "B"}));
}
@Test
public void testAllKeys() {

View File

@ -76,7 +76,7 @@ public class SearchParamPresenceSvcImpl implements ISearchParamPresenceSvc {
toDelete.add(nextEntry.getValue());
}
}
mySearchParamPresentDao.deleteInBatch(toDelete);
mySearchParamPresentDao.deleteAll(toDelete);
// Add any that should be added
List<SearchParamPresent> toAdd = new ArrayList<>();

View File

@ -398,7 +398,7 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc,
TransactionTemplate txTemplate = new TransactionTemplate(myTransactionManager);
txTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
txTemplate.execute(t -> {
theDao.deleteInBatch(link);
theDao.deleteAll(link);
return null;
});

View File

@ -2935,6 +2935,52 @@ public class FhirResourceDaoR4SearchNoFtTest extends BaseJpaR4Test {
assertThat(ids, containsInAnyOrder(pt2id));
}
@Test
public void testSearchWithContainsLowerCase() {
myDaoConfig.setAllowContainsSearches(true);
Patient pt1 = new Patient();
pt1.addName().setFamily("abcdefghijk");
String pt1id = myPatientDao.create(pt1).getId().toUnqualifiedVersionless().getValue();
Patient pt2 = new Patient();
pt2.addName().setFamily("fghijk");
String pt2id = myPatientDao.create(pt2).getId().toUnqualifiedVersionless().getValue();
Patient pt3 = new Patient();
pt3.addName().setFamily("zzzzz");
myPatientDao.create(pt3).getId().toUnqualifiedVersionless().getValue();
List<String> ids;
SearchParameterMap map;
IBundleProvider results;
// Contains = true
map = new SearchParameterMap();
map.add(Patient.SP_NAME, new StringParam("FGHIJK").setContains(true));
map.setLoadSynchronous(true);
results = myPatientDao.search(map);
ids = toUnqualifiedVersionlessIdValues(results);
assertThat(ids, containsInAnyOrder(pt1id, pt2id));
// Contains = false
map = new SearchParameterMap();
map.add(Patient.SP_NAME, new StringParam("FGHIJK").setContains(false));
map.setLoadSynchronous(true);
results = myPatientDao.search(map);
ids = toUnqualifiedVersionlessIdValues(results);
assertThat(ids, containsInAnyOrder(pt2id));
// No contains
map = new SearchParameterMap();
map.add(Patient.SP_NAME, new StringParam("FGHIJK"));
map.setLoadSynchronous(true);
results = myPatientDao.search(map);
ids = toUnqualifiedVersionlessIdValues(results);
assertThat(ids, containsInAnyOrder(pt2id));
}
@Test
public void testSearchWithContainsDisabled() {
myDaoConfig.setAllowContainsSearches(false);

View File

@ -37,8 +37,10 @@ import java.util.Set;
import java.util.TreeSet;
import java.util.stream.Collectors;
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
import ca.uhn.fhir.jpa.util.TestUtil;
import ca.uhn.fhir.rest.api.PreferReturnEnum;
import ca.uhn.fhir.rest.api.server.IBundleProvider;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.Validate;
@ -137,6 +139,7 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test {
myDaoConfig.setReuseCachedSearchResultsForMillis(new DaoConfig().getReuseCachedSearchResultsForMillis());
myDaoConfig.setCountSearchResultsUpTo(new DaoConfig().getCountSearchResultsUpTo());
myDaoConfig.setSearchPreFetchThresholds(new DaoConfig().getSearchPreFetchThresholds());
myDaoConfig.setAllowContainsSearches(new DaoConfig().isAllowContainsSearches());
mySearchCoordinatorSvcRaw.setLoadingThrottleForUnitTests(null);
mySearchCoordinatorSvcRaw.setSyncSizeForUnitTests(SearchCoordinatorSvcImpl.DEFAULT_SYNC_SIZE);
@ -156,7 +159,42 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test {
myDaoConfig.setSearchPreFetchThresholds(new DaoConfig().getSearchPreFetchThresholds());
}
@Test
public void testSearchWithContainsLowerCase() {
myDaoConfig.setAllowContainsSearches(true);
Patient pt1 = new Patient();
pt1.addName().setFamily("Elizabeth");
String pt1id = myPatientDao.create(pt1).getId().toUnqualifiedVersionless().getValue();
Patient pt2 = new Patient();
pt2.addName().setFamily("fghijk");
String pt2id = myPatientDao.create(pt2).getId().toUnqualifiedVersionless().getValue();
Patient pt3 = new Patient();
pt3.addName().setFamily("zzzzz");
myPatientDao.create(pt3).getId().toUnqualifiedVersionless().getValue();
Bundle output = ourClient
.search()
.forResource("Patient")
.where(Patient.NAME.contains().value("ZAB"))
.returnBundle(Bundle.class)
.execute();
List<String> ids = output.getEntry().stream().map(t -> t.getResource().getIdElement().toUnqualifiedVersionless().getValue()).collect(Collectors.toList());
assertThat(ids, containsInAnyOrder(pt1id));
output = ourClient
.search()
.forResource("Patient")
.where(Patient.NAME.contains().value("zab"))
.returnBundle(Bundle.class)
.execute();
ids = output.getEntry().stream().map(t -> t.getResource().getIdElement().toUnqualifiedVersionless().getValue()).collect(Collectors.toList());
assertThat(ids, containsInAnyOrder(pt1id));
}
@Test
public void testManualPagingLinkOffsetDoesntReturnBeyondEnd() {

View File

@ -93,7 +93,7 @@ public class WebsocketWithCriteriaDstu3Test extends BaseResourceProviderDstu3Tes
}
@Test
public void createObservation() throws Exception {
public void createObservation() {
Observation observation = new Observation();
CodeableConcept codeableConcept = new CodeableConcept();
observation.setCode(codeableConcept);

View File

@ -46,7 +46,7 @@ import static org.apache.commons.lang3.StringUtils.left;
* IDX_SP_STRING
*/
// This one us used only for sorting
// This is used for sorting, and for :contains queries currently
@Index(name = "IDX_SP_STRING_HASH_IDENT", columnList = "HASH_IDENTITY"),
@Index(name = "IDX_SP_STRING_HASH_NRM", columnList = "HASH_NORM_PREFIX,SP_VALUE_NORMALIZED"),

View File

@ -61,6 +61,7 @@ public class TestDstu2Config extends BaseJavaConfigDstu2 {
retVal.setSubscriptionEnabled(true);
retVal.setSubscriptionPollDelay(5000);
retVal.setSubscriptionPurgeInactiveAfterMillis(DateUtils.MILLIS_PER_HOUR);
retVal.setAllowContainsSearches(true);
retVal.setAllowMultipleDelete(true);
retVal.setAllowInlineMatchUrlReferences(true);
retVal.setAllowExternalReferences(true);

View File

@ -52,6 +52,7 @@ public class TestDstu3Config extends BaseJavaConfigDstu3 {
retVal.setSubscriptionEnabled(true);
retVal.setSubscriptionPollDelay(5000);
retVal.setSubscriptionPurgeInactiveAfterMillis(DateUtils.MILLIS_PER_HOUR);
retVal.setAllowContainsSearches(true);
retVal.setAllowMultipleDelete(true);
retVal.setAllowInlineMatchUrlReferences(true);
retVal.setAllowExternalReferences(true);

View File

@ -52,6 +52,7 @@ public class TestR4Config extends BaseJavaConfigR4 {
retVal.setSubscriptionEnabled(true);
retVal.setSubscriptionPollDelay(5000);
retVal.setSubscriptionPurgeInactiveAfterMillis(DateUtils.MILLIS_PER_HOUR);
retVal.setAllowContainsSearches(true);
retVal.setAllowMultipleDelete(true);
retVal.setAllowInlineMatchUrlReferences(true);
retVal.setAllowExternalReferences(true);

View File

@ -77,6 +77,10 @@
A new config setting has been added to the JPA DaoConfig that disables validation
of the resource type for target resources in references.
</action>
<action type="add">
HapiLocalizer can now handle message patterns with braces that aren't a part of a
message format expression. E.g. "Here is an {example}".
</action>
</release>
<release version="3.7.0" date="2019-02-06" description="Gale">
<action type="add">