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.DatabaseBackedPagingProvider;
|
||||||
import ca.uhn.fhir.jpa.search.IStaleSearchDeletingSvc;
|
import ca.uhn.fhir.jpa.search.IStaleSearchDeletingSvc;
|
||||||
import ca.uhn.fhir.jpa.search.StaleSearchDeletingSvcImpl;
|
import ca.uhn.fhir.jpa.search.StaleSearchDeletingSvcImpl;
|
||||||
|
import ca.uhn.fhir.jpa.sp.ISearchParamPresenceSvc;
|
||||||
|
import ca.uhn.fhir.jpa.sp.SearchParamPresenceSvcImpl;
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
@EnableScheduling
|
@EnableScheduling
|
||||||
|
@ -64,11 +66,6 @@ public class BaseConfig implements SchedulingConfigurer {
|
||||||
return retVal;
|
return retVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean(autowire=Autowire.BY_TYPE)
|
|
||||||
public IStaleSearchDeletingSvc staleSearchDeletingSvc() {
|
|
||||||
return new StaleSearchDeletingSvcImpl();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Bean()
|
@Bean()
|
||||||
public ScheduledExecutorFactoryBean scheduledExecutorService() {
|
public ScheduledExecutorFactoryBean scheduledExecutorService() {
|
||||||
ScheduledExecutorFactoryBean b = new ScheduledExecutorFactoryBean();
|
ScheduledExecutorFactoryBean b = new ScheduledExecutorFactoryBean();
|
||||||
|
@ -76,6 +73,16 @@ public class BaseConfig implements SchedulingConfigurer {
|
||||||
return b;
|
return b;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public ISearchParamPresenceSvc searchParamPresenceSvc() {
|
||||||
|
return new SearchParamPresenceSvcImpl();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean(autowire=Autowire.BY_TYPE)
|
||||||
|
public IStaleSearchDeletingSvc staleSearchDeletingSvc() {
|
||||||
|
return new StaleSearchDeletingSvcImpl();
|
||||||
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public TaskScheduler taskScheduler() {
|
public TaskScheduler taskScheduler() {
|
||||||
ConcurrentTaskScheduler retVal = new ConcurrentTaskScheduler();
|
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.RuntimeResourceDefinition;
|
||||||
import ca.uhn.fhir.context.RuntimeSearchParam;
|
import ca.uhn.fhir.context.RuntimeSearchParam;
|
||||||
import ca.uhn.fhir.jpa.dao.data.*;
|
import ca.uhn.fhir.jpa.dao.data.*;
|
||||||
import ca.uhn.fhir.jpa.entity.BaseHasResource;
|
import ca.uhn.fhir.jpa.entity.*;
|
||||||
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.search.PersistedJpaBundleProvider;
|
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.term.IHapiTerminologySvc;
|
||||||
import ca.uhn.fhir.jpa.util.DeleteConflict;
|
import ca.uhn.fhir.jpa.util.DeleteConflict;
|
||||||
import ca.uhn.fhir.model.api.IQueryParameterAnd;
|
import ca.uhn.fhir.model.api.IQueryParameterAnd;
|
||||||
|
@ -197,7 +178,6 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
|
||||||
protected EntityManager myEntityManager;
|
protected EntityManager myEntityManager;
|
||||||
@Autowired
|
@Autowired
|
||||||
protected IForcedIdDao myForcedIdDao;
|
protected IForcedIdDao myForcedIdDao;
|
||||||
|
|
||||||
@Autowired(required = false)
|
@Autowired(required = false)
|
||||||
protected IFulltextSearchSvc myFulltextSearchSvc;
|
protected IFulltextSearchSvc myFulltextSearchSvc;
|
||||||
@Autowired
|
@Autowired
|
||||||
|
@ -220,6 +200,9 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
|
||||||
@Autowired
|
@Autowired
|
||||||
private ISearchParamExtractor mySearchParamExtractor;
|
private ISearchParamExtractor mySearchParamExtractor;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ISearchParamPresenceSvc mySearchParamPresenceSvc;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private ISearchParamRegistry mySearchParamRegistry;
|
private ISearchParamRegistry mySearchParamRegistry;
|
||||||
|
|
||||||
|
@ -258,14 +241,19 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
|
||||||
return InstantDt.withCurrentTime();
|
return InstantDt.withCurrentTime();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Returns a set containing all of the parameter names that
|
||||||
|
* were found to have a value
|
||||||
|
*/
|
||||||
@SuppressWarnings("unchecked")
|
@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..
|
* 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) {
|
if (theResource instanceof IBaseBundle) {
|
||||||
return;
|
return Collections.emptySet();
|
||||||
}
|
}
|
||||||
|
|
||||||
RuntimeResourceDefinition def = getContext().getResourceDefinition(theResource);
|
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)) {
|
if (isLogicalReference(nextId)) {
|
||||||
ResourceLink resourceLink = new ResourceLink(nextPathAndRef.getPath(), theEntity, nextId, theUpdateTime);
|
ResourceLink resourceLink = new ResourceLink(nextPathAndRef.getPath(), theEntity, nextId, theUpdateTime);
|
||||||
if (theLinks.add(resourceLink)) {
|
if (theLinks.add(resourceLink)) {
|
||||||
|
@ -401,6 +391,7 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
|
||||||
|
|
||||||
theEntity.setHasLinks(theLinks.size() > 0);
|
theEntity.setHasLinks(theLinks.size() > 0);
|
||||||
|
|
||||||
|
return retVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Set<ResourceIndexedSearchParamCoords> extractSearchParamCoords(ResourceTable theEntity, IBaseResource theResource) {
|
protected Set<ResourceIndexedSearchParamCoords> extractSearchParamCoords(ResourceTable theEntity, IBaseResource theResource) {
|
||||||
|
@ -978,9 +969,9 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
|
||||||
* Subclasses may override to provide behaviour. Called when a resource has been inserted into the database for the first time.
|
* Subclasses may override to provide behaviour. Called when a resource has been inserted into the database for the first time.
|
||||||
*
|
*
|
||||||
* @param theEntity
|
* @param theEntity
|
||||||
* The entity being updated (Do not modify the entity! Undefined behaviour will occur!)
|
* The entity being updated (Do not modify the entity! Undefined behaviour will occur!)
|
||||||
* @param theTag
|
* @param theTag
|
||||||
* The tag
|
* The tag
|
||||||
*/
|
*/
|
||||||
protected void postPersist(ResourceTable theEntity, T theResource) {
|
protected void postPersist(ResourceTable theEntity, T theResource) {
|
||||||
// nothing
|
// nothing
|
||||||
|
@ -990,9 +981,9 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
|
||||||
* Subclasses may override to provide behaviour. Called when a pre-existing resource has been updated in the database
|
* Subclasses may override to provide behaviour. Called when a pre-existing resource has been updated in the database
|
||||||
*
|
*
|
||||||
* @param theEntity
|
* @param theEntity
|
||||||
* The resource
|
* The resource
|
||||||
* @param theResource
|
* @param theResource
|
||||||
* The resource being persisted
|
* The resource being persisted
|
||||||
*/
|
*/
|
||||||
protected void postUpdate(ResourceTable theEntity, T theResource) {
|
protected void postUpdate(ResourceTable theEntity, T theResource) {
|
||||||
// nothing
|
// nothing
|
||||||
|
@ -1053,9 +1044,9 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
|
||||||
* </p>
|
* </p>
|
||||||
*
|
*
|
||||||
* @param theEntity
|
* @param theEntity
|
||||||
* The entity being updated (Do not modify the entity! Undefined behaviour will occur!)
|
* The entity being updated (Do not modify the entity! Undefined behaviour will occur!)
|
||||||
* @param theTag
|
* @param theTag
|
||||||
* The tag
|
* The tag
|
||||||
* @return Retturns <code>true</code> if the tag should be removed
|
* @return Retturns <code>true</code> if the tag should be removed
|
||||||
*/
|
*/
|
||||||
protected boolean shouldDroppedTagBeRemovedOnUpdate(ResourceTable theEntity, ResourceTag theTag) {
|
protected boolean shouldDroppedTagBeRemovedOnUpdate(ResourceTable theEntity, ResourceTag theTag) {
|
||||||
|
@ -1343,7 +1334,7 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
|
||||||
}
|
}
|
||||||
|
|
||||||
links = new HashSet<ResourceLink>();
|
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
|
* 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);
|
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 {
|
||||||
|
|
||||||
populateResourceIntoEntity(theResource, theEntity);
|
populateResourceIntoEntity(theResource, theEntity);
|
||||||
|
@ -1502,6 +1516,12 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
|
||||||
return theEntity;
|
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) {
|
protected ResourceTable updateEntity(IBaseResource theResource, ResourceTable entity, Date theDeletedTimestampOrNull, Date theUpdateTime) {
|
||||||
return updateEntity(theResource, entity, theDeletedTimestampOrNull, true, true, theUpdateTime);
|
return updateEntity(theResource, entity, theDeletedTimestampOrNull, true, true, theUpdateTime);
|
||||||
}
|
}
|
||||||
|
@ -1594,9 +1614,9 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
|
||||||
* "subsetted" tag and rejects resources which have it. Subclasses should call the superclass implementation to preserve this check.
|
* "subsetted" tag and rejects resources which have it. Subclasses should call the superclass implementation to preserve this check.
|
||||||
*
|
*
|
||||||
* @param theResource
|
* @param theResource
|
||||||
* The resource that is about to be persisted
|
* The resource that is about to be persisted
|
||||||
* @param theEntityToSave
|
* @param theEntityToSave
|
||||||
* TODO
|
* TODO
|
||||||
*/
|
*/
|
||||||
protected void validateResourceForStorage(T theResource, ResourceTable theEntityToSave) {
|
protected void validateResourceForStorage(T theResource, ResourceTable theEntityToSave) {
|
||||||
Object tag = null;
|
Object tag = null;
|
||||||
|
|
|
@ -106,6 +106,8 @@ public class SearchBuilder {
|
||||||
|
|
||||||
private CriteriaBuilder myBuilder;
|
private CriteriaBuilder myBuilder;
|
||||||
|
|
||||||
|
private CriteriaQuery<Tuple> myResourceTableQuery;
|
||||||
|
|
||||||
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,
|
||||||
IResourceIndexedSearchParamUriDao theResourceIndexedSearchParamUriDao, IForcedIdDao theForcedIdDao, IHapiTerminologySvc theTerminologySvc, ISearchParamRegistry theSearchParamRegistry) {
|
IResourceIndexedSearchParamUriDao theResourceIndexedSearchParamUriDao, IForcedIdDao theForcedIdDao, IHapiTerminologySvc theTerminologySvc, ISearchParamRegistry theSearchParamRegistry) {
|
||||||
|
@ -317,7 +319,7 @@ public class SearchBuilder {
|
||||||
return missingFalse;
|
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) {
|
IQueryParameterType nextOr) {
|
||||||
boolean missingFalse = false;
|
boolean missingFalse = false;
|
||||||
if (nextOr.getMissing() != null) {
|
if (nextOr.getMissing() != null) {
|
||||||
|
@ -456,17 +458,14 @@ public class SearchBuilder {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
CriteriaBuilder builder = myEntityManager.getCriteriaBuilder();
|
Join<ResourceTable, ResourceLink> join = myResourceTableRoot.join("myResourceLinks", JoinType.LEFT);
|
||||||
CriteriaQuery<Long> cq = builder.createQuery(Long.class);
|
|
||||||
Root<ResourceLink> from = cq.from(ResourceLink.class);
|
|
||||||
cq.select(from.get("mySourceResourcePid").as(Long.class));
|
|
||||||
|
|
||||||
List<Predicate> codePredicates = new ArrayList<Predicate>();
|
List<Predicate> codePredicates = new ArrayList<Predicate>();
|
||||||
|
|
||||||
for (IQueryParameterType nextOr : theList) {
|
for (IQueryParameterType nextOr : theList) {
|
||||||
IQueryParameterType params = nextOr;
|
IQueryParameterType params = nextOr;
|
||||||
|
|
||||||
if (addPredicateMissingFalseIfPresentForResourceLink(builder, theParamName, from, codePredicates, nextOr)) {
|
if (addPredicateMissingFalseIfPresentForResourceLink(myBuilder, theParamName, join, codePredicates, nextOr)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -481,7 +480,7 @@ public class SearchBuilder {
|
||||||
dt = dt.toUnqualified();
|
dt = dt.toUnqualified();
|
||||||
} else {
|
} else {
|
||||||
ourLog.debug("Searching for resource link with target URL: {}", dt.getValue());
|
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);
|
codePredicates.add(eq);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -491,12 +490,12 @@ public class SearchBuilder {
|
||||||
try {
|
try {
|
||||||
targetPid = myCallingDao.translateForcedIdToPids(dt);
|
targetPid = myCallingDao.translateForcedIdToPids(dt);
|
||||||
} catch (ResourceNotFoundException e) {
|
} catch (ResourceNotFoundException e) {
|
||||||
doSetPids(new ArrayList<Long>());
|
// Use a PID that will never exist
|
||||||
return;
|
targetPid = Collections.singletonList(-1L);
|
||||||
}
|
}
|
||||||
for (Long next : targetPid) {
|
for (Long next : targetPid) {
|
||||||
ourLog.debug("Searching for resource link with target PID: {}", next);
|
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);
|
codePredicates.add(eq);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -586,13 +585,35 @@ 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);
|
||||||
if (pids.isEmpty()) {
|
Root<ResourceTable> subQfrom = subQ.from(ResourceTable.class);
|
||||||
continue;
|
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);
|
codePredicates.add(eq);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -608,16 +629,7 @@ public class SearchBuilder {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
List<Predicate> predicates = new ArrayList<Predicate>();
|
myPredicates.add(myBuilder.or(toArray(codePredicates)));
|
||||||
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()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addPredicateString(String theParamName, List<? extends IQueryParameterType> theList) {
|
private void addPredicateString(String theParamName, List<? extends IQueryParameterType> theList) {
|
||||||
|
@ -713,8 +725,6 @@ public class SearchBuilder {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
CriteriaBuilder builder = myEntityManager.getCriteriaBuilder();
|
|
||||||
|
|
||||||
boolean paramInverted = false;
|
boolean paramInverted = false;
|
||||||
List<Pair<String, String>> tokens = Lists.newArrayList();
|
List<Pair<String, String>> tokens = Lists.newArrayList();
|
||||||
for (IQueryParameterType nextOrParams : nextAndParams) {
|
for (IQueryParameterType nextOrParams : nextAndParams) {
|
||||||
|
@ -745,19 +755,11 @@ public class SearchBuilder {
|
||||||
if (paramInverted) {
|
if (paramInverted) {
|
||||||
ourLog.debug("Searching for _tag:not");
|
ourLog.debug("Searching for _tag:not");
|
||||||
|
|
||||||
CriteriaQuery<Long> cq = builder.createQuery(Long.class);
|
Subquery<Long> subQ = myResourceTableQuery.subquery(Long.class);
|
||||||
Root<ResourceTable> newFrom = cq.from(ResourceTable.class);
|
|
||||||
|
|
||||||
Subquery<Long> subQ = cq.subquery(Long.class);
|
|
||||||
Root<ResourceTag> subQfrom = subQ.from(ResourceTag.class);
|
Root<ResourceTag> subQfrom = subQ.from(ResourceTag.class);
|
||||||
subQ.select(subQfrom.get("myResourceId").as(Long.class));
|
subQ.select(subQfrom.get("myResourceId").as(Long.class));
|
||||||
|
|
||||||
cq.select(newFrom.get("myId").as(Long.class));
|
myPredicates.add(myBuilder.not(myBuilder.in(myResourceTableRoot.get("myId")).value(subQ)));
|
||||||
|
|
||||||
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)));
|
|
||||||
|
|
||||||
Subquery<Long> defJoin = subQ.subquery(Long.class);
|
Subquery<Long> defJoin = subQ.subquery(Long.class);
|
||||||
Root<TagDefinition> defJoinFrom = defJoin.from(TagDefinition.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));
|
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));
|
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;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
CriteriaQuery<Long> cq = builder.createQuery(Long.class);
|
Join<ResourceTable, ResourceTag> tagJoin = myResourceTableRoot.join("myTags", JoinType.LEFT);
|
||||||
Root<ResourceTag> from = cq.from(ResourceTag.class);
|
From<ResourceTag, TagDefinition> defJoin = tagJoin.join("myTag");
|
||||||
List<Predicate> andPredicates = new ArrayList<Predicate>();
|
|
||||||
andPredicates.add(builder.equal(from.get("myResourceType"), myResourceName));
|
|
||||||
From<ResourceTag, TagDefinition> defJoin = from.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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
CriteriaBuilder builder = myEntityManager.getCriteriaBuilder();
|
Join<ResourceTable, ResourceIndexedSearchParamUri> join = myResourceTableRoot.join("myParamsUri", JoinType.LEFT);
|
||||||
CriteriaQuery<Long> cq = builder.createQuery(Long.class);
|
|
||||||
Root<ResourceIndexedSearchParamUri> from = cq.from(ResourceIndexedSearchParamUri.class);
|
|
||||||
cq.select(from.get("myResourcePid").as(Long.class));
|
|
||||||
|
|
||||||
List<Predicate> codePredicates = new ArrayList<Predicate>();
|
List<Predicate> codePredicates = new ArrayList<Predicate>();
|
||||||
for (IQueryParameterType nextOr : theList) {
|
for (IQueryParameterType nextOr : theList) {
|
||||||
IQueryParameterType params = nextOr;
|
IQueryParameterType params = nextOr;
|
||||||
|
|
||||||
if (addPredicateMissingFalseIfPresent(builder, theParamName, from, codePredicates, nextOr)) {
|
if (addPredicateMissingFalseIfPresent(myBuilder, theParamName, join, codePredicates, nextOr)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -872,7 +845,7 @@ public class SearchBuilder {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
Path<Object> fromObj = from.get("myUri");
|
Path<Object> fromObj = join.get("myUri");
|
||||||
Predicate predicate;
|
Predicate predicate;
|
||||||
if (param.getQualifier() == UriParamQualifierEnum.ABOVE) {
|
if (param.getQualifier() == UriParamQualifierEnum.ABOVE) {
|
||||||
|
|
||||||
|
@ -905,9 +878,9 @@ public class SearchBuilder {
|
||||||
predicate = fromObj.as(String.class).in(toFind);
|
predicate = fromObj.as(String.class).in(toFind);
|
||||||
|
|
||||||
} else if (param.getQualifier() == UriParamQualifierEnum.BELOW) {
|
} 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 {
|
} else {
|
||||||
predicate = builder.equal(fromObj.as(String.class), value);
|
predicate = myBuilder.equal(fromObj.as(String.class), value);
|
||||||
}
|
}
|
||||||
codePredicates.add(predicate);
|
codePredicates.add(predicate);
|
||||||
} else {
|
} else {
|
||||||
|
@ -921,16 +894,8 @@ public class SearchBuilder {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
List<Predicate> predicates = new ArrayList<Predicate>();
|
Predicate orPredicate = myBuilder.or(toArray(codePredicates));
|
||||||
predicates.add(builder.equal(from.get("myResourceType"), myResourceName));
|
myPredicates.add(orPredicate);
|
||||||
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()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private Predicate createCompositeParamPart(CriteriaBuilder builder, Root<ResourceTable> from, RuntimeSearchParam left, IQueryParameterType leftValue) {
|
private Predicate createCompositeParamPart(CriteriaBuilder builder, Root<ResourceTable> from, RuntimeSearchParam left, IQueryParameterType leftValue) {
|
||||||
|
@ -1300,7 +1265,7 @@ public class SearchBuilder {
|
||||||
return singleCode;
|
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);
|
return createResourceLinkPathPredicate(myCallingDao, myContext, theParamName, from, myResourceType);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1642,9 +1607,9 @@ public class SearchBuilder {
|
||||||
}
|
}
|
||||||
|
|
||||||
myBuilder = myEntityManager.getCriteriaBuilder();
|
myBuilder = myEntityManager.getCriteriaBuilder();
|
||||||
CriteriaQuery<Tuple> cq = myBuilder.createTupleQuery();
|
myResourceTableQuery = myBuilder.createTupleQuery();
|
||||||
cq.distinct(true);
|
myResourceTableQuery.distinct(true);
|
||||||
myResourceTableRoot = cq.from(ResourceTable.class);
|
myResourceTableRoot = myResourceTableQuery.from(ResourceTable.class);
|
||||||
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")));
|
||||||
|
@ -1655,10 +1620,10 @@ public class SearchBuilder {
|
||||||
|
|
||||||
searchForIdsWithAndOr(theParams);
|
searchForIdsWithAndOr(theParams);
|
||||||
|
|
||||||
cq.where(myBuilder.and(SearchBuilder.toArray(myPredicates)));
|
myResourceTableQuery.where(myBuilder.and(SearchBuilder.toArray(myPredicates)));
|
||||||
|
|
||||||
cq.multiselect(myResourceTableRoot.get("myId").as(Long.class));
|
myResourceTableQuery.multiselect(myResourceTableRoot.get("myId").as(Long.class));
|
||||||
TypedQuery<Tuple> query = myEntityManager.createQuery(cq);
|
TypedQuery<Tuple> query = myEntityManager.createQuery(myResourceTableQuery);
|
||||||
query.setFirstResult(theFromIndex);
|
query.setFirstResult(theFromIndex);
|
||||||
query.setMaxResults(theToIndex - theFromIndex);
|
query.setMaxResults(theToIndex - theFromIndex);
|
||||||
|
|
||||||
|
@ -1774,80 +1739,85 @@ public class SearchBuilder {
|
||||||
|
|
||||||
for (Entry<String, List<List<? extends IQueryParameterType>>> nextParamEntry : params.entrySet()) {
|
for (Entry<String, List<List<? extends IQueryParameterType>>> nextParamEntry : params.entrySet()) {
|
||||||
String nextParamName = nextParamEntry.getKey();
|
String nextParamName = nextParamEntry.getKey();
|
||||||
if (nextParamName.equals(BaseResource.SP_RES_ID)) {
|
List<List<? extends IQueryParameterType>> andOrParams = nextParamEntry.getValue();
|
||||||
|
searchForIdsWithAndOr(nextParamName, andOrParams);
|
||||||
addPredicateResourceId(nextParamEntry.getValue());
|
|
||||||
|
|
||||||
} else if (nextParamName.equals(BaseResource.SP_RES_LANGUAGE)) {
|
|
||||||
|
|
||||||
addPredicateLanguage(nextParamEntry.getValue());
|
|
||||||
|
|
||||||
} else if (nextParamName.equals(Constants.PARAM_HAS)) {
|
|
||||||
|
|
||||||
// FIXME
|
|
||||||
addPredicateHas(nextParamEntry.getValue(), null);
|
|
||||||
|
|
||||||
} else if (nextParamName.equals(Constants.PARAM_TAG) || nextParamName.equals(Constants.PARAM_PROFILE) || nextParamName.equals(Constants.PARAM_SECURITY)) {
|
|
||||||
|
|
||||||
// FIXME
|
|
||||||
addPredicateTag(nextParamEntry.getValue(), nextParamName, null);
|
|
||||||
|
|
||||||
} else {
|
|
||||||
|
|
||||||
RuntimeSearchParam nextParamDef = mySearchParamRegistry.getActiveSearchParam(myResourceName, nextParamName);
|
|
||||||
if (nextParamDef != null) {
|
|
||||||
switch (nextParamDef.getParamType()) {
|
|
||||||
case DATE:
|
|
||||||
for (List<? extends IQueryParameterType> nextAnd : nextParamEntry.getValue()) {
|
|
||||||
addPredicateDate(nextParamName, nextAnd);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case QUANTITY:
|
|
||||||
for (List<? extends IQueryParameterType> nextAnd : nextParamEntry.getValue()) {
|
|
||||||
addPredicateQuantity(nextParamName, nextAnd);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case REFERENCE:
|
|
||||||
for (List<? extends IQueryParameterType> nextAnd : nextParamEntry.getValue()) {
|
|
||||||
addPredicateReference(nextParamName, nextAnd);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case STRING:
|
|
||||||
for (List<? extends IQueryParameterType> nextAnd : nextParamEntry.getValue()) {
|
|
||||||
addPredicateString(nextParamName, nextAnd);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case TOKEN:
|
|
||||||
for (List<? extends IQueryParameterType> nextAnd : nextParamEntry.getValue()) {
|
|
||||||
addPredicateToken(nextParamName, nextAnd);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case NUMBER:
|
|
||||||
for (List<? extends IQueryParameterType> nextAnd : nextParamEntry.getValue()) {
|
|
||||||
addPredicateNumber(nextParamName, nextAnd);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case COMPOSITE:
|
|
||||||
for (List<? extends IQueryParameterType> nextAnd : nextParamEntry.getValue()) {
|
|
||||||
addPredicateComposite(nextParamDef, nextAnd);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case URI:
|
|
||||||
for (List<? extends IQueryParameterType> nextAnd : nextParamEntry.getValue()) {
|
|
||||||
addPredicateUri(nextParamName, nextAnd);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case HAS:
|
|
||||||
// should not happen
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void searchForIdsWithAndOr(String nextParamName, List<List<? extends IQueryParameterType>> andOrParams) {
|
||||||
|
if (nextParamName.equals(BaseResource.SP_RES_ID)) {
|
||||||
|
|
||||||
|
addPredicateResourceId(andOrParams);
|
||||||
|
|
||||||
|
} else if (nextParamName.equals(BaseResource.SP_RES_LANGUAGE)) {
|
||||||
|
|
||||||
|
addPredicateLanguage(andOrParams);
|
||||||
|
|
||||||
|
} else if (nextParamName.equals(Constants.PARAM_HAS)) {
|
||||||
|
|
||||||
|
// FIXME
|
||||||
|
addPredicateHas(andOrParams, null);
|
||||||
|
|
||||||
|
} else if (nextParamName.equals(Constants.PARAM_TAG) || nextParamName.equals(Constants.PARAM_PROFILE) || nextParamName.equals(Constants.PARAM_SECURITY)) {
|
||||||
|
|
||||||
|
// FIXME
|
||||||
|
addPredicateTag(andOrParams, nextParamName, null);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
RuntimeSearchParam nextParamDef = mySearchParamRegistry.getActiveSearchParam(myResourceName, nextParamName);
|
||||||
|
if (nextParamDef != null) {
|
||||||
|
switch (nextParamDef.getParamType()) {
|
||||||
|
case DATE:
|
||||||
|
for (List<? extends IQueryParameterType> nextAnd : andOrParams) {
|
||||||
|
addPredicateDate(nextParamName, nextAnd);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case QUANTITY:
|
||||||
|
for (List<? extends IQueryParameterType> nextAnd : andOrParams) {
|
||||||
|
addPredicateQuantity(nextParamName, nextAnd);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case REFERENCE:
|
||||||
|
for (List<? extends IQueryParameterType> nextAnd : andOrParams) {
|
||||||
|
addPredicateReference(nextParamName, nextAnd);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case STRING:
|
||||||
|
for (List<? extends IQueryParameterType> nextAnd : andOrParams) {
|
||||||
|
addPredicateString(nextParamName, nextAnd);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case TOKEN:
|
||||||
|
for (List<? extends IQueryParameterType> nextAnd : andOrParams) {
|
||||||
|
addPredicateToken(nextParamName, nextAnd);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case NUMBER:
|
||||||
|
for (List<? extends IQueryParameterType> nextAnd : andOrParams) {
|
||||||
|
addPredicateNumber(nextParamName, nextAnd);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case COMPOSITE:
|
||||||
|
for (List<? extends IQueryParameterType> nextAnd : andOrParams) {
|
||||||
|
addPredicateComposite(nextParamDef, nextAnd);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case URI:
|
||||||
|
for (List<? extends IQueryParameterType> nextAnd : andOrParams) {
|
||||||
|
addPredicateUri(nextParamName, nextAnd);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case HAS:
|
||||||
|
// should not happen
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void addPredicateResourceId(List<List<? extends IQueryParameterType>> theValues) {
|
private void addPredicateResourceId(List<List<? extends IQueryParameterType>> theValues) {
|
||||||
for (List<? extends IQueryParameterType> nextValue : theValues) {
|
for (List<? extends IQueryParameterType> nextValue : theValues) {
|
||||||
Set<Long> orPids = new HashSet<Long>();
|
Set<Long> orPids = new HashSet<Long>();
|
||||||
|
@ -1972,7 +1942,7 @@ public class SearchBuilder {
|
||||||
return likeExpression.replace("%", "[%]") + "%";
|
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) {
|
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);
|
||||||
|
|
|
@ -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;
|
import ca.uhn.fhir.model.primitive.InstantDt;
|
||||||
|
|
||||||
//@formatter:off
|
|
||||||
@Embeddable
|
@Embeddable
|
||||||
@Entity
|
@Entity
|
||||||
@Table(name = "HFJ_SPIDX_DATE", indexes= {
|
@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_UPDATED", columnList = "SP_UPDATED"),
|
||||||
@Index(name = "IDX_SP_DATE_RESID", columnList = "RES_ID")
|
@Index(name = "IDX_SP_DATE_RESID", columnList = "RES_ID")
|
||||||
})
|
})
|
||||||
//@formatter:on
|
|
||||||
public class ResourceIndexedSearchParamDate extends BaseResourceIndexedSearchParam {
|
public class ResourceIndexedSearchParamDate extends BaseResourceIndexedSearchParam {
|
||||||
|
|
||||||
private static final long serialVersionUID = 1L;
|
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));
|
result = myValueSetDao.search(ValueSet.SP_URL, new UriParam("http://hl7.org/fhir/ValueSet/").setQualifier(UriParamQualifierEnum.BELOW));
|
||||||
assertThat(toUnqualifiedVersionlessIds(result), contains(id1));
|
assertThat(toUnqualifiedVersionlessIds(result), contains(id1));
|
||||||
|
|
||||||
|
result = myValueSetDao.search(ValueSet.SP_URL, new UriParam("http://hl7.org/fhir/ValueSet/FOOOOOO"));
|
||||||
|
assertThat(toUnqualifiedVersionlessIds(result), empty());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
Loading…
Reference in New Issue