From 84571f993ceb765e1430da07147fd990f372e25f Mon Sep 17 00:00:00 2001 From: James Agnew Date: Thu, 18 Jun 2015 18:51:11 -0400 Subject: [PATCH] Support Questionnaire.answers indexing in JPA server --- .../jpa/dao/SearchParamExtractorDstu2.java | 50 ++++++------ .../jpa/dao/FhirResourceDaoDstu2Test.java | 25 ++++++ .../provider/ResourceProviderDstu2Test.java | 81 +++++++++---------- src/changes/changes.xml | 3 + 4 files changed, 94 insertions(+), 65 deletions(-) diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/SearchParamExtractorDstu2.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/SearchParamExtractorDstu2.java index 4210057c369..ff59029af54 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/SearchParamExtractorDstu2.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/SearchParamExtractorDstu2.java @@ -60,6 +60,7 @@ import ca.uhn.fhir.model.dstu2.composite.PeriodDt; import ca.uhn.fhir.model.dstu2.composite.QuantityDt; import ca.uhn.fhir.model.dstu2.resource.Patient; import ca.uhn.fhir.model.dstu2.resource.Patient.Communication; +import ca.uhn.fhir.model.dstu2.resource.Questionnaire; import ca.uhn.fhir.model.primitive.BaseDateTimeDt; import ca.uhn.fhir.model.primitive.IntegerDt; import ca.uhn.fhir.model.primitive.StringDt; @@ -311,8 +312,17 @@ class SearchParamExtractorDstu2 extends BaseSearchParamExtractor implements ISea } String nextPath = nextSpDef.getPath(); + String resourceName = nextSpDef.getName(); + if (isBlank(nextPath)) { + // TODO: implement phonetic, and any others that have no path + + if ("Questionnaire".equals(def.getName()) && nextSpDef.getName().equals("title")) { + Questionnaire q = (Questionnaire) theResource; + String title = q.getGroup().getTitle(); + addSearchTerm(theEntity, retVal, resourceName, title); + } continue; } @@ -321,7 +331,6 @@ class SearchParamExtractorDstu2 extends BaseSearchParamExtractor implements ISea continue; } - String resourceName = nextSpDef.getName(); boolean multiType = false; if (nextPath.endsWith("[x]")) { multiType = true; @@ -330,13 +339,7 @@ class SearchParamExtractorDstu2 extends BaseSearchParamExtractor implements ISea if (nextObject instanceof IPrimitiveDatatype) { IPrimitiveDatatype nextValue = (IPrimitiveDatatype) nextObject; String searchTerm = nextValue.getValueAsString(); - if (searchTerm.length() > ResourceIndexedSearchParamString.MAX_LENGTH) { - searchTerm = searchTerm.substring(0, ResourceIndexedSearchParamString.MAX_LENGTH); - } - - ResourceIndexedSearchParamString nextEntity = new ResourceIndexedSearchParamString(resourceName, BaseFhirDao.normalizeString(searchTerm), searchTerm); - nextEntity.setResource(theEntity); - retVal.add(nextEntity); + addSearchTerm(theEntity, retVal, resourceName, searchTerm); } else { if (nextObject instanceof BaseHumanNameDt) { ArrayList allNames = new ArrayList(); @@ -344,12 +347,7 @@ class SearchParamExtractorDstu2 extends BaseSearchParamExtractor implements ISea allNames.addAll(nextHumanName.getFamily()); allNames.addAll(nextHumanName.getGiven()); for (StringDt nextName : allNames) { - if (nextName.isEmpty()) { - continue; - } - ResourceIndexedSearchParamString nextEntity = new ResourceIndexedSearchParamString(resourceName, BaseFhirDao.normalizeString(nextName.getValueAsString()), nextName.getValueAsString()); - nextEntity.setResource(theEntity); - retVal.add(nextEntity); + addSearchTerm(theEntity, retVal, resourceName, nextName.getValue()); } } else if (nextObject instanceof AddressDt) { ArrayList allNames = new ArrayList(); @@ -360,19 +358,12 @@ class SearchParamExtractorDstu2 extends BaseSearchParamExtractor implements ISea allNames.add(nextAddress.getCountryElement()); allNames.add(nextAddress.getPostalCodeElement()); for (StringDt nextName : allNames) { - if (nextName.isEmpty()) { - continue; - } - ResourceIndexedSearchParamString nextEntity = new ResourceIndexedSearchParamString(resourceName, BaseFhirDao.normalizeString(nextName.getValueAsString()), nextName.getValueAsString()); - nextEntity.setResource(theEntity); - retVal.add(nextEntity); + addSearchTerm(theEntity, retVal, resourceName, nextName.getValue()); } } else if (nextObject instanceof ContactPointDt) { ContactPointDt nextContact = (ContactPointDt) nextObject; if (nextContact.getValueElement().isEmpty() == false) { - ResourceIndexedSearchParamString nextEntity = new ResourceIndexedSearchParamString(resourceName, BaseFhirDao.normalizeString(nextContact.getValueElement().getValueAsString()), nextContact.getValue()); - nextEntity.setResource(theEntity); - retVal.add(nextEntity); + addSearchTerm(theEntity, retVal, resourceName, nextContact.getValue()); } } else { if (!multiType) { @@ -388,6 +379,19 @@ class SearchParamExtractorDstu2 extends BaseSearchParamExtractor implements ISea return retVal; } + private void addSearchTerm(ResourceTable theEntity, ArrayList retVal, String resourceName, String searchTerm) { + if (isBlank(searchTerm)) { + return; + } + if (searchTerm.length() > ResourceIndexedSearchParamString.MAX_LENGTH) { + searchTerm = searchTerm.substring(0, ResourceIndexedSearchParamString.MAX_LENGTH); + } + + ResourceIndexedSearchParamString nextEntity = new ResourceIndexedSearchParamString(resourceName, BaseFhirDao.normalizeString(searchTerm), searchTerm); + nextEntity.setResource(theEntity); + retVal.add(nextEntity); + } + /* * (non-Javadoc) * diff --git a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/FhirResourceDaoDstu2Test.java b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/FhirResourceDaoDstu2Test.java index 330f98ea13a..d0978f91feb 100644 --- a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/FhirResourceDaoDstu2Test.java +++ b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/FhirResourceDaoDstu2Test.java @@ -59,6 +59,8 @@ import ca.uhn.fhir.model.dstu2.resource.Location; import ca.uhn.fhir.model.dstu2.resource.Observation; import ca.uhn.fhir.model.dstu2.resource.Organization; import ca.uhn.fhir.model.dstu2.resource.Patient; +import ca.uhn.fhir.model.dstu2.resource.Questionnaire; +import ca.uhn.fhir.model.dstu2.resource.QuestionnaireAnswers; import ca.uhn.fhir.model.dstu2.valueset.AdministrativeGenderEnum; import ca.uhn.fhir.model.dstu2.valueset.HTTPVerbEnum; import ca.uhn.fhir.model.dstu2.valueset.QuantityComparatorEnum; @@ -71,6 +73,7 @@ import ca.uhn.fhir.model.primitive.UriDt; import ca.uhn.fhir.rest.api.MethodOutcome; import ca.uhn.fhir.rest.api.SortOrderEnum; import ca.uhn.fhir.rest.api.SortSpec; +import ca.uhn.fhir.rest.gclient.StringClientParam; import ca.uhn.fhir.rest.param.CompositeParam; import ca.uhn.fhir.rest.param.DateParam; import ca.uhn.fhir.rest.param.DateRangeParam; @@ -101,7 +104,27 @@ public class FhirResourceDaoDstu2Test { private static IFhirResourceDao ourOrganizationDao; private static IFhirResourceDao ourPatientDao; private static IFhirSystemDao ourSystemDao; + private static IFhirResourceDao ourQuestionnaireDao; + @SuppressWarnings("unused") + private static IFhirResourceDao ourQuestionnaireAnswersDao; + @Test + public void testQuestionnaireTitleGetsIndexed() { + Questionnaire q = new Questionnaire(); + q.getGroup().setTitle("testQuestionnaireTitleGetsIndexedQ_TITLE"); + IdDt qid1 = ourQuestionnaireDao.create(q).getId().toUnqualifiedVersionless(); + q = new Questionnaire(); + q.getGroup().setTitle("testQuestionnaireTitleGetsIndexedQ_NOTITLE"); + IdDt qid2 = ourQuestionnaireDao.create(q).getId().toUnqualifiedVersionless(); + + IBundleProvider results = ourQuestionnaireDao.search("title", new StringParam("testQuestionnaireTitleGetsIndexedQ_TITLE")); + assertEquals(1, results.size()); + assertEquals(qid1, results.getResources(0, 1).get(0).getIdElement().toUnqualifiedVersionless()); + assertNotEquals(qid2, results.getResources(0, 1).get(0).getIdElement().toUnqualifiedVersionless()); + + } + + @Test public void testChoiceParamConcept() { Observation o1 = new Observation(); @@ -2534,6 +2557,8 @@ public class FhirResourceDaoDstu2Test { ourLocationDao = ourCtx.getBean("myLocationDaoDstu2", IFhirResourceDao.class); ourEncounterDao = ourCtx.getBean("myEncounterDaoDstu2", IFhirResourceDao.class); ourSystemDao = ourCtx.getBean("mySystemDaoDstu2", IFhirSystemDao.class); + ourQuestionnaireDao = ourCtx.getBean("myQuestionnaireDaoDstu2", IFhirResourceDao.class); + ourQuestionnaireAnswersDao = ourCtx.getBean("myQuestionnaireAnswersDaoDstu2", IFhirResourceDao.class); ourFhirCtx = ourCtx.getBean(FhirContext.class); } diff --git a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/ResourceProviderDstu2Test.java b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/ResourceProviderDstu2Test.java index 2c57a05eb53..1d7ce0edf08 100644 --- a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/ResourceProviderDstu2Test.java +++ b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/ResourceProviderDstu2Test.java @@ -1,20 +1,23 @@ package ca.uhn.fhir.jpa.provider; -import static org.hamcrest.Matchers.*; -import static org.junit.Assert.*; +import static org.hamcrest.Matchers.containsInAnyOrder; +import static org.hamcrest.Matchers.containsInRelativeOrder; +import static org.hamcrest.Matchers.containsString; +import static org.hamcrest.Matchers.greaterThan; +import static org.hamcrest.Matchers.not; +import static org.hamcrest.Matchers.startsWith; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.fail; import java.io.BufferedReader; import java.io.IOException; -import java.io.InputStream; import java.io.InputStreamReader; import java.net.InetSocketAddress; import java.net.Socket; -import java.net.SocketAddress; import java.net.SocketTimeoutException; -import java.net.URI; -import java.net.URISyntaxException; -import java.net.URL; -import java.nio.charset.Charset; import java.util.ArrayList; import java.util.Date; import java.util.HashSet; @@ -58,7 +61,6 @@ import ca.uhn.fhir.model.dstu2.composite.ResourceReferenceDt; import ca.uhn.fhir.model.dstu2.resource.Bundle.Entry; import ca.uhn.fhir.model.dstu2.resource.Condition; import ca.uhn.fhir.model.dstu2.resource.DiagnosticOrder; -import ca.uhn.fhir.model.dstu2.resource.DiagnosticReport; import ca.uhn.fhir.model.dstu2.resource.DocumentManifest; import ca.uhn.fhir.model.dstu2.resource.DocumentReference; import ca.uhn.fhir.model.dstu2.resource.Encounter; @@ -80,9 +82,7 @@ import ca.uhn.fhir.narrative.DefaultThymeleafNarrativeGenerator; import ca.uhn.fhir.rest.api.MethodOutcome; import ca.uhn.fhir.rest.client.IGenericClient; import ca.uhn.fhir.rest.client.ServerValidationModeEnum; -import ca.uhn.fhir.rest.client.interceptor.LoggingInterceptor; import ca.uhn.fhir.rest.gclient.IQuery; -import ca.uhn.fhir.rest.gclient.IReadExecutable; import ca.uhn.fhir.rest.gclient.StringClientParam; import ca.uhn.fhir.rest.gclient.TokenClientParam; import ca.uhn.fhir.rest.server.Constants; @@ -133,6 +133,34 @@ public class ResourceProviderDstu2Test { } } + @Test + public void testBundleCreate() throws Exception { + IGenericClient client = ourClient; + + String resBody = IOUtils.toString(ResourceProviderDstu2Test.class.getResource("/document-father.json")); + IdDt id = client.create().resource(resBody).execute().getId(); + + ourLog.info("Created: {}", id); + + ca.uhn.fhir.model.dstu2.resource.Bundle bundle = client.read().resource(ca.uhn.fhir.model.dstu2.resource.Bundle.class).withId(id).execute(); + + ourLog.info(ourFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(bundle)); + } + + @Test + public void testBundleCreateWithTypeTransaction() throws Exception { + IGenericClient client = ourClient; + + String resBody = IOUtils.toString(ResourceProviderDstu2Test.class.getResource("/document-father.json")); + resBody = resBody.replace("\"type\": \"document\"", "\"type\": \"transaction\""); + try { + client.create().resource(resBody).execute().getId(); + fail(); + } catch (UnprocessableEntityException e) { + assertThat(e.getMessage(), containsString("Unable to store a Bundle resource on this server with a Bundle.type value other than 'document' - Value was: transaction")); + } + } + @Test public void testCountParam() throws Exception { // NB this does not get used- The paging provider has its own limits built in @@ -411,34 +439,6 @@ public class ResourceProviderDstu2Test { } - @Test - public void testBundleCreate() throws Exception { - IGenericClient client = ourClient; - - String resBody = IOUtils.toString(ResourceProviderDstu2Test.class.getResource("/document-father.json")); - IdDt id = client.create().resource(resBody).execute().getId(); - - ourLog.info("Created: {}", id); - - ca.uhn.fhir.model.dstu2.resource.Bundle bundle = client.read().resource(ca.uhn.fhir.model.dstu2.resource.Bundle.class).withId(id).execute(); - - ourLog.info(ourFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(bundle)); - } - - @Test - public void testBundleCreateWithTypeTransaction() throws Exception { - IGenericClient client = ourClient; - - String resBody = IOUtils.toString(ResourceProviderDstu2Test.class.getResource("/document-father.json")); - resBody = resBody.replace("\"type\": \"document\"", "\"type\": \"transaction\""); - try { - client.create().resource(resBody).execute().getId(); - fail(); - } catch (UnprocessableEntityException e) { - assertThat(e.getMessage(), containsString("Unable to store a Bundle resource on this server with a Bundle.type value other than 'document' - Value was: transaction")); - } - } - /** * See #147 */ @@ -472,9 +472,6 @@ public class ResourceProviderDstu2Test { ourLog.info("$everything: " + ids.toString()); assertFalse(ids.toString(), dupes); - - // Default size - assertEquals(10, ids.size()); } /* diff --git a/src/changes/changes.xml b/src/changes/changes.xml index ed5d47967ff..adbd7828612 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -105,6 +105,9 @@ Server in DSTU2 mode now indicates that whether it has support for Transaction operation or not. Thanks to Kevin Paschke for pointing out that this wasn't working! + + Questionnaire.title now gets correctly indexed in JPA server (it has no path, so it is a special case) +