More perf work

This commit is contained in:
James 2017-04-09 11:48:56 -04:00
parent c5c154346e
commit fa435fb8b2
12 changed files with 262 additions and 91 deletions

View File

@ -46,6 +46,7 @@ import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionStatus; import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.TransactionCallback; import org.springframework.transaction.support.TransactionCallback;
import org.springframework.transaction.support.TransactionTemplate; import org.springframework.transaction.support.TransactionTemplate;
import org.springframework.util.CollectionUtils;
import org.springframework.web.servlet.ThemeResolver; import org.springframework.web.servlet.ThemeResolver;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
@ -100,7 +101,7 @@ public class SearchBuilder {
private Root<ResourceTable> myResourceTableRoot; private Root<ResourceTable> myResourceTableRoot;
private ArrayList<Predicate> myPredicates; private ArrayList<Predicate> myPredicates;
private CriteriaBuilder myBuilder; private CriteriaBuilder myBuilder;
private CriteriaQuery<Tuple> myResourceTableQuery; private AbstractQuery<Long> myResourceTableQuery;
private PlatformTransactionManager myPlatformTransactionManager; private PlatformTransactionManager myPlatformTransactionManager;
public SearchBuilder(FhirContext theFhirContext, EntityManager theEntityManager, PlatformTransactionManager thePlatformTransactionManager, IFulltextSearchSvc theFulltextSearchSvc, public SearchBuilder(FhirContext theFhirContext, EntityManager theEntityManager, PlatformTransactionManager thePlatformTransactionManager, IFulltextSearchSvc theFulltextSearchSvc,
@ -1257,19 +1258,20 @@ public class SearchBuilder {
throw new InvalidRequestException("This server does not support _sort specifications of type " + param.getParamType() + " - Can't serve _sort=" + theSort.getParamName()); throw new InvalidRequestException("This server does not support _sort specifications of type " + param.getParamType() + " - Can't serve _sort=" + theSort.getParamName());
} }
From<?, ?> stringJoin = theFrom.join(joinAttrName, JoinType.INNER); From<?, ?> join = theFrom.join(joinAttrName, JoinType.LEFT);
if (param.getParamType() == RestSearchParameterTypeEnum.REFERENCE) { if (param.getParamType() == RestSearchParameterTypeEnum.REFERENCE) {
thePredicates.add(stringJoin.get("mySourcePath").as(String.class).in(param.getPathsSplit())); thePredicates.add(join.get("mySourcePath").as(String.class).in(param.getPathsSplit()));
} else { } else {
thePredicates.add(theBuilder.equal(stringJoin.get("myParamName"), theSort.getParamName())); Predicate joinParam1 = theBuilder.equal(join.get("myParamName"), theSort.getParamName());
thePredicates.add(joinParam1);
} }
for (String next : sortAttrName) { for (String next : sortAttrName) {
if (theSort.getOrder() == null || theSort.getOrder() == SortOrderEnum.ASC) { if (theSort.getOrder() == null || theSort.getOrder() == SortOrderEnum.ASC) {
theOrders.add(theBuilder.asc(stringJoin.get(next))); theOrders.add(theBuilder.asc(join.get(next)));
} else { } else {
theOrders.add(theBuilder.desc(stringJoin.get(next))); theOrders.add(theBuilder.desc(join.get(next)));
} }
} }
@ -1470,27 +1472,53 @@ public class SearchBuilder {
public List<Long> loadSearchPage(SearchParameterMap theParams, int theFromIndex, int theToIndex) { public List<Long> loadSearchPage(SearchParameterMap theParams, int theFromIndex, int theToIndex) {
// if (myFulltextSearchSvc == null) {
// if (theParams.containsKey(Constants.PARAM_TEXT)) {
// throw new InvalidRequestException("Fulltext search is not enabled on this service, can not process parameter: " + Constants.PARAM_TEXT);
// } else if (theParams.containsKey(Constants.PARAM_CONTENT)) {
// throw new InvalidRequestException("Fulltext search is not enabled on this service, can not process parameter: " + Constants.PARAM_CONTENT);
// }
// } else {
// // FIXME: add from and to
// List<Long> searchResultPids = myFulltextSearchSvc.search(myResourceName, theParams);
// if (searchResultPids != null) {
// if (searchResultPids.isEmpty()) {
// return Collections.emptyList();
// }
// return searchResultPids;
// }
// }
myBuilder = myEntityManager.getCriteriaBuilder(); myBuilder = myEntityManager.getCriteriaBuilder();
myResourceTableQuery = myBuilder.createTupleQuery(); CriteriaQuery<Long> outerQuery = null;
/*
* Sort
*
* If we have a sort, we wrap the criteria search (the search that actually
* finds the appropriate resources) in an outer search which is then sorted
*/
if (theParams.getSort() != null) {
outerQuery = myBuilder.createQuery(Long.class);
Root<ResourceTable> outerQueryFrom = outerQuery.from(ResourceTable.class);
List<Order> orders = Lists.newArrayList();
List<Predicate> predicates = Lists.newArrayList();
createSort(myBuilder, outerQueryFrom, theParams.getSort(), orders, predicates);
if (orders.size() > 0) {
outerQuery.orderBy(orders);
}
Subquery<Long> subQ = outerQuery.subquery(Long.class);
Root<ResourceTable> subQfrom = subQ.from(ResourceTable.class);
myResourceTableQuery = subQ;
myResourceTableRoot = subQfrom;
Expression<Long> selectExpr = subQfrom.get("myId").as(Long.class);
subQ.select(selectExpr);
predicates.add(0, myBuilder.in(outerQueryFrom.get("myId").as(Long.class)).value(subQ));
outerQuery.multiselect(outerQueryFrom.get("myId").as(Long.class));
outerQuery.where(predicates.toArray(new Predicate[0]));
} else {
outerQuery = myBuilder.createQuery(Long.class);
myResourceTableQuery = outerQuery;
myResourceTableRoot = myResourceTableQuery.from(ResourceTable.class);
outerQuery.multiselect(myResourceTableRoot.get("myId").as(Long.class));
}
myResourceTableQuery.distinct(true); myResourceTableQuery.distinct(true);
myResourceTableRoot = myResourceTableQuery.from(ResourceTable.class);
myPredicates = new ArrayList<Predicate>(); myPredicates = new ArrayList<Predicate>();
if (theParams.getEverythingMode() == null) { if (theParams.getEverythingMode() == null) {
myPredicates.add(myBuilder.equal(myResourceTableRoot.get("myResourceType"), myResourceName)); myPredicates.add(myBuilder.equal(myResourceTableRoot.get("myResourceType"), myResourceName));
@ -1509,7 +1537,9 @@ public class SearchBuilder {
Long pid = BaseHapiFhirDao.translateForcedIdToPid(myResourceName, idParm.getValue(), myForcedIdDao); Long pid = BaseHapiFhirDao.translateForcedIdToPid(myResourceName, idParm.getValue(), myForcedIdDao);
myPredicates.add(myBuilder.equal(join.get("myTargetResourcePid").as(Long.class), pid)); myPredicates.add(myBuilder.equal(join.get("myTargetResourcePid").as(Long.class), pid));
} else { } else {
myPredicates.add(myBuilder.equal(join.get("myTargetResourceType").as(String.class), myResourceName)); Predicate targetTypePredicate = myBuilder.equal(join.get("myTargetResourceType").as(String.class), myResourceName);
Predicate sourceTypePredicate = myBuilder.equal(myResourceTableRoot.get("myResourceType").as(String.class), myResourceName);
myPredicates.add(myBuilder.or(sourceTypePredicate, targetTypePredicate));
} }
} else { } else {
@ -1539,14 +1569,19 @@ public class SearchBuilder {
myResourceTableQuery.where(myBuilder.and(SearchBuilder.toArray(myPredicates))); myResourceTableQuery.where(myBuilder.and(SearchBuilder.toArray(myPredicates)));
myResourceTableQuery.multiselect(myResourceTableRoot.get("myId").as(Long.class)); /*
TypedQuery<Tuple> query = myEntityManager.createQuery(myResourceTableQuery); * Now perform the search
*/
TypedQuery<Long> query = myEntityManager.createQuery(outerQuery);
query.setFirstResult(theFromIndex); query.setFirstResult(theFromIndex);
query.setMaxResults(theToIndex - theFromIndex); query.setMaxResults(theToIndex - theFromIndex);
List<Long> pids = new ArrayList<Long>(); List<Long> pids = new ArrayList<Long>();
for (Tuple next : query.getResultList()) {
pids.add(next.get(0, Long.class)); for (Long next : query.getResultList()) {
if (next != null) {
pids.add(next);
}
} }
return pids; return pids;
@ -1889,6 +1924,10 @@ public class SearchBuilder {
return; return;
} }
// Dupes will cause a crash later anyhow, but this is expensive so only do it
// when running asserts
assert new HashSet<Long>(theIncludePids).size() == theIncludePids.size() : "PID list contains duplicates: " + theIncludePids;
Map<Long, Integer> position = new HashMap<Long, Integer>(); Map<Long, Integer> position = new HashMap<Long, Integer>();
for (Long next : theIncludePids) { for (Long next : theIncludePids) {
position.put(next, theResourceListToPopulate.size()); position.put(next, theResourceListToPopulate.size());

View File

@ -77,11 +77,11 @@ public class SearchParamPresenceSvcImpl implements ISearchParamPresenceSvc {
entitiesToSave.add(present); entitiesToSave.add(present);
} }
mySearchParamPresentDao.deleteInBatch(entitiesToDelete);
mySearchParamPresentDao.save(entitiesToSave);
} }
mySearchParamPresentDao.deleteInBatch(entitiesToDelete);
mySearchParamPresentDao.save(entitiesToSave);
} }
@Override @Override

View File

@ -32,6 +32,7 @@ import org.springframework.transaction.support.TransactionTemplate;
import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.jpa.entity.*; import ca.uhn.fhir.jpa.entity.*;
import ca.uhn.fhir.jpa.provider.SystemProviderDstu2Test; import ca.uhn.fhir.jpa.provider.SystemProviderDstu2Test;
import ca.uhn.fhir.jpa.sp.ISearchParamPresenceSvc;
import ca.uhn.fhir.jpa.term.VersionIndependentConcept; import ca.uhn.fhir.jpa.term.VersionIndependentConcept;
import ca.uhn.fhir.model.dstu2.resource.Bundle; import ca.uhn.fhir.model.dstu2.resource.Bundle;
import ca.uhn.fhir.model.dstu2.resource.Bundle.Entry; import ca.uhn.fhir.model.dstu2.resource.Bundle.Entry;
@ -190,7 +191,7 @@ public abstract class BaseJpaTest {
return bundleStr; return bundleStr;
} }
public static void purgeDatabase(final EntityManager entityManager, PlatformTransactionManager theTxManager) { public static void purgeDatabase(final EntityManager entityManager, PlatformTransactionManager theTxManager, ISearchParamPresenceSvc theSearchParamPresenceSvc) {
TransactionTemplate txTemplate = new TransactionTemplate(theTxManager); TransactionTemplate txTemplate = new TransactionTemplate(theTxManager);
txTemplate.setPropagationBehavior(TransactionTemplate.PROPAGATION_REQUIRED); txTemplate.setPropagationBehavior(TransactionTemplate.PROPAGATION_REQUIRED);
txTemplate.execute(new TransactionCallback<Void>() { txTemplate.execute(new TransactionCallback<Void>() {
@ -255,6 +256,7 @@ public abstract class BaseJpaTest {
return null; return null;
} }
}); });
theSearchParamPresenceSvc.flushCachesForUnitTest();
} }
public static Set<String> toCodes(Set<TermConcept> theConcepts) { public static Set<String> toCodes(Set<TermConcept> theConcepts) {

View File

@ -26,12 +26,14 @@ import org.junit.AfterClass;
import org.junit.Before; import org.junit.Before;
import org.junit.BeforeClass; import org.junit.BeforeClass;
import org.junit.Test; import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.transaction.PlatformTransactionManager; import org.springframework.transaction.PlatformTransactionManager;
import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.jpa.config.TestDstu1Config; import ca.uhn.fhir.jpa.config.TestDstu1Config;
import ca.uhn.fhir.jpa.entity.TagTypeEnum; import ca.uhn.fhir.jpa.entity.TagTypeEnum;
import ca.uhn.fhir.jpa.sp.ISearchParamPresenceSvc;
import ca.uhn.fhir.model.api.Bundle; import ca.uhn.fhir.model.api.Bundle;
import ca.uhn.fhir.model.api.BundleEntry; import ca.uhn.fhir.model.api.BundleEntry;
import ca.uhn.fhir.model.api.IResource; import ca.uhn.fhir.model.api.IResource;
@ -61,10 +63,11 @@ public class FhirSystemDaoDstu1Test extends BaseJpaTest {
private static IFhirResourceDao<Patient> ourPatientDao; private static IFhirResourceDao<Patient> ourPatientDao;
private static IFhirSystemDao<List<IResource>, MetaDt> ourSystemDao; private static IFhirSystemDao<List<IResource>, MetaDt> ourSystemDao;
private static PlatformTransactionManager ourTxManager; private static PlatformTransactionManager ourTxManager;
private static ISearchParamPresenceSvc ourSearchParamPresenceSvc;
@Before @Before
public void before() { public void before() {
super.purgeDatabase(ourEntityManager, ourTxManager); super.purgeDatabase(ourEntityManager, ourTxManager, ourSearchParamPresenceSvc);
} }
@Override @Override
@ -493,6 +496,7 @@ public class FhirSystemDaoDstu1Test extends BaseJpaTest {
ourSystemDao = ourCtx.getBean("mySystemDaoDstu1", IFhirSystemDao.class); ourSystemDao = ourCtx.getBean("mySystemDaoDstu1", IFhirSystemDao.class);
ourEntityManager = ourCtx.getBean(EntityManager.class); ourEntityManager = ourCtx.getBean(EntityManager.class);
ourTxManager = ourCtx.getBean(PlatformTransactionManager.class); ourTxManager = ourCtx.getBean(PlatformTransactionManager.class);
ourSearchParamPresenceSvc = ourCtx.getBean(ISearchParamPresenceSvc.class);
} }
} }

View File

@ -37,6 +37,7 @@ import ca.uhn.fhir.jpa.dao.IFulltextSearchSvc;
import ca.uhn.fhir.jpa.entity.ResourceIndexedSearchParamString; import ca.uhn.fhir.jpa.entity.ResourceIndexedSearchParamString;
import ca.uhn.fhir.jpa.entity.ResourceTable; import ca.uhn.fhir.jpa.entity.ResourceTable;
import ca.uhn.fhir.jpa.provider.JpaSystemProviderDstu2; import ca.uhn.fhir.jpa.provider.JpaSystemProviderDstu2;
import ca.uhn.fhir.jpa.sp.ISearchParamPresenceSvc;
import ca.uhn.fhir.model.dstu2.composite.CodeableConceptDt; import ca.uhn.fhir.model.dstu2.composite.CodeableConceptDt;
import ca.uhn.fhir.model.dstu2.composite.CodingDt; import ca.uhn.fhir.model.dstu2.composite.CodingDt;
import ca.uhn.fhir.model.dstu2.composite.MetaDt; import ca.uhn.fhir.model.dstu2.composite.MetaDt;
@ -147,6 +148,9 @@ public abstract class BaseJpaDstu2Test extends BaseJpaTest {
@Autowired @Autowired
@Qualifier("myValueSetDaoDstu2") @Qualifier("myValueSetDaoDstu2")
protected IFhirResourceDaoValueSet<ValueSet, CodingDt, CodeableConceptDt> myValueSetDao; protected IFhirResourceDaoValueSet<ValueSet, CodingDt, CodeableConceptDt> myValueSetDao;
@Autowired
protected ISearchParamPresenceSvc mySearchParamPresenceSvc;
@Before @Before
public void beforeCreateInterceptor() { public void beforeCreateInterceptor() {
myInterceptor = mock(IServerInterceptor.class); myInterceptor = mock(IServerInterceptor.class);
@ -167,7 +171,7 @@ public abstract class BaseJpaDstu2Test extends BaseJpaTest {
@Transactional() @Transactional()
public void beforePurgeDatabase() { public void beforePurgeDatabase() {
final EntityManager entityManager = this.myEntityManager; final EntityManager entityManager = this.myEntityManager;
purgeDatabase(entityManager, myTxManager); purgeDatabase(entityManager, myTxManager, mySearchParamPresenceSvc);
} }
@Before @Before

View File

@ -1307,15 +1307,15 @@ public class FhirResourceDaoDstu2SearchNoFtTest extends BaseJpaDstu2Test {
SearchParameterMap params; SearchParameterMap params;
params = new SearchParameterMap();
params.add(Patient.SP_ORGANIZATION, new ReferenceParam().setMissing(true));
assertThat(toUnqualifiedVersionlessIds(myPatientDao.search(params)), containsInAnyOrder(pid1, pid3));
params = new SearchParameterMap(); params = new SearchParameterMap();
params.add(Patient.SP_NAME, new StringParam("FAMILY1")); params.add(Patient.SP_NAME, new StringParam("FAMILY1"));
params.add(Patient.SP_ORGANIZATION, new ReferenceParam().setMissing(true)); params.add(Patient.SP_ORGANIZATION, new ReferenceParam().setMissing(true));
assertThat(toUnqualifiedVersionlessIds(myPatientDao.search(params)), containsInAnyOrder(pid1)); assertThat(toUnqualifiedVersionlessIds(myPatientDao.search(params)), containsInAnyOrder(pid1));
params = new SearchParameterMap();
params.add(Patient.SP_ORGANIZATION, new ReferenceParam().setMissing(true));
assertThat(toUnqualifiedVersionlessIds(myPatientDao.search(params)), containsInAnyOrder(pid1, pid3));
params = new SearchParameterMap(); params = new SearchParameterMap();
params.add(Patient.SP_NAME, new StringParam("FAMILY9999")); params.add(Patient.SP_NAME, new StringParam("FAMILY9999"));
params.add(Patient.SP_ORGANIZATION, new ReferenceParam().setMissing(true)); params.add(Patient.SP_ORGANIZATION, new ReferenceParam().setMissing(true));

View File

@ -224,8 +224,7 @@ public abstract class BaseJpaDstu3Test extends BaseJpaTest {
@Transactional() @Transactional()
public void beforePurgeDatabase() { public void beforePurgeDatabase() {
final EntityManager entityManager = this.myEntityManager; final EntityManager entityManager = this.myEntityManager;
purgeDatabase(entityManager, myTxManager); purgeDatabase(entityManager, myTxManager, mySearchParamPresenceSvc);
mySearchParamPresenceSvc.flushCachesForUnitTest();
} }
@Before @Before

View File

@ -108,7 +108,7 @@ public class FhirResourceDaoDstu3SearchNoFtTest extends BaseJpaDstu3Test {
@Test @Test
public void testEverythingTimings() throws Exception { public void testEverythingTimings() throws Exception {
String methodName = "testEverythingIncludesBackReferences"; String methodName = "testEverythingTimings";
Organization org = new Organization(); Organization org = new Organization();
org.setName(methodName); org.setName(methodName);
@ -124,7 +124,7 @@ public class FhirResourceDaoDstu3SearchNoFtTest extends BaseJpaDstu3Test {
IIdType patId = myPatientDao.create(pat, mySrd).getId().toUnqualifiedVersionless(); IIdType patId = myPatientDao.create(pat, mySrd).getId().toUnqualifiedVersionless();
Patient pat2 = new Patient(); Patient pat2 = new Patient();
pat2.addAddress().addLine(methodName); pat2.addAddress().addLine(methodName + "2");
pat2.getManagingOrganization().setReferenceElement(orgId); pat2.getManagingOrganization().setReferenceElement(orgId);
IIdType patId2 = myPatientDao.create(pat2, mySrd).getId().toUnqualifiedVersionless(); IIdType patId2 = myPatientDao.create(pat2, mySrd).getId().toUnqualifiedVersionless();
@ -2862,6 +2862,125 @@ public class FhirResourceDaoDstu3SearchNoFtTest extends BaseJpaDstu3Test {
} }
@Test
public void testSortOnPopulatedField() throws Exception {
Patient pBA = new Patient();
pBA.setId("BA");
pBA.setActive(true);
pBA.setGender(AdministrativeGender.MALE);
pBA.addName().setFamily("B").addGiven("A");
myPatientDao.update(pBA);
Patient pBB = new Patient();
pBB.setId("BB");
pBB.setActive(true);
pBB.setGender(AdministrativeGender.MALE);
pBB.addName().setFamily("B").addGiven("B");
pBB.addName().setFamily("Z").addGiven("Z");
myPatientDao.update(pBB);
Patient pAB = new Patient();
pAB.setId("AB");
pAB.setActive(true);
pAB.setGender(AdministrativeGender.MALE);
pAB.addName().setFamily("A").addGiven("B");
myPatientDao.update(pAB);
Patient pAA = new Patient();
pAA.setId("AA");
pAA.setActive(true);
pAA.setGender(AdministrativeGender.MALE);
pAA.addName().setFamily("A").addGiven("A");
myPatientDao.update(pAA);
SearchParameterMap map;
List<String> ids;
map = new SearchParameterMap();
map.setSort(new SortSpec("family", SortOrderEnum.ASC).setChain(new SortSpec("given", SortOrderEnum.ASC)));
ids = toUnqualifiedVersionlessIdValues(myPatientDao.search(map));
assertThat(ids, contains("Patient/AA", "Patient/AB", "Patient/BA", "Patient/BB"));
map = new SearchParameterMap();
map.setSort(new SortSpec("gender").setChain(new SortSpec("family", SortOrderEnum.ASC).setChain(new SortSpec("given", SortOrderEnum.ASC))));
ids = toUnqualifiedVersionlessIdValues(myPatientDao.search(map));
ourLog.info("IDS: {}", ids);
assertThat(ids, contains("Patient/AA", "Patient/AB", "Patient/BA", "Patient/BB"));
map = new SearchParameterMap();
map.add(Patient.SP_ACTIVE, new TokenParam(null, "true"));
map.setSort(new SortSpec("family", SortOrderEnum.ASC).setChain(new SortSpec("given", SortOrderEnum.ASC)));
ids = toUnqualifiedVersionlessIdValues(myPatientDao.search(map));
assertThat(ids, contains("Patient/AA", "Patient/AB", "Patient/BA", "Patient/BB"));
}
@Test
public void testSort() throws Exception {
Patient pBA = new Patient();
pBA.setId("BA");
pBA.setActive(true);
pBA.setGender(AdministrativeGender.MALE);
pBA.addName().setFamily("B").addGiven("A");
myPatientDao.update(pBA);
Patient pBB = new Patient();
pBB.setId("BB");
pBB.setActive(true);
pBB.setGender(AdministrativeGender.MALE);
pBB.addName().setFamily("B").addGiven("B");
myPatientDao.update(pBB);
Patient pAB = new Patient();
pAB.setId("AB");
pAB.setActive(true);
pAB.setGender(AdministrativeGender.MALE);
pAB.addName().setFamily("A").addGiven("B");
myPatientDao.update(pAB);
Patient pAA = new Patient();
pAA.setId("AA");
pAA.setActive(true);
pAA.setGender(AdministrativeGender.MALE);
pAA.addName().setFamily("A").addGiven("A");
myPatientDao.update(pAA);
Patient pCA = new Patient();
pCA.setId("CA");
pCA.setActive(false);
pCA.addName().setFamily("C").addGiven("A");
pCA.addName().setFamily("Z").addGiven("A");
myPatientDao.update(pCA);
SearchParameterMap map;
List<String> ids;
// Sort across all resources
map = new SearchParameterMap();
map.setSort(new SortSpec("family", SortOrderEnum.ASC).setChain(new SortSpec("given", SortOrderEnum.ASC)));
ids = toUnqualifiedVersionlessIdValues(myPatientDao.search(map));
assertThat(ids, contains("Patient/AA", "Patient/AB", "Patient/BA", "Patient/BB", "Patient/CA"));
// A sort on a field that isn't populated in all cases
map = new SearchParameterMap();
map.setSort(new SortSpec("gender"));
ids = toUnqualifiedVersionlessIdValues(myPatientDao.search(map));
ourLog.info("IDS: {}", ids);
assertThat(ids, containsInAnyOrder("Patient/AA", "Patient/AB", "Patient/BA", "Patient/BB", "Patient/CA"));
map = new SearchParameterMap();
map.setSort(new SortSpec("gender").setChain(new SortSpec("family", SortOrderEnum.ASC).setChain(new SortSpec("given", SortOrderEnum.ASC))));
ids = toUnqualifiedVersionlessIdValues(myPatientDao.search(map));
ourLog.info("IDS: {}", ids);
assertThat(ids, contains("Patient/AA", "Patient/AB", "Patient/BA", "Patient/BB", "Patient/CA"));
// Sort
map = new SearchParameterMap();
map.add(Patient.SP_ACTIVE, new TokenParam(null, "true"));
map.setSort(new SortSpec("family", SortOrderEnum.ASC).setChain(new SortSpec("given", SortOrderEnum.ASC)));
ids = toUnqualifiedVersionlessIdValues(myPatientDao.search(map));
assertThat(ids, contains("Patient/AA", "Patient/AB", "Patient/BA", "Patient/BB"));
}
@Test @Test
public void testSearchWithUriParamAbove() throws Exception { public void testSearchWithUriParamAbove() throws Exception {
ValueSet vs1 = new ValueSet(); ValueSet vs1 = new ValueSet();

View File

@ -23,6 +23,7 @@ import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.jpa.config.TestDstu3WithoutLuceneConfig; import ca.uhn.fhir.jpa.config.TestDstu3WithoutLuceneConfig;
import ca.uhn.fhir.jpa.dao.*; import ca.uhn.fhir.jpa.dao.*;
import ca.uhn.fhir.jpa.provider.dstu3.JpaSystemProviderDstu3; import ca.uhn.fhir.jpa.provider.dstu3.JpaSystemProviderDstu3;
import ca.uhn.fhir.jpa.sp.ISearchParamPresenceSvc;
import ca.uhn.fhir.rest.param.StringParam; import ca.uhn.fhir.rest.param.StringParam;
import ca.uhn.fhir.rest.server.Constants; import ca.uhn.fhir.rest.server.Constants;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException; import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
@ -139,6 +140,8 @@ public class FhirResourceDaoDstu3SearchWithLuceneDisabledTest extends BaseJpaTes
@Autowired @Autowired
protected PlatformTransactionManager myTxManager; protected PlatformTransactionManager myTxManager;
@Autowired
protected ISearchParamPresenceSvc mySearchParamPresenceSvc;
@Autowired @Autowired
@Qualifier("myJpaValidationSupportChainDstu3") @Qualifier("myJpaValidationSupportChainDstu3")
@ -148,7 +151,7 @@ public class FhirResourceDaoDstu3SearchWithLuceneDisabledTest extends BaseJpaTes
@Transactional() @Transactional()
public void beforePurgeDatabase() { public void beforePurgeDatabase() {
final EntityManager entityManager = this.myEntityManager; final EntityManager entityManager = this.myEntityManager;
purgeDatabase(entityManager, myTxManager); purgeDatabase(entityManager, myTxManager, mySearchParamPresenceSvc);
} }
@Before @Before

View File

@ -39,6 +39,7 @@ import ca.uhn.fhir.jpa.dao.BaseJpaTest;
import ca.uhn.fhir.jpa.dao.DaoConfig; import ca.uhn.fhir.jpa.dao.DaoConfig;
import ca.uhn.fhir.jpa.dao.IFhirResourceDao; import ca.uhn.fhir.jpa.dao.IFhirResourceDao;
import ca.uhn.fhir.jpa.dao.IFhirSystemDao; import ca.uhn.fhir.jpa.dao.IFhirSystemDao;
import ca.uhn.fhir.jpa.sp.ISearchParamPresenceSvc;
import ca.uhn.fhir.jpa.testutil.RandomServerPortProvider; import ca.uhn.fhir.jpa.testutil.RandomServerPortProvider;
import ca.uhn.fhir.model.api.Bundle; import ca.uhn.fhir.model.api.Bundle;
import ca.uhn.fhir.model.api.IResource; import ca.uhn.fhir.model.api.IResource;
@ -87,6 +88,7 @@ public class ResourceProviderDstu1Test extends BaseJpaTest {
private static CloseableHttpClient ourHttpClient; private static CloseableHttpClient ourHttpClient;
private static EntityManager ourEntityManager; private static EntityManager ourEntityManager;
private static PlatformTransactionManager ourTxManager; private static PlatformTransactionManager ourTxManager;
private static ISearchParamPresenceSvc ourSearchParamPresenceSvc;
@AfterClass @AfterClass
public static void afterClassClearContext() throws Exception { public static void afterClassClearContext() throws Exception {
@ -551,6 +553,7 @@ public class ResourceProviderDstu1Test extends BaseJpaTest {
ourOrganizationDao = (IFhirResourceDao<Organization>) ourAppCtx.getBean("myOrganizationDaoDstu1", IFhirResourceDao.class); ourOrganizationDao = (IFhirResourceDao<Organization>) ourAppCtx.getBean("myOrganizationDaoDstu1", IFhirResourceDao.class);
ourEntityManager = ourAppCtx.getBean(EntityManager.class); ourEntityManager = ourAppCtx.getBean(EntityManager.class);
ourTxManager = ourAppCtx.getBean(PlatformTransactionManager.class); ourTxManager = ourAppCtx.getBean(PlatformTransactionManager.class);
ourSearchParamPresenceSvc = ourAppCtx.getBean(ISearchParamPresenceSvc.class);
List<IResourceProvider> rpsDev = (List<IResourceProvider>) ourAppCtx.getBean("myResourceProvidersDstu1", List.class); List<IResourceProvider> rpsDev = (List<IResourceProvider>) ourAppCtx.getBean("myResourceProvidersDstu1", List.class);
restServer.setResourceProviders(rpsDev); restServer.setResourceProviders(rpsDev);
@ -593,7 +596,7 @@ public class ResourceProviderDstu1Test extends BaseJpaTest {
@Before @Before
public void before() { public void before() {
super.purgeDatabase(ourEntityManager, ourTxManager); super.purgeDatabase(ourEntityManager, ourTxManager, ourSearchParamPresenceSvc);
} }
} }

View File

@ -2169,7 +2169,6 @@ public class ResourceProviderDstu3Test extends BaseResourceProviderDstu3Test {
} }
} }
@Test @Test
public void testSaveAndRetrieveExistingNarrativeJson() { public void testSaveAndRetrieveExistingNarrativeJson() {
Patient p1 = new Patient(); Patient p1 = new Patient();
@ -3046,41 +3045,37 @@ public class ResourceProviderDstu3Test extends BaseResourceProviderDstu3Test {
p.addName().addGiven("Sarah").setFamily("Graham"); p.addName().addGiven("Sarah").setFamily("Graham");
ourClient.create().resource(p).execute(); ourClient.create().resource(p).execute();
//@formatter:off
Bundle resp = ourClient Bundle resp = ourClient
.search() .search()
.forResource(Patient.class) .forResource(Patient.class)
.where(Patient.IDENTIFIER.exactly().systemAndCode("urn:system", methodName)) .where(Patient.IDENTIFIER.exactly().systemAndCode("urn:system", methodName))
.sort().ascending(Patient.FAMILY) .sort().ascending(Patient.FAMILY)
.sort().ascending(Patient.GIVEN) .sort().ascending(Patient.GIVEN)
.count(100) .count(100)
.returnBundle(Bundle.class) .returnBundle(Bundle.class)
.execute(); .execute();
//@formatter:on
List<String> names = toNameList(resp); List<String> names = toNameList(resp);
ourLog.info(StringUtils.join(names, '\n')); ourLog.info(StringUtils.join(names, '\n'));
//@formatter:off
assertThat(names, contains( // this matches in order only assertThat(names, contains( // this matches in order only
"Daniel Adams", "Daniel Adams",
"Aaron Alexis", "Aaron Alexis",
"Carol Allen", "Carol Allen",
"Ruth Black", "Ruth Black",
"Brian Brooks", "Brian Brooks",
"Amy Clark", "Amy Clark",
"Susan Clark", "Susan Clark",
"Anthony Coleman", "Anthony Coleman",
"Lisa Coleman", "Lisa Coleman",
"Steven Coleman", "Steven Coleman",
"Ruth Cook", "Ruth Cook",
"Betty Davis", "Betty Davis",
"Joshua Diaz", "Joshua Diaz",
"Brian Gracia", "Brian Gracia",
"Sarah Graham", "Sarah Graham",
"Stephan Graham")); "Stephan Graham"));
//@formatter:om
} }
@ -3118,7 +3113,7 @@ public class ResourceProviderDstu3Test extends BaseResourceProviderDstu3Test {
CloseableHttpResponse resp = ourHttpClient.execute(post); CloseableHttpResponse resp = ourHttpClient.execute(post);
try { try {
assertEquals(200, resp.getStatusLine().getStatusCode()); assertEquals(200, resp.getStatusLine().getStatusCode());
String output= IOUtils.toString(resp.getEntity().getContent(), StandardCharsets.UTF_8); String output = IOUtils.toString(resp.getEntity().getContent(), StandardCharsets.UTF_8);
ourLog.info(output); ourLog.info(output);
} finally { } finally {
resp.close(); resp.close();
@ -3157,7 +3152,8 @@ public class ResourceProviderDstu3Test extends BaseResourceProviderDstu3Test {
ourLog.info(responseString); ourLog.info(responseString);
assertEquals(400, response.getStatusLine().getStatusCode()); assertEquals(400, response.getStatusLine().getStatusCode());
OperationOutcome oo = myFhirCtx.newXmlParser().parseResource(OperationOutcome.class, responseString); OperationOutcome oo = myFhirCtx.newXmlParser().parseResource(OperationOutcome.class, responseString);
assertThat(oo.getIssue().get(0).getDiagnostics(), containsString("Can not update resource, request URL must contain an ID element for update (PUT) operation (it must be of the form [base]/[resource type]/[id])")); assertThat(oo.getIssue().get(0).getDiagnostics(),
containsString("Can not update resource, request URL must contain an ID element for update (PUT) operation (it must be of the form [base]/[resource type]/[id])"));
} finally { } finally {
response.close(); response.close();
} }
@ -3234,13 +3230,16 @@ public class ResourceProviderDstu3Test extends BaseResourceProviderDstu3Test {
try { try {
assertEquals(400, response.getStatusLine().getStatusCode()); assertEquals(400, response.getStatusLine().getStatusCode());
OperationOutcome oo = myFhirCtx.newJsonParser().parseResource(OperationOutcome.class, new InputStreamReader(response.getEntity().getContent())); OperationOutcome oo = myFhirCtx.newJsonParser().parseResource(OperationOutcome.class, new InputStreamReader(response.getEntity().getContent()));
assertEquals("Can not update resource, resource body must contain an ID element which matches the request URL for update (PUT) operation - Resource body ID of \"FOO\" does not match URL ID of \"" + p1id.getIdPart() + "\"", oo.getIssue().get(0).getDiagnostics()); assertEquals(
"Can not update resource, resource body must contain an ID element which matches the request URL for update (PUT) operation - Resource body ID of \"FOO\" does not match URL ID of \""
+ p1id.getIdPart() + "\"",
oo.getIssue().get(0).getDiagnostics());
} finally { } finally {
response.close(); response.close();
} }
// Try to update with the no ID in the resource body // Try to update with the no ID in the resource body
p1.setId((String)null); p1.setId((String) null);
encoded = myFhirCtx.newJsonParser().encodeResourceToString(p1); encoded = myFhirCtx.newJsonParser().encodeResourceToString(p1);
put = new HttpPut(ourServerBase + "/Patient/" + p1id.getIdPart()); put = new HttpPut(ourServerBase + "/Patient/" + p1id.getIdPart());
@ -3270,7 +3269,6 @@ public class ResourceProviderDstu3Test extends BaseResourceProviderDstu3Test {
} }
@Test @Test
public void testUpdateRejectsInvalidTypes() throws InterruptedException { public void testUpdateRejectsInvalidTypes() throws InterruptedException {

View File

@ -38,7 +38,7 @@
<appender-ref ref="STDOUT" /> <appender-ref ref="STDOUT" />
</logger> </logger>
<!-- Set to 'trace' to enable SQL Value logging --> <!-- Set to 'trace' to enable SQL Value logging -->
<logger name="org.hibernate.type" additivity="false" level="trace"> <logger name="org.hibernate.type" additivity="false" level="info">
<appender-ref ref="STDOUT" /> <appender-ref ref="STDOUT" />
</logger> </logger>