From 660c2bde72a0090507030c05a8aad09a23304db4 Mon Sep 17 00:00:00 2001 From: James Agnew Date: Thu, 6 Apr 2017 22:23:20 -0400 Subject: [PATCH] More work on perf --- .editorconfig | 11 + .../java/ca/uhn/fhir/model/api/Include.java | 6 +- .../java/ca/uhn/fhir/model/api/TagList.java | 4 +- .../ca/uhn/fhir/jpa/dao/BaseHapiFhirDao.java | 50 ++-- .../ca/uhn/fhir/jpa/dao/SearchBuilder.java | 218 +++++------------- .../jpa/dao/data/ISearchParamPresentDao.java | 2 +- .../ca/uhn/fhir/jpa/entity/ResourceTable.java | 3 + .../ca/uhn/fhir/jpa/entity/SearchParam.java | 2 +- .../fhir/jpa/entity/SearchParamPresent.java | 10 +- .../jpa/sp/SearchParamPresenceSvcImpl.java | 38 +-- .../java/ca/uhn/fhir/jpa/dao/BaseJpaTest.java | 26 +-- .../FhirResourceDaoDstu3SearchNoFtTest.java | 20 +- 12 files changed, 148 insertions(+), 242 deletions(-) diff --git a/.editorconfig b/.editorconfig index c15d04c8487..499513576f9 100644 --- a/.editorconfig +++ b/.editorconfig @@ -3,19 +3,30 @@ root = true [*] end_of_line = lf insert_final_newline = true +tab_width = 3 +indent_size = 3 [*.java] charset = utf-8 indent_style = tab +tab_width = 3 +indent_size = 3 [*.xml] charset = utf-8 indent_style = tab +tab_width = 3 +indent_size = 3 [*.json] charset = utf-8 indent_style = tab +tab_width = 3 +indent_size = 3 [*.vm] charset = utf-8 indent_style = tab +tab_width = 3 +indent_size = 3 + diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/model/api/Include.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/model/api/Include.java index f1fa8ea571c..d4f7cbfb469 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/model/api/Include.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/model/api/Include.java @@ -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.isNotBlank; +import java.io.Serializable; + import org.apache.commons.lang3.builder.ToStringBuilder; /* @@ -33,8 +35,10 @@ import org.apache.commons.lang3.builder.ToStringBuilder; * upgrading servers. *

*/ -public class Include { +public class Include implements Serializable { + private static final long serialVersionUID = 1L; + private final boolean myImmutable; private boolean myRecurse; private String myValue; diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/model/api/TagList.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/model/api/TagList.java index 9571ca98845..d0f7da498bc 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/model/api/TagList.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/model/api/TagList.java @@ -104,9 +104,9 @@ public class TagList implements Set, Serializable, IBase { * Add a new tag instance * * @param theScheme - * The tag scheme + * The tag scheme (the system) * @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 * generally do not need to interact directly with the added tag. */ 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 0b9f21725aa..8e95ba357e8 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 @@ -1235,6 +1235,7 @@ public abstract class BaseHapiFhirDao implements IDao { Set coordsParams = null; Set links = null; + Set populatedResourceLinkParameters = null; if (theDeletedTimestampOrNull != null) { stringParams = Collections.emptySet(); @@ -1334,7 +1335,7 @@ public abstract class BaseHapiFhirDao implements IDao { } links = new HashSet(); - Set 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 @@ -1374,28 +1375,6 @@ public abstract class BaseHapiFhirDao implements IDao { theEntity.setIndexStatus(INDEX_STATUS_INDEXED); populateFullTextFields(theResource, theEntity); - /* - * Update the "search param present" table which is used for the - * ?foo:missing=true queries - */ - Map presentSearchParams = new HashMap(); - 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 activeSearchParamNames = mySearchParamRegistry.getActiveSearchParams(theEntity.getResourceType()).keySet(); - for (String nextSpName : activeSearchParamNames) { - if (!presentSearchParams.containsKey(nextSpName)) { - presentSearchParams.put(nextSpName, Boolean.FALSE); - } - } - mySearchParamPresenceSvc.updatePresence(theEntity, presentSearchParams); } else { @@ -1426,6 +1405,31 @@ public abstract class BaseHapiFhirDao implements IDao { postUpdate(theEntity, (T) theResource); } + /* + * Update the "search param present" table which is used for the + * ?foo:missing=true queries + */ + if (thePerformIndexing) { + Map presentSearchParams = new HashMap(); + 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 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 */ 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 c7ab8d61158..216aa983ffa 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 @@ -88,8 +88,6 @@ public class SearchBuilder { private EntityManager myEntityManager; private IForcedIdDao myForcedIdDao; private SearchParameterMap myParams; - private Collection myPids; - private PlatformTransactionManager myPlatformTransactionManager; private IResourceIndexedSearchParamUriDao myResourceIndexedSearchParamUriDao; private String myResourceName; private Class myResourceType; @@ -97,16 +95,12 @@ public class SearchBuilder { private Search mySearchEntity; private ISearchResultDao mySearchResultDao; private ISearchParamRegistry mySearchParamRegistry; - private IHapiTerminologySvc myTerminologySvc; - private Root myResourceTableRoot; - private ArrayList myPredicates; - private CriteriaBuilder myBuilder; - private CriteriaQuery myResourceTableQuery; + private PlatformTransactionManager myPlatformTransactionManager; public SearchBuilder(FhirContext theFhirContext, EntityManager theEntityManager, PlatformTransactionManager thePlatformTransactionManager, IFulltextSearchSvc theFulltextSearchSvc, ISearchResultDao theSearchResultDao, BaseHapiFhirDao theDao, @@ -158,8 +152,8 @@ public class SearchBuilder { private void addPredicateDate(String theParamName, List theList) { - if (Boolean.TRUE.equals(theList.get(0).getMissing())) { - addPredicateParamMissing("myParamsDate", theParamName, ResourceIndexedSearchParamDate.class); + if (theList.get(0).getMissing() != null) { + addPredicateParamMissing(theParamName, theList.get(0).getMissing()); return; } @@ -167,10 +161,6 @@ public class SearchBuilder { List codePredicates = new ArrayList(); for (IQueryParameterType nextOr : theList) { - if (addPredicateMissingFalseIfPresent(myBuilder, theParamName, join, codePredicates, nextOr)) { - continue; - } - IQueryParameterType params = nextOr; Predicate p = createPredicateDate(myBuilder, join, params); codePredicates.add(p); @@ -304,40 +294,10 @@ public class SearchBuilder { return; } - private boolean addPredicateMissingFalseIfPresent(CriteriaBuilder theBuilder, String theParamName, From from, List 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 from, List 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 theList) { - if (Boolean.TRUE.equals(theList.get(0).getMissing())) { - addPredicateParamMissing("myParamsNumber", theParamName, ResourceIndexedSearchParamNumber.class); + if (theList.get(0).getMissing() != null) { + addPredicateParamMissing(theParamName, theList.get(0).getMissing()); return; } @@ -347,10 +307,6 @@ public class SearchBuilder { for (IQueryParameterType nextOr : theList) { IQueryParameterType params = nextOr; - if (addPredicateMissingFalseIfPresent(myBuilder, theParamName, join, codePredicates, nextOr)) { - continue; - } - if (params instanceof NumberParam) { NumberParam param = (NumberParam) params; @@ -376,62 +332,18 @@ public class SearchBuilder { myPredicates.add(myBuilder.or(toArray(codePredicates))); } - private void addPredicateParamMissing(String joinName, String theParamName, Class theParamTable) { - CriteriaBuilder builder = myEntityManager.getCriteriaBuilder(); - CriteriaQuery cq = builder.createQuery(Long.class); - Root from = cq.from(ResourceTable.class); - cq.select(from.get("myId").as(Long.class)); + private void addPredicateParamMissing(String theParamName, boolean theMissing) { + Join paramPresentJoin = myResourceTableRoot.join("mySearchParamPresents", JoinType.LEFT); + Join paramJoin = paramPresentJoin.join("mySearchParam", JoinType.LEFT); - Subquery subQ = cq.subquery(Long.class); - Root subQfrom = subQ.from(theParamTable); - subQ.select(subQfrom.get("myResourcePid").as(Long.class)); - Predicate subQname = builder.equal(subQfrom.get("myParamName"), theParamName); - Predicate subQtype = builder.equal(subQfrom.get("myResourceType"), myResourceName); - subQ.where(builder.and(subQtype, subQname)); - - 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"))); - 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 q = myEntityManager.createQuery(cq); - doSetPids(q.getResultList()); - } - - private void addPredicateParamMissingResourceLink(String joinName, String theParamName) { - CriteriaBuilder builder = myEntityManager.getCriteriaBuilder(); - CriteriaQuery cq = builder.createQuery(Long.class); - Root from = cq.from(ResourceTable.class); - cq.select(from.get("myId").as(Long.class)); - - Subquery subQ = cq.subquery(Long.class); - Root 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 predicates = new ArrayList(); - 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 q = myEntityManager.createQuery(cq); - List resultList = q.getResultList(); - doSetPids(new HashSet(resultList)); + myPredicates.add(myBuilder.equal(paramJoin.get("myResourceName"), myResourceName)); + myPredicates.add(myBuilder.equal(paramJoin.get("myParamName"), theParamName)); + myPredicates.add(myBuilder.equal(paramPresentJoin.get("myPresent"), !theMissing)); } private void addPredicateQuantity(String theParamName, List theList) { - if (Boolean.TRUE.equals(theList.get(0).getMissing())) { - addPredicateParamMissing("myParamsQuantity", theParamName, ResourceIndexedSearchParamQuantity.class); + if (theList.get(0).getMissing() != null) { + addPredicateParamMissing(theParamName, theList.get(0).getMissing()); return; } @@ -439,9 +351,6 @@ public class SearchBuilder { List codePredicates = new ArrayList(); for (IQueryParameterType nextOr : theList) { - if (addPredicateMissingFalseIfPresent(myBuilder, theParamName, join, codePredicates, nextOr)) { - continue; - } Predicate singleCode = createPredicateQuantity(myBuilder, join, nextOr); codePredicates.add(singleCode); @@ -453,8 +362,8 @@ public class SearchBuilder { private void addPredicateReference(String theParamName, List theList) { assert theParamName.contains(".") == false; - if (Boolean.TRUE.equals(theList.get(0).getMissing())) { - addPredicateParamMissingResourceLink("myResourceLinks", theParamName); + if (theList.get(0).getMissing() != null) { + addPredicateParamMissing(theParamName, theList.get(0).getMissing()); return; } @@ -465,10 +374,6 @@ public class SearchBuilder { for (IQueryParameterType nextOr : theList) { IQueryParameterType params = nextOr; - if (addPredicateMissingFalseIfPresentForResourceLink(myBuilder, theParamName, join, codePredicates, nextOr)) { - continue; - } - if (params instanceof ReferenceParam) { ReferenceParam ref = (ReferenceParam) params; @@ -585,34 +490,34 @@ public class SearchBuilder { } foundChainMatch = true; -// Set pids = dao.searchForIds(chain, chainValue); + // Set pids = dao.searchForIds(chain, chainValue); Subquery subQ = myResourceTableQuery.subquery(Long.class); Root subQfrom = subQ.from(ResourceTable.class); subQ.select(subQfrom.get("myId").as(Long.class)); - + List> andOrParams = new ArrayList>(); andOrParams.add(Collections.singletonList(chainValue)); /* * 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 - * stack and run a subuery + * stack and run a subuery */ Root stackRoot = myResourceTableRoot; ArrayList stackPredicates = myPredicates; myResourceTableRoot = subQfrom; myPredicates = new ArrayList(); - + searchForIdsWithAndOr(chain, andOrParams); subQ.where(toArray(myPredicates)); - + /* * Pop the old query root and predicate list back */ myResourceTableRoot = stackRoot; myPredicates = stackPredicates; - + Predicate eq = join.get("myTargetResourcePid").in(subQ); codePredicates.add(eq); @@ -633,20 +538,16 @@ public class SearchBuilder { } private void addPredicateString(String theParamName, List theList) { - if (Boolean.TRUE.equals(theList.get(0).getMissing())) { - addPredicateParamMissing("myParamsString", theParamName, ResourceIndexedSearchParamString.class); + if (theList.get(0).getMissing() != null) { + addPredicateParamMissing(theParamName, theList.get(0).getMissing()); return; } Join join = myResourceTableRoot.join("myParamsString", JoinType.LEFT); - + List codePredicates = new ArrayList(); for (IQueryParameterType nextOr : theList) { IQueryParameterType theParameter = nextOr; - if (addPredicateMissingFalseIfPresent(myBuilder, theParamName, join, codePredicates, nextOr)) { - continue; - } - Predicate singleCode = createPredicateString(theParameter, theParamName, myBuilder, join); codePredicates.add(singleCode); } @@ -775,7 +676,7 @@ public class SearchBuilder { Join tagJoin = myResourceTableRoot.join("myTags", JoinType.LEFT); From defJoin = tagJoin.join("myTag"); - + List orPredicates = createPredicateTagList(defJoin, myBuilder, tagType, tokens); myPredicates.add(myBuilder.or(toArray(orPredicates))); @@ -785,8 +686,8 @@ public class SearchBuilder { private void addPredicateToken(String theParamName, List theList) { - if (Boolean.TRUE.equals(theList.get(0).getMissing())) { - addPredicateParamMissing("myParamsToken", theParamName, ResourceIndexedSearchParamToken.class); + if (theList.get(0).getMissing() != null) { + addPredicateParamMissing(theParamName, theList.get(0).getMissing()); return; } @@ -794,9 +695,6 @@ public class SearchBuilder { List codePredicates = new ArrayList(); for (IQueryParameterType nextOr : theList) { - if (addPredicateMissingFalseIfPresent(myBuilder, theParamName, join, codePredicates, nextOr)) { - continue; - } if (nextOr instanceof TokenParam) { TokenParam id = (TokenParam) nextOr; @@ -822,8 +720,8 @@ public class SearchBuilder { } private void addPredicateUri(String theParamName, List theList) { - if (Boolean.TRUE.equals(theList.get(0).getMissing())) { - addPredicateParamMissing("myParamsUri", theParamName, ResourceIndexedSearchParamUri.class); + if (theList.get(0).getMissing() != null) { + addPredicateParamMissing(theParamName, theList.get(0).getMissing()); return; } @@ -833,10 +731,6 @@ public class SearchBuilder { for (IQueryParameterType nextOr : theList) { IQueryParameterType params = nextOr; - if (addPredicateMissingFalseIfPresent(myBuilder, theParamName, join, codePredicates, nextOr)) { - continue; - } - if (params instanceof UriParam) { UriParam param = (UriParam) params; @@ -1265,7 +1159,7 @@ public class SearchBuilder { return singleCode; } - private Predicate createResourceLinkPathPredicate(String theParamName, From from) { + private Predicate createResourceLinkPathPredicate(String theParamName, From from) { return createResourceLinkPathPredicate(myCallingDao, myContext, theParamName, from, myResourceType); } @@ -1368,10 +1262,6 @@ public class SearchBuilder { 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) { if (theSort.getOrder() == null || theSort.getOrder() == SortOrderEnum.ASC) { theOrders.add(theBuilder.asc(stringJoin.get(next))); @@ -1565,30 +1455,30 @@ public class SearchBuilder { mySearchEntity.setSearchType(myParams.getEverythingMode() != null ? SearchTypeEnum.EVERYTHING : SearchTypeEnum.SEARCH); mySearchEntity.setLastUpdated(myParams.getLastUpdated()); mySearchEntity.setResourceType(myResourceName); - + for (Include next : myParams.getIncludes()) { mySearchEntity.getIncludes().add(new SearchInclude(mySearchEntity, next.getValue(), false, next.isRecurse())); } for (Include next : myParams.getRevIncludes()) { mySearchEntity.getIncludes().add(new SearchInclude(mySearchEntity, next.getValue(), true, next.isRecurse())); } - + List firstPage = loadSearchPage(theParams, 0, 999); mySearchEntity.setTotalCount(firstPage.size()); - + myEntityManager.persist(mySearchEntity); for (SearchInclude next : mySearchEntity.getIncludes()) { myEntityManager.persist(next); } - + IBundleProvider retVal = doReturnProvider(); - + ourLog.info("Search initial phase completed in {}ms", w); return retVal; } public List loadSearchPage(SearchParameterMap theParams, int theFromIndex, int theToIndex) { - + if (myFulltextSearchSvc == null) { if (theParams.containsKey(Constants.PARAM_TEXT)) { throw new InvalidRequestException("Fulltext search is not enabled on this service, can not process parameter: " + Constants.PARAM_TEXT); @@ -1613,28 +1503,28 @@ public class SearchBuilder { myPredicates = new ArrayList(); myPredicates.add(myBuilder.equal(myResourceTableRoot.get("myResourceType"), myResourceName)); myPredicates.add(myBuilder.isNull(myResourceTableRoot.get("myDeleted"))); - + DateRangeParam lu = theParams.getLastUpdated(); List lastUpdatedPredicates = createLastUpdatedPredicates(lu, myBuilder, myResourceTableRoot); myPredicates.addAll(lastUpdatedPredicates); - + searchForIdsWithAndOr(theParams); - + myResourceTableQuery.where(myBuilder.and(SearchBuilder.toArray(myPredicates))); myResourceTableQuery.multiselect(myResourceTableRoot.get("myId").as(Long.class)); TypedQuery query = myEntityManager.createQuery(myResourceTableQuery); query.setFirstResult(theFromIndex); query.setMaxResults(theToIndex - theFromIndex); - + List pids = new ArrayList(); for (Tuple next : query.getResultList()) { pids.add(next.get(0, Long.class)); } - return pids; + return pids; } - + public IBundleProvider loadPage(SearchParameterMap theParams, int theFromIndex, int theToIndex) { StopWatch sw = new StopWatch(); DateRangeParam lu = theParams.getLastUpdated(); @@ -1702,9 +1592,8 @@ public class SearchBuilder { } } - if (!theParams.isEmpty()) { -// searchForIdsWithAndOr(theParams, lu); + // searchForIdsWithAndOr(theParams, lu); } } @@ -1729,7 +1618,7 @@ public class SearchBuilder { return doReturnProvider(); } - + private void searchForIdsWithAndOr(SearchParameterMap theParams) { SearchParameterMap params = theParams; if (params == null) { @@ -1810,7 +1699,7 @@ public class SearchBuilder { addPredicateUri(nextParamName, nextAnd); } break; - case HAS: + case HAS: // should not happen break; } @@ -1834,21 +1723,20 @@ public class SearchBuilder { orPids.add(entity.getId()); } } catch (ResourceNotFoundException e) { - /* + /* * This isn't an error, just means no result found * 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("%", "[%]") + "%"; } - private static Predicate createResourceLinkPathPredicate(IDao theCallingDao, FhirContext theContext, String theParamName, From from, + private static Predicate createResourceLinkPathPredicate(IDao theCallingDao, FhirContext theContext, String theParamName, From from, Class resourceType) { RuntimeResourceDefinition resourceDef = theContext.getResourceDefinition(resourceType); RuntimeSearchParam param = theCallingDao.getSearchParamByName(resourceDef, theParamName); diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/data/ISearchParamPresentDao.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/data/ISearchParamPresentDao.java index 1290e524da1..dceaf04331c 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/data/ISearchParamPresentDao.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/data/ISearchParamPresentDao.java @@ -32,7 +32,7 @@ import ca.uhn.fhir.jpa.entity.SearchParamPresent; public interface ISearchParamPresentDao extends JpaRepository { - @Query("SELECT s FROM SearchParamPresent s WHERE s.myResourceTable = :res") + @Query("SELECT s FROM SearchParamPresent s WHERE s.myResource = :res") public Collection findAllForResource(@Param("res") ResourceTable theResource); } diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/ResourceTable.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/ResourceTable.java index 4a4250a57c1..5757cbb64dd 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/ResourceTable.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/ResourceTable.java @@ -236,6 +236,9 @@ public class ResourceTable extends BaseHasResource implements Serializable { @OneToMany(mappedBy = "myResource", cascade = CascadeType.ALL, fetch = FetchType.LAZY, orphanRemoval = true) private Set myTags; + @OneToMany(mappedBy = "myResource", cascade = CascadeType.ALL, fetch = FetchType.LAZY, orphanRemoval = true) + private Collection mySearchParamPresents; + @Column(name = "RES_VER") private long myVersion; diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/SearchParam.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/SearchParam.java index 548e83ebee2..1c5d55cc8f3 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/SearchParam.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/SearchParam.java @@ -11,7 +11,7 @@ public class SearchParam { @Id @SequenceGenerator(name = "SEQ_SEARCHPARM_ID", sequenceName = "SEQ_SEARCHPARM_ID") @GeneratedValue(strategy = GenerationType.AUTO, generator = "SEQ_SEARCHPARM_ID") - @Column(name = "RES_ID") + @Column(name = "PID") private Long myId; @Column(name="PARAM_NAME", length=BaseResourceIndexedSearchParam.MAX_SP_NAME, nullable=false, updatable=false) diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/SearchParamPresent.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/SearchParamPresent.java index 1b7b283f6f6..7db7d707f32 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/SearchParamPresent.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/SearchParamPresent.java @@ -25,14 +25,14 @@ public class SearchParamPresent implements Serializable { @ManyToOne() @JoinColumn(name = "RES_ID", referencedColumnName = "RES_ID", nullable = false, foreignKey = @ForeignKey(name = "FK_RESPARMPRES_RESID")) - private ResourceTable myResourceTable; + private ResourceTable myResource; @ManyToOne() @JoinColumn(name = "SP_ID", referencedColumnName = "PID", nullable = false, foreignKey = @ForeignKey(name = "FK_RESPARMPRES_SPID")) private SearchParam mySearchParam; - public ResourceTable getResourceTable() { - return myResourceTable; + public ResourceTable getResource() { + return myResource; } public SearchParam getSearchParam() { @@ -47,8 +47,8 @@ public class SearchParamPresent implements Serializable { myPresent = thePresent; } - public void setResourceTable(ResourceTable theResourceTable) { - myResourceTable = theResourceTable; + public void setResource(ResourceTable theResourceTable) { + myResource = theResourceTable; } public void setSearchParam(SearchParam theSearchParam) { diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/sp/SearchParamPresenceSvcImpl.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/sp/SearchParamPresenceSvcImpl.java index ad5ffe15030..55d5e846012 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/sp/SearchParamPresenceSvcImpl.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/sp/SearchParamPresenceSvcImpl.java @@ -16,23 +16,29 @@ import ca.uhn.fhir.jpa.entity.SearchParamPresent; public class SearchParamPresenceSvcImpl implements ISearchParamPresenceSvc { private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(SearchParamPresenceSvcImpl.class); - - private Map, SearchParam> myResourceTypeToSearchParamToEntity = new ConcurrentHashMap, SearchParam>(); - + + private Map, SearchParam> myResourceTypeToSearchParamToEntity = new ConcurrentHashMap, SearchParam>(); + @Autowired private ISearchParamDao mySearchParamDao; - + @Autowired private ISearchParamPresentDao mySearchParamPresentDao; @Override public void updatePresence(ResourceTable theResource, Map theParamNameToPresence) { - + Map presenceMap = new HashMap(theParamNameToPresence); List entitiesToSave = new ArrayList(); List entitiesToDelete = new ArrayList(); - - Collection existing = mySearchParamPresentDao.findAllForResource(theResource); + + Collection existing; +// if (theResource.getId() != null) { + existing = mySearchParamPresentDao.findAllForResource(theResource); +// } else { +// existing = Collections.emptyList(); +// } + for (SearchParamPresent nextExistingEntity : existing) { String nextSearchParamName = nextExistingEntity.getSearchParam().getParamName(); Boolean existingValue = presenceMap.remove(nextSearchParamName); @@ -45,12 +51,12 @@ public class SearchParamPresenceSvcImpl implements ISearchParamPresenceSvc { entitiesToSave.add(nextExistingEntity); } } - + for (Entry next : presenceMap.entrySet()) { - String resourceType = theResource.getResourceType(); + String resourceType = theResource.getResourceType(); String paramName = next.getKey(); Pair key = Pair.of(resourceType, paramName); - + SearchParam searchParam = myResourceTypeToSearchParamToEntity.get(key); if (searchParam == null) { searchParam = mySearchParamDao.findForResource(resourceType, paramName); @@ -63,19 +69,19 @@ public class SearchParamPresenceSvcImpl implements ISearchParamPresenceSvc { mySearchParamDao.save(searchParam); // Don't add the newly saved entity to the map in case the save fails } - + SearchParamPresent present = new SearchParamPresent(); - present.setResourceTable(theResource); + present.setResource(theResource); present.setSearchParam(searchParam); present.setPresent(next.getValue()); entitiesToSave.add(present); } - + mySearchParamPresentDao.deleteInBatch(entitiesToDelete); mySearchParamPresentDao.save(entitiesToSave); - + } - + } - + } diff --git a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/BaseJpaTest.java b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/BaseJpaTest.java index fab33bd1fc7..fc57677dbbf 100644 --- a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/BaseJpaTest.java +++ b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/BaseJpaTest.java @@ -30,28 +30,7 @@ import org.springframework.transaction.support.TransactionCallback; import org.springframework.transaction.support.TransactionTemplate; import ca.uhn.fhir.context.FhirContext; -import ca.uhn.fhir.jpa.entity.ForcedId; -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.entity.*; import ca.uhn.fhir.jpa.provider.SystemProviderDstu2Test; import ca.uhn.fhir.jpa.term.VersionIndependentConcept; import ca.uhn.fhir.model.dstu2.resource.Bundle; @@ -225,6 +204,9 @@ public abstract class BaseJpaTest { txTemplate.execute(new TransactionCallback() { @Override 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 " + ForcedId.class.getSimpleName() + " d").executeUpdate(); entityManager.createQuery("DELETE from " + ResourceIndexedSearchParamDate.class.getSimpleName() + " d").executeUpdate(); diff --git a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/dstu3/FhirResourceDaoDstu3SearchNoFtTest.java b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/dstu3/FhirResourceDaoDstu3SearchNoFtTest.java index 7c2c8e25845..d49b07b899d 100644 --- a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/dstu3/FhirResourceDaoDstu3SearchNoFtTest.java +++ b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/dstu3/FhirResourceDaoDstu3SearchNoFtTest.java @@ -1747,27 +1747,27 @@ public class FhirResourceDaoDstu3SearchNoFtTest extends BaseJpaDstu3Test { String methodName = "testSearchValueQuantity"; String id1; - { + { Observation o = new Observation(); o.getCode().addCoding().setSystem("urn:foo").setCode(methodName + "code"); Quantity q = new Quantity().setSystem("urn:bar:" + methodName).setCode(methodName + "units").setValue(100); o.setValue(q); id1 = myObservationDao.create(o, mySrd).getId().toUnqualifiedVersionless().getValue(); } - + String id2; - { + { Observation o = new Observation(); o.getCode().addCoding().setSystem("urn:foo").setCode(methodName + "code"); Quantity q = new Quantity().setSystem("urn:bar:" + methodName).setCode(methodName + "units").setValue(5); o.setValue(q); id2 = myObservationDao.create(o, mySrd).getId().toUnqualifiedVersionless().getValue(); } - + Map map = new HashMap(); IBundleProvider found; QuantityParam param; - + param = new QuantityParam(ParamPrefixEnum.GREATERTHAN_OR_EQUALS, new BigDecimal("10"), null, null); map.put(Observation.SP_VALUE_QUANTITY, param); found = myObservationDao.search(map); @@ -2146,8 +2146,8 @@ public class FhirResourceDaoDstu3SearchNoFtTest extends BaseJpaDstu3Test { param.setMissing(false); params.put(Patient.SP_BIRTHDATE, param); List patients = toUnqualifiedVersionlessIds(myPatientDao.search(params)); - assertThat(patients, not(containsInRelativeOrder(missing))); assertThat(patients, containsInRelativeOrder(notMissing)); + assertThat(patients, not(containsInRelativeOrder(missing))); } { Map params = new HashMap(); @@ -2158,6 +2158,14 @@ public class FhirResourceDaoDstu3SearchNoFtTest extends BaseJpaDstu3Test { assertThat(patients, containsInRelativeOrder(missing)); assertThat(patients, not(containsInRelativeOrder(notMissing))); } + // { + // Map params = new HashMap(); + // DateParam param = new DateParam(); + // param.setMissing(true); + // params.put(Patient.SP_DECEASED, param); + // List patients = toUnqualifiedVersionlessIds(myPatientDao.search(params)); + // assertThat(patients, containsInRelativeOrder(missing, notMissing)); + // } } @Test