Work on custom search params

This commit is contained in:
James Agnew 2017-02-02 22:31:34 -05:00
parent 97ff79d730
commit aa5588826e
7 changed files with 194 additions and 144 deletions

View File

@ -25,24 +25,9 @@ import static org.apache.commons.lang3.StringUtils.isNotBlank;
import java.io.UnsupportedEncodingException;
import java.text.Normalizer;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.*;
import javax.persistence.EntityManager;
import javax.persistence.NoResultException;
import javax.persistence.PersistenceContext;
import javax.persistence.PersistenceContextType;
import javax.persistence.Tuple;
import javax.persistence.TypedQuery;
import javax.persistence.*;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
@ -58,64 +43,22 @@ import org.apache.http.client.utils.URLEncodedUtils;
import org.hl7.fhir.dstu3.model.Bundle.HTTPVerb;
import org.hl7.fhir.dstu3.model.IdType;
import org.hl7.fhir.dstu3.model.StringType;
import org.hl7.fhir.instance.model.api.IAnyResource;
import org.hl7.fhir.instance.model.api.IBase;
import org.hl7.fhir.instance.model.api.IBaseBundle;
import org.hl7.fhir.instance.model.api.IBaseCoding;
import org.hl7.fhir.instance.model.api.IBaseOperationOutcome;
import org.hl7.fhir.instance.model.api.IBaseReference;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.instance.model.api.IDomainResource;
import org.hl7.fhir.instance.model.api.IIdType;
import org.hl7.fhir.instance.model.api.IPrimitiveType;
import org.hl7.fhir.instance.model.api.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.PlatformTransactionManager;
import com.google.common.base.Charsets;
import com.google.common.collect.ArrayListMultimap;
import ca.uhn.fhir.context.BaseRuntimeChildDefinition;
import ca.uhn.fhir.context.BaseRuntimeElementCompositeDefinition;
import ca.uhn.fhir.context.BaseRuntimeElementDefinition;
import ca.uhn.fhir.context.ConfigurationException;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.context.FhirVersionEnum;
import ca.uhn.fhir.context.RuntimeChildResourceDefinition;
import ca.uhn.fhir.context.RuntimeResourceDefinition;
import ca.uhn.fhir.context.RuntimeSearchParam;
import ca.uhn.fhir.context.*;
import ca.uhn.fhir.jpa.dao.data.IForcedIdDao;
import ca.uhn.fhir.jpa.dao.data.IResourceHistoryTableDao;
import ca.uhn.fhir.jpa.dao.data.ISearchDao;
import ca.uhn.fhir.jpa.dao.data.ISearchResultDao;
import ca.uhn.fhir.jpa.entity.BaseHasResource;
import ca.uhn.fhir.jpa.entity.BaseResourceIndexedSearchParam;
import ca.uhn.fhir.jpa.entity.BaseTag;
import ca.uhn.fhir.jpa.entity.ForcedId;
import ca.uhn.fhir.jpa.entity.ResourceEncodingEnum;
import ca.uhn.fhir.jpa.entity.ResourceHistoryTable;
import ca.uhn.fhir.jpa.entity.ResourceHistoryTag;
import ca.uhn.fhir.jpa.entity.ResourceIndexedSearchParamCoords;
import ca.uhn.fhir.jpa.entity.ResourceIndexedSearchParamDate;
import ca.uhn.fhir.jpa.entity.ResourceIndexedSearchParamNumber;
import ca.uhn.fhir.jpa.entity.ResourceIndexedSearchParamQuantity;
import ca.uhn.fhir.jpa.entity.ResourceIndexedSearchParamString;
import ca.uhn.fhir.jpa.entity.ResourceIndexedSearchParamToken;
import ca.uhn.fhir.jpa.entity.ResourceIndexedSearchParamUri;
import ca.uhn.fhir.jpa.entity.ResourceLink;
import ca.uhn.fhir.jpa.entity.ResourceTable;
import ca.uhn.fhir.jpa.entity.ResourceTag;
import ca.uhn.fhir.jpa.entity.Search;
import ca.uhn.fhir.jpa.entity.SearchTypeEnum;
import ca.uhn.fhir.jpa.entity.TagDefinition;
import ca.uhn.fhir.jpa.entity.TagTypeEnum;
import ca.uhn.fhir.jpa.entity.*;
import ca.uhn.fhir.jpa.search.PersistedJpaBundleProvider;
import ca.uhn.fhir.jpa.util.DeleteConflict;
import ca.uhn.fhir.model.api.IQueryParameterAnd;
import ca.uhn.fhir.model.api.IQueryParameterType;
import ca.uhn.fhir.model.api.IResource;
import ca.uhn.fhir.model.api.ResourceMetadataKeyEnum;
import ca.uhn.fhir.model.api.Tag;
import ca.uhn.fhir.model.api.TagList;
import ca.uhn.fhir.model.api.*;
import ca.uhn.fhir.model.base.composite.BaseCodingDt;
import ca.uhn.fhir.model.base.composite.BaseResourceReferenceDt;
import ca.uhn.fhir.model.dstu.resource.BaseResource;
@ -133,12 +76,7 @@ import ca.uhn.fhir.rest.method.RestSearchParameterTypeEnum;
import ca.uhn.fhir.rest.param.*;
import ca.uhn.fhir.rest.server.Constants;
import ca.uhn.fhir.rest.server.IBundleProvider;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import ca.uhn.fhir.rest.server.exceptions.PreconditionFailedException;
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
import ca.uhn.fhir.rest.server.exceptions.ResourceVersionConflictException;
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
import ca.uhn.fhir.rest.server.exceptions.*;
import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor;
import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor.ActionRequestDetails;
import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails;
@ -917,7 +855,7 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
}
/**
* Subclasses may override to provide behaviour. Called when a resource has been inserved into the database for the first time.
* Subclasses may override to provide behaviour. Called when a resource has been inserted into the database for the first time.
*
* @param theEntity
* The entity being updated (Do not modify the entity! Undefined behaviour will occur!)
@ -931,7 +869,7 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
}
/**
* Subclasses may override to provide behaviour. Called when a resource has been inserved into the database for the first time.
* Subclasses may override to provide behaviour. Called when a pre-existing resource has been updated in the database
*
* @param theEntity
* The resource

View File

@ -57,6 +57,7 @@ import ca.uhn.fhir.context.RuntimeResourceDefinition;
import ca.uhn.fhir.context.RuntimeSearchParam;
import ca.uhn.fhir.jpa.dao.data.IResourceHistoryTableDao;
import ca.uhn.fhir.jpa.dao.data.IResourceIndexedSearchParamUriDao;
import ca.uhn.fhir.jpa.dao.data.IResourceTableDao;
import ca.uhn.fhir.jpa.dao.data.ISearchResultDao;
import ca.uhn.fhir.jpa.entity.BaseHasResource;
import ca.uhn.fhir.jpa.entity.BaseTag;
@ -108,7 +109,8 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
@Autowired
private DaoConfig myDaoConfig;
@Autowired
protected IResourceTableDao myResourceTableDao;
@Autowired
protected PlatformTransactionManager myPlatformTransactionManager;
@Autowired

View File

@ -40,7 +40,7 @@ import ca.uhn.fhir.util.FhirTerser;
public abstract class BaseSearchParamExtractor implements ISearchParamExtractor {
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(BaseSearchParamExtractor.class);
protected static final Pattern SPLIT = Pattern.compile("\\||( or )");
public static final Pattern SPLIT = Pattern.compile("\\||( or )");
@Autowired
private FhirContext myContext;

View File

@ -10,7 +10,7 @@ package ca.uhn.fhir.jpa.dao.data;
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
@ -21,9 +21,16 @@ package ca.uhn.fhir.jpa.dao.data;
*/
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import ca.uhn.fhir.jpa.entity.ResourceTable;
public interface IResourceTableDao extends JpaRepository<ResourceTable, Long> {
// nothing yet
@Modifying
@Query("UPDATE ResourceTable r SET r.myIndexStatus = null WHERE r.myResourceType = :restype")
int markResourcesOfTypeAsRequiringReindexing(@Param("restype") String theResourceType);
}

View File

@ -1,5 +1,7 @@
package ca.uhn.fhir.jpa.dao.dstu3;
import static org.apache.commons.lang3.StringUtils.isBlank;
/*
* #%L
* HAPI FHIR JPA Server
@ -10,7 +12,7 @@ package ca.uhn.fhir.jpa.dao.dstu3;
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
@ -27,23 +29,27 @@ import org.hl7.fhir.dstu3.model.SearchParameter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import ca.uhn.fhir.jpa.dao.BaseSearchParamExtractor;
import ca.uhn.fhir.jpa.dao.IFhirResourceDaoSearchParameter;
import ca.uhn.fhir.jpa.dao.IFhirSystemDao;
import ca.uhn.fhir.jpa.entity.ResourceTable;
import ca.uhn.fhir.parser.DataFormatException;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
public class FhirResourceDaoSearchParameterDstu3 extends FhirResourceDaoDstu3<SearchParameter>implements IFhirResourceDaoSearchParameter<SearchParameter> {
public class FhirResourceDaoSearchParameterDstu3 extends FhirResourceDaoDstu3<SearchParameter> implements IFhirResourceDaoSearchParameter<SearchParameter> {
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(FhirResourceDaoSearchParameterDstu3.class);
@Autowired
private IFhirSystemDao<Bundle, Meta> mySystemDao;
@Override
protected void validateResourceForStorage(SearchParameter theResource, ResourceTable theEntityToSave) {
super.validateResourceForStorage(theResource, theEntityToSave);
if (theResource.getStatus() == null) {
throw new InvalidRequestException("Resource.status is missing or invalid: " + theResource.getStatusElement().getValueAsString());
}
private void markAffectedResources(SearchParameter theResource) {
String xpath = theResource.getXpath();
String resourceType = xpath.substring(0, xpath.indexOf('.'));
ourLog.info("Marking all resources of type {} for reindexing due to updated search parameter with path: {}", xpath);
int updatedCount = myResourceTableDao.markResourcesOfTypeAsRequiringReindexing(resourceType);
ourLog.info("Marked {} resources for reindexing", updatedCount);
}
/**
@ -53,7 +59,7 @@ public class FhirResourceDaoSearchParameterDstu3 extends FhirResourceDaoDstu3<Se
* reindexing passes and then return.
*/
@Override
@Scheduled(fixedDelay=DateUtils.MILLIS_PER_MINUTE)
@Scheduled(fixedDelay = DateUtils.MILLIS_PER_MINUTE)
public void performReindexingPass() {
if (getConfig().isSchedulingDisabled()) {
return;
@ -68,7 +74,57 @@ public class FhirResourceDaoSearchParameterDstu3 extends FhirResourceDaoDstu3<Se
break;
}
}
}
@Override
protected void postPersist(ResourceTable theEntity, SearchParameter theResource) {
markAffectedResources(theResource);
}
@Override
protected void postUpdate(ResourceTable theEntity, SearchParameter theResource) {
markAffectedResources(theResource);
}
@Override
protected void validateResourceForStorage(SearchParameter theResource, ResourceTable theEntityToSave) {
super.validateResourceForStorage(theResource, theEntityToSave);
if (theResource.getStatus() == null) {
throw new UnprocessableEntityException("Resource.status is missing or invalid: " + theResource.getStatusElement().getValueAsString());
}
String xpath = theResource.getXpath();
if (isBlank(xpath)) {
throw new UnprocessableEntityException("Resource.xpath is missing");
}
String[] xpathSplit = BaseSearchParamExtractor.SPLIT.split(xpath);
String allResourceName = null;
for (String nextPath : xpathSplit) {
int dotIdx = nextPath.indexOf('.');
if (dotIdx == -1) {
throw new UnprocessableEntityException("Invalid path value \"" + nextPath + "\". Must start with a resource name");
}
String resourceName = nextPath.substring(0, dotIdx);
try {
getContext().getResourceDefinition(resourceName);
} catch (DataFormatException e) {
throw new UnprocessableEntityException("Invalid path value \"" + nextPath + "\": " + e.getMessage());
}
if (allResourceName == null) {
allResourceName = resourceName;
} else {
if (!allResourceName.equals(resourceName)) {
throw new UnprocessableEntityException("Invalid path value \"" + nextPath + "\". All paths in a single SearchParameter must match the same resource type");
}
}
}
}
}

View File

@ -77,6 +77,7 @@ import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
@Index(name = "IDX_RES_DATE", columnList="RES_UPDATED"),
@Index(name = "IDX_RES_LANG", columnList="RES_TYPE,RES_LANGUAGE"),
@Index(name = "IDX_RES_PROFILE", columnList="RES_PROFILE"),
@Index(name = "IDX_RES_TYPE", columnList="RES_TYPE"),
@Index(name = "IDX_INDEXSTATUS", columnList="SP_INDEX_STATUS")
})
@AnalyzerDefs({

View File

@ -2,7 +2,9 @@ package ca.uhn.fhir.jpa.dao.dstu3;
import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.empty;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.fail;
import java.util.List;
@ -16,10 +18,97 @@ import org.junit.Test;
import ca.uhn.fhir.jpa.dao.SearchParameterMap;
import ca.uhn.fhir.rest.param.TokenParam;
import ca.uhn.fhir.rest.server.IBundleProvider;
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
import ca.uhn.fhir.util.TestUtil;
public class FhirResourceDaoDstu3SearchCustomParamTest extends BaseJpaDstu3Test {
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(FhirResourceDaoDstu3SearchCustomParamTest.class);
public class FhirResourceDaoDstu3SearchCustomSearchParamTest extends BaseJpaDstu3Test {
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(FhirResourceDaoDstu3SearchCustomSearchParamTest.class);
@Test
public void testCreateInvalidParamInvalidResourceName() {
SearchParameter fooSp = new SearchParameter();
fooSp.setCode("foo");
fooSp.setType(org.hl7.fhir.dstu3.model.Enumerations.SearchParamType.TOKEN);
fooSp.setTitle("FOO SP");
fooSp.setXpath("PatientFoo.gender");
fooSp.setXpathUsage(org.hl7.fhir.dstu3.model.SearchParameter.XPathUsageType.NORMAL);
fooSp.setStatus(org.hl7.fhir.dstu3.model.Enumerations.PublicationStatus.ACTIVE);
try {
mySearchParameterDao.create(fooSp, mySrd);
fail();
} catch (UnprocessableEntityException e) {
assertEquals("Invalid path value \"PatientFoo.gender\": Unknown resource name \"PatientFoo\" (this name is not known in FHIR version \"DSTU3\")", e.getMessage());
}
}
@Test
public void testCreateInvalidParamMismatchedResourceName() {
SearchParameter fooSp = new SearchParameter();
fooSp.setCode("foo");
fooSp.setType(org.hl7.fhir.dstu3.model.Enumerations.SearchParamType.TOKEN);
fooSp.setTitle("FOO SP");
fooSp.setXpath("Patient.gender or Observation.code");
fooSp.setXpathUsage(org.hl7.fhir.dstu3.model.SearchParameter.XPathUsageType.NORMAL);
fooSp.setStatus(org.hl7.fhir.dstu3.model.Enumerations.PublicationStatus.ACTIVE);
try {
mySearchParameterDao.create(fooSp, mySrd);
fail();
} catch (UnprocessableEntityException e) {
assertEquals("Invalid path value \"Observation.code\". All paths in a single SearchParameter must match the same resource type", e.getMessage());
}
}
@Test
public void testCreateInvalidParamNoPath() {
SearchParameter fooSp = new SearchParameter();
fooSp.setCode("foo");
fooSp.setType(org.hl7.fhir.dstu3.model.Enumerations.SearchParamType.TOKEN);
fooSp.setTitle("FOO SP");
fooSp.setXpathUsage(org.hl7.fhir.dstu3.model.SearchParameter.XPathUsageType.NORMAL);
fooSp.setStatus(org.hl7.fhir.dstu3.model.Enumerations.PublicationStatus.ACTIVE);
try {
mySearchParameterDao.create(fooSp, mySrd);
fail();
} catch (UnprocessableEntityException e) {
assertEquals("Resource.xpath is missing", e.getMessage());
}
}
@Test
public void testCreateInvalidParamNoResourceName() {
SearchParameter fooSp = new SearchParameter();
fooSp.setCode("foo");
fooSp.setType(org.hl7.fhir.dstu3.model.Enumerations.SearchParamType.TOKEN);
fooSp.setTitle("FOO SP");
fooSp.setXpath("gender");
fooSp.setXpathUsage(org.hl7.fhir.dstu3.model.SearchParameter.XPathUsageType.NORMAL);
fooSp.setStatus(org.hl7.fhir.dstu3.model.Enumerations.PublicationStatus.ACTIVE);
try {
mySearchParameterDao.create(fooSp, mySrd);
fail();
} catch (UnprocessableEntityException e) {
assertEquals("Invalid path value \"gender\". Must start with a resource name", e.getMessage());
}
}
@Test
public void testCreateInvalidParamParamNullStatus() {
SearchParameter fooSp = new SearchParameter();
fooSp.setCode("foo");
fooSp.setType(org.hl7.fhir.dstu3.model.Enumerations.SearchParamType.TOKEN);
fooSp.setTitle("FOO SP");
fooSp.setXpath("Patient.gender");
fooSp.setXpathUsage(org.hl7.fhir.dstu3.model.SearchParameter.XPathUsageType.NORMAL);
fooSp.setStatus(null);
try {
mySearchParameterDao.create(fooSp, mySrd);
fail();
} catch (UnprocessableEntityException e) {
assertEquals("Resource.status is missing or invalid: null", e.getMessage());
}
}
@Test
public void testSearchWithCustomParam() {
@ -32,9 +121,9 @@ public class FhirResourceDaoDstu3SearchCustomParamTest extends BaseJpaDstu3Test
fooSp.setXpathUsage(org.hl7.fhir.dstu3.model.SearchParameter.XPathUsageType.NORMAL);
fooSp.setStatus(org.hl7.fhir.dstu3.model.Enumerations.PublicationStatus.ACTIVE);
mySearchParameterDao.create(fooSp, mySrd);
mySearchParamRegsitry.forceRefresh();
Patient pat = new Patient();
pat.setGender(AdministrativeGender.MALE);
IIdType patId = myPatientDao.create(pat, mySrd).getId().toUnqualifiedVersionless();
@ -46,21 +135,21 @@ public class FhirResourceDaoDstu3SearchCustomParamTest extends BaseJpaDstu3Test
SearchParameterMap map;
IBundleProvider results;
List<String> foundResources;
//Try with custom gender SP
// Try with custom gender SP
map = new SearchParameterMap();
map.add("foo", new TokenParam(null, "male"));
results = myPatientDao.search(map);
foundResources = toUnqualifiedVersionlessIdValues(results);
assertThat(foundResources, contains(patId.getValue()));
//Try with normal gender SP
// Try with normal gender SP
map = new SearchParameterMap();
map.add("gender", new TokenParam(null, "male"));
results = myPatientDao.search(map);
foundResources = toUnqualifiedVersionlessIdValues(results);
assertThat(foundResources, contains(patId.getValue()));
}
@Test
@ -74,9 +163,9 @@ public class FhirResourceDaoDstu3SearchCustomParamTest extends BaseJpaDstu3Test
fooSp.setXpathUsage(org.hl7.fhir.dstu3.model.SearchParameter.XPathUsageType.NORMAL);
fooSp.setStatus(org.hl7.fhir.dstu3.model.Enumerations.PublicationStatus.DRAFT);
mySearchParameterDao.create(fooSp, mySrd);
mySearchParamRegsitry.forceRefresh();
Patient pat = new Patient();
pat.setGender(AdministrativeGender.MALE);
IIdType patId = myPatientDao.create(pat, mySrd).getId().toUnqualifiedVersionless();
@ -88,63 +177,21 @@ public class FhirResourceDaoDstu3SearchCustomParamTest extends BaseJpaDstu3Test
SearchParameterMap map;
IBundleProvider results;
List<String> foundResources;
//Try with custom gender SP (should find nothing)
// Try with custom gender SP (should find nothing)
map = new SearchParameterMap();
map.add("foo", new TokenParam(null, "male"));
results = myPatientDao.search(map);
foundResources = toUnqualifiedVersionlessIdValues(results);
assertThat(foundResources, empty());
//Try with normal gender SP
// Try with normal gender SP
map = new SearchParameterMap();
map.add("gender", new TokenParam(null, "male"));
results = myPatientDao.search(map);
foundResources = toUnqualifiedVersionlessIdValues(results);
assertThat(foundResources, contains(patId.getValue()));
}
@Test
public void testSearchWithCustomParamNullStatus() {
SearchParameter fooSp = new SearchParameter();
fooSp.setCode("foo");
fooSp.setType(org.hl7.fhir.dstu3.model.Enumerations.SearchParamType.TOKEN);
fooSp.setTitle("FOO SP");
fooSp.setXpath("Patient.gender");
fooSp.setXpathUsage(org.hl7.fhir.dstu3.model.SearchParameter.XPathUsageType.NORMAL);
fooSp.setStatus(null);
mySearchParameterDao.create(fooSp, mySrd);
mySearchParamRegsitry.forceRefresh();
Patient pat = new Patient();
pat.setGender(AdministrativeGender.MALE);
IIdType patId = myPatientDao.create(pat, mySrd).getId().toUnqualifiedVersionless();
Patient pat2 = new Patient();
pat.setGender(AdministrativeGender.FEMALE);
IIdType patId2 = myPatientDao.create(pat2, mySrd).getId().toUnqualifiedVersionless();
SearchParameterMap map;
IBundleProvider results;
List<String> foundResources;
//Try with custom gender SP (should find nothing)
map = new SearchParameterMap();
map.add("foo", new TokenParam(null, "male"));
results = myPatientDao.search(map);
foundResources = toUnqualifiedVersionlessIdValues(results);
assertThat(foundResources, empty());
//Try with normal gender SP
map = new SearchParameterMap();
map.add("gender", new TokenParam(null, "male"));
results = myPatientDao.search(map);
foundResources = toUnqualifiedVersionlessIdValues(results);
assertThat(foundResources, contains(patId.getValue()));
}
@AfterClass
@ -152,5 +199,4 @@ public class FhirResourceDaoDstu3SearchCustomParamTest extends BaseJpaDstu3Test
TestUtil.clearAllStaticFieldsForUnitTest();
}
}