More work on perf

This commit is contained in:
James Agnew 2017-04-06 22:23:20 -04:00
parent f48d0d677b
commit 660c2bde72
12 changed files with 148 additions and 242 deletions

View File

@ -3,19 +3,30 @@ root = true
[*] [*]
end_of_line = lf end_of_line = lf
insert_final_newline = true insert_final_newline = true
tab_width = 3
indent_size = 3
[*.java] [*.java]
charset = utf-8 charset = utf-8
indent_style = tab indent_style = tab
tab_width = 3
indent_size = 3
[*.xml] [*.xml]
charset = utf-8 charset = utf-8
indent_style = tab indent_style = tab
tab_width = 3
indent_size = 3
[*.json] [*.json]
charset = utf-8 charset = utf-8
indent_style = tab indent_style = tab
tab_width = 3
indent_size = 3
[*.vm] [*.vm]
charset = utf-8 charset = utf-8
indent_style = tab indent_style = tab
tab_width = 3
indent_size = 3

View File

@ -3,6 +3,8 @@ package ca.uhn.fhir.model.api;
import static org.apache.commons.lang3.StringUtils.isBlank; import static org.apache.commons.lang3.StringUtils.isBlank;
import static org.apache.commons.lang3.StringUtils.isNotBlank; import static org.apache.commons.lang3.StringUtils.isNotBlank;
import java.io.Serializable;
import org.apache.commons.lang3.builder.ToStringBuilder; import org.apache.commons.lang3.builder.ToStringBuilder;
/* /*
@ -33,8 +35,10 @@ import org.apache.commons.lang3.builder.ToStringBuilder;
* upgrading servers. * upgrading servers.
* </p> * </p>
*/ */
public class Include { public class Include implements Serializable {
private static final long serialVersionUID = 1L;
private final boolean myImmutable; private final boolean myImmutable;
private boolean myRecurse; private boolean myRecurse;
private String myValue; private String myValue;

View File

@ -104,9 +104,9 @@ public class TagList implements Set<Tag>, Serializable, IBase {
* Add a new tag instance * Add a new tag instance
* *
* @param theScheme * @param theScheme
* The tag scheme * The tag scheme (the system)
* @param theTerm * @param theTerm
* The tag term * The tag term (the code)
* @return Returns the newly created tag instance. Note that the tag is added to the list by this method, so you * @return Returns the newly created tag instance. Note that the tag is added to the list by this method, so you
* generally do not need to interact directly with the added tag. * generally do not need to interact directly with the added tag.
*/ */

View File

@ -1235,6 +1235,7 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
Set<ResourceIndexedSearchParamCoords> coordsParams = null; Set<ResourceIndexedSearchParamCoords> coordsParams = null;
Set<ResourceLink> links = null; Set<ResourceLink> links = null;
Set<String> populatedResourceLinkParameters = null;
if (theDeletedTimestampOrNull != null) { if (theDeletedTimestampOrNull != null) {
stringParams = Collections.emptySet(); stringParams = Collections.emptySet();
@ -1334,7 +1335,7 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
} }
links = new HashSet<ResourceLink>(); links = new HashSet<ResourceLink>();
Set<String> populatedResourceLinkParameters = extractResourceLinks(theEntity, theResource, links, theUpdateTime); populatedResourceLinkParameters = extractResourceLinks(theEntity, theResource, links, theUpdateTime);
/* /*
* If the existing resource already has links and those match links we still want, use them instead of removing them and re adding them * If the existing resource already has links and those match links we still want, use them instead of removing them and re adding them
@ -1374,28 +1375,6 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
theEntity.setIndexStatus(INDEX_STATUS_INDEXED); theEntity.setIndexStatus(INDEX_STATUS_INDEXED);
populateFullTextFields(theResource, theEntity); populateFullTextFields(theResource, theEntity);
/*
* Update the "search param present" table which is used for the
* ?foo:missing=true queries
*/
Map<String, Boolean> presentSearchParams = new HashMap<String, Boolean>();
for (String nextKey : populatedResourceLinkParameters) {
presentSearchParams.put(nextKey, Boolean.TRUE);
}
updateSearchParamPresent(presentSearchParams, stringParams);
updateSearchParamPresent(presentSearchParams, tokenParams);
updateSearchParamPresent(presentSearchParams, numberParams);
updateSearchParamPresent(presentSearchParams, quantityParams);
updateSearchParamPresent(presentSearchParams, dateParams);
updateSearchParamPresent(presentSearchParams, uriParams);
updateSearchParamPresent(presentSearchParams, coordsParams);
Set<String> activeSearchParamNames = mySearchParamRegistry.getActiveSearchParams(theEntity.getResourceType()).keySet();
for (String nextSpName : activeSearchParamNames) {
if (!presentSearchParams.containsKey(nextSpName)) {
presentSearchParams.put(nextSpName, Boolean.FALSE);
}
}
mySearchParamPresenceSvc.updatePresence(theEntity, presentSearchParams);
} else { } else {
@ -1426,6 +1405,31 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
postUpdate(theEntity, (T) theResource); postUpdate(theEntity, (T) theResource);
} }
/*
* Update the "search param present" table which is used for the
* ?foo:missing=true queries
*/
if (thePerformIndexing) {
Map<String, Boolean> presentSearchParams = new HashMap<String, Boolean>();
for (String nextKey : populatedResourceLinkParameters) {
presentSearchParams.put(nextKey, Boolean.TRUE);
}
updateSearchParamPresent(presentSearchParams, stringParams);
updateSearchParamPresent(presentSearchParams, tokenParams);
updateSearchParamPresent(presentSearchParams, numberParams);
updateSearchParamPresent(presentSearchParams, quantityParams);
updateSearchParamPresent(presentSearchParams, dateParams);
updateSearchParamPresent(presentSearchParams, uriParams);
updateSearchParamPresent(presentSearchParams, coordsParams);
Set<String> activeSearchParamNames = mySearchParamRegistry.getActiveSearchParams(theEntity.getResourceType()).keySet();
for (String nextSpName : activeSearchParamNames) {
if (!presentSearchParams.containsKey(nextSpName)) {
presentSearchParams.put(nextSpName, Boolean.FALSE);
}
}
mySearchParamPresenceSvc.updatePresence(theEntity, presentSearchParams);
}
/* /*
* Create history entry * Create history entry
*/ */

View File

@ -88,8 +88,6 @@ public class SearchBuilder {
private EntityManager myEntityManager; private EntityManager myEntityManager;
private IForcedIdDao myForcedIdDao; private IForcedIdDao myForcedIdDao;
private SearchParameterMap myParams; private SearchParameterMap myParams;
private Collection<Long> myPids;
private PlatformTransactionManager myPlatformTransactionManager;
private IResourceIndexedSearchParamUriDao myResourceIndexedSearchParamUriDao; private IResourceIndexedSearchParamUriDao myResourceIndexedSearchParamUriDao;
private String myResourceName; private String myResourceName;
private Class<? extends IBaseResource> myResourceType; private Class<? extends IBaseResource> myResourceType;
@ -97,16 +95,12 @@ public class SearchBuilder {
private Search mySearchEntity; private Search mySearchEntity;
private ISearchResultDao mySearchResultDao; private ISearchResultDao mySearchResultDao;
private ISearchParamRegistry mySearchParamRegistry; private ISearchParamRegistry mySearchParamRegistry;
private IHapiTerminologySvc myTerminologySvc; private IHapiTerminologySvc myTerminologySvc;
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 CriteriaQuery<Tuple> myResourceTableQuery;
private PlatformTransactionManager myPlatformTransactionManager;
public SearchBuilder(FhirContext theFhirContext, EntityManager theEntityManager, PlatformTransactionManager thePlatformTransactionManager, IFulltextSearchSvc theFulltextSearchSvc, public SearchBuilder(FhirContext theFhirContext, EntityManager theEntityManager, PlatformTransactionManager thePlatformTransactionManager, IFulltextSearchSvc theFulltextSearchSvc,
ISearchResultDao theSearchResultDao, BaseHapiFhirDao<?> theDao, ISearchResultDao theSearchResultDao, BaseHapiFhirDao<?> theDao,
@ -158,8 +152,8 @@ public class SearchBuilder {
private void addPredicateDate(String theParamName, List<? extends IQueryParameterType> theList) { private void addPredicateDate(String theParamName, List<? extends IQueryParameterType> theList) {
if (Boolean.TRUE.equals(theList.get(0).getMissing())) { if (theList.get(0).getMissing() != null) {
addPredicateParamMissing("myParamsDate", theParamName, ResourceIndexedSearchParamDate.class); addPredicateParamMissing(theParamName, theList.get(0).getMissing());
return; return;
} }
@ -167,10 +161,6 @@ public class SearchBuilder {
List<Predicate> codePredicates = new ArrayList<Predicate>(); List<Predicate> codePredicates = new ArrayList<Predicate>();
for (IQueryParameterType nextOr : theList) { for (IQueryParameterType nextOr : theList) {
if (addPredicateMissingFalseIfPresent(myBuilder, theParamName, join, codePredicates, nextOr)) {
continue;
}
IQueryParameterType params = nextOr; IQueryParameterType params = nextOr;
Predicate p = createPredicateDate(myBuilder, join, params); Predicate p = createPredicateDate(myBuilder, join, params);
codePredicates.add(p); codePredicates.add(p);
@ -304,40 +294,10 @@ public class SearchBuilder {
return; return;
} }
private boolean addPredicateMissingFalseIfPresent(CriteriaBuilder theBuilder, String theParamName, From<?, ? extends BaseResourceIndexedSearchParam> from, List<Predicate> codePredicates,
IQueryParameterType nextOr) {
boolean missingFalse = false;
if (nextOr.getMissing() != null) {
if (nextOr.getMissing().booleanValue() == true) {
throw new InvalidRequestException(myContext.getLocalizer().getMessage(BaseHapiFhirResourceDao.class, "multipleParamsWithSameNameOneIsMissingTrue", theParamName));
}
Predicate singleCode = from.get("myId").isNotNull();
Predicate name = theBuilder.equal(from.get("myParamName"), theParamName);
codePredicates.add(theBuilder.and(name, singleCode));
missingFalse = true;
}
return missingFalse;
}
private boolean addPredicateMissingFalseIfPresentForResourceLink(CriteriaBuilder theBuilder, String theParamName, From<?,? extends ResourceLink> from, List<Predicate> codePredicates,
IQueryParameterType nextOr) {
boolean missingFalse = false;
if (nextOr.getMissing() != null) {
if (nextOr.getMissing().booleanValue() == true) {
throw new InvalidRequestException(myContext.getLocalizer().getMessage(BaseHapiFhirResourceDao.class, "multipleParamsWithSameNameOneIsMissingTrue", theParamName));
}
Predicate singleCode = from.get("mySourceResource").isNotNull();
Predicate name = createResourceLinkPathPredicate(theParamName, from);
codePredicates.add(theBuilder.and(name, singleCode));
missingFalse = true;
}
return missingFalse;
}
private void addPredicateNumber(String theParamName, List<? extends IQueryParameterType> theList) { private void addPredicateNumber(String theParamName, List<? extends IQueryParameterType> theList) {
if (Boolean.TRUE.equals(theList.get(0).getMissing())) { if (theList.get(0).getMissing() != null) {
addPredicateParamMissing("myParamsNumber", theParamName, ResourceIndexedSearchParamNumber.class); addPredicateParamMissing(theParamName, theList.get(0).getMissing());
return; return;
} }
@ -347,10 +307,6 @@ public class SearchBuilder {
for (IQueryParameterType nextOr : theList) { for (IQueryParameterType nextOr : theList) {
IQueryParameterType params = nextOr; IQueryParameterType params = nextOr;
if (addPredicateMissingFalseIfPresent(myBuilder, theParamName, join, codePredicates, nextOr)) {
continue;
}
if (params instanceof NumberParam) { if (params instanceof NumberParam) {
NumberParam param = (NumberParam) params; NumberParam param = (NumberParam) params;
@ -376,62 +332,18 @@ public class SearchBuilder {
myPredicates.add(myBuilder.or(toArray(codePredicates))); myPredicates.add(myBuilder.or(toArray(codePredicates)));
} }
private void addPredicateParamMissing(String joinName, String theParamName, Class<? extends BaseResourceIndexedSearchParam> theParamTable) { private void addPredicateParamMissing(String theParamName, boolean theMissing) {
CriteriaBuilder builder = myEntityManager.getCriteriaBuilder(); Join<ResourceTable, SearchParamPresent> paramPresentJoin = myResourceTableRoot.join("mySearchParamPresents", JoinType.LEFT);
CriteriaQuery<Long> cq = builder.createQuery(Long.class); Join<SearchParamPresent, SearchParam> paramJoin = paramPresentJoin.join("mySearchParam", JoinType.LEFT);
Root<ResourceTable> from = cq.from(ResourceTable.class);
cq.select(from.get("myId").as(Long.class));
Subquery<Long> subQ = cq.subquery(Long.class); myPredicates.add(myBuilder.equal(paramJoin.get("myResourceName"), myResourceName));
Root<? extends BaseResourceIndexedSearchParam> subQfrom = subQ.from(theParamTable); myPredicates.add(myBuilder.equal(paramJoin.get("myParamName"), theParamName));
subQ.select(subQfrom.get("myResourcePid").as(Long.class)); myPredicates.add(myBuilder.equal(paramPresentJoin.get("myPresent"), !theMissing));
Predicate subQname = builder.equal(subQfrom.get("myParamName"), theParamName);
Predicate subQtype = builder.equal(subQfrom.get("myResourceType"), myResourceName);
subQ.where(builder.and(subQtype, subQname));
List<Predicate> predicates = new ArrayList<Predicate>();
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")));
createPredicateResourceId(builder, cq, predicates, from.get("myId").as(Long.class));
cq.where(builder.and(toArray(predicates)));
ourLog.info("Adding :missing qualifier for parameter '{}'", theParamName);
TypedQuery<Long> q = myEntityManager.createQuery(cq);
doSetPids(q.getResultList());
}
private void addPredicateParamMissingResourceLink(String joinName, String theParamName) {
CriteriaBuilder builder = myEntityManager.getCriteriaBuilder();
CriteriaQuery<Long> cq = builder.createQuery(Long.class);
Root<ResourceTable> from = cq.from(ResourceTable.class);
cq.select(from.get("myId").as(Long.class));
Subquery<Long> subQ = cq.subquery(Long.class);
Root<ResourceLink> subQfrom = subQ.from(ResourceLink.class);
subQ.select(subQfrom.get("mySourceResourcePid").as(Long.class));
// subQ.where(builder.equal(subQfrom.get("myParamName"), theParamName));
Predicate path = createResourceLinkPathPredicate(theParamName, subQfrom);
subQ.where(path);
List<Predicate> predicates = new ArrayList<Predicate>();
createPredicateResourceId(builder, cq, 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));
cq.where(builder.and(toArray(predicates)));
TypedQuery<Long> q = myEntityManager.createQuery(cq);
List<Long> resultList = q.getResultList();
doSetPids(new HashSet<Long>(resultList));
} }
private void addPredicateQuantity(String theParamName, List<? extends IQueryParameterType> theList) { private void addPredicateQuantity(String theParamName, List<? extends IQueryParameterType> theList) {
if (Boolean.TRUE.equals(theList.get(0).getMissing())) { if (theList.get(0).getMissing() != null) {
addPredicateParamMissing("myParamsQuantity", theParamName, ResourceIndexedSearchParamQuantity.class); addPredicateParamMissing(theParamName, theList.get(0).getMissing());
return; return;
} }
@ -439,9 +351,6 @@ public class SearchBuilder {
List<Predicate> codePredicates = new ArrayList<Predicate>(); List<Predicate> codePredicates = new ArrayList<Predicate>();
for (IQueryParameterType nextOr : theList) { for (IQueryParameterType nextOr : theList) {
if (addPredicateMissingFalseIfPresent(myBuilder, theParamName, join, codePredicates, nextOr)) {
continue;
}
Predicate singleCode = createPredicateQuantity(myBuilder, join, nextOr); Predicate singleCode = createPredicateQuantity(myBuilder, join, nextOr);
codePredicates.add(singleCode); codePredicates.add(singleCode);
@ -453,8 +362,8 @@ public class SearchBuilder {
private void addPredicateReference(String theParamName, List<? extends IQueryParameterType> theList) { private void addPredicateReference(String theParamName, List<? extends IQueryParameterType> theList) {
assert theParamName.contains(".") == false; assert theParamName.contains(".") == false;
if (Boolean.TRUE.equals(theList.get(0).getMissing())) { if (theList.get(0).getMissing() != null) {
addPredicateParamMissingResourceLink("myResourceLinks", theParamName); addPredicateParamMissing(theParamName, theList.get(0).getMissing());
return; return;
} }
@ -465,10 +374,6 @@ public class SearchBuilder {
for (IQueryParameterType nextOr : theList) { for (IQueryParameterType nextOr : theList) {
IQueryParameterType params = nextOr; IQueryParameterType params = nextOr;
if (addPredicateMissingFalseIfPresentForResourceLink(myBuilder, theParamName, join, codePredicates, nextOr)) {
continue;
}
if (params instanceof ReferenceParam) { if (params instanceof ReferenceParam) {
ReferenceParam ref = (ReferenceParam) params; ReferenceParam ref = (ReferenceParam) params;
@ -585,34 +490,34 @@ public class SearchBuilder {
} }
foundChainMatch = true; foundChainMatch = true;
// Set<Long> pids = dao.searchForIds(chain, chainValue); // Set<Long> pids = dao.searchForIds(chain, chainValue);
Subquery<Long> subQ = myResourceTableQuery.subquery(Long.class); Subquery<Long> subQ = myResourceTableQuery.subquery(Long.class);
Root<ResourceTable> subQfrom = subQ.from(ResourceTable.class); Root<ResourceTable> subQfrom = subQ.from(ResourceTable.class);
subQ.select(subQfrom.get("myId").as(Long.class)); subQ.select(subQfrom.get("myId").as(Long.class));
List<List<? extends IQueryParameterType>> andOrParams = new ArrayList<List<? extends IQueryParameterType>>(); List<List<? extends IQueryParameterType>> andOrParams = new ArrayList<List<? extends IQueryParameterType>>();
andOrParams.add(Collections.singletonList(chainValue)); andOrParams.add(Collections.singletonList(chainValue));
/* /*
* We're doing a chain call, so push the current query root * We're doing a chain call, so push the current query root
* and predicate list down and put new ones at the top of the * and predicate list down and put new ones at the top of the
* stack and run a subuery * stack and run a subuery
*/ */
Root<ResourceTable> stackRoot = myResourceTableRoot; Root<ResourceTable> stackRoot = myResourceTableRoot;
ArrayList<Predicate> stackPredicates = myPredicates; ArrayList<Predicate> stackPredicates = myPredicates;
myResourceTableRoot = subQfrom; myResourceTableRoot = subQfrom;
myPredicates = new ArrayList<Predicate>(); myPredicates = new ArrayList<Predicate>();
searchForIdsWithAndOr(chain, andOrParams); searchForIdsWithAndOr(chain, andOrParams);
subQ.where(toArray(myPredicates)); subQ.where(toArray(myPredicates));
/* /*
* Pop the old query root and predicate list back * Pop the old query root and predicate list back
*/ */
myResourceTableRoot = stackRoot; myResourceTableRoot = stackRoot;
myPredicates = stackPredicates; myPredicates = stackPredicates;
Predicate eq = join.get("myTargetResourcePid").in(subQ); Predicate eq = join.get("myTargetResourcePid").in(subQ);
codePredicates.add(eq); codePredicates.add(eq);
@ -633,20 +538,16 @@ public class SearchBuilder {
} }
private void addPredicateString(String theParamName, List<? extends IQueryParameterType> theList) { private void addPredicateString(String theParamName, List<? extends IQueryParameterType> theList) {
if (Boolean.TRUE.equals(theList.get(0).getMissing())) { if (theList.get(0).getMissing() != null) {
addPredicateParamMissing("myParamsString", theParamName, ResourceIndexedSearchParamString.class); addPredicateParamMissing(theParamName, theList.get(0).getMissing());
return; return;
} }
Join<ResourceTable, ResourceIndexedSearchParamString> join = myResourceTableRoot.join("myParamsString", JoinType.LEFT); Join<ResourceTable, ResourceIndexedSearchParamString> join = myResourceTableRoot.join("myParamsString", JoinType.LEFT);
List<Predicate> codePredicates = new ArrayList<Predicate>(); List<Predicate> codePredicates = new ArrayList<Predicate>();
for (IQueryParameterType nextOr : theList) { for (IQueryParameterType nextOr : theList) {
IQueryParameterType theParameter = nextOr; IQueryParameterType theParameter = nextOr;
if (addPredicateMissingFalseIfPresent(myBuilder, theParamName, join, codePredicates, nextOr)) {
continue;
}
Predicate singleCode = createPredicateString(theParameter, theParamName, myBuilder, join); Predicate singleCode = createPredicateString(theParameter, theParamName, myBuilder, join);
codePredicates.add(singleCode); codePredicates.add(singleCode);
} }
@ -775,7 +676,7 @@ public class SearchBuilder {
Join<ResourceTable, ResourceTag> tagJoin = myResourceTableRoot.join("myTags", JoinType.LEFT); Join<ResourceTable, ResourceTag> tagJoin = myResourceTableRoot.join("myTags", JoinType.LEFT);
From<ResourceTag, TagDefinition> defJoin = tagJoin.join("myTag"); From<ResourceTag, TagDefinition> defJoin = tagJoin.join("myTag");
List<Predicate> orPredicates = createPredicateTagList(defJoin, myBuilder, tagType, tokens); List<Predicate> orPredicates = createPredicateTagList(defJoin, myBuilder, tagType, tokens);
myPredicates.add(myBuilder.or(toArray(orPredicates))); myPredicates.add(myBuilder.or(toArray(orPredicates)));
@ -785,8 +686,8 @@ public class SearchBuilder {
private void addPredicateToken(String theParamName, List<? extends IQueryParameterType> theList) { private void addPredicateToken(String theParamName, List<? extends IQueryParameterType> theList) {
if (Boolean.TRUE.equals(theList.get(0).getMissing())) { if (theList.get(0).getMissing() != null) {
addPredicateParamMissing("myParamsToken", theParamName, ResourceIndexedSearchParamToken.class); addPredicateParamMissing(theParamName, theList.get(0).getMissing());
return; return;
} }
@ -794,9 +695,6 @@ public class SearchBuilder {
List<Predicate> codePredicates = new ArrayList<Predicate>(); List<Predicate> codePredicates = new ArrayList<Predicate>();
for (IQueryParameterType nextOr : theList) { for (IQueryParameterType nextOr : theList) {
if (addPredicateMissingFalseIfPresent(myBuilder, theParamName, join, codePredicates, nextOr)) {
continue;
}
if (nextOr instanceof TokenParam) { if (nextOr instanceof TokenParam) {
TokenParam id = (TokenParam) nextOr; TokenParam id = (TokenParam) nextOr;
@ -822,8 +720,8 @@ public class SearchBuilder {
} }
private void addPredicateUri(String theParamName, List<? extends IQueryParameterType> theList) { private void addPredicateUri(String theParamName, List<? extends IQueryParameterType> theList) {
if (Boolean.TRUE.equals(theList.get(0).getMissing())) { if (theList.get(0).getMissing() != null) {
addPredicateParamMissing("myParamsUri", theParamName, ResourceIndexedSearchParamUri.class); addPredicateParamMissing(theParamName, theList.get(0).getMissing());
return; return;
} }
@ -833,10 +731,6 @@ public class SearchBuilder {
for (IQueryParameterType nextOr : theList) { for (IQueryParameterType nextOr : theList) {
IQueryParameterType params = nextOr; IQueryParameterType params = nextOr;
if (addPredicateMissingFalseIfPresent(myBuilder, theParamName, join, codePredicates, nextOr)) {
continue;
}
if (params instanceof UriParam) { if (params instanceof UriParam) {
UriParam param = (UriParam) params; UriParam param = (UriParam) params;
@ -1265,7 +1159,7 @@ public class SearchBuilder {
return singleCode; return singleCode;
} }
private Predicate createResourceLinkPathPredicate(String theParamName, From<?,? extends ResourceLink> from) { private Predicate createResourceLinkPathPredicate(String theParamName, From<?, ? extends ResourceLink> from) {
return createResourceLinkPathPredicate(myCallingDao, myContext, theParamName, from, myResourceType); return createResourceLinkPathPredicate(myCallingDao, myContext, theParamName, from, myResourceType);
} }
@ -1368,10 +1262,6 @@ public class SearchBuilder {
thePredicates.add(theBuilder.equal(stringJoin.get("myParamName"), theSort.getParamName())); thePredicates.add(theBuilder.equal(stringJoin.get("myParamName"), theSort.getParamName()));
} }
// Predicate p = theBuilder.equal(stringJoin.get("myParamName"), theSort.getParamName());
// Predicate pn = theBuilder.isNull(stringJoin.get("myParamName"));
// thePredicates.add(theBuilder.or(p, pn));
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(stringJoin.get(next)));
@ -1565,30 +1455,30 @@ public class SearchBuilder {
mySearchEntity.setSearchType(myParams.getEverythingMode() != null ? SearchTypeEnum.EVERYTHING : SearchTypeEnum.SEARCH); mySearchEntity.setSearchType(myParams.getEverythingMode() != null ? SearchTypeEnum.EVERYTHING : SearchTypeEnum.SEARCH);
mySearchEntity.setLastUpdated(myParams.getLastUpdated()); mySearchEntity.setLastUpdated(myParams.getLastUpdated());
mySearchEntity.setResourceType(myResourceName); mySearchEntity.setResourceType(myResourceName);
for (Include next : myParams.getIncludes()) { for (Include next : myParams.getIncludes()) {
mySearchEntity.getIncludes().add(new SearchInclude(mySearchEntity, next.getValue(), false, next.isRecurse())); mySearchEntity.getIncludes().add(new SearchInclude(mySearchEntity, next.getValue(), false, next.isRecurse()));
} }
for (Include next : myParams.getRevIncludes()) { for (Include next : myParams.getRevIncludes()) {
mySearchEntity.getIncludes().add(new SearchInclude(mySearchEntity, next.getValue(), true, next.isRecurse())); mySearchEntity.getIncludes().add(new SearchInclude(mySearchEntity, next.getValue(), true, next.isRecurse()));
} }
List<Long> firstPage = loadSearchPage(theParams, 0, 999); List<Long> firstPage = loadSearchPage(theParams, 0, 999);
mySearchEntity.setTotalCount(firstPage.size()); mySearchEntity.setTotalCount(firstPage.size());
myEntityManager.persist(mySearchEntity); myEntityManager.persist(mySearchEntity);
for (SearchInclude next : mySearchEntity.getIncludes()) { for (SearchInclude next : mySearchEntity.getIncludes()) {
myEntityManager.persist(next); myEntityManager.persist(next);
} }
IBundleProvider retVal = doReturnProvider(); IBundleProvider retVal = doReturnProvider();
ourLog.info("Search initial phase completed in {}ms", w); ourLog.info("Search initial phase completed in {}ms", w);
return retVal; return retVal;
} }
public List<Long> loadSearchPage(SearchParameterMap theParams, int theFromIndex, int theToIndex) { public List<Long> loadSearchPage(SearchParameterMap theParams, int theFromIndex, int theToIndex) {
if (myFulltextSearchSvc == null) { if (myFulltextSearchSvc == null) {
if (theParams.containsKey(Constants.PARAM_TEXT)) { if (theParams.containsKey(Constants.PARAM_TEXT)) {
throw new InvalidRequestException("Fulltext search is not enabled on this service, can not process parameter: " + Constants.PARAM_TEXT); throw new InvalidRequestException("Fulltext search is not enabled on this service, can not process parameter: " + Constants.PARAM_TEXT);
@ -1613,28 +1503,28 @@ public class SearchBuilder {
myPredicates = new ArrayList<Predicate>(); myPredicates = new ArrayList<Predicate>();
myPredicates.add(myBuilder.equal(myResourceTableRoot.get("myResourceType"), myResourceName)); myPredicates.add(myBuilder.equal(myResourceTableRoot.get("myResourceType"), myResourceName));
myPredicates.add(myBuilder.isNull(myResourceTableRoot.get("myDeleted"))); myPredicates.add(myBuilder.isNull(myResourceTableRoot.get("myDeleted")));
DateRangeParam lu = theParams.getLastUpdated(); DateRangeParam lu = theParams.getLastUpdated();
List<Predicate> lastUpdatedPredicates = createLastUpdatedPredicates(lu, myBuilder, myResourceTableRoot); List<Predicate> lastUpdatedPredicates = createLastUpdatedPredicates(lu, myBuilder, myResourceTableRoot);
myPredicates.addAll(lastUpdatedPredicates); myPredicates.addAll(lastUpdatedPredicates);
searchForIdsWithAndOr(theParams); searchForIdsWithAndOr(theParams);
myResourceTableQuery.where(myBuilder.and(SearchBuilder.toArray(myPredicates))); myResourceTableQuery.where(myBuilder.and(SearchBuilder.toArray(myPredicates)));
myResourceTableQuery.multiselect(myResourceTableRoot.get("myId").as(Long.class)); myResourceTableQuery.multiselect(myResourceTableRoot.get("myId").as(Long.class));
TypedQuery<Tuple> query = myEntityManager.createQuery(myResourceTableQuery); TypedQuery<Tuple> query = myEntityManager.createQuery(myResourceTableQuery);
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()) { for (Tuple next : query.getResultList()) {
pids.add(next.get(0, Long.class)); pids.add(next.get(0, Long.class));
} }
return pids; return pids;
} }
public IBundleProvider loadPage(SearchParameterMap theParams, int theFromIndex, int theToIndex) { public IBundleProvider loadPage(SearchParameterMap theParams, int theFromIndex, int theToIndex) {
StopWatch sw = new StopWatch(); StopWatch sw = new StopWatch();
DateRangeParam lu = theParams.getLastUpdated(); DateRangeParam lu = theParams.getLastUpdated();
@ -1702,9 +1592,8 @@ public class SearchBuilder {
} }
} }
if (!theParams.isEmpty()) { if (!theParams.isEmpty()) {
// searchForIdsWithAndOr(theParams, lu); // searchForIdsWithAndOr(theParams, lu);
} }
} }
@ -1729,7 +1618,7 @@ public class SearchBuilder {
return doReturnProvider(); return doReturnProvider();
} }
private void searchForIdsWithAndOr(SearchParameterMap theParams) { private void searchForIdsWithAndOr(SearchParameterMap theParams) {
SearchParameterMap params = theParams; SearchParameterMap params = theParams;
if (params == null) { if (params == null) {
@ -1810,7 +1699,7 @@ public class SearchBuilder {
addPredicateUri(nextParamName, nextAnd); addPredicateUri(nextParamName, nextAnd);
} }
break; break;
case HAS: case HAS:
// should not happen // should not happen
break; break;
} }
@ -1834,21 +1723,20 @@ public class SearchBuilder {
orPids.add(entity.getId()); orPids.add(entity.getId());
} }
} catch (ResourceNotFoundException e) { } catch (ResourceNotFoundException e) {
/* /*
* This isn't an error, just means no result found * This isn't an error, just means no result found
* that matches the ID the client provided * that matches the ID the client provided
*/ */
} }
} }
} }
if (orPids.size() > 0) {
Predicate nextPredicate = myResourceTableRoot.get("myId").as(Long.class).in(orPids);
myPredicates.add(nextPredicate);
}
} }
if (orPids.size() > 0) {
Predicate nextPredicate = myResourceTableRoot.get("myId").as(Long.class).in(orPids);
myPredicates.add(nextPredicate);
}
} }
} }
@ -1942,7 +1830,7 @@ public class SearchBuilder {
return likeExpression.replace("%", "[%]") + "%"; return likeExpression.replace("%", "[%]") + "%";
} }
private static Predicate createResourceLinkPathPredicate(IDao theCallingDao, FhirContext theContext, String theParamName, From<?,? extends ResourceLink> from, private static Predicate createResourceLinkPathPredicate(IDao theCallingDao, FhirContext theContext, String theParamName, From<?, ? extends ResourceLink> from,
Class<? extends IBaseResource> resourceType) { Class<? extends IBaseResource> resourceType) {
RuntimeResourceDefinition resourceDef = theContext.getResourceDefinition(resourceType); RuntimeResourceDefinition resourceDef = theContext.getResourceDefinition(resourceType);
RuntimeSearchParam param = theCallingDao.getSearchParamByName(resourceDef, theParamName); RuntimeSearchParam param = theCallingDao.getSearchParamByName(resourceDef, theParamName);

View File

@ -32,7 +32,7 @@ import ca.uhn.fhir.jpa.entity.SearchParamPresent;
public interface ISearchParamPresentDao extends JpaRepository<SearchParamPresent, Long> { public interface ISearchParamPresentDao extends JpaRepository<SearchParamPresent, Long> {
@Query("SELECT s FROM SearchParamPresent s WHERE s.myResourceTable = :res") @Query("SELECT s FROM SearchParamPresent s WHERE s.myResource = :res")
public Collection<SearchParamPresent> findAllForResource(@Param("res") ResourceTable theResource); public Collection<SearchParamPresent> findAllForResource(@Param("res") ResourceTable theResource);
} }

View File

@ -236,6 +236,9 @@ public class ResourceTable extends BaseHasResource implements Serializable {
@OneToMany(mappedBy = "myResource", cascade = CascadeType.ALL, fetch = FetchType.LAZY, orphanRemoval = true) @OneToMany(mappedBy = "myResource", cascade = CascadeType.ALL, fetch = FetchType.LAZY, orphanRemoval = true)
private Set<ResourceTag> myTags; private Set<ResourceTag> myTags;
@OneToMany(mappedBy = "myResource", cascade = CascadeType.ALL, fetch = FetchType.LAZY, orphanRemoval = true)
private Collection<SearchParamPresent> mySearchParamPresents;
@Column(name = "RES_VER") @Column(name = "RES_VER")
private long myVersion; private long myVersion;

View File

@ -11,7 +11,7 @@ public class SearchParam {
@Id @Id
@SequenceGenerator(name = "SEQ_SEARCHPARM_ID", sequenceName = "SEQ_SEARCHPARM_ID") @SequenceGenerator(name = "SEQ_SEARCHPARM_ID", sequenceName = "SEQ_SEARCHPARM_ID")
@GeneratedValue(strategy = GenerationType.AUTO, generator = "SEQ_SEARCHPARM_ID") @GeneratedValue(strategy = GenerationType.AUTO, generator = "SEQ_SEARCHPARM_ID")
@Column(name = "RES_ID") @Column(name = "PID")
private Long myId; private Long myId;
@Column(name="PARAM_NAME", length=BaseResourceIndexedSearchParam.MAX_SP_NAME, nullable=false, updatable=false) @Column(name="PARAM_NAME", length=BaseResourceIndexedSearchParam.MAX_SP_NAME, nullable=false, updatable=false)

View File

@ -25,14 +25,14 @@ public class SearchParamPresent implements Serializable {
@ManyToOne() @ManyToOne()
@JoinColumn(name = "RES_ID", referencedColumnName = "RES_ID", nullable = false, foreignKey = @ForeignKey(name = "FK_RESPARMPRES_RESID")) @JoinColumn(name = "RES_ID", referencedColumnName = "RES_ID", nullable = false, foreignKey = @ForeignKey(name = "FK_RESPARMPRES_RESID"))
private ResourceTable myResourceTable; private ResourceTable myResource;
@ManyToOne() @ManyToOne()
@JoinColumn(name = "SP_ID", referencedColumnName = "PID", nullable = false, foreignKey = @ForeignKey(name = "FK_RESPARMPRES_SPID")) @JoinColumn(name = "SP_ID", referencedColumnName = "PID", nullable = false, foreignKey = @ForeignKey(name = "FK_RESPARMPRES_SPID"))
private SearchParam mySearchParam; private SearchParam mySearchParam;
public ResourceTable getResourceTable() { public ResourceTable getResource() {
return myResourceTable; return myResource;
} }
public SearchParam getSearchParam() { public SearchParam getSearchParam() {
@ -47,8 +47,8 @@ public class SearchParamPresent implements Serializable {
myPresent = thePresent; myPresent = thePresent;
} }
public void setResourceTable(ResourceTable theResourceTable) { public void setResource(ResourceTable theResourceTable) {
myResourceTable = theResourceTable; myResource = theResourceTable;
} }
public void setSearchParam(SearchParam theSearchParam) { public void setSearchParam(SearchParam theSearchParam) {

View File

@ -16,23 +16,29 @@ import ca.uhn.fhir.jpa.entity.SearchParamPresent;
public class SearchParamPresenceSvcImpl implements ISearchParamPresenceSvc { public class SearchParamPresenceSvcImpl implements ISearchParamPresenceSvc {
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(SearchParamPresenceSvcImpl.class); private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(SearchParamPresenceSvcImpl.class);
private Map<Pair<String, String>, SearchParam> myResourceTypeToSearchParamToEntity = new ConcurrentHashMap<Pair<String,String>, SearchParam>(); private Map<Pair<String, String>, SearchParam> myResourceTypeToSearchParamToEntity = new ConcurrentHashMap<Pair<String, String>, SearchParam>();
@Autowired @Autowired
private ISearchParamDao mySearchParamDao; private ISearchParamDao mySearchParamDao;
@Autowired @Autowired
private ISearchParamPresentDao mySearchParamPresentDao; private ISearchParamPresentDao mySearchParamPresentDao;
@Override @Override
public void updatePresence(ResourceTable theResource, Map<String, Boolean> theParamNameToPresence) { public void updatePresence(ResourceTable theResource, Map<String, Boolean> theParamNameToPresence) {
Map<String, Boolean> presenceMap = new HashMap<String, Boolean>(theParamNameToPresence); Map<String, Boolean> presenceMap = new HashMap<String, Boolean>(theParamNameToPresence);
List<SearchParamPresent> entitiesToSave = new ArrayList<SearchParamPresent>(); List<SearchParamPresent> entitiesToSave = new ArrayList<SearchParamPresent>();
List<SearchParamPresent> entitiesToDelete = new ArrayList<SearchParamPresent>(); List<SearchParamPresent> entitiesToDelete = new ArrayList<SearchParamPresent>();
Collection<SearchParamPresent> existing = mySearchParamPresentDao.findAllForResource(theResource); Collection<SearchParamPresent> existing;
// if (theResource.getId() != null) {
existing = mySearchParamPresentDao.findAllForResource(theResource);
// } else {
// existing = Collections.emptyList();
// }
for (SearchParamPresent nextExistingEntity : existing) { for (SearchParamPresent nextExistingEntity : existing) {
String nextSearchParamName = nextExistingEntity.getSearchParam().getParamName(); String nextSearchParamName = nextExistingEntity.getSearchParam().getParamName();
Boolean existingValue = presenceMap.remove(nextSearchParamName); Boolean existingValue = presenceMap.remove(nextSearchParamName);
@ -45,12 +51,12 @@ public class SearchParamPresenceSvcImpl implements ISearchParamPresenceSvc {
entitiesToSave.add(nextExistingEntity); entitiesToSave.add(nextExistingEntity);
} }
} }
for (Entry<String, Boolean> next : presenceMap.entrySet()) { for (Entry<String, Boolean> next : presenceMap.entrySet()) {
String resourceType = theResource.getResourceType(); String resourceType = theResource.getResourceType();
String paramName = next.getKey(); String paramName = next.getKey();
Pair<String, String> key = Pair.of(resourceType, paramName); Pair<String, String> key = Pair.of(resourceType, paramName);
SearchParam searchParam = myResourceTypeToSearchParamToEntity.get(key); SearchParam searchParam = myResourceTypeToSearchParamToEntity.get(key);
if (searchParam == null) { if (searchParam == null) {
searchParam = mySearchParamDao.findForResource(resourceType, paramName); searchParam = mySearchParamDao.findForResource(resourceType, paramName);
@ -63,19 +69,19 @@ public class SearchParamPresenceSvcImpl implements ISearchParamPresenceSvc {
mySearchParamDao.save(searchParam); mySearchParamDao.save(searchParam);
// Don't add the newly saved entity to the map in case the save fails // Don't add the newly saved entity to the map in case the save fails
} }
SearchParamPresent present = new SearchParamPresent(); SearchParamPresent present = new SearchParamPresent();
present.setResourceTable(theResource); present.setResource(theResource);
present.setSearchParam(searchParam); present.setSearchParam(searchParam);
present.setPresent(next.getValue()); present.setPresent(next.getValue());
entitiesToSave.add(present); entitiesToSave.add(present);
} }
mySearchParamPresentDao.deleteInBatch(entitiesToDelete); mySearchParamPresentDao.deleteInBatch(entitiesToDelete);
mySearchParamPresentDao.save(entitiesToSave); mySearchParamPresentDao.save(entitiesToSave);
} }
} }
} }

View File

@ -30,28 +30,7 @@ import org.springframework.transaction.support.TransactionCallback;
import org.springframework.transaction.support.TransactionTemplate; import org.springframework.transaction.support.TransactionTemplate;
import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.jpa.entity.ForcedId; import ca.uhn.fhir.jpa.entity.*;
import ca.uhn.fhir.jpa.entity.ResourceHistoryTable;
import ca.uhn.fhir.jpa.entity.ResourceHistoryTag;
import ca.uhn.fhir.jpa.entity.ResourceIndexedSearchParamCoords;
import ca.uhn.fhir.jpa.entity.ResourceIndexedSearchParamDate;
import ca.uhn.fhir.jpa.entity.ResourceIndexedSearchParamNumber;
import ca.uhn.fhir.jpa.entity.ResourceIndexedSearchParamQuantity;
import ca.uhn.fhir.jpa.entity.ResourceIndexedSearchParamString;
import ca.uhn.fhir.jpa.entity.ResourceIndexedSearchParamToken;
import ca.uhn.fhir.jpa.entity.ResourceIndexedSearchParamUri;
import ca.uhn.fhir.jpa.entity.ResourceLink;
import ca.uhn.fhir.jpa.entity.ResourceTable;
import ca.uhn.fhir.jpa.entity.ResourceTag;
import ca.uhn.fhir.jpa.entity.SearchInclude;
import ca.uhn.fhir.jpa.entity.SearchResult;
import ca.uhn.fhir.jpa.entity.SubscriptionFlaggedResource;
import ca.uhn.fhir.jpa.entity.SubscriptionTable;
import ca.uhn.fhir.jpa.entity.TagDefinition;
import ca.uhn.fhir.jpa.entity.TermCodeSystem;
import ca.uhn.fhir.jpa.entity.TermCodeSystemVersion;
import ca.uhn.fhir.jpa.entity.TermConcept;
import ca.uhn.fhir.jpa.entity.TermConceptParentChildLink;
import ca.uhn.fhir.jpa.provider.SystemProviderDstu2Test; import ca.uhn.fhir.jpa.provider.SystemProviderDstu2Test;
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;
@ -225,6 +204,9 @@ public abstract class BaseJpaTest {
txTemplate.execute(new TransactionCallback<Void>() { txTemplate.execute(new TransactionCallback<Void>() {
@Override @Override
public Void doInTransaction(TransactionStatus theStatus) { public Void doInTransaction(TransactionStatus theStatus) {
entityManager.createQuery("DELETE from " + SearchParamPresent.class.getSimpleName() + " d").executeUpdate();
entityManager.createQuery("DELETE from " + SearchParam.class.getSimpleName() + " d").executeUpdate();
entityManager.createQuery("DELETE from " + SubscriptionFlaggedResource.class.getSimpleName() + " d").executeUpdate();
entityManager.createQuery("DELETE from " + SubscriptionFlaggedResource.class.getSimpleName() + " d").executeUpdate(); entityManager.createQuery("DELETE from " + SubscriptionFlaggedResource.class.getSimpleName() + " d").executeUpdate();
entityManager.createQuery("DELETE from " + ForcedId.class.getSimpleName() + " d").executeUpdate(); entityManager.createQuery("DELETE from " + ForcedId.class.getSimpleName() + " d").executeUpdate();
entityManager.createQuery("DELETE from " + ResourceIndexedSearchParamDate.class.getSimpleName() + " d").executeUpdate(); entityManager.createQuery("DELETE from " + ResourceIndexedSearchParamDate.class.getSimpleName() + " d").executeUpdate();

View File

@ -1747,27 +1747,27 @@ public class FhirResourceDaoDstu3SearchNoFtTest extends BaseJpaDstu3Test {
String methodName = "testSearchValueQuantity"; String methodName = "testSearchValueQuantity";
String id1; String id1;
{ {
Observation o = new Observation(); Observation o = new Observation();
o.getCode().addCoding().setSystem("urn:foo").setCode(methodName + "code"); o.getCode().addCoding().setSystem("urn:foo").setCode(methodName + "code");
Quantity q = new Quantity().setSystem("urn:bar:" + methodName).setCode(methodName + "units").setValue(100); Quantity q = new Quantity().setSystem("urn:bar:" + methodName).setCode(methodName + "units").setValue(100);
o.setValue(q); o.setValue(q);
id1 = myObservationDao.create(o, mySrd).getId().toUnqualifiedVersionless().getValue(); id1 = myObservationDao.create(o, mySrd).getId().toUnqualifiedVersionless().getValue();
} }
String id2; String id2;
{ {
Observation o = new Observation(); Observation o = new Observation();
o.getCode().addCoding().setSystem("urn:foo").setCode(methodName + "code"); o.getCode().addCoding().setSystem("urn:foo").setCode(methodName + "code");
Quantity q = new Quantity().setSystem("urn:bar:" + methodName).setCode(methodName + "units").setValue(5); Quantity q = new Quantity().setSystem("urn:bar:" + methodName).setCode(methodName + "units").setValue(5);
o.setValue(q); o.setValue(q);
id2 = myObservationDao.create(o, mySrd).getId().toUnqualifiedVersionless().getValue(); id2 = myObservationDao.create(o, mySrd).getId().toUnqualifiedVersionless().getValue();
} }
Map<String, IQueryParameterType> map = new HashMap<String, IQueryParameterType>(); Map<String, IQueryParameterType> map = new HashMap<String, IQueryParameterType>();
IBundleProvider found; IBundleProvider found;
QuantityParam param; QuantityParam param;
param = new QuantityParam(ParamPrefixEnum.GREATERTHAN_OR_EQUALS, new BigDecimal("10"), null, null); param = new QuantityParam(ParamPrefixEnum.GREATERTHAN_OR_EQUALS, new BigDecimal("10"), null, null);
map.put(Observation.SP_VALUE_QUANTITY, param); map.put(Observation.SP_VALUE_QUANTITY, param);
found = myObservationDao.search(map); found = myObservationDao.search(map);
@ -2146,8 +2146,8 @@ public class FhirResourceDaoDstu3SearchNoFtTest extends BaseJpaDstu3Test {
param.setMissing(false); param.setMissing(false);
params.put(Patient.SP_BIRTHDATE, param); params.put(Patient.SP_BIRTHDATE, param);
List<IIdType> patients = toUnqualifiedVersionlessIds(myPatientDao.search(params)); List<IIdType> patients = toUnqualifiedVersionlessIds(myPatientDao.search(params));
assertThat(patients, not(containsInRelativeOrder(missing)));
assertThat(patients, containsInRelativeOrder(notMissing)); assertThat(patients, containsInRelativeOrder(notMissing));
assertThat(patients, not(containsInRelativeOrder(missing)));
} }
{ {
Map<String, IQueryParameterType> params = new HashMap<String, IQueryParameterType>(); Map<String, IQueryParameterType> params = new HashMap<String, IQueryParameterType>();
@ -2158,6 +2158,14 @@ public class FhirResourceDaoDstu3SearchNoFtTest extends BaseJpaDstu3Test {
assertThat(patients, containsInRelativeOrder(missing)); assertThat(patients, containsInRelativeOrder(missing));
assertThat(patients, not(containsInRelativeOrder(notMissing))); assertThat(patients, not(containsInRelativeOrder(notMissing)));
} }
// {
// Map<String, IQueryParameterType> params = new HashMap<String, IQueryParameterType>();
// DateParam param = new DateParam();
// param.setMissing(true);
// params.put(Patient.SP_DECEASED, param);
// List<IIdType> patients = toUnqualifiedVersionlessIds(myPatientDao.search(params));
// assertThat(patients, containsInRelativeOrder(missing, notMissing));
// }
} }
@Test @Test