From 99a4b2c29e5c9fe13c0f3861ff7400fded08c70a Mon Sep 17 00:00:00 2001
From: jamesagnew
Date: Sat, 5 Mar 2016 20:46:04 -0500
Subject: [PATCH] Refactor JPA SearchBuilder
---
.../fhir/model/api/IQueryParameterType.java | 6 +-
.../model/base/composite/BaseCodingDt.java | 2 +-
.../base/composite/BaseIdentifierDt.java | 2 +-
.../model/base/composite/BaseQuantityDt.java | 2 +-
.../ca/uhn/fhir/model/primitive/StringDt.java | 2 +-
.../ca/uhn/fhir/rest/param/BaseParam.java | 9 +-
.../uhn/fhir/rest/param/InternalCodingDt.java | 3 +-
.../ca/uhn/fhir/jpa/dao/BaseHapiFhirDao.java | 9 +-
.../fhir/jpa/dao/BaseHapiFhirResourceDao.java | 7 +-
.../ca/uhn/fhir/jpa/dao/IFhirResourceDao.java | 4 +-
.../ca/uhn/fhir/jpa/dao/SearchBuilder.java | 693 +++++++++---------
.../java/ca/uhn/fhir/jpa/entity/Search.java | 2 +-
.../uhn/fhir/jpa/term/TerminologySvcImpl.java | 9 +-
.../FhirResourceDaoDstu2SearchNoFtTest.java | 124 +++-
.../dao/dstu2/FhirResourceDaoDstu2Test.java | 2 +-
.../dao/dstu3/FhirResourceDaoDstu3Test.java | 2 +-
.../ca/uhn/fhir/testmodel/IdentifierDt.java | 2 +-
pom.xml | 9 +
src/site/site.xml | 16 +-
19 files changed, 516 insertions(+), 389 deletions(-)
diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/model/api/IQueryParameterType.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/model/api/IQueryParameterType.java
index 330ccc021d3..a01261ea202 100644
--- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/model/api/IQueryParameterType.java
+++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/model/api/IQueryParameterType.java
@@ -69,8 +69,10 @@ public interface IQueryParameterType {
/**
* If set to non-null value, indicates that this parameter has been populated with a "[name]:missing=true" or "[name]:missing=false" vale
- * instead of a normal value
+ * instead of a normal value
+ *
+ * @return Returns a reference to this
for easier method chaining
*/
- void setMissing(Boolean theMissing);
+ IQueryParameterType setMissing(Boolean theMissing);
}
diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/model/base/composite/BaseCodingDt.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/model/base/composite/BaseCodingDt.java
index 501db2575dc..8292495b262 100644
--- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/model/base/composite/BaseCodingDt.java
+++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/model/base/composite/BaseCodingDt.java
@@ -194,7 +194,7 @@ public abstract class BaseCodingDt extends BaseIdentifiableElement implements IC
*/
@Deprecated
@Override
- public void setMissing(Boolean theMissing) {
+ public IQueryParameterType setMissing(Boolean theMissing) {
throw new UnsupportedOperationException("get/setMissing is not supported in StringDt. Use {@link StringParam} instead if you need this functionality");
}
diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/model/base/composite/BaseIdentifierDt.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/model/base/composite/BaseIdentifierDt.java
index fc6fce34471..968d72979dd 100644
--- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/model/base/composite/BaseIdentifierDt.java
+++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/model/base/composite/BaseIdentifierDt.java
@@ -135,7 +135,7 @@ public abstract class BaseIdentifierDt extends BaseIdentifiableElement implement
*/
@Deprecated
@Override
- public void setMissing(Boolean theMissing) {
+ public IQueryParameterType setMissing(Boolean theMissing) {
throw new UnsupportedOperationException("get/setMissing is not supported in StringDt. Use {@link StringParam} instead if you need this functionality");
}
diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/model/base/composite/BaseQuantityDt.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/model/base/composite/BaseQuantityDt.java
index 2ee214a5526..b1565b0e225 100644
--- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/model/base/composite/BaseQuantityDt.java
+++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/model/base/composite/BaseQuantityDt.java
@@ -231,7 +231,7 @@ public abstract class BaseQuantityDt extends BaseIdentifiableElement implements
*/
@Deprecated
@Override
- public void setMissing(Boolean theMissing) {
+ public IQueryParameterType setMissing(Boolean theMissing) {
throw new UnsupportedOperationException("get/setMissing is not supported in StringDt. Use {@link StringParam} instead if you need this functionality");
}
diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/model/primitive/StringDt.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/model/primitive/StringDt.java
index 83cb0755576..9ccfabed60d 100644
--- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/model/primitive/StringDt.java
+++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/model/primitive/StringDt.java
@@ -144,7 +144,7 @@ public class StringDt extends BasePrimitive implements IQueryParameterTy
*/
@Deprecated
@Override
- public void setMissing(Boolean theMissing) {
+ public IQueryParameterType setMissing(Boolean theMissing) {
throw new UnsupportedOperationException("get/setMissing is not supported in StringDt. Use {@link StringParam} instead if you need this functionality");
}
diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/param/BaseParam.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/param/BaseParam.java
index 8ded069de12..9791ec71c60 100644
--- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/param/BaseParam.java
+++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/param/BaseParam.java
@@ -61,11 +61,16 @@ abstract class BaseParam implements IQueryParameterType {
}
/**
- * If set to non-null value, indicates that this parameter has been populated with a "[name]:missing=true" or "[name]:missing=false" vale instead of a normal value
+ * If set to non-null value, indicates that this parameter has been populated
+ * with a "[name]:missing=true" or "[name]:missing=false" vale instead of a
+ * normal value
+ *
+ * @return Returns a reference to this
for easier method chaining
*/
@Override
- public void setMissing(Boolean theMissing) {
+ public BaseParam setMissing(Boolean theMissing) {
myMissing = theMissing;
+ return this;
}
@Override
diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/param/InternalCodingDt.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/param/InternalCodingDt.java
index 9e613aa9a37..b87d2a64a1b 100644
--- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/param/InternalCodingDt.java
+++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/param/InternalCodingDt.java
@@ -24,6 +24,7 @@ import java.util.List;
import ca.uhn.fhir.model.api.ICompositeDatatype;
import ca.uhn.fhir.model.api.IElement;
+import ca.uhn.fhir.model.api.IQueryParameterType;
import ca.uhn.fhir.model.api.annotation.Child;
import ca.uhn.fhir.model.api.annotation.Description;
import ca.uhn.fhir.model.base.composite.BaseCodingDt;
@@ -297,7 +298,7 @@ public class InternalCodingDt extends BaseCodingDt implements ICompositeDatatype
}
@Override
- public void setMissing(Boolean theMissing) {
+ public IQueryParameterType setMissing(Boolean theMissing) {
throw new UnsupportedOperationException();
}
diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/BaseHapiFhirDao.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/BaseHapiFhirDao.java
index 9285b207d59..8d075138965 100644
--- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/BaseHapiFhirDao.java
+++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/BaseHapiFhirDao.java
@@ -936,7 +936,6 @@ public abstract class BaseHapiFhirDao implements IDao {
* @param theTag
* The tag
* @return Returns true
if the tag should be removed
- * @see Updates to Tags, Profiles, and Security Labels for a description of the logic that the default behaviour folows.
*/
@SuppressWarnings("unused")
protected void postPersist(ResourceTable theEntity, T theResource) {
@@ -966,7 +965,7 @@ public abstract class BaseHapiFhirDao implements IDao {
}
IFhirResourceDao dao = getDao(theResourceType);
- Set ids = dao.searchForIdsWithAndOr(paramMap, new HashSet(), paramMap.getLastUpdated());
+ Set ids = dao.searchForIdsWithAndOr(paramMap, paramMap.getLastUpdated());
return ids;
}
@@ -1168,14 +1167,16 @@ public abstract class BaseHapiFhirDao implements IDao {
* The default implementation removes any profile declarations, but leaves tags and security labels in place.
* Subclasses may choose to override and change this behaviour.
*
+ *
+ * See Updates to Tags, Profiles, and Security
+ * Labels for a description of the logic that the default behaviour folows.
+ *
*
* @param theEntity
* The entity being updated (Do not modify the entity! Undefined behaviour will occur!)
* @param theTag
* The tag
* @return Retturns true
if the tag should be removed
- * @see Updates to Tags, Profiles, and Security
- * Labels for a description of the logic that the default behaviour folows.
*/
protected boolean shouldDroppedTagBeRemovedOnUpdate(ResourceTable theEntity, ResourceTag theTag) {
if (theTag.getTag().getTagType() == TagTypeEnum.PROFILE) {
diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/BaseHapiFhirResourceDao.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/BaseHapiFhirResourceDao.java
index 728243c432b..77cd069baf0 100644
--- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/BaseHapiFhirResourceDao.java
+++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/BaseHapiFhirResourceDao.java
@@ -932,7 +932,7 @@ public abstract class BaseHapiFhirResourceDao extends B
for (Entry nextEntry : theParams.entrySet()) {
map.add(nextEntry.getKey(), (nextEntry.getValue()));
}
- return searchForIdsWithAndOr(map, null, null);
+ return searchForIdsWithAndOr(map, null);
}
@Override
@@ -941,10 +941,11 @@ public abstract class BaseHapiFhirResourceDao extends B
}
@Override
- public Set searchForIdsWithAndOr(SearchParameterMap theParams, Collection theInitialPids, DateRangeParam theLastUpdated) {
+ public Set searchForIdsWithAndOr(SearchParameterMap theParams, DateRangeParam theLastUpdated) {
SearchBuilder builder = new SearchBuilder(getContext(), myEntityManager, myPlatformTransactionManager, mySearchDao, mySearchResultDao, this, myResourceIndexedSearchParamUriDao);
builder.setType(getResourceType(), getResourceName());
- return builder.searchForIdsWithAndOr(theParams, theInitialPids, theLastUpdated);
+ builder.searchForIdsWithAndOr(theParams, theLastUpdated);
+ return builder.doGetPids();
}
@SuppressWarnings("unchecked")
diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/IFhirResourceDao.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/IFhirResourceDao.java
index adef7dcc5aa..69278a45c94 100644
--- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/IFhirResourceDao.java
+++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/IFhirResourceDao.java
@@ -1,7 +1,5 @@
package ca.uhn.fhir.jpa.dao;
-import java.util.Collection;
-
/*
* #%L
* HAPI FHIR JPA Server
@@ -164,7 +162,7 @@ public interface IFhirResourceDao extends IDao {
Set searchForIds(String theParameterName, IQueryParameterType theValue);
- Set searchForIdsWithAndOr(SearchParameterMap theParams, Collection theInitialPids, DateRangeParam theLastUpdated);
+ Set searchForIdsWithAndOr(SearchParameterMap theParams, DateRangeParam theLastUpdated);
DaoMethodOutcome update(T theResource, RequestDetails theRequestDetails);
diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/SearchBuilder.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/SearchBuilder.java
index e83ed5ebd9b..7b6b2f14b37 100644
--- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/SearchBuilder.java
+++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/SearchBuilder.java
@@ -39,6 +39,7 @@ import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
+import java.util.UUID;
import javax.persistence.EntityManager;
import javax.persistence.Tuple;
@@ -85,6 +86,7 @@ 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.TagDefinition;
import ca.uhn.fhir.jpa.entity.TagTypeEnum;
import ca.uhn.fhir.jpa.util.StopWatch;
@@ -134,6 +136,12 @@ public class SearchBuilder {
private ISearchResultDao mySearchResultDao;
private IResourceIndexedSearchParamUriDao myResourceIndexedSearchParamUriDao;
+ private Search mySearchEntity;
+
+ private boolean myHaveFlushedSearch;
+
+ private SearchParameterMap myParams;
+
public SearchBuilder(FhirContext theFhirContext, EntityManager theEntityManager, PlatformTransactionManager thePlatformTransactionManager, ISearchDao theSearchDao, ISearchResultDao theSearchResultDao, BaseHapiFhirDao theDao, IResourceIndexedSearchParamUriDao theResourceIndexedSearchParamUriDao) {
myContext = theFhirContext;
myEntityManager = theEntityManager;
@@ -144,7 +152,7 @@ public class SearchBuilder {
myResourceIndexedSearchParamUriDao = theResourceIndexedSearchParamUriDao;
}
- private Set addPredicateComposite(RuntimeSearchParam theParamDef, Set thePids, List extends IQueryParameterType> theNextAnd) {
+ private void addPredicateComposite(RuntimeSearchParam theParamDef, List extends IQueryParameterType> theNextAnd) {
// TODO: fail if missing is set for a composite query
CriteriaBuilder builder = myEntityManager.getCriteriaBuilder();
@@ -158,34 +166,30 @@ public class SearchBuilder {
}
CompositeParam, ?> cp = (CompositeParam, ?>) or;
+ List predicates = new ArrayList();
+ predicates.add(builder.equal(from.get("myResourceType"), myResourceName));
+
RuntimeSearchParam left = theParamDef.getCompositeOf().get(0);
IQueryParameterType leftValue = cp.getLeftValue();
- Predicate leftPredicate = createCompositeParamPart(builder, from, left, leftValue);
+ predicates.add(createCompositeParamPart(builder, from, left, leftValue));
RuntimeSearchParam right = theParamDef.getCompositeOf().get(1);
IQueryParameterType rightValue = cp.getRightValue();
- Predicate rightPredicate = createCompositeParamPart(builder, from, right, rightValue);
+ predicates.add(createCompositeParamPart(builder, from, right, rightValue));
- Predicate type = builder.equal(from.get("myResourceType"), myResourceName);
- if (thePids.size() > 0) {
- Predicate inPids = (from.get("myResourcePid").in(thePids));
- cq.where(builder.and(type, leftPredicate, rightPredicate, inPids));
- } else {
- cq.where(builder.and(type, leftPredicate, rightPredicate));
- }
+ doCreateIdPredicate(predicates, from.get("myId").as(Long.class));
+ cq.where(builder.and(toArray(predicates)));
TypedQuery q = myEntityManager.createQuery(cq);
- return new HashSet(q.getResultList());
+ doSetPids(new HashSet(q.getResultList()));
}
- private Set addPredicateDate(String theParamName, Set thePids, List extends IQueryParameterType> theList) {
- if (theList == null || theList.isEmpty()) {
- return thePids;
- }
+ private void addPredicateDate(String theParamName, List extends IQueryParameterType> theList) {
if (Boolean.TRUE.equals(theList.get(0).getMissing())) {
- return addPredicateParamMissing(thePids, "myParamsDate", theParamName, ResourceIndexedSearchParamDate.class);
+ addPredicateParamMissing("myParamsDate", theParamName, ResourceIndexedSearchParamDate.class);
+ return;
}
CriteriaBuilder builder = myEntityManager.getCriteriaBuilder();
@@ -206,22 +210,21 @@ public class SearchBuilder {
Predicate masterCodePredicate = builder.or(toArray(codePredicates));
- Predicate type = builder.equal(from.get("myResourceType"), myResourceName);
- Predicate name = builder.equal(from.get("myParamName"), theParamName);
- if (thePids.size() > 0) {
- Predicate inPids = (from.get("myResourcePid").in(thePids));
- cq.where(builder.and(type, name, masterCodePredicate, inPids));
- } else {
- cq.where(builder.and(type, name, masterCodePredicate));
- }
+ List predicates = new ArrayList();
+ predicates.add(builder.equal(from.get("myResourceType"), myResourceName));
+ predicates.add(builder.equal(from.get("myParamName"), theParamName));
+ doCreateIdPredicate(predicates, from.get("myResourcePid").as(Long.class));
+ predicates.add(masterCodePredicate);
+
+ cq.where(builder.and(toArray(predicates)));
TypedQuery q = myEntityManager.createQuery(cq);
- return new HashSet(q.getResultList());
+ doSetPids(new HashSet(q.getResultList()));
}
- private Set addPredicateId(Set theExistingPids, Set thePids, DateRangeParam theLastUpdated) {
+ private void addPredicateId(Set thePids, DateRangeParam theLastUpdated) {
if (thePids == null || thePids.isEmpty()) {
- return Collections.emptySet();
+ return;
}
CriteriaBuilder builder = myEntityManager.getCriteriaBuilder();
@@ -232,25 +235,23 @@ public class SearchBuilder {
List predicates = new ArrayList();
predicates.add(builder.equal(from.get("myResourceType"), myResourceName));
predicates.add(from.get("myId").in(thePids));
+ doCreateIdPredicate(predicates, from.get("myId").as(Long.class));
predicates.addAll(createLastUpdatedPredicates(theLastUpdated, builder, from));
-
+
cq.where(toArray(predicates));
TypedQuery q = myEntityManager.createQuery(cq);
HashSet found = new HashSet(q.getResultList());
- if (!theExistingPids.isEmpty()) {
- theExistingPids.retainAll(found);
- return theExistingPids;
- } else {
- return found;
+ doSetPids(found);
+ }
+
+ private void doCreateIdPredicate(List thePredicates, Expression theExpression) {
+ if (myPids != null) {
+ thePredicates.add(theExpression.in(myPids));
}
}
- private Set addPredicateLanguage(Set thePids, List> theList, DateRangeParam theLastUpdated) {
- Set retVal = thePids;
- if (theList == null || theList.isEmpty()) {
- return retVal;
- }
+ private void addPredicateLanguage(List> theList, DateRangeParam theLastUpdated) {
for (List extends IQueryParameterType> nextList : theList) {
CriteriaBuilder builder = myEntityManager.getCriteriaBuilder();
@@ -272,30 +273,27 @@ public class SearchBuilder {
}
if (values.isEmpty()) {
- return retVal;
+ continue;
}
List predicates = new ArrayList();
predicates.add(builder.equal(from.get("myResourceType"), myResourceName));
predicates.add(from.get("myLanguage").as(String.class).in(values));
-
- if (retVal.size() > 0) {
- Predicate inPids = (from.get("myId").in(retVal));
- predicates.add(inPids);
- }
+ doCreateIdPredicate(predicates, from.get("myId").as(Long.class));
predicates.add(builder.isNull(from.get("myDeleted")));
cq.where(toArray(predicates));
TypedQuery q = myEntityManager.createQuery(cq);
- retVal = new HashSet(q.getResultList());
- if (retVal.isEmpty()) {
- return retVal;
+ HashSet pids = new HashSet(q.getResultList());
+ doSetPids(pids);
+ if (doHaveNoResults()) {
+ return;
}
}
- return retVal;
+ return;
}
private boolean addPredicateMissingFalseIfPresent(CriteriaBuilder theBuilder, String theParamName, Root extends BaseResourceIndexedSearchParam> from, List codePredicates, IQueryParameterType nextOr) {
@@ -326,13 +324,11 @@ public class SearchBuilder {
return missingFalse;
}
- private Set addPredicateNumber(String theParamName, Set thePids, List extends IQueryParameterType> theList) {
- if (theList == null || theList.isEmpty()) {
- return thePids;
- }
-
+ private void addPredicateNumber(String theParamName, List extends IQueryParameterType> theList) {
+
if (Boolean.TRUE.equals(theList.get(0).getMissing())) {
- return addPredicateParamMissing(thePids, "myParamsNumber", theParamName, ResourceIndexedSearchParamNumber.class);
+ addPredicateParamMissing("myParamsNumber", theParamName, ResourceIndexedSearchParamNumber.class);
+ return;
}
CriteriaBuilder builder = myEntityManager.getCriteriaBuilder();
@@ -353,7 +349,7 @@ public class SearchBuilder {
BigDecimal value = param.getValue();
if (value == null) {
- return thePids;
+ continue;
}
final Expression fromObj = from.get("myValue");
@@ -370,22 +366,19 @@ public class SearchBuilder {
}
- Predicate masterCodePredicate = builder.or(toArray(codePredicates));
-
- Predicate type = builder.equal(from.get("myResourceType"), myResourceName);
- Predicate name = builder.equal(from.get("myParamName"), theParamName);
- if (thePids.size() > 0) {
- Predicate inPids = (from.get("myResourcePid").in(thePids));
- cq.where(builder.and(type, name, masterCodePredicate, inPids));
- } else {
- cq.where(builder.and(type, name, masterCodePredicate));
- }
+ List predicates = new ArrayList();
+ predicates.add(builder.equal(from.get("myResourceType"), myResourceName));
+ predicates.add(builder.equal(from.get("myParamName"), theParamName));
+ predicates.add(builder.or(toArray(codePredicates)));
+ doCreateIdPredicate(predicates, from.get("myResourcePid").as(Long.class));
+
+ cq.where(builder.and(toArray(predicates)));
TypedQuery q = myEntityManager.createQuery(cq);
- return new HashSet(q.getResultList());
+ doSetPids(new HashSet(q.getResultList()));
}
- private Set addPredicateParamMissing(Set thePids, String joinName, String theParamName, Class extends BaseResourceIndexedSearchParam> theParamTable) {
+ private void addPredicateParamMissing(String joinName, String theParamName, Class extends BaseResourceIndexedSearchParam> theParamTable) {
CriteriaBuilder builder = myEntityManager.getCriteriaBuilder();
CriteriaQuery cq = builder.createQuery(Long.class);
Root from = cq.from(ResourceTable.class);
@@ -398,26 +391,24 @@ public class SearchBuilder {
Predicate subQtype = builder.equal(subQfrom.get("myResourceType"), myResourceName);
subQ.where(builder.and(subQtype, subQname));
- Predicate joinPredicate = builder.not(builder.in(from.get("myId")).value(subQ));
- Predicate typePredicate = builder.equal(from.get("myResourceType"), myResourceName);
- Predicate notDeletedPredicate = builder.isNull(from.get("myDeleted"));
-
- if (thePids.size() > 0) {
- Predicate inPids = (from.get("myId").in(thePids));
- cq.where(builder.and(inPids, typePredicate, joinPredicate, notDeletedPredicate));
- } else {
- cq.where(builder.and(typePredicate, joinPredicate, notDeletedPredicate));
- }
+ List predicates = new ArrayList();
+ predicates.add(builder.not(builder.in(from.get("myId")).value(subQ)));
+ predicates.add(builder.equal(from.get("myResourceType"), myResourceName));
+ predicates.add(builder.isNull(from.get("myDeleted")));
+ doCreateIdPredicate(predicates, from.get("myId").as(Long.class));
+
+ cq.where(builder.and(toArray(predicates)));
ourLog.info("Adding :missing qualifier for parameter '{}'", theParamName);
TypedQuery q = myEntityManager.createQuery(cq);
List resultList = q.getResultList();
+
HashSet retVal = new HashSet(resultList);
- return retVal;
+ doSetPids(retVal);
}
- private Set addPredicateParamMissingResourceLink(Set thePids, String joinName, String theParamName) {
+ private void addPredicateParamMissingResourceLink(String joinName, String theParamName) {
CriteriaBuilder builder = myEntityManager.getCriteriaBuilder();
CriteriaQuery cq = builder.createQuery(Long.class);
Root from = cq.from(ResourceTable.class);
@@ -431,29 +422,22 @@ public class SearchBuilder {
Predicate path = createResourceLinkPathPredicate(theParamName, builder, subQfrom);
subQ.where(path);
- Predicate joinPredicate = builder.not(builder.in(from.get("myId")).value(subQ));
- Predicate typePredicate = builder.equal(from.get("myResourceType"), myResourceName);
+ List predicates = new ArrayList();
+ doCreateIdPredicate(predicates, from.get("myId").as(Long.class));
+ predicates.add(builder.not(builder.in(from.get("myId")).value(subQ)));
+ predicates.add(builder.equal(from.get("myResourceType"), myResourceName));
- if (thePids.size() > 0) {
- Predicate inPids = (from.get("myId").in(thePids));
- cq.where(builder.and(inPids, typePredicate, joinPredicate));
- } else {
- cq.where(builder.and(typePredicate, joinPredicate));
- }
+ cq.where(builder.and(toArray(predicates)));
TypedQuery q = myEntityManager.createQuery(cq);
List resultList = q.getResultList();
- HashSet retVal = new HashSet(resultList);
- return retVal;
+ doSetPids(new HashSet(resultList));
}
- private Set addPredicateQuantity(String theParamName, Set thePids, List extends IQueryParameterType> theList) {
- if (theList == null || theList.isEmpty()) {
- return thePids;
- }
-
+ private void addPredicateQuantity(String theParamName, List extends IQueryParameterType> theList) {
if (Boolean.TRUE.equals(theList.get(0).getMissing())) {
- return addPredicateParamMissing(thePids, "myParamsQuantity", theParamName, ResourceIndexedSearchParamQuantity.class);
+ addPredicateParamMissing("myParamsQuantity", theParamName, ResourceIndexedSearchParamQuantity.class);
+ return;
}
CriteriaBuilder builder = myEntityManager.getCriteriaBuilder();
@@ -523,31 +507,24 @@ public class SearchBuilder {
}
}
- Predicate masterCodePredicate = builder.or(toArray(codePredicates));
+ List predicates = new ArrayList();
+ predicates.add(builder.equal(from.get("myResourceType"), myResourceName));
+ predicates.add(builder.equal(from.get("myParamName"), theParamName));
+ predicates.add(builder.or(toArray(codePredicates)));
+ doCreateIdPredicate(predicates, from.get("myResourcePid").as(Long.class));
- Predicate type = builder.equal(from.get("myResourceType"), myResourceName);
- Predicate name = builder.equal(from.get("myParamName"), theParamName);
- if (thePids.size() > 0) {
- Predicate inPids = (from.get("myResourcePid").in(thePids));
- cq.where(builder.and(type, name, masterCodePredicate, inPids));
- } else {
- cq.where(builder.and(type, name, masterCodePredicate));
- }
+ cq.where(builder.and(toArray(predicates)));
TypedQuery q = myEntityManager.createQuery(cq);
- return new HashSet(q.getResultList());
+ doSetPids(new HashSet(q.getResultList()));
}
- private Set addPredicateReference(String theParamName, Set thePids, List extends IQueryParameterType> theList) {
+ private void addPredicateReference(String theParamName, List extends IQueryParameterType> theList) {
assert theParamName.contains(".") == false;
- Set pidsToRetain = thePids;
- if (theList == null || theList.isEmpty()) {
- return pidsToRetain;
- }
-
if (Boolean.TRUE.equals(theList.get(0).getMissing())) {
- return addPredicateParamMissingResourceLink(thePids, "myResourceLinks", theParamName);
+ addPredicateParamMissingResourceLink("myResourceLinks", theParamName);
+ return;
}
CriteriaBuilder builder = myEntityManager.getCriteriaBuilder();
@@ -677,27 +654,21 @@ public class SearchBuilder {
}
- Predicate masterCodePredicate = builder.or(toArray(codePredicates));
+ List predicates = new ArrayList();
+ predicates.add(createResourceLinkPathPredicate(theParamName, builder, from));
+ predicates.add(builder.or(toArray(codePredicates)));
+ doCreateIdPredicate(predicates, from.get("mySourceResourcePid").as(Long.class));
- Predicate type = createResourceLinkPathPredicate(theParamName, builder, from);
- if (pidsToRetain.size() > 0) {
- Predicate inPids = (from.get("mySourceResourcePid").in(pidsToRetain));
- cq.where(builder.and(type, masterCodePredicate, inPids));
- } else {
- cq.where(builder.and(type, masterCodePredicate));
- }
+ cq.where(builder.and(toArray(predicates)));
TypedQuery q = myEntityManager.createQuery(cq);
- return new HashSet(q.getResultList());
+ doSetPids(new HashSet(q.getResultList()));
}
- private Set addPredicateString(String theParamName, Set thePids, List extends IQueryParameterType> theList) {
- if (theList == null || theList.isEmpty()) {
- return thePids;
- }
-
+ private void addPredicateString(String theParamName, List extends IQueryParameterType> theList) {
if (Boolean.TRUE.equals(theList.get(0).getMissing())) {
- return addPredicateParamMissing(thePids, "myParamsString", theParamName, ResourceIndexedSearchParamString.class);
+ addPredicateParamMissing("myParamsString", theParamName, ResourceIndexedSearchParamString.class);
+ return;
}
CriteriaBuilder builder = myEntityManager.getCriteriaBuilder();
@@ -716,27 +687,19 @@ public class SearchBuilder {
codePredicates.add(singleCode);
}
- Predicate masterCodePredicate = builder.or(toArray(codePredicates));
-
- Predicate type = builder.equal(from.get("myResourceType"), myResourceName);
- Predicate name = builder.equal(from.get("myParamName"), theParamName);
- if (thePids.size() > 0) {
- Predicate inPids = (from.get("myResourcePid").in(thePids));
- cq.where(builder.and(type, name, masterCodePredicate, inPids));
- } else {
- cq.where(builder.and(type, name, masterCodePredicate));
- }
+ List predicates = new ArrayList();
+ predicates.add(builder.equal(from.get("myResourceType"), myResourceName));
+ predicates.add(builder.equal(from.get("myParamName"), theParamName));
+ predicates.add(builder.or(toArray(codePredicates)));
+ doCreateIdPredicate(predicates, from.get("myResourcePid").as(Long.class));
+
+ cq.where(builder.and(toArray(predicates)));
TypedQuery q = myEntityManager.createQuery(cq);
- return new HashSet(q.getResultList());
+ doSetPids(new HashSet(q.getResultList()));
}
- private Set addPredicateTag(Set thePids, List> theList, String theParamName, DateRangeParam theLastUpdated) {
- Set pids = thePids;
- if (theList == null || theList.isEmpty()) {
- return pids;
- }
-
+ private void addPredicateTag(List> theList, String theParamName, DateRangeParam theLastUpdated) {
TagTypeEnum tagType;
if (Constants.PARAM_TAG.equals(theParamName)) {
tagType = TagTypeEnum.TAG;
@@ -815,29 +778,23 @@ public class SearchBuilder {
andPredicates.addAll(createLastUpdatedPredicates(theLastUpdated, builder, defJoin));
}
+ doCreateIdPredicate(andPredicates, from.get("myResourceId").as(Long.class));
Predicate masterCodePredicate = builder.and(toArray(andPredicates));
- if (pids.size() > 0) {
- Predicate inPids = (from.get("myResourceId").in(pids));
- cq.where(builder.and(masterCodePredicate, inPids));
- } else {
- cq.where(masterCodePredicate);
- }
+ cq.where(masterCodePredicate);
TypedQuery q = myEntityManager.createQuery(cq);
- pids = new HashSet(q.getResultList());
+ Set pids = new HashSet(q.getResultList());
+ doSetPids(pids);
}
- return pids;
}
- private Set addPredicateToken(String theParamName, Set thePids, List extends IQueryParameterType> theList) {
- if (theList == null || theList.isEmpty()) {
- return thePids;
- }
+ private void addPredicateToken(String theParamName, List extends IQueryParameterType> theList) {
if (Boolean.TRUE.equals(theList.get(0).getMissing())) {
- return addPredicateParamMissing(thePids, "myParamsToken", theParamName, ResourceIndexedSearchParamToken.class);
+ addPredicateParamMissing("myParamsToken", theParamName, ResourceIndexedSearchParamToken.class);
+ return;
}
CriteriaBuilder builder = myEntityManager.getCriteriaBuilder();
@@ -854,7 +811,8 @@ public class SearchBuilder {
if (nextOr instanceof TokenParam) {
TokenParam id = (TokenParam) nextOr;
if (id.isText()) {
- return addPredicateString(theParamName, thePids, theList);
+ addPredicateString(theParamName, theList);
+ continue;
}
}
@@ -862,28 +820,26 @@ public class SearchBuilder {
codePredicates.add(singleCode);
}
- Predicate masterCodePredicate = builder.or(toArray(codePredicates));
-
- Predicate type = builder.equal(from.get("myResourceType"), myResourceName);
- Predicate name = builder.equal(from.get("myParamName"), theParamName);
- if (thePids.size() > 0) {
- Predicate inPids = (from.get("myResourcePid").in(thePids));
- cq.where(builder.and(type, name, masterCodePredicate, inPids));
- } else {
- cq.where(builder.and(type, name, masterCodePredicate));
+ if (codePredicates.isEmpty()) {
+ return;
}
+
+ List predicates = new ArrayList();
+ predicates.add(builder.equal(from.get("myResourceType"), myResourceName));
+ predicates.add(builder.equal(from.get("myParamName"), theParamName));
+ predicates.add(builder.or(toArray(codePredicates)));
+ doCreateIdPredicate(predicates, from.get("myResourcePid").as(Long.class));
+
+ cq.where(builder.and(toArray(predicates)));
TypedQuery q = myEntityManager.createQuery(cq);
- return new HashSet(q.getResultList());
+ doSetPids(new HashSet(q.getResultList()));
}
- private Set addPredicateUri(String theParamName, Set thePids, List extends IQueryParameterType> theList) {
- if (theList == null || theList.isEmpty()) {
- return thePids;
- }
-
+ private void addPredicateUri(String theParamName, List extends IQueryParameterType> theList) {
if (Boolean.TRUE.equals(theList.get(0).getMissing())) {
- return addPredicateParamMissing(thePids, "myParamsUri", theParamName, ResourceIndexedSearchParamUri.class);
+ addPredicateParamMissing("myParamsUri", theParamName, ResourceIndexedSearchParamUri.class);
+ return;
}
CriteriaBuilder builder = myEntityManager.getCriteriaBuilder();
@@ -904,7 +860,7 @@ public class SearchBuilder {
String value = param.getValue();
if (value == null) {
- return thePids;
+ continue;
}
Path fromObj = from.get("myUri");
@@ -954,22 +910,20 @@ public class SearchBuilder {
}
if (codePredicates.isEmpty()) {
- return new HashSet();
+ doSetPids(new HashSet());
+ return;
}
- Predicate masterCodePredicate = builder.or(toArray(codePredicates));
-
- Predicate type = builder.equal(from.get("myResourceType"), myResourceName);
- Predicate name = builder.equal(from.get("myParamName"), theParamName);
- if (thePids.size() > 0) {
- Predicate inPids = (from.get("myResourcePid").in(thePids));
- cq.where(builder.and(type, name, masterCodePredicate, inPids));
- } else {
- cq.where(builder.and(type, name, masterCodePredicate));
- }
+ List predicates = new ArrayList();
+ predicates.add(builder.equal(from.get("myResourceType"), myResourceName));
+ predicates.add(builder.equal(from.get("myParamName"), theParamName));
+ predicates.add(builder.or(toArray(codePredicates)));
+ doCreateIdPredicate(predicates, from.get("myResourcePid").as(Long.class));
+
+ cq.where(builder.and(toArray(predicates)));
TypedQuery q = myEntityManager.createQuery(cq);
- return new HashSet(q.getResultList());
+ doSetPids(new HashSet(q.getResultList()));
}
private Predicate createCompositeParamPart(CriteriaBuilder builder, Root from, RuntimeSearchParam left, IQueryParameterType leftValue) {
@@ -1111,10 +1065,6 @@ public class SearchBuilder {
return num;
}
- // private Set addPredicateComposite(String theParamName, Set thePids, List extends
- // IQueryParameterType> theList) {
- // }
-
private Predicate createPredicateString(IQueryParameterType theParameter, String theParamName, CriteriaBuilder theBuilder, From theFrom) {
String rawSearchTerm;
if (theParameter instanceof TokenParam) {
@@ -1317,17 +1267,34 @@ public class SearchBuilder {
createSort(theBuilder, theFrom, theSort.getChain(), theOrders, thePredicates);
}
- private List filterResourceIdsByLastUpdated(Collection thePids, final DateRangeParam theLastUpdated) {
+ private void filterResourceIdsByLastUpdated(final DateRangeParam theLastUpdated) {
CriteriaBuilder builder = myEntityManager.getCriteriaBuilder();
CriteriaQuery cq = builder.createQuery(Long.class);
Root from = cq.from(ResourceTable.class);
cq.select(from.get("myId").as(Long.class));
List lastUpdatedPredicates = createLastUpdatedPredicates(theLastUpdated, builder, from);
- lastUpdatedPredicates.add(0, from.get("myId").in(thePids));
-
+ doCreateIdPredicate(lastUpdatedPredicates, from.get("myId").as(Long.class));
+
cq.where(SearchBuilder.toArray(lastUpdatedPredicates));
TypedQuery query = myEntityManager.createQuery(cq);
+
+ List resultList = query.getResultList();
+ doSetPids(resultList);
+ }
+
+ private List filterResourceIdsByLastUpdated(final DateRangeParam theLastUpdated, Collection thePids) {
+ CriteriaBuilder builder = myEntityManager.getCriteriaBuilder();
+ CriteriaQuery cq = builder.createQuery(Long.class);
+ Root from = cq.from(ResourceTable.class);
+ cq.select(from.get("myId").as(Long.class));
+
+ List lastUpdatedPredicates = createLastUpdatedPredicates(theLastUpdated, builder, from);
+ lastUpdatedPredicates.add(from.get("myId").as(Long.class).in(thePids));
+
+ cq.where(SearchBuilder.toArray(lastUpdatedPredicates));
+ TypedQuery query = myEntityManager.createQuery(cq);
+
List resultList = query.getResultList();
return resultList;
}
@@ -1484,7 +1451,7 @@ public class SearchBuilder {
}
if (theLastUpdated != null && (theLastUpdated.getLowerBoundAsInstant() != null || theLastUpdated.getUpperBoundAsInstant() != null)) {
- pidsToInclude = new HashSet(filterResourceIdsByLastUpdated(pidsToInclude, theLastUpdated));
+ pidsToInclude = new HashSet(filterResourceIdsByLastUpdated(theLastUpdated, pidsToInclude));
}
for (Long next : pidsToInclude) {
if (original.contains(next) == false && allAdded.contains(next) == false) {
@@ -1503,8 +1470,8 @@ public class SearchBuilder {
return allAdded;
}
- private List processSort(final SearchParameterMap theParams, Collection theLoadPids) {
- final List pids;
+ private void processSort(final SearchParameterMap theParams) {
+
// Set loadPids = theLoadPids;
if (theParams.getSort() != null && isNotBlank(theParams.getSort().getParamName())) {
List orders = new ArrayList();
@@ -1512,10 +1479,16 @@ public class SearchBuilder {
CriteriaBuilder builder = myEntityManager.getCriteriaBuilder();
CriteriaQuery cq = builder.createTupleQuery();
Root from = cq.from(ResourceTable.class);
- predicates.add(from.get("myId").in(theLoadPids));
+
+ doCreateIdPredicate(predicates, from.get("myId").as(Long.class));
+
createSort(builder, from, theParams.getSort(), orders, predicates);
+
if (orders.size() > 0) {
- Collection originalPids = theLoadPids;
+
+ // TODO: why do we need the existing list for this join to work?
+ Collection originalPids = myPids;
+
LinkedHashSet loadPids = new LinkedHashSet();
cq.multiselect(from.get("myId").as(Long.class));
cq.where(toArray(predicates));
@@ -1529,7 +1502,7 @@ public class SearchBuilder {
ourLog.debug("Sort PID order is now: {}", loadPids);
- pids = new ArrayList(loadPids);
+ ArrayList pids = new ArrayList(loadPids);
// Any ressources which weren't matched by the sort get added to the bottom
for (Long next : originalPids) {
@@ -1538,25 +1511,24 @@ public class SearchBuilder {
}
}
- } else {
- pids = toList(theLoadPids);
- }
- } else {
- pids = toList(theLoadPids);
+ doSetPids(pids);
+ }
}
- return pids;
+
}
public IBundleProvider search(final SearchParameterMap theParams) {
+ myParams = theParams;
StopWatch w = new StopWatch();
- final InstantDt now = InstantDt.withCurrentTime();
+ doInitializeSearch();
+
DateRangeParam lu = theParams.getLastUpdated();
if (lu != null && lu.isEmpty()) {
lu = null;
}
- Collection loadPids;
+// Collection loadPids;
if (theParams.getEverythingMode() != null) {
Long pid = null;
@@ -1565,13 +1537,14 @@ public class SearchBuilder {
pid = BaseHapiFhirDao.translateForcedIdToPid(new IdDt(idParm.getValue()), myEntityManager);
}
- loadPids = new HashSet();
if (theParams.containsKey(Constants.PARAM_CONTENT) || theParams.containsKey(Constants.PARAM_TEXT)) {
List pids = mySearchDao.everything(myResourceName, theParams);
- // if (pid != null) {
- // loadPids.add(pid);
- // }
- loadPids.addAll(pids);
+ if (pids.isEmpty()) {
+ return doReturnProvider();
+ }
+
+ doSetPids(pids);
+
} else {
CriteriaBuilder builder = myEntityManager.getCriteriaBuilder();
CriteriaQuery cq = builder.createTupleQuery();
@@ -1588,49 +1561,55 @@ public class SearchBuilder {
cq.multiselect(from.get("myId").as(Long.class), join.get("mySourceResourcePid").as(Long.class));
TypedQuery query = myEntityManager.createQuery(cq);
+ Set pids = new HashSet();
for (Tuple next : query.getResultList()) {
- loadPids.add(next.get(0, Long.class));
+ pids.add(next.get(0, Long.class));
Long nextLong = next.get(1, Long.class);
if (nextLong != null) {
- loadPids.add(nextLong);
+ pids.add(nextLong);
}
}
+ doSetPids(pids);
+
}
} else if (theParams.isEmpty()) {
- loadPids = new HashSet();
TypedQuery query = createSearchAllByTypeQuery(lu);
lu = null;
- for (Tuple next : query.getResultList()) {
+ List resultList = query.getResultList();
+ if (resultList.isEmpty()) {
+ return doReturnProvider();
+ }
+
+ Set loadPids = new HashSet();
+ for (Tuple next : resultList) {
loadPids.add(next.get(0, Long.class));
}
- if (loadPids.isEmpty()) {
- return new SimpleBundleProvider();
- }
+ doSetPids(loadPids);
} else {
- List searchResultPids;
if (mySearchDao == 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);
}
- searchResultPids = null;
} else {
- searchResultPids = mySearchDao.search(myResourceName, theParams);
+ List searchResultPids = mySearchDao.search(myResourceName, theParams);
+ if (searchResultPids != null) {
+ if (searchResultPids.isEmpty()) {
+ return doReturnProvider();
+ }
+ doSetPids(searchResultPids);
+ }
}
- if (theParams.isEmpty()) {
- loadPids = searchResultPids;
- } else {
- loadPids = searchForIdsWithAndOr(theParams, searchResultPids, lu);
+
+ if (!theParams.isEmpty()) {
+ searchForIdsWithAndOr(theParams, lu);
}
- if (loadPids.isEmpty()) {
- return new SimpleBundleProvider();
- }
-
+
}
// // Load _include and _revinclude before filter and sort in everything mode
@@ -1642,82 +1621,118 @@ public class SearchBuilder {
// }
// }
+ if (doHaveNoResults()) {
+ return doReturnProvider();
+ }
+
// Handle _lastUpdated
if (lu != null) {
- List resultList = filterResourceIdsByLastUpdated(loadPids, lu);
- loadPids.clear();
- for (Long next : resultList) {
- loadPids.add(next);
- }
+ filterResourceIdsByLastUpdated(lu);
- if (loadPids.isEmpty()) {
- return new SimpleBundleProvider();
+ if (doHaveNoResults()) {
+ return doReturnProvider();
}
}
+
// Handle sorting if any was provided
- final List pids = processSort(theParams, loadPids);
-
- // Load _revinclude resources
- final Set revIncludedPids;
- if (theParams.getEverythingMode() == null) {
- if (theParams.getRevIncludes() != null && theParams.getRevIncludes().isEmpty() == false) {
- revIncludedPids = loadReverseIncludes(pids, theParams.getRevIncludes(), true, lu);
- } else {
- revIncludedPids = new HashSet();
- }
- } else {
- revIncludedPids = new HashSet();
- }
-
- ourLog.debug("Search returned PIDs: {}", pids);
-
- final int totalCount = pids.size();
-
- IBundleProvider retVal = new IBundleProvider() {
- @Override
- public InstantDt getPublished() {
- return now;
- }
-
- @Override
- public List getResources(final int theFromIndex, final int theToIndex) {
- TransactionTemplate template = new TransactionTemplate(myPlatformTransactionManager);
- return template.execute(new TransactionCallback>() {
- @Override
- public List doInTransaction(TransactionStatus theStatus) {
- List pidsSubList = pids.subList(theFromIndex, theToIndex);
-
- // Load includes
- pidsSubList = new ArrayList(pidsSubList);
- revIncludedPids.addAll(loadReverseIncludes(pidsSubList, theParams.getIncludes(), false, theParams.getLastUpdated()));
-
- // Execute the query and make sure we return distinct results
- List resources = new ArrayList();
- loadResourcesByPid(pidsSubList, resources, revIncludedPids, false);
-
- return resources;
- }
-
- });
- }
-
- @Override
- public Integer preferredPageSize() {
- return theParams.getCount();
- }
-
- @Override
- public int size() {
- return totalCount;
- }
- };
+ processSort(theParams);
ourLog.info(" {} on {} in {}ms", new Object[] { myResourceName, theParams, w.getMillisAndRestart() });
- return retVal;
+ return doReturnProvider();
}
- public Set searchForIdsWithAndOr(SearchParameterMap theParams, Collection theInitialPids, DateRangeParam theLastUpdated) {
+ private IBundleProvider doReturnProvider() {
+ if (myPids == null) {
+ return new SimpleBundleProvider();
+ } else {
+ final ArrayList pids;
+ if (!(myPids instanceof List)) {
+ pids = new ArrayList(myPids);
+ } else {
+ pids = (ArrayList) myPids;
+ }
+
+// // Load _revinclude resources
+// final Set revIncludedPids;
+// if (myParams.getEverythingMode() == null) {
+// if (myParams.getRevIncludes() != null && myParams.getRevIncludes().isEmpty() == false) {
+// revIncludedPids = loadReverseIncludes(pids, myParams.getRevIncludes(), true, myParams.getLastUpdated());
+// } else {
+// revIncludedPids = new HashSet();
+// }
+// } else {
+// revIncludedPids = new HashSet();
+// }
+
+ return new IBundleProvider() {
+ @Override
+ public InstantDt getPublished() {
+ return mySearchStarted;
+ }
+
+ @Override
+ public List getResources(final int theFromIndex, final int theToIndex) {
+ TransactionTemplate template = new TransactionTemplate(myPlatformTransactionManager);
+ return template.execute(new TransactionCallback>() {
+ @Override
+ public List doInTransaction(TransactionStatus theStatus) {
+ List pidsSubList = pids.subList(theFromIndex, theToIndex);
+
+ // Load includes
+ pidsSubList = new ArrayList(pidsSubList);
+
+ Set revIncludedPids = new HashSet();
+ if (myParams.getEverythingMode() == null) {
+ revIncludedPids.addAll(loadReverseIncludes(pidsSubList, myParams.getRevIncludes(), true, myParams.getLastUpdated()));
+ }
+ revIncludedPids.addAll(loadReverseIncludes(pidsSubList, myParams.getIncludes(), false, myParams.getLastUpdated()));
+
+ // Execute the query and make sure we return distinct results
+ List resources = new ArrayList();
+ loadResourcesByPid(pidsSubList, resources, revIncludedPids, false);
+
+ return resources;
+ }
+
+ });
+ }
+
+ @Override
+ public Integer preferredPageSize() {
+ return myParams.getCount();
+ }
+
+ @Override
+ public int size() {
+ return pids.size();
+ }
+ };
+
+ }
+ }
+
+ private Collection myPids;
+
+ private InstantDt mySearchStarted;
+
+ private void doSetPids(Collection thePids) {
+ myPids = thePids;
+ }
+
+ private void doInitializeSearch() {
+ assert mySearchEntity == null;
+
+ mySearchStarted = InstantDt.withCurrentTime();
+
+// mySearchEntity = new Search();
+// mySearchEntity.setUuid(UUID.randomUUID().toString());
+// myEntityManager.persist(mySearchEntity);
+//
+// myHaveFlushedSearch = false;
+ }
+
+ public void searchForIdsWithAndOr(SearchParameterMap theParams, DateRangeParam theLastUpdated) {
SearchParameterMap params = theParams;
if (params == null) {
params = new SearchParameterMap();
@@ -1725,11 +1740,6 @@ public class SearchBuilder {
RuntimeResourceDefinition resourceDef = myContext.getResourceDefinition(myResourceType);
- Set pids = new HashSet();
- if (theInitialPids != null) {
- pids.addAll(theInitialPids);
- }
-
for (Entry>> nextParamEntry : params.entrySet()) {
String nextParamName = nextParamEntry.getKey();
if (nextParamName.equals(BaseResource.SP_RES_ID)) {
@@ -1757,30 +1767,25 @@ public class SearchBuilder {
}
}
if (joinPids.isEmpty()) {
- return new HashSet();
+ doSetPids(new HashSet());
+ return;
}
}
- pids = addPredicateId(pids, joinPids, theLastUpdated);
- if (pids.isEmpty()) {
- return new HashSet();
- }
-
- if (pids.isEmpty()) {
- pids.addAll(joinPids);
- } else {
- pids.retainAll(joinPids);
+ addPredicateId(joinPids, theLastUpdated);
+ if (doHaveNoResults()) {
+ return;
}
}
}
} else if (nextParamName.equals(BaseResource.SP_RES_LANGUAGE)) {
- pids = addPredicateLanguage(pids, nextParamEntry.getValue(), theLastUpdated);
+ addPredicateLanguage(nextParamEntry.getValue(), theLastUpdated);
} else if (nextParamName.equals(Constants.PARAM_TAG) || nextParamName.equals(Constants.PARAM_PROFILE) || nextParamName.equals(Constants.PARAM_SECURITY)) {
- pids = addPredicateTag(pids, nextParamEntry.getValue(), nextParamName, theLastUpdated);
+ addPredicateTag(nextParamEntry.getValue(), nextParamName, theLastUpdated);
} else {
@@ -1789,74 +1794,82 @@ public class SearchBuilder {
switch (nextParamDef.getParamType()) {
case DATE:
for (List extends IQueryParameterType> nextAnd : nextParamEntry.getValue()) {
- pids = addPredicateDate(nextParamName, pids, nextAnd);
- if (pids.isEmpty()) {
- return new HashSet();
+ addPredicateDate(nextParamName, nextAnd);
+ if (doHaveNoResults()) {
+ return;
}
}
break;
case QUANTITY:
for (List extends IQueryParameterType> nextAnd : nextParamEntry.getValue()) {
- pids = addPredicateQuantity(nextParamName, pids, nextAnd);
- if (pids.isEmpty()) {
- return new HashSet();
+ addPredicateQuantity(nextParamName, nextAnd);
+ if (doHaveNoResults()) {
+ return;
}
}
break;
case REFERENCE:
for (List extends IQueryParameterType> nextAnd : nextParamEntry.getValue()) {
- pids = addPredicateReference(nextParamName, pids, nextAnd);
- if (pids.isEmpty()) {
- return new HashSet();
+ addPredicateReference(nextParamName, nextAnd);
+ if (doHaveNoResults()) {
+ return;
}
}
break;
case STRING:
for (List extends IQueryParameterType> nextAnd : nextParamEntry.getValue()) {
- pids = addPredicateString(nextParamName, pids, nextAnd);
- if (pids.isEmpty()) {
- return new HashSet();
+ addPredicateString(nextParamName, nextAnd);
+ if (doHaveNoResults()) {
+ return;
}
}
break;
case TOKEN:
for (List extends IQueryParameterType> nextAnd : nextParamEntry.getValue()) {
- pids = addPredicateToken(nextParamName, pids, nextAnd);
- if (pids.isEmpty()) {
- return new HashSet();
+ addPredicateToken(nextParamName, nextAnd);
+ if (doHaveNoResults()) {
+ return;
}
}
break;
case NUMBER:
for (List extends IQueryParameterType> nextAnd : nextParamEntry.getValue()) {
- pids = addPredicateNumber(nextParamName, pids, nextAnd);
- if (pids.isEmpty()) {
- return new HashSet();
+ addPredicateNumber(nextParamName, nextAnd);
+ if (doHaveNoResults()) {
+ return;
}
}
break;
case COMPOSITE:
for (List extends IQueryParameterType> nextAnd : nextParamEntry.getValue()) {
- pids = addPredicateComposite(nextParamDef, pids, nextAnd);
- if (pids.isEmpty()) {
- return new HashSet();
+ addPredicateComposite(nextParamDef, nextAnd);
+ if (doHaveNoResults()) {
+ return;
}
}
break;
case URI:
for (List extends IQueryParameterType> nextAnd : nextParamEntry.getValue()) {
- pids = addPredicateUri(nextParamName, pids, nextAnd);
- if (pids.isEmpty()) {
- return new HashSet();
+ addPredicateUri(nextParamName, nextAnd);
+ if (doHaveNoResults()) {
+ return;
}
}
break;
}
}
}
+
+ if (doHaveNoResults()) {
+ return;
+ }
+
}
- return pids;
+ }
+
+ private boolean doHaveNoResults() {
+ return myPids != null && myPids.isEmpty();
}
public void setType(Class extends IBaseResource> theResourceType, String theResourceName) {
@@ -1943,4 +1956,8 @@ public class SearchBuilder {
return thePredicates.toArray(new Predicate[thePredicates.size()]);
}
+ public Set doGetPids() {
+ return new HashSet(myPids);
+ }
+
}
diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/Search.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/Search.java
index d5a6f135e94..6411e970cb3 100644
--- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/Search.java
+++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/Search.java
@@ -53,13 +53,13 @@ public class Search implements Serializable {
@GeneratedValue(strategy = GenerationType.AUTO, generator="SEQ_SEARCH")
@SequenceGenerator(name="SEQ_SEARCH", sequenceName="SEQ_SEARCH")
- @Id
@Column(name = "PID")
private Long myId;
@Column(name="TOTAL_COUNT")
private int myTotalCount;
+ @Id
@Column(name="SEARCH_UUID", length=40, nullable=false)
private String myUuid;
diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/TerminologySvcImpl.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/TerminologySvcImpl.java
index 5e5a6702830..dbdd18201c5 100644
--- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/TerminologySvcImpl.java
+++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/TerminologySvcImpl.java
@@ -4,10 +4,9 @@ import java.util.HashSet;
import java.util.IdentityHashMap;
import java.util.Set;
-import javax.transaction.Transactional;
-import javax.transaction.Transactional.TxType;
-
import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.transaction.annotation.Propagation;
+import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.ValidationUtils;
import ca.uhn.fhir.context.FhirContext;
@@ -44,7 +43,7 @@ public class TerminologySvcImpl implements ITerminologySvc {
@Override
- @Transactional(value=TxType.REQUIRED)
+ @Transactional(propagation=Propagation.REQUIRED)
public void storeNewCodeSystemVersion(String theSystemUri, TermCodeSystemVersion theCodeSystem) {
ourLog.info("Storing code system");
@@ -108,7 +107,7 @@ public class TerminologySvcImpl implements ITerminologySvc {
theConceptsStack.remove(theConcept);
}
- @Transactional(value=TxType.REQUIRED)
+ @Transactional(propagation=Propagation.REQUIRED)
@Override
public Set findCodesBelow(Long theCodeSystemResourcePid, Long theCodeSystemVersionPid, String theCode) {
TermCodeSystemVersion codeSystem = myCodeSystemVersionDao.findByCodeSystemResourceAndVersion(theCodeSystemResourcePid, theCodeSystemVersionPid);
diff --git a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/dstu2/FhirResourceDaoDstu2SearchNoFtTest.java b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/dstu2/FhirResourceDaoDstu2SearchNoFtTest.java
index 8af3159e324..f63e0efea56 100644
--- a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/dstu2/FhirResourceDaoDstu2SearchNoFtTest.java
+++ b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/dstu2/FhirResourceDaoDstu2SearchNoFtTest.java
@@ -395,6 +395,60 @@ public class FhirResourceDaoDstu2SearchNoFtTest extends BaseJpaDstu2Test {
}
+ @SuppressWarnings("unused")
+ @Test
+ public void testSearchResourceReferenceMissing() {
+ IIdType oid1;
+ {
+ Organization org = new Organization();
+ org.setName("ORG1");
+ oid1 = myOrganizationDao.create(org, new ServletRequestDetails()).getId().toUnqualifiedVersionless();
+ }
+
+ IIdType pid1;
+ {
+ Patient patient = new Patient();
+ patient.addName().addFamily("FAMILY1");
+ pid1 = myPatientDao.create(patient, new ServletRequestDetails()).getId().toUnqualifiedVersionless();
+ }
+ IIdType pid2;
+ {
+ Patient patient = new Patient();
+ patient.addName().addFamily("FAMILY1");
+ patient.getManagingOrganization().setReference(oid1);
+ pid2 = myPatientDao.create(patient, new ServletRequestDetails()).getId().toUnqualifiedVersionless();
+ }
+ IIdType pid3;
+ {
+ Patient patient = new Patient();
+ patient.addName().addFamily("FAMILY2");
+ pid3 = myPatientDao.create(patient, new ServletRequestDetails()).getId().toUnqualifiedVersionless();
+ }
+ IIdType pid4;
+ {
+ Patient patient = new Patient();
+ patient.addName().addFamily("FAMILY2");
+ patient.getManagingOrganization().setReference(oid1);
+ pid4 = myPatientDao.create(patient, new ServletRequestDetails()).getId().toUnqualifiedVersionless();
+ }
+
+ SearchParameterMap params;
+
+ params = new SearchParameterMap();
+ params.add(Patient.SP_NAME, new StringParam("FAMILY1"));
+ params.add(Patient.SP_ORGANIZATION, new ReferenceParam().setMissing(true));
+ 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.add(Patient.SP_NAME, new StringParam("FAMILY9999"));
+ params.add(Patient.SP_ORGANIZATION, new ReferenceParam().setMissing(true));
+ assertThat(toUnqualifiedVersionlessIds(myPatientDao.search(params)), empty());
+ }
+
@Test
public void testSearchByIdParamOr() {
IIdType id1;
@@ -1290,6 +1344,23 @@ public class FhirResourceDaoDstu2SearchNoFtTest extends BaseJpaDstu2Test {
patient.addName().addFamily("Tester").addGiven("testSearchTokenParam2");
myPatientDao.create(patient, new ServletRequestDetails());
+ {
+ SearchParameterMap map = new SearchParameterMap();
+ map.add(Patient.SP_LANGUAGE, new TokenParam(null, "testSearchTokenParamCode", true));
+ assertEquals(0, myPatientDao.search(map).size());
+ }
+ {
+ SearchParameterMap map = new SearchParameterMap();
+ map.add(Patient.SP_LANGUAGE, new TokenParam(null, "testSearchTokenParamCode", true));
+ map.add(Patient.SP_IDENTIFIER, new IdentifierDt("urn:system", "testSearchTokenParam001"));
+ assertEquals(0, myPatientDao.search(map).size());
+ }
+ {
+ SearchParameterMap map = new SearchParameterMap();
+ map.add(Patient.SP_LANGUAGE, new TokenParam(null, "testSearchTokenParamComText", true));
+ map.add(Patient.SP_IDENTIFIER, new IdentifierDt("urn:system", "testSearchTokenParam001"));
+ assertEquals(1, myPatientDao.search(map).size());
+ }
{
SearchParameterMap map = new SearchParameterMap();
map.add(Patient.SP_IDENTIFIER, new IdentifierDt("urn:system", "testSearchTokenParam001"));
@@ -1307,11 +1378,6 @@ public class FhirResourceDaoDstu2SearchNoFtTest extends BaseJpaDstu2Test {
map.add(Patient.SP_LANGUAGE, new IdentifierDt("testSearchTokenParamSystem", "testSearchTokenParamCode"));
assertEquals(1, myPatientDao.search(map).size());
}
- {
- SearchParameterMap map = new SearchParameterMap();
- map.add(Patient.SP_LANGUAGE, new TokenParam(null, "testSearchTokenParamCode", true));
- assertEquals(0, myPatientDao.search(map).size());
- }
{
// Complete match
SearchParameterMap map = new SearchParameterMap();
@@ -1896,15 +1962,6 @@ public class FhirResourceDaoDstu2SearchNoFtTest extends BaseJpaDstu2Test {
notMissing = myPatientDao.create(patient, new ServletRequestDetails()).getId().toUnqualifiedVersionless();
}
// String Param
- {
- HashMap params = new HashMap();
- StringParam param = new StringParam();
- param.setMissing(false);
- params.put(Patient.SP_FAMILY, param);
- List patients = toUnqualifiedVersionlessIds(myPatientDao.search(params));
- assertThat(patients, not(containsInRelativeOrder(missing)));
- assertThat(patients, containsInRelativeOrder(notMissing));
- }
{
Map params = new HashMap();
StringParam param = new StringParam();
@@ -1914,8 +1971,47 @@ public class FhirResourceDaoDstu2SearchNoFtTest extends BaseJpaDstu2Test {
assertThat(patients, containsInRelativeOrder(missing));
assertThat(patients, not(containsInRelativeOrder(notMissing)));
}
+ {
+ HashMap params = new HashMap();
+ StringParam param = new StringParam();
+ param.setMissing(false);
+ params.put(Patient.SP_FAMILY, param);
+ List patients = toUnqualifiedVersionlessIds(myPatientDao.search(params));
+ assertThat(patients, not(containsInRelativeOrder(missing)));
+ assertThat(patients, containsInRelativeOrder(notMissing));
+ }
}
+ /**
+ * See #310
+ */
+ @Test
+ @Ignore
+ public void testSearchMultiMatches() {
+
+ for (int i = 0; i < 100; i++) {
+ Practitioner p = new Practitioner();
+ p.addAddress().addLine("FOO");
+ IIdType pid = myPractitionerDao.create(p, mySrd).getId().toUnqualifiedVersionless();
+
+ Patient pt = new Patient();
+ pt.addCareProvider().setReference(pid);
+ IIdType ptid = myPatientDao.create(pt, mySrd).getId().toUnqualifiedVersionless();
+
+ Observation obs = new Observation();
+ obs.setSubject(new ResourceReferenceDt(ptid));
+ myObservationDao.create(obs, mySrd);
+ }
+
+ SearchParameterMap map = new SearchParameterMap();
+ map.addInclude(new Include("Patient:careprovider"));
+ map.addRevInclude(new Include("Observation:patient"));
+
+ myPatientDao.search(map);
+
+ }
+
+
@Test
public void testSearchWithNoResults() {
Device dev = new Device();
diff --git a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/dstu2/FhirResourceDaoDstu2Test.java b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/dstu2/FhirResourceDaoDstu2Test.java
index 3e430822d0d..8101cd676eb 100644
--- a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/dstu2/FhirResourceDaoDstu2Test.java
+++ b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/dstu2/FhirResourceDaoDstu2Test.java
@@ -2186,7 +2186,7 @@ public class FhirResourceDaoDstu2Test extends BaseJpaDstu2Test {
map.add(Organization.SP_NAME, new StringParam("X" + methodName + "X"));
map.setRevIncludes(Collections.singleton(Patient.INCLUDE_ORGANIZATION));
IBundleProvider resultsP = myOrganizationDao.search(map);
- assertEquals(2, resultsP.size());
+ assertEquals(1, resultsP.size());
List results = resultsP.getResources(0, resultsP.size());
assertEquals(2, results.size());
diff --git a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/dstu3/FhirResourceDaoDstu3Test.java b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/dstu3/FhirResourceDaoDstu3Test.java
index dae0984d07c..face966346f 100644
--- a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/dstu3/FhirResourceDaoDstu3Test.java
+++ b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/dstu3/FhirResourceDaoDstu3Test.java
@@ -2250,7 +2250,7 @@ public class FhirResourceDaoDstu3Test extends BaseJpaDstu3Test {
map.add(Organization.SP_NAME, new StringParam("X" + methodName + "X"));
map.setRevIncludes(Collections.singleton(Patient.INCLUDE_ORGANIZATION));
IBundleProvider resultsP = myOrganizationDao.search(map);
- assertEquals(2, resultsP.size());
+ assertEquals(1, resultsP.size());
List results = resultsP.getResources(0, resultsP.size());
assertEquals(2, results.size());
diff --git a/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/testmodel/IdentifierDt.java b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/testmodel/IdentifierDt.java
index b3a32d08ebf..1e0d1a80941 100644
--- a/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/testmodel/IdentifierDt.java
+++ b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/testmodel/IdentifierDt.java
@@ -424,7 +424,7 @@ public class IdentifierDt
*/
@Deprecated
@Override
- public void setMissing(Boolean theMissing) {
+ public IQueryParameterType setMissing(Boolean theMissing) {
throw new UnsupportedOperationException("get/setMissing is not supported in StringDt. Use {@link StringParam} instead if you need this functionality");
}
diff --git a/pom.xml b/pom.xml
index 6c86e76ede7..8012bb44495 100644
--- a/pom.xml
+++ b/pom.xml
@@ -846,6 +846,10 @@
org.apache.maven.scm
maven-scm-api
+
+ org.apache.maven.doxia
+ doxia-core
+
org.apache.maven.doxia
doxia-module-markdown
@@ -1263,6 +1267,11 @@
maven-scm-api
1.9.4
+
+ org.apache.maven.doxia
+ doxia-core
+ 1.7
+
org.apache.maven.doxia
doxia-module-markdown
diff --git a/src/site/site.xml b/src/site/site.xml
index 37b1bf3d54f..6537101dd2a 100644
--- a/src/site/site.xml
+++ b/src/site/site.xml
@@ -32,14 +32,13 @@
+
-
-
-
-
-
-
+
+
+
+
+
@@ -47,12 +46,11 @@
HAPI stylesheet comes after because it overwrites the Syntax Highlighter
font size
-->
-
+ ]]>