Merge branch 'master' of github.com:jamesagnew/hapi-fhir

This commit is contained in:
James Agnew 2017-09-17 20:05:59 -04:00
commit 79cb251b7e
13 changed files with 465 additions and 340 deletions

View File

@ -1464,12 +1464,14 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
} }
Set<Entry<String, RuntimeSearchParam>> activeSearchParams = mySearchParamRegistry.getActiveSearchParams(theEntity.getResourceType()).entrySet(); Set<Entry<String, RuntimeSearchParam>> activeSearchParams = mySearchParamRegistry.getActiveSearchParams(theEntity.getResourceType()).entrySet();
findMissingSearchParams(theEntity, activeSearchParams, RestSearchParameterTypeEnum.STRING, stringParams); if (myConfig.getIndexMissingFields() == DaoConfig.IndexEnabledEnum.ENABLED) {
findMissingSearchParams(theEntity, activeSearchParams, RestSearchParameterTypeEnum.NUMBER, numberParams); findMissingSearchParams(theEntity, activeSearchParams, RestSearchParameterTypeEnum.STRING, stringParams);
findMissingSearchParams(theEntity, activeSearchParams, RestSearchParameterTypeEnum.QUANTITY, quantityParams); findMissingSearchParams(theEntity, activeSearchParams, RestSearchParameterTypeEnum.NUMBER, numberParams);
findMissingSearchParams(theEntity, activeSearchParams, RestSearchParameterTypeEnum.DATE, dateParams); findMissingSearchParams(theEntity, activeSearchParams, RestSearchParameterTypeEnum.QUANTITY, quantityParams);
findMissingSearchParams(theEntity, activeSearchParams, RestSearchParameterTypeEnum.URI, uriParams); findMissingSearchParams(theEntity, activeSearchParams, RestSearchParameterTypeEnum.DATE, dateParams);
findMissingSearchParams(theEntity, activeSearchParams, RestSearchParameterTypeEnum.TOKEN, tokenParams); findMissingSearchParams(theEntity, activeSearchParams, RestSearchParameterTypeEnum.URI, uriParams);
findMissingSearchParams(theEntity, activeSearchParams, RestSearchParameterTypeEnum.TOKEN, tokenParams);
}
setUpdatedTime(stringParams, theUpdateTime); setUpdatedTime(stringParams, theUpdateTime);
setUpdatedTime(numberParams, theUpdateTime); setUpdatedTime(numberParams, theUpdateTime);

View File

@ -34,10 +34,7 @@ import ca.uhn.fhir.jpa.util.DeleteConflict;
import ca.uhn.fhir.jpa.util.StopWatch; import ca.uhn.fhir.jpa.util.StopWatch;
import ca.uhn.fhir.jpa.util.jsonpatch.JsonPatchUtils; import ca.uhn.fhir.jpa.util.jsonpatch.JsonPatchUtils;
import ca.uhn.fhir.jpa.util.xmlpatch.XmlPatchUtils; import ca.uhn.fhir.jpa.util.xmlpatch.XmlPatchUtils;
import ca.uhn.fhir.model.api.IQueryParameterAnd; import ca.uhn.fhir.model.api.*;
import ca.uhn.fhir.model.api.IResource;
import ca.uhn.fhir.model.api.ResourceMetadataKeyEnum;
import ca.uhn.fhir.model.api.TagList;
import ca.uhn.fhir.model.primitive.IdDt; import ca.uhn.fhir.model.primitive.IdDt;
import ca.uhn.fhir.rest.api.PatchTypeEnum; import ca.uhn.fhir.rest.api.PatchTypeEnum;
import ca.uhn.fhir.rest.api.QualifiedParamList; import ca.uhn.fhir.rest.api.QualifiedParamList;
@ -900,6 +897,19 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
@Transactional(propagation = Propagation.SUPPORTS) @Transactional(propagation = Propagation.SUPPORTS)
@Override @Override
public IBundleProvider search(final SearchParameterMap theParams, RequestDetails theRequestDetails) { public IBundleProvider search(final SearchParameterMap theParams, RequestDetails theRequestDetails) {
if (myDaoConfig.getIndexMissingFields() == DaoConfig.IndexEnabledEnum.DISABLED) {
for (List<List<? extends IQueryParameterType>> nextAnds : theParams.values()) {
for (List<? extends IQueryParameterType> nextOrs : nextAnds) {
for (IQueryParameterType next : nextOrs) {
if (next.getMissing() != null) {
throw new MethodNotAllowedException(":missing modifier is disabled on this server");
}
}
}
}
}
// Notify interceptors // Notify interceptors
if (theRequestDetails != null) { if (theRequestDetails != null) {
ActionRequestDetails requestDetails = new ActionRequestDetails(theRequestDetails, getContext(), getResourceName(), null); ActionRequestDetails requestDetails = new ActionRequestDetails(theRequestDetails, getContext(), getResourceName(), null);

View File

@ -30,15 +30,6 @@ import java.util.*;
public class DaoConfig { public class DaoConfig {
/**
* Constructor
*/
public DaoConfig() {
setSubscriptionEnabled(true);
setSubscriptionPollDelay(0);
setSubscriptionPurgeInactiveAfterMillis(Long.MAX_VALUE);
}
/** /**
* Default {@link #getTreatReferencesAsLogical() logical URL bases}. Includes the following * Default {@link #getTreatReferencesAsLogical() logical URL bases}. Includes the following
* values: * values:
@ -64,25 +55,22 @@ public class DaoConfig {
* @see #setMaximumSearchResultCountInTransaction(Integer) * @see #setMaximumSearchResultCountInTransaction(Integer)
*/ */
private static final Integer DEFAULT_MAXIMUM_SEARCH_RESULT_COUNT_IN_TRANSACTION = null; private static final Integer DEFAULT_MAXIMUM_SEARCH_RESULT_COUNT_IN_TRANSACTION = null;
private IndexEnabledEnum myIndexMissingFieldsEnabled = IndexEnabledEnum.ENABLED;
/** /**
* update setter javadoc if default changes * update setter javadoc if default changes
*/ */
private boolean myAllowExternalReferences = false; private boolean myAllowExternalReferences = false;
/** /**
* update setter javadoc if default changes * update setter javadoc if default changes
*/ */
private boolean myAllowInlineMatchUrlReferences = true; private boolean myAllowInlineMatchUrlReferences = true;
private boolean myAllowMultipleDelete; private boolean myAllowMultipleDelete;
private boolean myDefaultSearchParamsCanBeOverridden = false; private boolean myDefaultSearchParamsCanBeOverridden = false;
/** /**
* update setter javadoc if default changes * update setter javadoc if default changes
*/ */
private int myDeferIndexingForCodesystemsOfSize = 2000; private int myDeferIndexingForCodesystemsOfSize = 2000;
private boolean myDeleteStaleSearches = true; private boolean myDeleteStaleSearches = true;
private boolean myEnforceReferentialIntegrityOnDelete = true; private boolean myEnforceReferentialIntegrityOnDelete = true;
private boolean myUniqueIndexesEnabled = true; private boolean myUniqueIndexesEnabled = true;
private boolean myUniqueIndexesCheckedBeforeSave = true; private boolean myUniqueIndexesCheckedBeforeSave = true;
@ -119,6 +107,14 @@ public class DaoConfig {
private Set<String> myTreatBaseUrlsAsLocal = new HashSet<String>(); private Set<String> myTreatBaseUrlsAsLocal = new HashSet<String>();
private Set<String> myTreatReferencesAsLogical = new HashSet<String>(DEFAULT_LOGICAL_BASE_URLS); private Set<String> myTreatReferencesAsLogical = new HashSet<String>(DEFAULT_LOGICAL_BASE_URLS);
private boolean myAutoCreatePlaceholderReferenceTargets; private boolean myAutoCreatePlaceholderReferenceTargets;
/**
* Constructor
*/
public DaoConfig() {
setSubscriptionEnabled(true);
setSubscriptionPollDelay(0);
setSubscriptionPurgeInactiveAfterMillis(Long.MAX_VALUE);
}
/** /**
* Add a value to the {@link #setTreatReferencesAsLogical(Set) logical references list}. * Add a value to the {@link #setTreatReferencesAsLogical(Set) logical references list}.
@ -287,6 +283,35 @@ public class DaoConfig {
myIncludeLimit = theIncludeLimit; myIncludeLimit = theIncludeLimit;
} }
/**
* If set to {@link IndexEnabledEnum#DISABLED} (default is {@link IndexEnabledEnum#ENABLED})
* the server will not create search indexes for search parameters with no values in resources.
* <p>
* Disabling this feature means that the <code>:missing</code> search modifier will not be
* supported on the server, but also means that storage and indexing (i.e. writes to the
* database) may be much faster on servers which have lots of search parameters and need
* to write quickly.
* </p>
*/
public IndexEnabledEnum getIndexMissingFields() {
return myIndexMissingFieldsEnabled;
}
/**
* If set to {@link IndexEnabledEnum#DISABLED} (default is {@link IndexEnabledEnum#ENABLED})
* the server will not create search indexes for search parameters with no values in resources.
* <p>
* Disabling this feature means that the <code>:missing</code> search modifier will not be
* supported on the server, but also means that storage and indexing (i.e. writes to the
* database) may be much faster on servers which have lots of search parameters and need
* to write quickly.
* </p>
*/
public void setIndexMissingFields(IndexEnabledEnum theIndexMissingFields) {
Validate.notNull(theIndexMissingFields, "theIndexMissingFields must not be null");
myIndexMissingFieldsEnabled = theIndexMissingFields;
}
/** /**
* Returns the interceptors which will be notified of operations. * Returns the interceptors which will be notified of operations.
* *
@ -420,24 +445,6 @@ public class DaoConfig {
myReuseCachedSearchResultsForMillis = theReuseCachedSearchResultsForMillis; myReuseCachedSearchResultsForMillis = theReuseCachedSearchResultsForMillis;
} }
/**
* @deprecated As of HAPI FHIR 3.0.0, subscriptions no longer use polling for
* detecting changes, so this setting has no effect
*/
@Deprecated
public void setSubscriptionPollDelay(long theSubscriptionPollDelay) {
// ignore
}
/**
* @deprecated As of HAPI FHIR 3.0.0, subscriptions no longer use polling for
* detecting changes, so this setting has no effect
*/
@Deprecated
public void setSubscriptionPurgeInactiveAfterMillis(Long theMillis) {
// ignore
}
/** /**
* This setting may be used to advise the server that any references found in * This setting may be used to advise the server that any references found in
* resources that have any of the base URLs given here will be replaced with * resources that have any of the base URLs given here will be replaced with
@ -814,16 +821,6 @@ public class DaoConfig {
mySchedulingDisabled = theSchedulingDisabled; mySchedulingDisabled = theSchedulingDisabled;
} }
/**
* @deprecated As of HAPI FHIR 3.0.0, subscriptions no longer use polling for
* detecting changes, so this setting has no effect
*/
@Deprecated
public void setSubscriptionEnabled(boolean theSubscriptionEnabled) {
// nothing
}
/** /**
* If set to {@literal true} (default is true), if a client performs an update which does not actually * If set to {@literal true} (default is true), if a client performs an update which does not actually
* result in any chance to a given resource (e.g. an update where the resource body matches the * result in any chance to a given resource (e.g. an update where the resource body matches the
@ -926,6 +923,33 @@ public class DaoConfig {
} }
} }
/**
* @deprecated As of HAPI FHIR 3.0.0, subscriptions no longer use polling for
* detecting changes, so this setting has no effect
*/
@Deprecated
public void setSubscriptionEnabled(boolean theSubscriptionEnabled) {
// nothing
}
/**
* @deprecated As of HAPI FHIR 3.0.0, subscriptions no longer use polling for
* detecting changes, so this setting has no effect
*/
@Deprecated
public void setSubscriptionPollDelay(long theSubscriptionPollDelay) {
// ignore
}
/**
* @deprecated As of HAPI FHIR 3.0.0, subscriptions no longer use polling for
* detecting changes, so this setting has no effect
*/
@Deprecated
public void setSubscriptionPurgeInactiveAfterMillis(Long theMillis) {
// ignore
}
public void setSubscriptionPurgeInactiveAfterSeconds(int theSeconds) { public void setSubscriptionPurgeInactiveAfterSeconds(int theSeconds) {
setSubscriptionPurgeInactiveAfterMillis(theSeconds * DateUtils.MILLIS_PER_SECOND); setSubscriptionPurgeInactiveAfterMillis(theSeconds * DateUtils.MILLIS_PER_SECOND);
} }
@ -942,4 +966,9 @@ public class DaoConfig {
} }
public enum IndexEnabledEnum {
ENABLED,
DISABLED
}
} }

View File

@ -136,7 +136,7 @@ public class ResourceIndexedSearchParamCoords extends BaseResourceIndexedSearchP
public String toString() { public String toString() {
ToStringBuilder b = new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE); ToStringBuilder b = new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE);
b.append("paramName", getParamName()); b.append("paramName", getParamName());
b.append("resourceId", getResource().getId()); // TODO: add a field so we don't need to resolve this b.append("resourceId", getResourcePid());
b.append("lat", getLatitude()); b.append("lat", getLatitude());
b.append("lon", getLongitude()); b.append("lon", getLongitude());
return b.build(); return b.build();

View File

@ -146,7 +146,7 @@ public class ResourceIndexedSearchParamQuantity extends BaseResourceIndexedSearc
public String toString() { public String toString() {
ToStringBuilder b = new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE); ToStringBuilder b = new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE);
b.append("paramName", getParamName()); b.append("paramName", getParamName());
b.append("resourceId", getResource().getId()); // TODO: add a field so we don't need to resolve this b.append("resourceId", getResourcePid());
b.append("system", getSystem()); b.append("system", getSystem());
b.append("units", getUnits()); b.append("units", getUnits());
b.append("value", getValue()); b.append("value", getValue());

View File

@ -118,6 +118,7 @@ public class ResourceIndexedSearchParamString extends BaseResourceIndexedSearchP
private String myValueNormalized; private String myValueNormalized;
public ResourceIndexedSearchParamString() { public ResourceIndexedSearchParamString() {
super();
} }
@ -191,7 +192,7 @@ public class ResourceIndexedSearchParamString extends BaseResourceIndexedSearchP
public String toString() { public String toString() {
ToStringBuilder b = new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE); ToStringBuilder b = new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE);
b.append("paramName", getParamName()); b.append("paramName", getParamName());
b.append("resourceId", getResource().getId()); // TODO: add a field so we don't need to resolve this b.append("resourceId", getResourcePid());
b.append("value", getValueNormalized()); b.append("value", getValueNormalized());
return b.build(); return b.build();
} }

View File

@ -127,7 +127,7 @@ public class ResourceIndexedSearchParamToken extends BaseResourceIndexedSearchPa
public String toString() { public String toString() {
ToStringBuilder b = new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE); ToStringBuilder b = new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE);
b.append("paramName", getParamName()); b.append("paramName", getParamName());
b.append("resourceId", getResource().getId()); // TODO: add a field so we don't need to resolve this b.append("resourceId", getResourcePid());
b.append("system", getSystem()); b.append("system", getSystem());
b.append("value", getValue()); b.append("value", getValue());
return b.build(); return b.build();

View File

@ -113,11 +113,12 @@ public class ResourceIndexedSearchParamUri extends BaseResourceIndexedSearchPara
@Override @Override
public String toString() { public String toString() {
ToStringBuilder builder = new ToStringBuilder(this); ToStringBuilder b = new ToStringBuilder(this);
builder.append("id", getId()); b.append("id", getId());
builder.append("paramName", getParamName()); b.append("resourceId", getResourcePid());
builder.append("uri", myUri); b.append("paramName", getParamName());
return builder.toString(); b.append("uri", myUri);
return b.toString();
} }
} }

View File

@ -24,6 +24,7 @@ import java.util.*;
import java.util.Map.Entry; import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import ca.uhn.fhir.jpa.dao.DaoConfig;
import org.apache.commons.lang3.tuple.Pair; import org.apache.commons.lang3.tuple.Pair;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
@ -45,8 +46,14 @@ public class SearchParamPresenceSvcImpl implements ISearchParamPresenceSvc {
@Autowired @Autowired
private ISearchParamPresentDao mySearchParamPresentDao; private ISearchParamPresentDao mySearchParamPresentDao;
@Autowired
private DaoConfig myDaoConfig;
@Override @Override
public void updatePresence(ResourceTable theResource, Map<String, Boolean> theParamNameToPresence) { public void updatePresence(ResourceTable theResource, Map<String, Boolean> theParamNameToPresence) {
if (myDaoConfig.getIndexMissingFields() == DaoConfig.IndexEnabledEnum.DISABLED) {
return;
}
Map<String, Boolean> presenceMap = new HashMap<String, Boolean>(theParamNameToPresence); Map<String, Boolean> presenceMap = new HashMap<String, Boolean>(theParamNameToPresence);
List<SearchParamPresent> entitiesToSave = new ArrayList<SearchParamPresent>(); List<SearchParamPresent> entitiesToSave = new ArrayList<SearchParamPresent>();

View File

@ -56,9 +56,19 @@ public abstract class BaseJpaR4Test extends BaseJpaTest {
private static JpaValidationSupportChainR4 ourJpaValidationSupportChainR4; private static JpaValidationSupportChainR4 ourJpaValidationSupportChainR4;
private static IFhirResourceDaoValueSet<ValueSet, Coding, CodeableConcept> ourValueSetDao; private static IFhirResourceDaoValueSet<ValueSet, Coding, CodeableConcept> ourValueSetDao;
@Autowired
protected ISearchParamDao mySearchParamDao;
@Autowired
protected ISearchParamPresentDao mySearchParamPresentDao;
@Autowired @Autowired
protected IResourceIndexedSearchParamStringDao myResourceIndexedSearchParamStringDao; protected IResourceIndexedSearchParamStringDao myResourceIndexedSearchParamStringDao;
@Autowired @Autowired
protected IResourceIndexedSearchParamTokenDao myResourceIndexedSearchParamTokenDao;
@Autowired
protected IResourceIndexedSearchParamQuantityDao myResourceIndexedSearchParamQuantityDao;
@Autowired
protected IResourceIndexedSearchParamDateDao myResourceIndexedSearchParamDateDao;
@Autowired
protected IResourceIndexedCompositeStringUniqueDao myResourceIndexedCompositeStringUniqueDao; protected IResourceIndexedCompositeStringUniqueDao myResourceIndexedCompositeStringUniqueDao;
@Autowired @Autowired
@Qualifier("myAllergyIntoleranceDaoR4") @Qualifier("myAllergyIntoleranceDaoR4")

View File

@ -0,0 +1,340 @@
package ca.uhn.fhir.jpa.dao.r4;
import ca.uhn.fhir.jpa.dao.DaoConfig;
import ca.uhn.fhir.jpa.dao.SearchParameterMap;
import ca.uhn.fhir.rest.api.server.IBundleProvider;
import ca.uhn.fhir.rest.param.*;
import ca.uhn.fhir.rest.server.exceptions.MethodNotAllowedException;
import org.hl7.fhir.instance.model.api.IIdType;
import org.hl7.fhir.r4.model.*;
import org.junit.Before;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.List;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;
public class FhirResourceDaoR4SearchMissingTest extends BaseJpaR4Test {
private static final Logger ourLog = LoggerFactory.getLogger(FhirResourceDaoR4SearchMissingTest.class);
@Before
public void beforeResetMissing() {
myDaoConfig.setIndexMissingFields(new DaoConfig().getIndexMissingFields());
}
@Test
public void testIndexMissingFieldsDisabledDontAllowInSearch() {
myDaoConfig.setIndexMissingFields(DaoConfig.IndexEnabledEnum.DISABLED);
SearchParameterMap params = new SearchParameterMap();
params.add("foo", new StringParam().setMissing(true));
try {
myPatientDao.search(params);
} catch (MethodNotAllowedException e) {
assertEquals(":missing modifier is disabled on this server", e.getMessage());
}
}
@Test
public void testIndexMissingFieldsDisabledDontCreateIndexes() {
myDaoConfig.setIndexMissingFields(DaoConfig.IndexEnabledEnum.DISABLED);
Organization org = new Organization();
org.setActive(true);
myOrganizationDao.create(org, mySrd).getId().toUnqualifiedVersionless();
assertThat(mySearchParamDao.findAll(), empty());
assertThat(mySearchParamPresentDao.findAll(), empty());
assertThat(myResourceIndexedSearchParamStringDao.findAll(), empty());
assertThat(myResourceIndexedSearchParamDateDao.findAll(), empty());
assertThat(myResourceIndexedSearchParamTokenDao.findAll(), hasSize(1));
assertThat(myResourceIndexedSearchParamQuantityDao.findAll(), empty());
}
@SuppressWarnings("unused")
@Test
public void testSearchResourceReferenceMissingChain() {
IIdType oid1;
{
Organization org = new Organization();
org.setActive(true);
oid1 = myOrganizationDao.create(org, mySrd).getId().toUnqualifiedVersionless();
}
IIdType tid1;
{
Task task = new Task();
task.getRequester().setOnBehalfOf(new Reference(oid1));
tid1 = myTaskDao.create(task, mySrd).getId().toUnqualifiedVersionless();
}
IIdType tid2;
{
Task task = new Task();
task.setOwner(new Reference(oid1));
tid2 = myTaskDao.create(task, mySrd).getId().toUnqualifiedVersionless();
}
IIdType oid2;
{
Organization org = new Organization();
org.setActive(true);
org.setName("NAME");
oid2 = myOrganizationDao.create(org, mySrd).getId().toUnqualifiedVersionless();
}
IIdType tid3;
{
Task task = new Task();
task.getRequester().setOnBehalfOf(new Reference(oid2));
tid3 = myTaskDao.create(task, mySrd).getId().toUnqualifiedVersionless();
}
SearchParameterMap map;
List<IIdType> ids;
map = new SearchParameterMap();
map.add(Organization.SP_NAME, new StringParam().setMissing(true));
ids = toUnqualifiedVersionlessIds(myOrganizationDao.search(map));
assertThat(ids, contains(oid1));
ourLog.info("Starting Search 2");
map = new SearchParameterMap();
map.add(Task.SP_ORGANIZATION, new ReferenceParam("Organization", "name:missing", "true"));
ids = toUnqualifiedVersionlessIds(myTaskDao.search(map));
assertThat(ids, contains(tid1)); // NOT tid2
map = new SearchParameterMap();
map.add(Task.SP_ORGANIZATION, new ReferenceParam("Organization", "name:missing", "false"));
ids = toUnqualifiedVersionlessIds(myTaskDao.search(map));
assertThat(ids, contains(tid3));
map = new SearchParameterMap();
map.add(Task.SP_ORGANIZATION, new ReferenceParam("Organization", "name:missing", "true"));
ids = toUnqualifiedVersionlessIds(myPatientDao.search(map));
assertThat(ids, empty());
}
@Test
public void testSearchWithMissingDate() {
IIdType orgId = myOrganizationDao.create(new Organization(), mySrd).getId();
IIdType notMissing;
IIdType missing;
{
Patient patient = new Patient();
patient.addIdentifier().setSystem("urn:system").setValue("001");
missing = myPatientDao.create(patient, mySrd).getId().toUnqualifiedVersionless();
}
{
Patient patient = new Patient();
patient.addIdentifier().setSystem("urn:system").setValue("002");
patient.addName().setFamily("Tester_testSearchStringParam").addGiven("John");
patient.setBirthDateElement(new DateType("2011-01-01"));
patient.getManagingOrganization().setReferenceElement(orgId);
notMissing = myPatientDao.create(patient, mySrd).getId().toUnqualifiedVersionless();
}
// Date Param
{
SearchParameterMap params = new SearchParameterMap();
params.setLoadSynchronous(true);
DateParam param = new DateParam();
param.setMissing(false);
params.add(Patient.SP_BIRTHDATE, param);
List<IIdType> patients = toUnqualifiedVersionlessIds(myPatientDao.search(params));
assertThat(patients, containsInRelativeOrder(notMissing));
assertThat(patients, not(containsInRelativeOrder(missing)));
}
{
SearchParameterMap params = new SearchParameterMap();
params.setLoadSynchronous(true);
DateParam param = new DateParam();
param.setMissing(true);
params.add(Patient.SP_BIRTHDATE, param);
List<IIdType> patients = toUnqualifiedVersionlessIds(myPatientDao.search(params));
assertThat(patients, containsInRelativeOrder(missing));
assertThat(patients, not(containsInRelativeOrder(notMissing)));
}
}
@Test
public void testSearchWithMissingDate2() {
MedicationRequest mr1 = new MedicationRequest();
mr1.getCategory().addCoding().setSystem("urn:medicationroute").setCode("oral");
mr1.addDosageInstruction().getTiming().addEventElement().setValueAsString("2017-01-01");
IIdType id1 = myMedicationRequestDao.create(mr1).getId().toUnqualifiedVersionless();
MedicationRequest mr2 = new MedicationRequest();
mr2.getCategory().addCoding().setSystem("urn:medicationroute").setCode("oral");
IIdType id2 = myMedicationRequestDao.create(mr2).getId().toUnqualifiedVersionless();
SearchParameterMap map = new SearchParameterMap();
map.add(MedicationRequest.SP_DATE, new DateParam().setMissing(true));
IBundleProvider results = myMedicationRequestDao.search(map);
List<String> ids = toUnqualifiedVersionlessIdValues(results);
assertThat(ids, contains(id2.getValue()));
}
@Test
public void testSearchWithMissingQuantity() {
IIdType notMissing;
IIdType missing;
{
Observation obs = new Observation();
obs.addIdentifier().setSystem("urn:system").setValue("001");
missing = myObservationDao.create(obs, mySrd).getId().toUnqualifiedVersionless();
}
{
Observation obs = new Observation();
obs.addIdentifier().setSystem("urn:system").setValue("002");
obs.setValue(new Quantity(123));
notMissing = myObservationDao.create(obs, mySrd).getId().toUnqualifiedVersionless();
}
// Quantity Param
{
SearchParameterMap params = new SearchParameterMap();
params.setLoadSynchronous(true);
QuantityParam param = new QuantityParam();
param.setMissing(false);
params.add(Observation.SP_VALUE_QUANTITY, param);
List<IIdType> patients = toUnqualifiedVersionlessIds(myObservationDao.search(params));
assertThat(patients, not(containsInRelativeOrder(missing)));
assertThat(patients, containsInRelativeOrder(notMissing));
}
{
SearchParameterMap params = new SearchParameterMap();
params.setLoadSynchronous(true);
QuantityParam param = new QuantityParam();
param.setMissing(true);
params.add(Observation.SP_VALUE_QUANTITY, param);
List<IIdType> patients = toUnqualifiedVersionlessIds(myObservationDao.search(params));
assertThat(patients, containsInRelativeOrder(missing));
assertThat(patients, not(containsInRelativeOrder(notMissing)));
}
}
@Test
public void testSearchWithMissingReference() {
IIdType orgId = myOrganizationDao.create(new Organization(), mySrd).getId().toUnqualifiedVersionless();
IIdType notMissing;
IIdType missing;
{
Patient patient = new Patient();
patient.addIdentifier().setSystem("urn:system").setValue("001");
missing = myPatientDao.create(patient, mySrd).getId().toUnqualifiedVersionless();
}
{
Patient patient = new Patient();
patient.addIdentifier().setSystem("urn:system").setValue("002");
patient.addName().setFamily("Tester_testSearchStringParam").addGiven("John");
patient.setBirthDateElement(new DateType("2011-01-01"));
patient.getManagingOrganization().setReferenceElement(orgId);
notMissing = myPatientDao.create(patient, mySrd).getId().toUnqualifiedVersionless();
}
// Reference Param
{
SearchParameterMap params = new SearchParameterMap();
params.setLoadSynchronous(true);
ReferenceParam param = new ReferenceParam();
param.setMissing(false);
params.add(Patient.SP_ORGANIZATION, param);
List<IIdType> patients = toUnqualifiedVersionlessIds(myPatientDao.search(params));
assertThat(patients, not(containsInRelativeOrder(missing)));
assertThat(patients, containsInRelativeOrder(notMissing));
}
{
SearchParameterMap params = new SearchParameterMap();
params.setLoadSynchronous(true);
ReferenceParam param = new ReferenceParam();
param.setMissing(true);
params.add(Patient.SP_ORGANIZATION, param);
List<IIdType> patients = toUnqualifiedVersionlessIds(myPatientDao.search(params));
assertThat(patients, containsInRelativeOrder(missing));
assertThat(patients, not(containsInRelativeOrder(notMissing)));
assertThat(patients, not(containsInRelativeOrder(orgId)));
}
}
@Test
public void testSearchWithMissingString() {
IIdType orgId = myOrganizationDao.create(new Organization(), mySrd).getId();
IIdType notMissing;
IIdType missing;
{
Patient patient = new Patient();
patient.addIdentifier().setSystem("urn:system").setValue("001");
missing = myPatientDao.create(patient, mySrd).getId().toUnqualifiedVersionless();
}
{
Patient patient = new Patient();
patient.addIdentifier().setSystem("urn:system").setValue("002");
patient.addName().setFamily("Tester_testSearchStringParam").addGiven("John");
patient.setBirthDateElement(new DateType("2011-01-01"));
patient.getManagingOrganization().setReferenceElement(orgId);
notMissing = myPatientDao.create(patient, mySrd).getId().toUnqualifiedVersionless();
}
// String Param
{
SearchParameterMap params = new SearchParameterMap();
params.setLoadSynchronous(true);
StringParam param = new StringParam();
param.setMissing(false);
params.add(Patient.SP_FAMILY, param);
List<IIdType> patients = toUnqualifiedVersionlessIds(myPatientDao.search(params));
assertThat(patients, not(containsInRelativeOrder(missing)));
assertThat(patients, containsInRelativeOrder(notMissing));
}
{
SearchParameterMap params = new SearchParameterMap();
params.setLoadSynchronous(true);
StringParam param = new StringParam();
param.setMissing(true);
params.add(Patient.SP_FAMILY, param);
List<IIdType> patients = toUnqualifiedVersionlessIds(myPatientDao.search(params));
assertThat(patients, containsInRelativeOrder(missing));
assertThat(patients, not(containsInRelativeOrder(notMissing)));
}
}
@Test
public void testSearchWithToken() {
IIdType notMissing;
IIdType missing;
{
Observation obs = new Observation();
obs.addIdentifier().setSystem("urn:system").setValue("001");
missing = myObservationDao.create(obs, mySrd).getId().toUnqualifiedVersionless();
}
{
Observation obs = new Observation();
obs.addIdentifier().setSystem("urn:system").setValue("002");
obs.getCode().addCoding().setSystem("urn:system").setCode("002");
notMissing = myObservationDao.create(obs, mySrd).getId().toUnqualifiedVersionless();
}
// Token Param
{
SearchParameterMap params = new SearchParameterMap();
params.setLoadSynchronous(true);
TokenParam param = new TokenParam();
param.setMissing(false);
params.add(Observation.SP_CODE, param);
List<IIdType> patients = toUnqualifiedVersionlessIds(myObservationDao.search(params));
assertThat(patients, not(containsInRelativeOrder(missing)));
assertThat(patients, containsInRelativeOrder(notMissing));
}
{
SearchParameterMap params = new SearchParameterMap();
params.setLoadSynchronous(true);
TokenParam param = new TokenParam();
param.setMissing(true);
params.add(Observation.SP_CODE, param);
List<IIdType> patients = toUnqualifiedVersionlessIds(myObservationDao.search(params));
assertThat(patients, containsInRelativeOrder(missing));
assertThat(patients, not(containsInRelativeOrder(notMissing)));
}
}
}

View File

@ -1782,68 +1782,6 @@ public class FhirResourceDaoR4SearchNoFtTest extends BaseJpaR4Test {
} }
@SuppressWarnings("unused")
@Test
public void testSearchResourceReferenceMissingChain() {
IIdType oid1;
{
Organization org = new Organization();
org.setActive(true);
oid1 = myOrganizationDao.create(org, mySrd).getId().toUnqualifiedVersionless();
}
IIdType tid1;
{
Task task = new Task();
task.getRequester().setOnBehalfOf(new Reference(oid1));
tid1 = myTaskDao.create(task, mySrd).getId().toUnqualifiedVersionless();
}
IIdType tid2;
{
Task task = new Task();
task.setOwner(new Reference(oid1));
tid2 = myTaskDao.create(task, mySrd).getId().toUnqualifiedVersionless();
}
IIdType oid2;
{
Organization org = new Organization();
org.setActive(true);
org.setName("NAME");
oid2 = myOrganizationDao.create(org, mySrd).getId().toUnqualifiedVersionless();
}
IIdType tid3;
{
Task task = new Task();
task.getRequester().setOnBehalfOf(new Reference(oid2));
tid3 = myTaskDao.create(task, mySrd).getId().toUnqualifiedVersionless();
}
SearchParameterMap map;
List<IIdType> ids;
map = new SearchParameterMap();
map.add(Organization.SP_NAME, new StringParam().setMissing(true));
ids = toUnqualifiedVersionlessIds(myOrganizationDao.search(map));
assertThat(ids, contains(oid1));
ourLog.info("Starting Search 2");
map = new SearchParameterMap();
map.add(Task.SP_ORGANIZATION, new ReferenceParam("Organization", "name:missing", "true"));
ids = toUnqualifiedVersionlessIds(myTaskDao.search(map));
assertThat(ids, contains(tid1)); // NOT tid2
map = new SearchParameterMap();
map.add(Task.SP_ORGANIZATION, new ReferenceParam("Organization", "name:missing", "false"));
ids = toUnqualifiedVersionlessIds(myTaskDao.search(map));
assertThat(ids, contains(tid3));
map = new SearchParameterMap();
map.add(Task.SP_ORGANIZATION, new ReferenceParam("Organization", "name:missing", "true"));
ids = toUnqualifiedVersionlessIds(myPatientDao.search(map));
assertThat(ids, empty());
}
@SuppressWarnings("unused") @SuppressWarnings("unused")
@Test @Test
@ -2665,187 +2603,6 @@ public class FhirResourceDaoR4SearchNoFtTest extends BaseJpaR4Test {
} }
@Test
public void testSearchWithMissingDate() {
IIdType orgId = myOrganizationDao.create(new Organization(), mySrd).getId();
IIdType notMissing;
IIdType missing;
{
Patient patient = new Patient();
patient.addIdentifier().setSystem("urn:system").setValue("001");
missing = myPatientDao.create(patient, mySrd).getId().toUnqualifiedVersionless();
}
{
Patient patient = new Patient();
patient.addIdentifier().setSystem("urn:system").setValue("002");
patient.addName().setFamily("Tester_testSearchStringParam").addGiven("John");
patient.setBirthDateElement(new DateType("2011-01-01"));
patient.getManagingOrganization().setReferenceElement(orgId);
notMissing = myPatientDao.create(patient, mySrd).getId().toUnqualifiedVersionless();
}
// Date Param
{
SearchParameterMap params = new SearchParameterMap();
params.setLoadSynchronous(true);
DateParam param = new DateParam();
param.setMissing(false);
params.add(Patient.SP_BIRTHDATE, param);
List<IIdType> patients = toUnqualifiedVersionlessIds(myPatientDao.search(params));
assertThat(patients, containsInRelativeOrder(notMissing));
assertThat(patients, not(containsInRelativeOrder(missing)));
}
{
SearchParameterMap params = new SearchParameterMap();
params.setLoadSynchronous(true);
DateParam param = new DateParam();
param.setMissing(true);
params.add(Patient.SP_BIRTHDATE, param);
List<IIdType> patients = toUnqualifiedVersionlessIds(myPatientDao.search(params));
assertThat(patients, containsInRelativeOrder(missing));
assertThat(patients, not(containsInRelativeOrder(notMissing)));
}
}
@Test
public void testSearchWithMissingDate2() {
MedicationRequest mr1 = new MedicationRequest();
mr1.getCategory().addCoding().setSystem("urn:medicationroute").setCode("oral");
mr1.addDosageInstruction().getTiming().addEventElement().setValueAsString("2017-01-01");
IIdType id1 = myMedicationRequestDao.create(mr1).getId().toUnqualifiedVersionless();
MedicationRequest mr2 = new MedicationRequest();
mr2.getCategory().addCoding().setSystem("urn:medicationroute").setCode("oral");
IIdType id2 = myMedicationRequestDao.create(mr2).getId().toUnqualifiedVersionless();
SearchParameterMap map = new SearchParameterMap();
map.add(MedicationRequest.SP_DATE, new DateParam().setMissing(true));
IBundleProvider results = myMedicationRequestDao.search(map);
List<String> ids = toUnqualifiedVersionlessIdValues(results);
assertThat(ids, contains(id2.getValue()));
}
@Test
public void testSearchWithMissingQuantity() {
IIdType notMissing;
IIdType missing;
{
Observation obs = new Observation();
obs.addIdentifier().setSystem("urn:system").setValue("001");
missing = myObservationDao.create(obs, mySrd).getId().toUnqualifiedVersionless();
}
{
Observation obs = new Observation();
obs.addIdentifier().setSystem("urn:system").setValue("002");
obs.setValue(new Quantity(123));
notMissing = myObservationDao.create(obs, mySrd).getId().toUnqualifiedVersionless();
}
// Quantity Param
{
SearchParameterMap params = new SearchParameterMap();
params.setLoadSynchronous(true);
QuantityParam param = new QuantityParam();
param.setMissing(false);
params.add(Observation.SP_VALUE_QUANTITY, param);
List<IIdType> patients = toUnqualifiedVersionlessIds(myObservationDao.search(params));
assertThat(patients, not(containsInRelativeOrder(missing)));
assertThat(patients, containsInRelativeOrder(notMissing));
}
{
SearchParameterMap params = new SearchParameterMap();
params.setLoadSynchronous(true);
QuantityParam param = new QuantityParam();
param.setMissing(true);
params.add(Observation.SP_VALUE_QUANTITY, param);
List<IIdType> patients = toUnqualifiedVersionlessIds(myObservationDao.search(params));
assertThat(patients, containsInRelativeOrder(missing));
assertThat(patients, not(containsInRelativeOrder(notMissing)));
}
}
@Test
public void testSearchWithMissingReference() {
IIdType orgId = myOrganizationDao.create(new Organization(), mySrd).getId().toUnqualifiedVersionless();
IIdType notMissing;
IIdType missing;
{
Patient patient = new Patient();
patient.addIdentifier().setSystem("urn:system").setValue("001");
missing = myPatientDao.create(patient, mySrd).getId().toUnqualifiedVersionless();
}
{
Patient patient = new Patient();
patient.addIdentifier().setSystem("urn:system").setValue("002");
patient.addName().setFamily("Tester_testSearchStringParam").addGiven("John");
patient.setBirthDateElement(new DateType("2011-01-01"));
patient.getManagingOrganization().setReferenceElement(orgId);
notMissing = myPatientDao.create(patient, mySrd).getId().toUnqualifiedVersionless();
}
// Reference Param
{
SearchParameterMap params = new SearchParameterMap();
params.setLoadSynchronous(true);
ReferenceParam param = new ReferenceParam();
param.setMissing(false);
params.add(Patient.SP_ORGANIZATION, param);
List<IIdType> patients = toUnqualifiedVersionlessIds(myPatientDao.search(params));
assertThat(patients, not(containsInRelativeOrder(missing)));
assertThat(patients, containsInRelativeOrder(notMissing));
}
{
SearchParameterMap params = new SearchParameterMap();
params.setLoadSynchronous(true);
ReferenceParam param = new ReferenceParam();
param.setMissing(true);
params.add(Patient.SP_ORGANIZATION, param);
List<IIdType> patients = toUnqualifiedVersionlessIds(myPatientDao.search(params));
assertThat(patients, containsInRelativeOrder(missing));
assertThat(patients, not(containsInRelativeOrder(notMissing)));
assertThat(patients, not(containsInRelativeOrder(orgId)));
}
}
@Test
public void testSearchWithMissingString() {
IIdType orgId = myOrganizationDao.create(new Organization(), mySrd).getId();
IIdType notMissing;
IIdType missing;
{
Patient patient = new Patient();
patient.addIdentifier().setSystem("urn:system").setValue("001");
missing = myPatientDao.create(patient, mySrd).getId().toUnqualifiedVersionless();
}
{
Patient patient = new Patient();
patient.addIdentifier().setSystem("urn:system").setValue("002");
patient.addName().setFamily("Tester_testSearchStringParam").addGiven("John");
patient.setBirthDateElement(new DateType("2011-01-01"));
patient.getManagingOrganization().setReferenceElement(orgId);
notMissing = myPatientDao.create(patient, mySrd).getId().toUnqualifiedVersionless();
}
// String Param
{
SearchParameterMap params = new SearchParameterMap();
params.setLoadSynchronous(true);
StringParam param = new StringParam();
param.setMissing(false);
params.add(Patient.SP_FAMILY, param);
List<IIdType> patients = toUnqualifiedVersionlessIds(myPatientDao.search(params));
assertThat(patients, not(containsInRelativeOrder(missing)));
assertThat(patients, containsInRelativeOrder(notMissing));
}
{
SearchParameterMap params = new SearchParameterMap();
params.setLoadSynchronous(true);
StringParam param = new StringParam();
param.setMissing(true);
params.add(Patient.SP_FAMILY, param);
List<IIdType> patients = toUnqualifiedVersionlessIds(myPatientDao.search(params));
assertThat(patients, containsInRelativeOrder(missing));
assertThat(patients, not(containsInRelativeOrder(notMissing)));
}
}
@Test @Test
public void testSearchWithNoResults() { public void testSearchWithNoResults() {
@ -3063,43 +2820,6 @@ public class FhirResourceDaoR4SearchNoFtTest extends BaseJpaR4Test {
} }
} }
@Test
public void testSearchWithToken() {
IIdType notMissing;
IIdType missing;
{
Observation obs = new Observation();
obs.addIdentifier().setSystem("urn:system").setValue("001");
missing = myObservationDao.create(obs, mySrd).getId().toUnqualifiedVersionless();
}
{
Observation obs = new Observation();
obs.addIdentifier().setSystem("urn:system").setValue("002");
obs.getCode().addCoding().setSystem("urn:system").setCode("002");
notMissing = myObservationDao.create(obs, mySrd).getId().toUnqualifiedVersionless();
}
// Token Param
{
SearchParameterMap params = new SearchParameterMap();
params.setLoadSynchronous(true);
TokenParam param = new TokenParam();
param.setMissing(false);
params.add(Observation.SP_CODE, param);
List<IIdType> patients = toUnqualifiedVersionlessIds(myObservationDao.search(params));
assertThat(patients, not(containsInRelativeOrder(missing)));
assertThat(patients, containsInRelativeOrder(notMissing));
}
{
SearchParameterMap params = new SearchParameterMap();
params.setLoadSynchronous(true);
TokenParam param = new TokenParam();
param.setMissing(true);
params.add(Observation.SP_CODE, param);
List<IIdType> patients = toUnqualifiedVersionlessIds(myObservationDao.search(params));
assertThat(patients, containsInRelativeOrder(missing));
assertThat(patients, not(containsInRelativeOrder(notMissing)));
}
}
/** /**
* https://chat.fhir.org/#narrow/stream/implementers/topic/Understanding.20_include * https://chat.fhir.org/#narrow/stream/implementers/topic/Understanding.20_include

View File

@ -379,6 +379,11 @@
Subscriptions in JPA server now support "email" delivery type through the Subscriptions in JPA server now support "email" delivery type through the
use of a new interceptor which handles that type use of a new interceptor which handles that type
</action> </action>
<action type="add">
JPA server can now be configured to not support
<![CDATA[<code>:missing</code>]]> modifiers, which
increases write performance since fewer indexes are written
</action>
</release> </release>
<release version="2.5" date="2017-06-08"> <release version="2.5" date="2017-06-08">
<action type="fix"> <action type="fix">