More work on performance
This commit is contained in:
parent
1581cdf9a8
commit
f48d0d677b
|
@ -40,6 +40,8 @@ import org.springframework.scheduling.config.ScheduledTaskRegistrar;
|
|||
import ca.uhn.fhir.jpa.search.DatabaseBackedPagingProvider;
|
||||
import ca.uhn.fhir.jpa.search.IStaleSearchDeletingSvc;
|
||||
import ca.uhn.fhir.jpa.search.StaleSearchDeletingSvcImpl;
|
||||
import ca.uhn.fhir.jpa.sp.ISearchParamPresenceSvc;
|
||||
import ca.uhn.fhir.jpa.sp.SearchParamPresenceSvcImpl;
|
||||
|
||||
@Configuration
|
||||
@EnableScheduling
|
||||
|
@ -64,11 +66,6 @@ public class BaseConfig implements SchedulingConfigurer {
|
|||
return retVal;
|
||||
}
|
||||
|
||||
@Bean(autowire=Autowire.BY_TYPE)
|
||||
public IStaleSearchDeletingSvc staleSearchDeletingSvc() {
|
||||
return new StaleSearchDeletingSvcImpl();
|
||||
}
|
||||
|
||||
@Bean()
|
||||
public ScheduledExecutorFactoryBean scheduledExecutorService() {
|
||||
ScheduledExecutorFactoryBean b = new ScheduledExecutorFactoryBean();
|
||||
|
@ -76,6 +73,16 @@ public class BaseConfig implements SchedulingConfigurer {
|
|||
return b;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public ISearchParamPresenceSvc searchParamPresenceSvc() {
|
||||
return new SearchParamPresenceSvcImpl();
|
||||
}
|
||||
|
||||
@Bean(autowire=Autowire.BY_TYPE)
|
||||
public IStaleSearchDeletingSvc staleSearchDeletingSvc() {
|
||||
return new StaleSearchDeletingSvcImpl();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public TaskScheduler taskScheduler() {
|
||||
ConcurrentTaskScheduler retVal = new ConcurrentTaskScheduler();
|
||||
|
|
|
@ -85,28 +85,9 @@ import ca.uhn.fhir.context.RuntimeChildResourceDefinition;
|
|||
import ca.uhn.fhir.context.RuntimeResourceDefinition;
|
||||
import ca.uhn.fhir.context.RuntimeSearchParam;
|
||||
import ca.uhn.fhir.jpa.dao.data.*;
|
||||
import ca.uhn.fhir.jpa.entity.BaseHasResource;
|
||||
import ca.uhn.fhir.jpa.entity.BaseResourceIndexedSearchParam;
|
||||
import ca.uhn.fhir.jpa.entity.BaseTag;
|
||||
import ca.uhn.fhir.jpa.entity.ForcedId;
|
||||
import ca.uhn.fhir.jpa.entity.ResourceEncodingEnum;
|
||||
import ca.uhn.fhir.jpa.entity.ResourceHistoryTable;
|
||||
import ca.uhn.fhir.jpa.entity.ResourceHistoryTag;
|
||||
import ca.uhn.fhir.jpa.entity.ResourceIndexedSearchParamCoords;
|
||||
import ca.uhn.fhir.jpa.entity.ResourceIndexedSearchParamDate;
|
||||
import ca.uhn.fhir.jpa.entity.ResourceIndexedSearchParamNumber;
|
||||
import ca.uhn.fhir.jpa.entity.ResourceIndexedSearchParamQuantity;
|
||||
import ca.uhn.fhir.jpa.entity.ResourceIndexedSearchParamString;
|
||||
import ca.uhn.fhir.jpa.entity.ResourceIndexedSearchParamToken;
|
||||
import ca.uhn.fhir.jpa.entity.ResourceIndexedSearchParamUri;
|
||||
import ca.uhn.fhir.jpa.entity.ResourceLink;
|
||||
import ca.uhn.fhir.jpa.entity.ResourceTable;
|
||||
import ca.uhn.fhir.jpa.entity.ResourceTag;
|
||||
import ca.uhn.fhir.jpa.entity.Search;
|
||||
import ca.uhn.fhir.jpa.entity.SearchTypeEnum;
|
||||
import ca.uhn.fhir.jpa.entity.TagDefinition;
|
||||
import ca.uhn.fhir.jpa.entity.TagTypeEnum;
|
||||
import ca.uhn.fhir.jpa.entity.*;
|
||||
import ca.uhn.fhir.jpa.search.PersistedJpaBundleProvider;
|
||||
import ca.uhn.fhir.jpa.sp.ISearchParamPresenceSvc;
|
||||
import ca.uhn.fhir.jpa.term.IHapiTerminologySvc;
|
||||
import ca.uhn.fhir.jpa.util.DeleteConflict;
|
||||
import ca.uhn.fhir.model.api.IQueryParameterAnd;
|
||||
|
@ -197,7 +178,6 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
|
|||
protected EntityManager myEntityManager;
|
||||
@Autowired
|
||||
protected IForcedIdDao myForcedIdDao;
|
||||
|
||||
@Autowired(required = false)
|
||||
protected IFulltextSearchSvc myFulltextSearchSvc;
|
||||
@Autowired
|
||||
|
@ -220,6 +200,9 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
|
|||
@Autowired
|
||||
private ISearchParamExtractor mySearchParamExtractor;
|
||||
|
||||
@Autowired
|
||||
private ISearchParamPresenceSvc mySearchParamPresenceSvc;
|
||||
|
||||
@Autowired
|
||||
private ISearchParamRegistry mySearchParamRegistry;
|
||||
|
||||
|
@ -258,14 +241,19 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
|
|||
return InstantDt.withCurrentTime();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Returns a set containing all of the parameter names that
|
||||
* were found to have a value
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
protected void extractResourceLinks(ResourceTable theEntity, IBaseResource theResource, Set<ResourceLink> theLinks, Date theUpdateTime) {
|
||||
protected Set<String> extractResourceLinks(ResourceTable theEntity, IBaseResource theResource, Set<ResourceLink> theLinks, Date theUpdateTime) {
|
||||
HashSet<String> retVal = new HashSet<String>();
|
||||
|
||||
/*
|
||||
* For now we don't try to load any of the links in a bundle if it's the actual bundle we're storing..
|
||||
*/
|
||||
if (theResource instanceof IBaseBundle) {
|
||||
return;
|
||||
return Collections.emptySet();
|
||||
}
|
||||
|
||||
RuntimeResourceDefinition def = getContext().getResourceDefinition(theResource);
|
||||
|
@ -318,6 +306,8 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
|
|||
}
|
||||
}
|
||||
|
||||
retVal.add(nextSpDef.getName());
|
||||
|
||||
if (isLogicalReference(nextId)) {
|
||||
ResourceLink resourceLink = new ResourceLink(nextPathAndRef.getPath(), theEntity, nextId, theUpdateTime);
|
||||
if (theLinks.add(resourceLink)) {
|
||||
|
@ -401,6 +391,7 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
|
|||
|
||||
theEntity.setHasLinks(theLinks.size() > 0);
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
protected Set<ResourceIndexedSearchParamCoords> extractSearchParamCoords(ResourceTable theEntity, IBaseResource theResource) {
|
||||
|
@ -1343,7 +1334,7 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
|
|||
}
|
||||
|
||||
links = new HashSet<ResourceLink>();
|
||||
extractResourceLinks(theEntity, theResource, links, theUpdateTime);
|
||||
Set<String> 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
|
||||
|
@ -1383,6 +1374,29 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> 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<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 {
|
||||
|
||||
populateResourceIntoEntity(theResource, theEntity);
|
||||
|
@ -1502,6 +1516,12 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
|
|||
return theEntity;
|
||||
}
|
||||
|
||||
private void updateSearchParamPresent(Map<String, Boolean> presentSearchParams, Set<? extends BaseResourceIndexedSearchParam> params) {
|
||||
for (BaseResourceIndexedSearchParam nextSearchParam : params) {
|
||||
presentSearchParams.put(nextSearchParam.getParamName(), Boolean.TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
protected ResourceTable updateEntity(IBaseResource theResource, ResourceTable entity, Date theDeletedTimestampOrNull, Date theUpdateTime) {
|
||||
return updateEntity(theResource, entity, theDeletedTimestampOrNull, true, true, theUpdateTime);
|
||||
}
|
||||
|
|
|
@ -106,6 +106,8 @@ public class SearchBuilder {
|
|||
|
||||
private CriteriaBuilder myBuilder;
|
||||
|
||||
private CriteriaQuery<Tuple> myResourceTableQuery;
|
||||
|
||||
public SearchBuilder(FhirContext theFhirContext, EntityManager theEntityManager, PlatformTransactionManager thePlatformTransactionManager, IFulltextSearchSvc theFulltextSearchSvc,
|
||||
ISearchResultDao theSearchResultDao, BaseHapiFhirDao<?> theDao,
|
||||
IResourceIndexedSearchParamUriDao theResourceIndexedSearchParamUriDao, IForcedIdDao theForcedIdDao, IHapiTerminologySvc theTerminologySvc, ISearchParamRegistry theSearchParamRegistry) {
|
||||
|
@ -317,7 +319,7 @@ public class SearchBuilder {
|
|||
return missingFalse;
|
||||
}
|
||||
|
||||
private boolean addPredicateMissingFalseIfPresentForResourceLink(CriteriaBuilder theBuilder, String theParamName, Root<? extends ResourceLink> from, List<Predicate> codePredicates,
|
||||
private boolean addPredicateMissingFalseIfPresentForResourceLink(CriteriaBuilder theBuilder, String theParamName, From<?,? extends ResourceLink> from, List<Predicate> codePredicates,
|
||||
IQueryParameterType nextOr) {
|
||||
boolean missingFalse = false;
|
||||
if (nextOr.getMissing() != null) {
|
||||
|
@ -456,17 +458,14 @@ public class SearchBuilder {
|
|||
return;
|
||||
}
|
||||
|
||||
CriteriaBuilder builder = myEntityManager.getCriteriaBuilder();
|
||||
CriteriaQuery<Long> cq = builder.createQuery(Long.class);
|
||||
Root<ResourceLink> from = cq.from(ResourceLink.class);
|
||||
cq.select(from.get("mySourceResourcePid").as(Long.class));
|
||||
Join<ResourceTable, ResourceLink> join = myResourceTableRoot.join("myResourceLinks", JoinType.LEFT);
|
||||
|
||||
List<Predicate> codePredicates = new ArrayList<Predicate>();
|
||||
|
||||
for (IQueryParameterType nextOr : theList) {
|
||||
IQueryParameterType params = nextOr;
|
||||
|
||||
if (addPredicateMissingFalseIfPresentForResourceLink(builder, theParamName, from, codePredicates, nextOr)) {
|
||||
if (addPredicateMissingFalseIfPresentForResourceLink(myBuilder, theParamName, join, codePredicates, nextOr)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -481,7 +480,7 @@ public class SearchBuilder {
|
|||
dt = dt.toUnqualified();
|
||||
} else {
|
||||
ourLog.debug("Searching for resource link with target URL: {}", dt.getValue());
|
||||
Predicate eq = builder.equal(from.get("myTargetResourceUrl"), dt.getValue());
|
||||
Predicate eq = myBuilder.equal(join.get("myTargetResourceUrl"), dt.getValue());
|
||||
codePredicates.add(eq);
|
||||
continue;
|
||||
}
|
||||
|
@ -491,12 +490,12 @@ public class SearchBuilder {
|
|||
try {
|
||||
targetPid = myCallingDao.translateForcedIdToPids(dt);
|
||||
} catch (ResourceNotFoundException e) {
|
||||
doSetPids(new ArrayList<Long>());
|
||||
return;
|
||||
// Use a PID that will never exist
|
||||
targetPid = Collections.singletonList(-1L);
|
||||
}
|
||||
for (Long next : targetPid) {
|
||||
ourLog.debug("Searching for resource link with target PID: {}", next);
|
||||
Predicate eq = builder.equal(from.get("myTargetResourcePid"), next);
|
||||
Predicate eq = myBuilder.equal(join.get("myTargetResourcePid"), next);
|
||||
codePredicates.add(eq);
|
||||
}
|
||||
} else {
|
||||
|
@ -586,13 +585,35 @@ public class SearchBuilder {
|
|||
}
|
||||
|
||||
foundChainMatch = true;
|
||||
// Set<Long> pids = dao.searchForIds(chain, chainValue);
|
||||
|
||||
Set<Long> pids = dao.searchForIds(chain, chainValue);
|
||||
if (pids.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
Subquery<Long> subQ = myResourceTableQuery.subquery(Long.class);
|
||||
Root<ResourceTable> subQfrom = subQ.from(ResourceTable.class);
|
||||
subQ.select(subQfrom.get("myId").as(Long.class));
|
||||
|
||||
Predicate eq = from.get("myTargetResourcePid").in(pids);
|
||||
List<List<? extends IQueryParameterType>> andOrParams = new ArrayList<List<? extends IQueryParameterType>>();
|
||||
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
|
||||
*/
|
||||
Root<ResourceTable> stackRoot = myResourceTableRoot;
|
||||
ArrayList<Predicate> stackPredicates = myPredicates;
|
||||
myResourceTableRoot = subQfrom;
|
||||
myPredicates = new ArrayList<Predicate>();
|
||||
|
||||
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);
|
||||
|
||||
}
|
||||
|
@ -608,16 +629,7 @@ public class SearchBuilder {
|
|||
|
||||
}
|
||||
|
||||
List<Predicate> predicates = new ArrayList<Predicate>();
|
||||
predicates.add(createResourceLinkPathPredicate(theParamName, from));
|
||||
predicates.add(builder.or(toArray(codePredicates)));
|
||||
createPredicateResourceId(builder, cq, predicates, from.get("mySourceResourcePid").as(Long.class));
|
||||
createPredicateLastUpdatedForResourceLink(builder, from, predicates);
|
||||
|
||||
cq.where(builder.and(toArray(predicates)));
|
||||
|
||||
TypedQuery<Long> q = myEntityManager.createQuery(cq);
|
||||
doSetPids(new HashSet<Long>(q.getResultList()));
|
||||
myPredicates.add(myBuilder.or(toArray(codePredicates)));
|
||||
}
|
||||
|
||||
private void addPredicateString(String theParamName, List<? extends IQueryParameterType> theList) {
|
||||
|
@ -713,8 +725,6 @@ public class SearchBuilder {
|
|||
continue;
|
||||
}
|
||||
|
||||
CriteriaBuilder builder = myEntityManager.getCriteriaBuilder();
|
||||
|
||||
boolean paramInverted = false;
|
||||
List<Pair<String, String>> tokens = Lists.newArrayList();
|
||||
for (IQueryParameterType nextOrParams : nextAndParams) {
|
||||
|
@ -745,19 +755,11 @@ public class SearchBuilder {
|
|||
if (paramInverted) {
|
||||
ourLog.debug("Searching for _tag:not");
|
||||
|
||||
CriteriaQuery<Long> cq = builder.createQuery(Long.class);
|
||||
Root<ResourceTable> newFrom = cq.from(ResourceTable.class);
|
||||
|
||||
Subquery<Long> subQ = cq.subquery(Long.class);
|
||||
Subquery<Long> subQ = myResourceTableQuery.subquery(Long.class);
|
||||
Root<ResourceTag> subQfrom = subQ.from(ResourceTag.class);
|
||||
subQ.select(subQfrom.get("myResourceId").as(Long.class));
|
||||
|
||||
cq.select(newFrom.get("myId").as(Long.class));
|
||||
|
||||
List<Predicate> andPredicates = new ArrayList<Predicate>();
|
||||
andPredicates = new ArrayList<Predicate>();
|
||||
andPredicates.add(builder.equal(newFrom.get("myResourceType"), myResourceName));
|
||||
andPredicates.add(builder.not(builder.in(newFrom.get("myId")).value(subQ)));
|
||||
myPredicates.add(myBuilder.not(myBuilder.in(myResourceTableRoot.get("myId")).value(subQ)));
|
||||
|
||||
Subquery<Long> defJoin = subQ.subquery(Long.class);
|
||||
Root<TagDefinition> defJoinFrom = defJoin.from(TagDefinition.class);
|
||||
|
@ -765,44 +767,18 @@ public class SearchBuilder {
|
|||
|
||||
subQ.where(subQfrom.get("myTagId").as(Long.class).in(defJoin));
|
||||
|
||||
List<Predicate> orPredicates = createPredicateTagList(defJoinFrom, builder, tagType, tokens);
|
||||
List<Predicate> orPredicates = createPredicateTagList(defJoinFrom, myBuilder, tagType, tokens);
|
||||
defJoin.where(toArray(orPredicates));
|
||||
|
||||
cq.where(toArray(andPredicates));
|
||||
|
||||
TypedQuery<Long> q = myEntityManager.createQuery(cq);
|
||||
Set<Long> pids = new HashSet<Long>(q.getResultList());
|
||||
doSetPids(pids);
|
||||
continue;
|
||||
}
|
||||
|
||||
CriteriaQuery<Long> cq = builder.createQuery(Long.class);
|
||||
Root<ResourceTag> from = cq.from(ResourceTag.class);
|
||||
List<Predicate> andPredicates = new ArrayList<Predicate>();
|
||||
andPredicates.add(builder.equal(from.get("myResourceType"), myResourceName));
|
||||
From<ResourceTag, TagDefinition> defJoin = from.join("myTag");
|
||||
Join<ResourceTable, ResourceTag> tagJoin = myResourceTableRoot.join("myTags", JoinType.LEFT);
|
||||
From<ResourceTag, TagDefinition> defJoin = tagJoin.join("myTag");
|
||||
|
||||
Join<?, ResourceTable> defJoin2 = from.join("myResource");
|
||||
List<Predicate> orPredicates = createPredicateTagList(defJoin, myBuilder, tagType, tokens);
|
||||
myPredicates.add(myBuilder.or(toArray(orPredicates)));
|
||||
|
||||
Predicate notDeletedPredicatePrediate = builder.isNull(defJoin2.get("myDeleted"));
|
||||
andPredicates.add(notDeletedPredicatePrediate);
|
||||
|
||||
List<Predicate> orPredicates = createPredicateTagList(defJoin, builder, tagType, tokens);
|
||||
andPredicates.add(builder.or(toArray(orPredicates)));
|
||||
|
||||
if (theLastUpdated != null) {
|
||||
andPredicates.addAll(createLastUpdatedPredicates(theLastUpdated, builder, defJoin2));
|
||||
}
|
||||
|
||||
createPredicateResourceId(builder, cq, andPredicates, from.get("myResourceId").as(Long.class));
|
||||
Predicate masterCodePredicate = builder.and(toArray(andPredicates));
|
||||
|
||||
cq.select(from.get("myResourceId").as(Long.class));
|
||||
cq.where(masterCodePredicate);
|
||||
|
||||
TypedQuery<Long> q = myEntityManager.createQuery(cq);
|
||||
Set<Long> pids = new HashSet<Long>(q.getResultList());
|
||||
doSetPids(pids);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -851,16 +827,13 @@ public class SearchBuilder {
|
|||
return;
|
||||
}
|
||||
|
||||
CriteriaBuilder builder = myEntityManager.getCriteriaBuilder();
|
||||
CriteriaQuery<Long> cq = builder.createQuery(Long.class);
|
||||
Root<ResourceIndexedSearchParamUri> from = cq.from(ResourceIndexedSearchParamUri.class);
|
||||
cq.select(from.get("myResourcePid").as(Long.class));
|
||||
Join<ResourceTable, ResourceIndexedSearchParamUri> join = myResourceTableRoot.join("myParamsUri", JoinType.LEFT);
|
||||
|
||||
List<Predicate> codePredicates = new ArrayList<Predicate>();
|
||||
for (IQueryParameterType nextOr : theList) {
|
||||
IQueryParameterType params = nextOr;
|
||||
|
||||
if (addPredicateMissingFalseIfPresent(builder, theParamName, from, codePredicates, nextOr)) {
|
||||
if (addPredicateMissingFalseIfPresent(myBuilder, theParamName, join, codePredicates, nextOr)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -872,7 +845,7 @@ public class SearchBuilder {
|
|||
continue;
|
||||
}
|
||||
|
||||
Path<Object> fromObj = from.get("myUri");
|
||||
Path<Object> fromObj = join.get("myUri");
|
||||
Predicate predicate;
|
||||
if (param.getQualifier() == UriParamQualifierEnum.ABOVE) {
|
||||
|
||||
|
@ -905,9 +878,9 @@ public class SearchBuilder {
|
|||
predicate = fromObj.as(String.class).in(toFind);
|
||||
|
||||
} else if (param.getQualifier() == UriParamQualifierEnum.BELOW) {
|
||||
predicate = builder.like(fromObj.as(String.class), createLeftMatchLikeExpression(value));
|
||||
predicate = myBuilder.like(fromObj.as(String.class), createLeftMatchLikeExpression(value));
|
||||
} else {
|
||||
predicate = builder.equal(fromObj.as(String.class), value);
|
||||
predicate = myBuilder.equal(fromObj.as(String.class), value);
|
||||
}
|
||||
codePredicates.add(predicate);
|
||||
} else {
|
||||
|
@ -921,16 +894,8 @@ public class SearchBuilder {
|
|||
return;
|
||||
}
|
||||
|
||||
List<Predicate> predicates = new ArrayList<Predicate>();
|
||||
predicates.add(builder.equal(from.get("myResourceType"), myResourceName));
|
||||
predicates.add(builder.equal(from.get("myParamName"), theParamName));
|
||||
predicates.add(builder.or(toArray(codePredicates)));
|
||||
createPredicateResourceId(builder, cq, predicates, from.get("myResourcePid").as(Long.class));
|
||||
|
||||
cq.where(builder.and(toArray(predicates)));
|
||||
|
||||
TypedQuery<Long> q = myEntityManager.createQuery(cq);
|
||||
doSetPids(new HashSet<Long>(q.getResultList()));
|
||||
Predicate orPredicate = myBuilder.or(toArray(codePredicates));
|
||||
myPredicates.add(orPredicate);
|
||||
}
|
||||
|
||||
private Predicate createCompositeParamPart(CriteriaBuilder builder, Root<ResourceTable> from, RuntimeSearchParam left, IQueryParameterType leftValue) {
|
||||
|
@ -1300,7 +1265,7 @@ public class SearchBuilder {
|
|||
return singleCode;
|
||||
}
|
||||
|
||||
private Predicate createResourceLinkPathPredicate(String theParamName, Root<? extends ResourceLink> from) {
|
||||
private Predicate createResourceLinkPathPredicate(String theParamName, From<?,? extends ResourceLink> from) {
|
||||
return createResourceLinkPathPredicate(myCallingDao, myContext, theParamName, from, myResourceType);
|
||||
}
|
||||
|
||||
|
@ -1642,9 +1607,9 @@ public class SearchBuilder {
|
|||
}
|
||||
|
||||
myBuilder = myEntityManager.getCriteriaBuilder();
|
||||
CriteriaQuery<Tuple> cq = myBuilder.createTupleQuery();
|
||||
cq.distinct(true);
|
||||
myResourceTableRoot = cq.from(ResourceTable.class);
|
||||
myResourceTableQuery = myBuilder.createTupleQuery();
|
||||
myResourceTableQuery.distinct(true);
|
||||
myResourceTableRoot = myResourceTableQuery.from(ResourceTable.class);
|
||||
myPredicates = new ArrayList<Predicate>();
|
||||
myPredicates.add(myBuilder.equal(myResourceTableRoot.get("myResourceType"), myResourceName));
|
||||
myPredicates.add(myBuilder.isNull(myResourceTableRoot.get("myDeleted")));
|
||||
|
@ -1655,10 +1620,10 @@ public class SearchBuilder {
|
|||
|
||||
searchForIdsWithAndOr(theParams);
|
||||
|
||||
cq.where(myBuilder.and(SearchBuilder.toArray(myPredicates)));
|
||||
myResourceTableQuery.where(myBuilder.and(SearchBuilder.toArray(myPredicates)));
|
||||
|
||||
cq.multiselect(myResourceTableRoot.get("myId").as(Long.class));
|
||||
TypedQuery<Tuple> query = myEntityManager.createQuery(cq);
|
||||
myResourceTableQuery.multiselect(myResourceTableRoot.get("myId").as(Long.class));
|
||||
TypedQuery<Tuple> query = myEntityManager.createQuery(myResourceTableQuery);
|
||||
query.setFirstResult(theFromIndex);
|
||||
query.setMaxResults(theToIndex - theFromIndex);
|
||||
|
||||
|
@ -1774,23 +1739,31 @@ public class SearchBuilder {
|
|||
|
||||
for (Entry<String, List<List<? extends IQueryParameterType>>> nextParamEntry : params.entrySet()) {
|
||||
String nextParamName = nextParamEntry.getKey();
|
||||
List<List<? extends IQueryParameterType>> andOrParams = nextParamEntry.getValue();
|
||||
searchForIdsWithAndOr(nextParamName, andOrParams);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void searchForIdsWithAndOr(String nextParamName, List<List<? extends IQueryParameterType>> andOrParams) {
|
||||
if (nextParamName.equals(BaseResource.SP_RES_ID)) {
|
||||
|
||||
addPredicateResourceId(nextParamEntry.getValue());
|
||||
addPredicateResourceId(andOrParams);
|
||||
|
||||
} else if (nextParamName.equals(BaseResource.SP_RES_LANGUAGE)) {
|
||||
|
||||
addPredicateLanguage(nextParamEntry.getValue());
|
||||
addPredicateLanguage(andOrParams);
|
||||
|
||||
} else if (nextParamName.equals(Constants.PARAM_HAS)) {
|
||||
|
||||
// FIXME
|
||||
addPredicateHas(nextParamEntry.getValue(), null);
|
||||
addPredicateHas(andOrParams, null);
|
||||
|
||||
} else if (nextParamName.equals(Constants.PARAM_TAG) || nextParamName.equals(Constants.PARAM_PROFILE) || nextParamName.equals(Constants.PARAM_SECURITY)) {
|
||||
|
||||
// FIXME
|
||||
addPredicateTag(nextParamEntry.getValue(), nextParamName, null);
|
||||
addPredicateTag(andOrParams, nextParamName, null);
|
||||
|
||||
} else {
|
||||
|
||||
|
@ -1798,42 +1771,42 @@ public class SearchBuilder {
|
|||
if (nextParamDef != null) {
|
||||
switch (nextParamDef.getParamType()) {
|
||||
case DATE:
|
||||
for (List<? extends IQueryParameterType> nextAnd : nextParamEntry.getValue()) {
|
||||
for (List<? extends IQueryParameterType> nextAnd : andOrParams) {
|
||||
addPredicateDate(nextParamName, nextAnd);
|
||||
}
|
||||
break;
|
||||
case QUANTITY:
|
||||
for (List<? extends IQueryParameterType> nextAnd : nextParamEntry.getValue()) {
|
||||
for (List<? extends IQueryParameterType> nextAnd : andOrParams) {
|
||||
addPredicateQuantity(nextParamName, nextAnd);
|
||||
}
|
||||
break;
|
||||
case REFERENCE:
|
||||
for (List<? extends IQueryParameterType> nextAnd : nextParamEntry.getValue()) {
|
||||
for (List<? extends IQueryParameterType> nextAnd : andOrParams) {
|
||||
addPredicateReference(nextParamName, nextAnd);
|
||||
}
|
||||
break;
|
||||
case STRING:
|
||||
for (List<? extends IQueryParameterType> nextAnd : nextParamEntry.getValue()) {
|
||||
for (List<? extends IQueryParameterType> nextAnd : andOrParams) {
|
||||
addPredicateString(nextParamName, nextAnd);
|
||||
}
|
||||
break;
|
||||
case TOKEN:
|
||||
for (List<? extends IQueryParameterType> nextAnd : nextParamEntry.getValue()) {
|
||||
for (List<? extends IQueryParameterType> nextAnd : andOrParams) {
|
||||
addPredicateToken(nextParamName, nextAnd);
|
||||
}
|
||||
break;
|
||||
case NUMBER:
|
||||
for (List<? extends IQueryParameterType> nextAnd : nextParamEntry.getValue()) {
|
||||
for (List<? extends IQueryParameterType> nextAnd : andOrParams) {
|
||||
addPredicateNumber(nextParamName, nextAnd);
|
||||
}
|
||||
break;
|
||||
case COMPOSITE:
|
||||
for (List<? extends IQueryParameterType> nextAnd : nextParamEntry.getValue()) {
|
||||
for (List<? extends IQueryParameterType> nextAnd : andOrParams) {
|
||||
addPredicateComposite(nextParamDef, nextAnd);
|
||||
}
|
||||
break;
|
||||
case URI:
|
||||
for (List<? extends IQueryParameterType> nextAnd : nextParamEntry.getValue()) {
|
||||
for (List<? extends IQueryParameterType> nextAnd : andOrParams) {
|
||||
addPredicateUri(nextParamName, nextAnd);
|
||||
}
|
||||
break;
|
||||
|
@ -1843,9 +1816,6 @@ public class SearchBuilder {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void addPredicateResourceId(List<List<? extends IQueryParameterType>> theValues) {
|
||||
|
@ -1972,7 +1942,7 @@ public class SearchBuilder {
|
|||
return likeExpression.replace("%", "[%]") + "%";
|
||||
}
|
||||
|
||||
private static Predicate createResourceLinkPathPredicate(IDao theCallingDao, FhirContext theContext, String theParamName, Root<? extends ResourceLink> from,
|
||||
private static Predicate createResourceLinkPathPredicate(IDao theCallingDao, FhirContext theContext, String theParamName, From<?,? extends ResourceLink> from,
|
||||
Class<? extends IBaseResource> resourceType) {
|
||||
RuntimeResourceDefinition resourceDef = theContext.getResourceDefinition(resourceType);
|
||||
RuntimeSearchParam param = theCallingDao.getSearchParamByName(resourceDef, theParamName);
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
package ca.uhn.fhir.jpa.dao.data;
|
||||
|
||||
/*
|
||||
* #%L
|
||||
* HAPI FHIR JPA Server
|
||||
* %%
|
||||
* Copyright (C) 2014 - 2017 University Health Network
|
||||
* %%
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
* #L%
|
||||
*/
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
|
||||
import ca.uhn.fhir.jpa.entity.SearchParam;
|
||||
|
||||
public interface ISearchParamDao extends JpaRepository<SearchParam, Long> {
|
||||
|
||||
@Query("SELECT s FROM SearchParam s WHERE s.myResourceName = :resname AND s.myParamName = :parmname")
|
||||
public SearchParam findForResource(@Param("resname") String theResourceType, @Param("parmname") String theParamName);
|
||||
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
package ca.uhn.fhir.jpa.dao.data;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Date;
|
||||
|
||||
/*
|
||||
* #%L
|
||||
* HAPI FHIR JPA Server
|
||||
* %%
|
||||
* Copyright (C) 2014 - 2017 University Health Network
|
||||
* %%
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
* #L%
|
||||
*/
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
|
||||
import ca.uhn.fhir.jpa.entity.ResourceTable;
|
||||
import ca.uhn.fhir.jpa.entity.SearchParamPresent;
|
||||
|
||||
public interface ISearchParamPresentDao extends JpaRepository<SearchParamPresent, Long> {
|
||||
|
||||
@Query("SELECT s FROM SearchParamPresent s WHERE s.myResourceTable = :res")
|
||||
public Collection<SearchParamPresent> findAllForResource(@Param("res") ResourceTable theResource);
|
||||
|
||||
}
|
|
@ -42,7 +42,6 @@ import org.hibernate.search.annotations.Field;
|
|||
|
||||
import ca.uhn.fhir.model.primitive.InstantDt;
|
||||
|
||||
//@formatter:off
|
||||
@Embeddable
|
||||
@Entity
|
||||
@Table(name = "HFJ_SPIDX_DATE", indexes= {
|
||||
|
@ -50,7 +49,6 @@ import ca.uhn.fhir.model.primitive.InstantDt;
|
|||
@Index(name = "IDX_SP_DATE_UPDATED", columnList = "SP_UPDATED"),
|
||||
@Index(name = "IDX_SP_DATE_RESID", columnList = "RES_ID")
|
||||
})
|
||||
//@formatter:on
|
||||
public class ResourceIndexedSearchParamDate extends BaseResourceIndexedSearchParam {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
package ca.uhn.fhir.jpa.entity;
|
||||
|
||||
import javax.persistence.*;
|
||||
|
||||
@Entity
|
||||
@Table(name = "HFJ_SEARCH_PARM", uniqueConstraints= {
|
||||
@UniqueConstraint(name="IDX_SEARCHPARM_RESTYPE_SPNAME", columnNames= {"RES_TYPE", "PARAM_NAME"})
|
||||
})
|
||||
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")
|
||||
private Long myId;
|
||||
|
||||
@Column(name="PARAM_NAME", length=BaseResourceIndexedSearchParam.MAX_SP_NAME, nullable=false, updatable=false)
|
||||
private String myParamName;
|
||||
|
||||
@Column(name="RES_TYPE", length=ResourceTable.RESTYPE_LEN, nullable=false, updatable=false)
|
||||
private String myResourceName;
|
||||
|
||||
public String getParamName() {
|
||||
return myParamName;
|
||||
}
|
||||
|
||||
public void setParamName(String theParamName) {
|
||||
myParamName = theParamName;
|
||||
}
|
||||
|
||||
public void setResourceName(String theResourceName) {
|
||||
myResourceName = theResourceName;
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
package ca.uhn.fhir.jpa.entity;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import javax.persistence.*;
|
||||
|
||||
@Entity
|
||||
@Table(name = "HFJ_RES_PARAM_PRESENT", indexes = {
|
||||
@Index(name = "IDX_RESPARMPRESENT_RESID", columnList = "RES_ID")
|
||||
}, uniqueConstraints = {
|
||||
@UniqueConstraint(name = "IDX_RESPARMPRESENT_SPID_RESID", columnNames = { "SP_ID", "RES_ID" })
|
||||
})
|
||||
public class SearchParamPresent implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Id
|
||||
@SequenceGenerator(name = "SEQ_RESPARMPRESENT_ID", sequenceName = "SEQ_RESPARMPRESENT_ID")
|
||||
@GeneratedValue(strategy = GenerationType.AUTO, generator = "SEQ_RESPARMPRESENT_ID")
|
||||
@Column(name = "PID")
|
||||
private Long myId;
|
||||
|
||||
@Column(name = "SP_PRESENT", nullable = false)
|
||||
private boolean myPresent;
|
||||
|
||||
@ManyToOne()
|
||||
@JoinColumn(name = "RES_ID", referencedColumnName = "RES_ID", nullable = false, foreignKey = @ForeignKey(name = "FK_RESPARMPRES_RESID"))
|
||||
private ResourceTable myResourceTable;
|
||||
|
||||
@ManyToOne()
|
||||
@JoinColumn(name = "SP_ID", referencedColumnName = "PID", nullable = false, foreignKey = @ForeignKey(name = "FK_RESPARMPRES_SPID"))
|
||||
private SearchParam mySearchParam;
|
||||
|
||||
public ResourceTable getResourceTable() {
|
||||
return myResourceTable;
|
||||
}
|
||||
|
||||
public SearchParam getSearchParam() {
|
||||
return mySearchParam;
|
||||
}
|
||||
|
||||
public boolean isPresent() {
|
||||
return myPresent;
|
||||
}
|
||||
|
||||
public void setPresent(boolean thePresent) {
|
||||
myPresent = thePresent;
|
||||
}
|
||||
|
||||
public void setResourceTable(ResourceTable theResourceTable) {
|
||||
myResourceTable = theResourceTable;
|
||||
}
|
||||
|
||||
public void setSearchParam(SearchParam theSearchParam) {
|
||||
mySearchParam = theSearchParam;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
package ca.uhn.fhir.jpa.sp;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import ca.uhn.fhir.jpa.entity.ResourceTable;
|
||||
|
||||
public interface ISearchParamPresenceSvc {
|
||||
|
||||
void updatePresence(ResourceTable theResource, Map<String, Boolean> theParamNameToPresence);
|
||||
|
||||
}
|
|
@ -0,0 +1,81 @@
|
|||
package ca.uhn.fhir.jpa.sp;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
import ca.uhn.fhir.jpa.dao.data.ISearchParamDao;
|
||||
import ca.uhn.fhir.jpa.dao.data.ISearchParamPresentDao;
|
||||
import ca.uhn.fhir.jpa.entity.ResourceTable;
|
||||
import ca.uhn.fhir.jpa.entity.SearchParam;
|
||||
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<Pair<String, String>, SearchParam> myResourceTypeToSearchParamToEntity = new ConcurrentHashMap<Pair<String,String>, SearchParam>();
|
||||
|
||||
@Autowired
|
||||
private ISearchParamDao mySearchParamDao;
|
||||
|
||||
@Autowired
|
||||
private ISearchParamPresentDao mySearchParamPresentDao;
|
||||
|
||||
@Override
|
||||
public void updatePresence(ResourceTable theResource, Map<String, Boolean> theParamNameToPresence) {
|
||||
|
||||
Map<String, Boolean> presenceMap = new HashMap<String, Boolean>(theParamNameToPresence);
|
||||
List<SearchParamPresent> entitiesToSave = new ArrayList<SearchParamPresent>();
|
||||
List<SearchParamPresent> entitiesToDelete = new ArrayList<SearchParamPresent>();
|
||||
|
||||
Collection<SearchParamPresent> existing = mySearchParamPresentDao.findAllForResource(theResource);
|
||||
for (SearchParamPresent nextExistingEntity : existing) {
|
||||
String nextSearchParamName = nextExistingEntity.getSearchParam().getParamName();
|
||||
Boolean existingValue = presenceMap.remove(nextSearchParamName);
|
||||
if (existingValue == null) {
|
||||
entitiesToDelete.add(nextExistingEntity);
|
||||
} else if (existingValue.booleanValue() == nextExistingEntity.isPresent()) {
|
||||
ourLog.trace("No change for search param {}", nextSearchParamName);
|
||||
} else {
|
||||
nextExistingEntity.setPresent(existingValue);
|
||||
entitiesToSave.add(nextExistingEntity);
|
||||
}
|
||||
}
|
||||
|
||||
for (Entry<String, Boolean> next : presenceMap.entrySet()) {
|
||||
String resourceType = theResource.getResourceType();
|
||||
String paramName = next.getKey();
|
||||
Pair<String, String> key = Pair.of(resourceType, paramName);
|
||||
|
||||
SearchParam searchParam = myResourceTypeToSearchParamToEntity.get(key);
|
||||
if (searchParam == null) {
|
||||
searchParam = mySearchParamDao.findForResource(resourceType, paramName);
|
||||
if (searchParam != null) {
|
||||
myResourceTypeToSearchParamToEntity.put(key, searchParam);
|
||||
} else {
|
||||
searchParam = new SearchParam();
|
||||
searchParam.setResourceName(resourceType);
|
||||
searchParam.setParamName(paramName);
|
||||
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.setSearchParam(searchParam);
|
||||
present.setPresent(next.getValue());
|
||||
entitiesToSave.add(present);
|
||||
}
|
||||
|
||||
mySearchParamPresentDao.deleteInBatch(entitiesToDelete);
|
||||
mySearchParamPresentDao.save(entitiesToSave);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -2620,6 +2620,10 @@ public class FhirResourceDaoDstu3SearchNoFtTest extends BaseJpaDstu3Test {
|
|||
|
||||
result = myValueSetDao.search(ValueSet.SP_URL, new UriParam("http://hl7.org/fhir/ValueSet/").setQualifier(UriParamQualifierEnum.BELOW));
|
||||
assertThat(toUnqualifiedVersionlessIds(result), contains(id1));
|
||||
|
||||
result = myValueSetDao.search(ValueSet.SP_URL, new UriParam("http://hl7.org/fhir/ValueSet/FOOOOOO"));
|
||||
assertThat(toUnqualifiedVersionlessIds(result), empty());
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
Loading…
Reference in New Issue