Refactor search capability in JPA out of resource specific module
This commit is contained in:
parent
65598c200e
commit
30ab0203a3
|
@ -48,6 +48,7 @@ import javax.persistence.criteria.Root;
|
||||||
import javax.xml.stream.events.Characters;
|
import javax.xml.stream.events.Characters;
|
||||||
import javax.xml.stream.events.XMLEvent;
|
import javax.xml.stream.events.XMLEvent;
|
||||||
|
|
||||||
|
import org.apache.commons.lang3.NotImplementedException;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.apache.http.NameValuePair;
|
import org.apache.http.NameValuePair;
|
||||||
import org.apache.http.client.utils.URLEncodedUtils;
|
import org.apache.http.client.utils.URLEncodedUtils;
|
||||||
|
@ -134,11 +135,11 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
|
||||||
/**
|
/**
|
||||||
* These are parameters which are supported by {@link BaseHapiFhirResourceDao#searchForIds(Map)}
|
* These are parameters which are supported by {@link BaseHapiFhirResourceDao#searchForIds(Map)}
|
||||||
*/
|
*/
|
||||||
protected static final Map<String, Class<? extends IQueryParameterType>> RESOURCE_META_PARAMS;
|
static final Map<String, Class<? extends IQueryParameterType>> RESOURCE_META_PARAMS;
|
||||||
/**
|
/**
|
||||||
* These are parameters which are supported by {@link BaseHapiFhirResourceDao#searchForIds(Map)}
|
* These are parameters which are supported by {@link BaseHapiFhirResourceDao#searchForIds(Map)}
|
||||||
*/
|
*/
|
||||||
protected static final Map<String, Class<? extends IQueryParameterAnd<?>>> RESOURCE_META_AND_PARAMS;
|
static final Map<String, Class<? extends IQueryParameterAnd<?>>> RESOURCE_META_AND_PARAMS;
|
||||||
|
|
||||||
static {
|
static {
|
||||||
Map<String, Class<? extends IQueryParameterType>> resourceMetaParams = new HashMap<String, Class<? extends IQueryParameterType>>();
|
Map<String, Class<? extends IQueryParameterType>> resourceMetaParams = new HashMap<String, Class<? extends IQueryParameterType>>();
|
||||||
|
@ -1535,4 +1536,8 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
|
||||||
return b.toString();
|
return b.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public BaseHasResource readEntity(IIdType theValueId) {
|
||||||
|
throw new NotImplementedException("");
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,20 +22,15 @@ package ca.uhn.fhir.jpa.dao;
|
||||||
import static org.apache.commons.lang3.StringUtils.isBlank;
|
import static org.apache.commons.lang3.StringUtils.isBlank;
|
||||||
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.LinkedHashSet;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Map.Entry;
|
import java.util.Map.Entry;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
import javax.annotation.PostConstruct;
|
import javax.annotation.PostConstruct;
|
||||||
import javax.persistence.EntityManager;
|
import javax.persistence.EntityManager;
|
||||||
|
@ -43,94 +38,45 @@ import javax.persistence.NoResultException;
|
||||||
import javax.persistence.PersistenceContext;
|
import javax.persistence.PersistenceContext;
|
||||||
import javax.persistence.PersistenceContextType;
|
import javax.persistence.PersistenceContextType;
|
||||||
import javax.persistence.TemporalType;
|
import javax.persistence.TemporalType;
|
||||||
import javax.persistence.Tuple;
|
|
||||||
import javax.persistence.TypedQuery;
|
import javax.persistence.TypedQuery;
|
||||||
import javax.persistence.criteria.CriteriaBuilder;
|
|
||||||
import javax.persistence.criteria.CriteriaQuery;
|
|
||||||
import javax.persistence.criteria.Expression;
|
|
||||||
import javax.persistence.criteria.From;
|
|
||||||
import javax.persistence.criteria.Join;
|
|
||||||
import javax.persistence.criteria.JoinType;
|
|
||||||
import javax.persistence.criteria.Order;
|
|
||||||
import javax.persistence.criteria.Path;
|
|
||||||
import javax.persistence.criteria.Predicate;
|
|
||||||
import javax.persistence.criteria.Root;
|
|
||||||
import javax.persistence.criteria.Subquery;
|
|
||||||
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
|
||||||
import org.hl7.fhir.instance.model.api.IBaseOperationOutcome;
|
import org.hl7.fhir.instance.model.api.IBaseOperationOutcome;
|
||||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||||
import org.hl7.fhir.instance.model.api.IIdType;
|
import org.hl7.fhir.instance.model.api.IIdType;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.beans.factory.annotation.Required;
|
import org.springframework.beans.factory.annotation.Required;
|
||||||
import org.springframework.transaction.PlatformTransactionManager;
|
import org.springframework.transaction.PlatformTransactionManager;
|
||||||
import org.springframework.transaction.TransactionStatus;
|
|
||||||
import org.springframework.transaction.annotation.Propagation;
|
import org.springframework.transaction.annotation.Propagation;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
import org.springframework.transaction.support.TransactionCallback;
|
|
||||||
import org.springframework.transaction.support.TransactionTemplate;
|
|
||||||
|
|
||||||
import ca.uhn.fhir.context.BaseRuntimeChildDefinition;
|
|
||||||
import ca.uhn.fhir.context.ConfigurationException;
|
import ca.uhn.fhir.context.ConfigurationException;
|
||||||
import ca.uhn.fhir.context.FhirVersionEnum;
|
import ca.uhn.fhir.context.FhirVersionEnum;
|
||||||
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.SearchParameterMap.EverythingModeEnum;
|
|
||||||
import ca.uhn.fhir.jpa.dao.data.ISearchResultDao;
|
import ca.uhn.fhir.jpa.dao.data.ISearchResultDao;
|
||||||
import ca.uhn.fhir.jpa.entity.BaseHasResource;
|
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.BaseTag;
|
||||||
import ca.uhn.fhir.jpa.entity.ResourceHistoryTable;
|
import ca.uhn.fhir.jpa.entity.ResourceHistoryTable;
|
||||||
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.ResourceLink;
|
||||||
import ca.uhn.fhir.jpa.entity.ResourceTable;
|
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.SearchResult;
|
|
||||||
import ca.uhn.fhir.jpa.entity.TagDefinition;
|
import ca.uhn.fhir.jpa.entity.TagDefinition;
|
||||||
import ca.uhn.fhir.jpa.entity.TagTypeEnum;
|
import ca.uhn.fhir.jpa.entity.TagTypeEnum;
|
||||||
import ca.uhn.fhir.jpa.interceptor.IJpaServerInterceptor;
|
import ca.uhn.fhir.jpa.interceptor.IJpaServerInterceptor;
|
||||||
import ca.uhn.fhir.jpa.util.StopWatch;
|
import ca.uhn.fhir.jpa.util.StopWatch;
|
||||||
import ca.uhn.fhir.model.api.IPrimitiveDatatype;
|
|
||||||
import ca.uhn.fhir.model.api.IQueryParameterType;
|
import ca.uhn.fhir.model.api.IQueryParameterType;
|
||||||
import ca.uhn.fhir.model.api.IResource;
|
import ca.uhn.fhir.model.api.IResource;
|
||||||
import ca.uhn.fhir.model.api.Include;
|
import ca.uhn.fhir.model.api.Include;
|
||||||
import ca.uhn.fhir.model.api.ResourceMetadataKeyEnum;
|
import ca.uhn.fhir.model.api.ResourceMetadataKeyEnum;
|
||||||
import ca.uhn.fhir.model.api.TagList;
|
import ca.uhn.fhir.model.api.TagList;
|
||||||
import ca.uhn.fhir.model.base.composite.BaseCodingDt;
|
|
||||||
import ca.uhn.fhir.model.base.composite.BaseIdentifierDt;
|
|
||||||
import ca.uhn.fhir.model.base.composite.BaseQuantityDt;
|
|
||||||
import ca.uhn.fhir.model.dstu.resource.BaseResource;
|
|
||||||
import ca.uhn.fhir.model.dstu.valueset.QuantityCompararatorEnum;
|
|
||||||
import ca.uhn.fhir.model.dstu2.composite.CodingDt;
|
import ca.uhn.fhir.model.dstu2.composite.CodingDt;
|
||||||
import ca.uhn.fhir.model.dstu2.composite.MetaDt;
|
import ca.uhn.fhir.model.dstu2.composite.MetaDt;
|
||||||
import ca.uhn.fhir.model.primitive.IdDt;
|
import ca.uhn.fhir.model.primitive.IdDt;
|
||||||
import ca.uhn.fhir.model.primitive.InstantDt;
|
import ca.uhn.fhir.model.primitive.InstantDt;
|
||||||
import ca.uhn.fhir.model.primitive.UriDt;
|
import ca.uhn.fhir.model.primitive.UriDt;
|
||||||
import ca.uhn.fhir.model.valueset.BundleEntrySearchModeEnum;
|
|
||||||
import ca.uhn.fhir.rest.api.RestOperationTypeEnum;
|
import ca.uhn.fhir.rest.api.RestOperationTypeEnum;
|
||||||
import ca.uhn.fhir.rest.api.SortOrderEnum;
|
|
||||||
import ca.uhn.fhir.rest.api.SortSpec;
|
|
||||||
import ca.uhn.fhir.rest.method.RestSearchParameterTypeEnum;
|
import ca.uhn.fhir.rest.method.RestSearchParameterTypeEnum;
|
||||||
import ca.uhn.fhir.rest.param.CompositeParam;
|
|
||||||
import ca.uhn.fhir.rest.param.DateParam;
|
|
||||||
import ca.uhn.fhir.rest.param.DateRangeParam;
|
import ca.uhn.fhir.rest.param.DateRangeParam;
|
||||||
import ca.uhn.fhir.rest.param.NumberParam;
|
|
||||||
import ca.uhn.fhir.rest.param.QuantityParam;
|
|
||||||
import ca.uhn.fhir.rest.param.ReferenceParam;
|
|
||||||
import ca.uhn.fhir.rest.param.StringParam;
|
|
||||||
import ca.uhn.fhir.rest.param.TokenParam;
|
|
||||||
import ca.uhn.fhir.rest.param.UriParam;
|
|
||||||
import ca.uhn.fhir.rest.server.Constants;
|
|
||||||
import ca.uhn.fhir.rest.server.IBundleProvider;
|
import ca.uhn.fhir.rest.server.IBundleProvider;
|
||||||
import ca.uhn.fhir.rest.server.SimpleBundleProvider;
|
|
||||||
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
|
||||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||||
import ca.uhn.fhir.rest.server.exceptions.PreconditionFailedException;
|
import ca.uhn.fhir.rest.server.exceptions.PreconditionFailedException;
|
||||||
import ca.uhn.fhir.rest.server.exceptions.ResourceGoneException;
|
import ca.uhn.fhir.rest.server.exceptions.ResourceGoneException;
|
||||||
|
@ -143,7 +89,7 @@ import ca.uhn.fhir.util.FhirTerser;
|
||||||
import ca.uhn.fhir.util.ObjectUtil;
|
import ca.uhn.fhir.util.ObjectUtil;
|
||||||
|
|
||||||
@Transactional(propagation = Propagation.REQUIRED)
|
@Transactional(propagation = Propagation.REQUIRED)
|
||||||
public abstract class BaseHapiFhirResourceDao<T extends IResource> extends BaseHapiFhirDao<T>implements IFhirResourceDao<T> {
|
public abstract class BaseHapiFhirResourceDao<T extends IResource> extends BaseHapiFhirDao<T> implements IFhirResourceDao<T> {
|
||||||
|
|
||||||
static final String OO_SEVERITY_ERROR = "error";
|
static final String OO_SEVERITY_ERROR = "error";
|
||||||
static final String OO_SEVERITY_INFO = "information";
|
static final String OO_SEVERITY_INFO = "information";
|
||||||
|
@ -160,7 +106,7 @@ public abstract class BaseHapiFhirResourceDao<T extends IResource> extends BaseH
|
||||||
@Autowired
|
@Autowired
|
||||||
private DaoConfig myDaoConfig;
|
private DaoConfig myDaoConfig;
|
||||||
|
|
||||||
@Autowired(required=false)
|
@Autowired(required = false)
|
||||||
private ISearchDao mySearchDao;
|
private ISearchDao mySearchDao;
|
||||||
|
|
||||||
private String myResourceName;
|
private String myResourceName;
|
||||||
|
@ -170,7 +116,6 @@ public abstract class BaseHapiFhirResourceDao<T extends IResource> extends BaseH
|
||||||
@Autowired()
|
@Autowired()
|
||||||
private ISearchResultDao mySearchResultDao;
|
private ISearchResultDao mySearchResultDao;
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addTag(IIdType theId, TagTypeEnum theTagType, String theScheme, String theTerm, String theLabel) {
|
public void addTag(IIdType theId, TagTypeEnum theTagType, String theScheme, String theTerm, String theLabel) {
|
||||||
StopWatch w = new StopWatch();
|
StopWatch w = new StopWatch();
|
||||||
|
@ -227,8 +172,6 @@ public abstract class BaseHapiFhirResourceDao<T extends IResource> extends BaseH
|
||||||
return doCreate(theResource, theIfNoneExist, thePerformIndexing, new Date());
|
return doCreate(theResource, theIfNoneExist, thePerformIndexing, new Date());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
protected IBaseOperationOutcome createErrorOperationOutcome(String theMessage) {
|
protected IBaseOperationOutcome createErrorOperationOutcome(String theMessage) {
|
||||||
return createOperationOutcome(OO_SEVERITY_ERROR, theMessage);
|
return createOperationOutcome(OO_SEVERITY_ERROR, theMessage);
|
||||||
}
|
}
|
||||||
|
@ -239,7 +182,6 @@ public abstract class BaseHapiFhirResourceDao<T extends IResource> extends BaseH
|
||||||
|
|
||||||
protected abstract IBaseOperationOutcome createOperationOutcome(String theSeverity, String theMessage);
|
protected abstract IBaseOperationOutcome createOperationOutcome(String theSeverity, String theMessage);
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public DaoMethodOutcome delete(IIdType theId) {
|
public DaoMethodOutcome delete(IIdType theId) {
|
||||||
if (theId == null || !theId.hasIdPart()) {
|
if (theId == null || !theId.hasIdPart()) {
|
||||||
|
@ -343,8 +285,7 @@ public abstract class BaseHapiFhirResourceDao<T extends IResource> extends BaseH
|
||||||
|
|
||||||
if (isNotBlank(theResource.getId().getIdPart())) {
|
if (isNotBlank(theResource.getId().getIdPart())) {
|
||||||
if (isValidPid(theResource.getId())) {
|
if (isValidPid(theResource.getId())) {
|
||||||
throw new UnprocessableEntityException(
|
throw new UnprocessableEntityException("This server cannot create an entity with a user-specified numeric ID - Client should not specify an ID when creating a new resource, or should include at least one letter in the ID to force a client-defined ID");
|
||||||
"This server cannot create an entity with a user-specified numeric ID - Client should not specify an ID when creating a new resource, or should include at least one letter in the ID to force a client-defined ID");
|
|
||||||
}
|
}
|
||||||
createForcedIdIfNeeded(entity, theResource.getId());
|
createForcedIdIfNeeded(entity, theResource.getId());
|
||||||
|
|
||||||
|
@ -550,240 +491,87 @@ public abstract class BaseHapiFhirResourceDao<T extends IResource> extends BaseH
|
||||||
return retVal;
|
return retVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void loadResourcesByPid(Collection<Long> theIncludePids, List<IBaseResource> theResourceListToPopulate, Set<Long> theRevIncludedPids, boolean theForHistoryOperation) {
|
// @Override
|
||||||
if (theIncludePids.isEmpty()) {
|
// public IBundleProvider everything(IIdType theId) {
|
||||||
return;
|
// Search search = new Search();
|
||||||
}
|
// search.setUuid(UUID.randomUUID().toString());
|
||||||
|
// search.setCreated(new Date());
|
||||||
Map<Long, Integer> position = new HashMap<Long, Integer>();
|
// myEntityManager.persist(search);
|
||||||
for (Long next : theIncludePids) {
|
//
|
||||||
position.put(next, theResourceListToPopulate.size());
|
// List<SearchResult> results = new ArrayList<SearchResult>();
|
||||||
theResourceListToPopulate.add(null);
|
// if (theId != null) {
|
||||||
}
|
// Long pid = translateForcedIdToPid(theId);
|
||||||
|
// ResourceTable entity = myEntityManager.find(ResourceTable.class, pid);
|
||||||
CriteriaBuilder builder = myEntityManager.getCriteriaBuilder();
|
// validateGivenIdIsAppropriateToRetrieveResource(theId, entity);
|
||||||
CriteriaQuery<ResourceTable> cq = builder.createQuery(ResourceTable.class);
|
// SearchResult res = new SearchResult(search);
|
||||||
Root<ResourceTable> from = cq.from(ResourceTable.class);
|
// res.setResourcePid(pid);
|
||||||
cq.where(from.get("myId").in(theIncludePids));
|
// results.add(res);
|
||||||
TypedQuery<ResourceTable> q = myEntityManager.createQuery(cq);
|
// } else {
|
||||||
|
// TypedQuery<Tuple> query = createSearchAllByTypeQuery();
|
||||||
for (ResourceTable next : q.getResultList()) {
|
// for (Tuple next : query.getResultList()) {
|
||||||
Class<? extends IBaseResource> resourceType = getContext().getResourceDefinition(next.getResourceType()).getImplementingClass();
|
// SearchResult res = new SearchResult(search);
|
||||||
IResource resource = (IResource) toResource(resourceType, next, theForHistoryOperation);
|
// res.setResourcePid(next.get(0, Long.class));
|
||||||
Integer index = position.get(next.getId());
|
// results.add(res);
|
||||||
if (index == null) {
|
// }
|
||||||
ourLog.warn("Got back unexpected resource PID {}", next.getId());
|
// }
|
||||||
continue;
|
//
|
||||||
}
|
// int totalCount = results.size();
|
||||||
|
// mySearchResultDao.save(results);
|
||||||
if (theRevIncludedPids.contains(next.getId())) {
|
// mySearchResultDao.flush();
|
||||||
ResourceMetadataKeyEnum.ENTRY_SEARCH_MODE.put(resource, BundleEntrySearchModeEnum.INCLUDE);
|
//
|
||||||
} else {
|
// CriteriaBuilder builder = myEntityManager.getCriteriaBuilder();
|
||||||
ResourceMetadataKeyEnum.ENTRY_SEARCH_MODE.put(resource, BundleEntrySearchModeEnum.MATCH);
|
//
|
||||||
}
|
// // Load _revincludes
|
||||||
|
// CriteriaQuery<Long> cq = builder.createQuery(Long.class);
|
||||||
theResourceListToPopulate.set(index, resource);
|
// Root<ResourceLink> from = cq.from(ResourceLink.class);
|
||||||
}
|
// cq.select(from.get("mySourceResourcePid").as(Long.class));
|
||||||
}
|
//
|
||||||
|
// Subquery<Long> pidsSubquery = cq.subquery(Long.class);
|
||||||
// @Override
|
// Root<SearchResult> pidsSubqueryFrom = pidsSubquery.from(SearchResult.class);
|
||||||
// public IBundleProvider everything(IIdType theId) {
|
// pidsSubquery.select(pidsSubqueryFrom.get("myResourcePid").as(Long.class));
|
||||||
// Search search = new Search();
|
// pidsSubquery.where(pidsSubqueryFrom.get("mySearch").in(search));
|
||||||
// search.setUuid(UUID.randomUUID().toString());
|
//
|
||||||
// search.setCreated(new Date());
|
// cq.where(from.get("myTargetResourceId").in(pidsSubquery));
|
||||||
// myEntityManager.persist(search);
|
// TypedQuery<Long> query = myEntityManager.createQuery(cq);
|
||||||
//
|
//
|
||||||
// List<SearchResult> results = new ArrayList<SearchResult>();
|
// results = new ArrayList<SearchResult>();
|
||||||
// if (theId != null) {
|
// for (Long next : query.getResultList()) {
|
||||||
// Long pid = translateForcedIdToPid(theId);
|
// SearchResult res = new SearchResult(search);
|
||||||
// ResourceTable entity = myEntityManager.find(ResourceTable.class, pid);
|
// res.setResourcePid(next);
|
||||||
// validateGivenIdIsAppropriateToRetrieveResource(theId, entity);
|
// results.add(res);
|
||||||
// SearchResult res = new SearchResult(search);
|
// }
|
||||||
// res.setResourcePid(pid);
|
//
|
||||||
// results.add(res);
|
// // Save _revincludes
|
||||||
// } else {
|
// totalCount += results.size();
|
||||||
// TypedQuery<Tuple> query = createSearchAllByTypeQuery();
|
// mySearchResultDao.save(results);
|
||||||
// for (Tuple next : query.getResultList()) {
|
// mySearchResultDao.flush();
|
||||||
// SearchResult res = new SearchResult(search);
|
//
|
||||||
// res.setResourcePid(next.get(0, Long.class));
|
// final int finalTotalCount = totalCount;
|
||||||
// results.add(res);
|
// return new IBundleProvider() {
|
||||||
// }
|
//
|
||||||
// }
|
// @Override
|
||||||
//
|
// public int size() {
|
||||||
// int totalCount = results.size();
|
// return finalTotalCount;
|
||||||
// mySearchResultDao.save(results);
|
// }
|
||||||
// mySearchResultDao.flush();
|
//
|
||||||
//
|
// @Override
|
||||||
// CriteriaBuilder builder = myEntityManager.getCriteriaBuilder();
|
// public Integer preferredPageSize() {
|
||||||
//
|
// return null;
|
||||||
// // Load _revincludes
|
// }
|
||||||
// CriteriaQuery<Long> cq = builder.createQuery(Long.class);
|
//
|
||||||
// Root<ResourceLink> from = cq.from(ResourceLink.class);
|
// @Override
|
||||||
// cq.select(from.get("mySourceResourcePid").as(Long.class));
|
// public List<IBaseResource> getResources(int theFromIndex, int theToIndex) {
|
||||||
//
|
// // TODO Auto-generated method stub
|
||||||
// Subquery<Long> pidsSubquery = cq.subquery(Long.class);
|
// return null;
|
||||||
// Root<SearchResult> pidsSubqueryFrom = pidsSubquery.from(SearchResult.class);
|
// }
|
||||||
// pidsSubquery.select(pidsSubqueryFrom.get("myResourcePid").as(Long.class));
|
//
|
||||||
// pidsSubquery.where(pidsSubqueryFrom.get("mySearch").in(search));
|
// @Override
|
||||||
//
|
// public InstantDt getPublished() {
|
||||||
// cq.where(from.get("myTargetResourceId").in(pidsSubquery));
|
// // TODO Auto-generated method stub
|
||||||
// TypedQuery<Long> query = myEntityManager.createQuery(cq);
|
// return null;
|
||||||
//
|
// }
|
||||||
// results = new ArrayList<SearchResult>();
|
// };
|
||||||
// for (Long next : query.getResultList()) {
|
// }
|
||||||
// SearchResult res = new SearchResult(search);
|
|
||||||
// res.setResourcePid(next);
|
|
||||||
// results.add(res);
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// // Save _revincludes
|
|
||||||
// totalCount += results.size();
|
|
||||||
// mySearchResultDao.save(results);
|
|
||||||
// mySearchResultDao.flush();
|
|
||||||
//
|
|
||||||
// final int finalTotalCount = totalCount;
|
|
||||||
// return new IBundleProvider() {
|
|
||||||
//
|
|
||||||
// @Override
|
|
||||||
// public int size() {
|
|
||||||
// return finalTotalCount;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// @Override
|
|
||||||
// public Integer preferredPageSize() {
|
|
||||||
// return null;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// @Override
|
|
||||||
// public List<IBaseResource> getResources(int theFromIndex, int theToIndex) {
|
|
||||||
// // TODO Auto-generated method stub
|
|
||||||
// return null;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// @Override
|
|
||||||
// public InstantDt getPublished() {
|
|
||||||
// // TODO Auto-generated method stub
|
|
||||||
// return null;
|
|
||||||
// }
|
|
||||||
// };
|
|
||||||
// }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* THIS SHOULD RETURN HASHSET and not jsut Set because we add to it later (so it can't be Collections.emptySet())
|
|
||||||
* @param theLastUpdated
|
|
||||||
*/
|
|
||||||
private HashSet<Long> loadReverseIncludes(Collection<Long> theMatches, Set<Include> theRevIncludes, boolean theReverseMode, EverythingModeEnum theEverythingModeEnum, DateRangeParam theLastUpdated) {
|
|
||||||
if (theMatches.size() == 0) {
|
|
||||||
return new HashSet<Long>();
|
|
||||||
}
|
|
||||||
if (theRevIncludes == null || theRevIncludes.isEmpty()) {
|
|
||||||
return new HashSet<Long>();
|
|
||||||
}
|
|
||||||
String searchFieldName = theReverseMode ? "myTargetResourcePid" : "mySourceResourcePid";
|
|
||||||
|
|
||||||
Collection<Long> nextRoundMatches = theMatches;
|
|
||||||
HashSet<Long> allAdded = new HashSet<Long>();
|
|
||||||
HashSet<Long> original = new HashSet<Long>(theMatches);
|
|
||||||
ArrayList<Include> includes = new ArrayList<Include>(theRevIncludes);
|
|
||||||
|
|
||||||
int roundCounts = 0;
|
|
||||||
StopWatch w = new StopWatch();
|
|
||||||
|
|
||||||
boolean addedSomeThisRound;
|
|
||||||
do {
|
|
||||||
roundCounts++;
|
|
||||||
|
|
||||||
HashSet<Long> pidsToInclude = new HashSet<Long>();
|
|
||||||
Set<Long> nextRoundOmit = new HashSet<Long>();
|
|
||||||
|
|
||||||
for (Iterator<Include> iter = includes.iterator(); iter.hasNext();) {
|
|
||||||
Include nextInclude = iter.next();
|
|
||||||
if (nextInclude.isRecurse() == false) {
|
|
||||||
iter.remove();
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean matchAll = "*".equals(nextInclude.getValue());
|
|
||||||
if (matchAll) {
|
|
||||||
String sql;
|
|
||||||
sql = "SELECT r FROM ResourceLink r WHERE r." + searchFieldName + " IN (:target_pids)";
|
|
||||||
TypedQuery<ResourceLink> q = myEntityManager.createQuery(sql, ResourceLink.class);
|
|
||||||
q.setParameter("target_pids", nextRoundMatches);
|
|
||||||
List<ResourceLink> results = q.getResultList();
|
|
||||||
for (ResourceLink resourceLink : results) {
|
|
||||||
if (theReverseMode) {
|
|
||||||
// if (theEverythingModeEnum.isEncounter()) {
|
|
||||||
// if (resourceLink.getSourcePath().equals("Encounter.subject") || resourceLink.getSourcePath().equals("Encounter.patient")) {
|
|
||||||
// nextRoundOmit.add(resourceLink.getSourceResourcePid());
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
pidsToInclude.add(resourceLink.getSourceResourcePid());
|
|
||||||
} else {
|
|
||||||
pidsToInclude.add(resourceLink.getTargetResourcePid());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
|
|
||||||
List<String> paths;
|
|
||||||
if (getContext().getVersion().getVersion() == FhirVersionEnum.DSTU1) {
|
|
||||||
paths = Collections.singletonList(nextInclude.getValue());
|
|
||||||
} else {
|
|
||||||
int colonIdx = nextInclude.getValue().indexOf(':');
|
|
||||||
if (colonIdx < 2) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
String resType = nextInclude.getValue().substring(0, colonIdx);
|
|
||||||
RuntimeResourceDefinition def = getContext().getResourceDefinition(resType);
|
|
||||||
if (def == null) {
|
|
||||||
ourLog.warn("Unknown resource type in include/revinclude=" + nextInclude.getValue());
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
String paramName = nextInclude.getValue().substring(colonIdx + 1);
|
|
||||||
RuntimeSearchParam param = def.getSearchParam(paramName);
|
|
||||||
if (param == null) {
|
|
||||||
ourLog.warn("Unknown param name in include/revinclude=" + nextInclude.getValue());
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
paths = param.getPathsSplit();
|
|
||||||
}
|
|
||||||
|
|
||||||
for (String nextPath : paths) {
|
|
||||||
String sql = "SELECT r FROM ResourceLink r WHERE r.mySourcePath = :src_path AND r." + searchFieldName + " IN (:target_pids)";
|
|
||||||
TypedQuery<ResourceLink> q = myEntityManager.createQuery(sql, ResourceLink.class);
|
|
||||||
q.setParameter("src_path", nextPath);
|
|
||||||
q.setParameter("target_pids", nextRoundMatches);
|
|
||||||
List<ResourceLink> results = q.getResultList();
|
|
||||||
for (ResourceLink resourceLink : results) {
|
|
||||||
if (theReverseMode) {
|
|
||||||
pidsToInclude.add(resourceLink.getSourceResourcePid());
|
|
||||||
} else {
|
|
||||||
pidsToInclude.add(resourceLink.getTargetResourcePid());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (theLastUpdated != null && (theLastUpdated.getLowerBoundAsInstant() != null || theLastUpdated.getUpperBoundAsInstant() != null)) {
|
|
||||||
pidsToInclude = new HashSet<Long>(filterResourceIdsByLastUpdated(pidsToInclude, theLastUpdated));
|
|
||||||
}
|
|
||||||
for (Long next : pidsToInclude) {
|
|
||||||
if (original.contains(next) == false && allAdded.contains(next) == false) {
|
|
||||||
theMatches.add(next);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pidsToInclude.removeAll(nextRoundOmit);
|
|
||||||
|
|
||||||
addedSomeThisRound = allAdded.addAll(pidsToInclude);
|
|
||||||
nextRoundMatches = pidsToInclude;
|
|
||||||
} while (includes.size() > 0 && nextRoundMatches.size() > 0 && addedSomeThisRound);
|
|
||||||
|
|
||||||
ourLog.info("Loaded {} {} in {} rounds and {} ms", new Object[] { allAdded.size(), theReverseMode ? "_revincludes" : "_includes", roundCounts, w.getMillisAndRestart() });
|
|
||||||
|
|
||||||
return allAdded;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public MetaDt metaAddOperation(IIdType theResourceId, MetaDt theMetaAdd) {
|
public MetaDt metaAddOperation(IIdType theResourceId, MetaDt theMetaAdd) {
|
||||||
|
@ -993,8 +781,7 @@ public abstract class BaseHapiFhirResourceDao<T extends IResource> extends BaseH
|
||||||
|
|
||||||
if (entity == null) {
|
if (entity == null) {
|
||||||
if (theId.hasVersionIdPart()) {
|
if (theId.hasVersionIdPart()) {
|
||||||
TypedQuery<ResourceHistoryTable> q = myEntityManager
|
TypedQuery<ResourceHistoryTable> q = myEntityManager.createQuery("SELECT t from ResourceHistoryTable t WHERE t.myResourceId = :RID AND t.myResourceType = :RTYP AND t.myResourceVersion = :RVER", ResourceHistoryTable.class);
|
||||||
.createQuery("SELECT t from ResourceHistoryTable t WHERE t.myResourceId = :RID AND t.myResourceType = :RTYP AND t.myResourceVersion = :RVER", ResourceHistoryTable.class);
|
|
||||||
q.setParameter("RID", pid);
|
q.setParameter("RID", pid);
|
||||||
q.setParameter("RTYP", myResourceName);
|
q.setParameter("RTYP", myResourceName);
|
||||||
q.setParameter("RVER", theId.getVersionIdPartAsLong());
|
q.setParameter("RVER", theId.getVersionIdPartAsLong());
|
||||||
|
@ -1070,202 +857,9 @@ public abstract class BaseHapiFhirResourceDao<T extends IResource> extends BaseH
|
||||||
ActionRequestDetails requestDetails = new ActionRequestDetails(null, getResourceName());
|
ActionRequestDetails requestDetails = new ActionRequestDetails(null, getResourceName());
|
||||||
notifyInterceptors(RestOperationTypeEnum.SEARCH_TYPE, requestDetails);
|
notifyInterceptors(RestOperationTypeEnum.SEARCH_TYPE, requestDetails);
|
||||||
|
|
||||||
StopWatch w = new StopWatch();
|
SearchBuilder builder = new SearchBuilder(getContext(), myEntityManager, myPlatformTransactionManager, mySearchDao, mySearchResultDao, this);
|
||||||
final InstantDt now = InstantDt.withCurrentTime();
|
builder.setType(getResourceType(), getResourceName());
|
||||||
|
return builder.search(theParams);
|
||||||
DateRangeParam lu = theParams.getLastUpdated();
|
|
||||||
if (lu != null && lu.isEmpty()) {
|
|
||||||
lu = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
Collection<Long> loadPids;
|
|
||||||
if (theParams.getEverythingMode() != null) {
|
|
||||||
|
|
||||||
CriteriaBuilder builder = myEntityManager.getCriteriaBuilder();
|
|
||||||
CriteriaQuery<Tuple> cq = builder.createTupleQuery();
|
|
||||||
Root<ResourceTable> from = cq.from(ResourceTable.class);
|
|
||||||
List<Predicate> predicates = new ArrayList<Predicate>();
|
|
||||||
if (theParams.get(BaseResource.SP_RES_ID) != null) {
|
|
||||||
StringParam idParm = (StringParam) theParams.get(BaseResource.SP_RES_ID).get(0).get(0);
|
|
||||||
predicates.add(builder.equal(from.get("myId"), idParm.getValue()));
|
|
||||||
}
|
|
||||||
predicates.add(builder.equal(from.get("myResourceType"), myResourceName));
|
|
||||||
predicates.add(builder.isNull(from.get("myDeleted")));
|
|
||||||
cq.where(builder.and(SearchBuilder.toArray(predicates)));
|
|
||||||
|
|
||||||
Join<Object, Object> join = from.join("myIncomingResourceLinks", JoinType.LEFT);
|
|
||||||
cq.multiselect(from.get("myId").as(Long.class), join.get("mySourceResourcePid").as(Long.class));
|
|
||||||
|
|
||||||
TypedQuery<Tuple> query = myEntityManager.createQuery(cq);
|
|
||||||
loadPids = new HashSet<Long>();
|
|
||||||
for (Tuple next : query.getResultList()) {
|
|
||||||
loadPids.add(next.get(0, Long.class));
|
|
||||||
Long nextLong = next.get(1, Long.class);
|
|
||||||
if(nextLong != null) {
|
|
||||||
loadPids.add(nextLong);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} else if (theParams.isEmpty()) {
|
|
||||||
|
|
||||||
loadPids = new HashSet<Long>();
|
|
||||||
TypedQuery<Tuple> query = createSearchAllByTypeQuery(lu);
|
|
||||||
lu = null;
|
|
||||||
for (Tuple next : query.getResultList()) {
|
|
||||||
loadPids.add(next.get(0, Long.class));
|
|
||||||
}
|
|
||||||
if (loadPids.isEmpty()) {
|
|
||||||
return new SimpleBundleProvider();
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
|
|
||||||
List<Long> searchResultPids;
|
|
||||||
if (mySearchDao == null) {
|
|
||||||
if (theParams.containsKey(Constants.PARAM_TEXT)) {
|
|
||||||
throw new InvalidRequestException("Fulltext search is not enabled on this service, can not process parameter: " + Constants.PARAM_TEXT);
|
|
||||||
} else if (theParams.containsKey(Constants.PARAM_CONTENT)) {
|
|
||||||
throw new InvalidRequestException("Fulltext search is not enabled on this service, can not process parameter: " + Constants.PARAM_CONTENT);
|
|
||||||
}
|
|
||||||
searchResultPids = null;
|
|
||||||
} else {
|
|
||||||
searchResultPids = mySearchDao.search(getResourceName(), theParams);
|
|
||||||
}
|
|
||||||
if (theParams.isEmpty()) {
|
|
||||||
loadPids = searchResultPids;
|
|
||||||
} else {
|
|
||||||
loadPids = searchForIdsWithAndOr(theParams, searchResultPids, lu);
|
|
||||||
}
|
|
||||||
if (loadPids.isEmpty()) {
|
|
||||||
return new SimpleBundleProvider();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// // Load _include and _revinclude before filter and sort in everything mode
|
|
||||||
// if (theParams.getEverythingMode() != null) {
|
|
||||||
// if (theParams.getRevIncludes() != null && theParams.getRevIncludes().isEmpty() == false) {
|
|
||||||
// loadPids.addAll(loadReverseIncludes(loadPids, theParams.getRevIncludes(), true, theParams.getEverythingMode()));
|
|
||||||
// loadPids.addAll(loadReverseIncludes(loadPids, theParams.getIncludes(), false, theParams.getEverythingMode()));
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// Handle _lastUpdated
|
|
||||||
if (lu != null) {
|
|
||||||
List<Long> resultList = filterResourceIdsByLastUpdated(loadPids, lu);
|
|
||||||
loadPids.clear();
|
|
||||||
for (Long next : resultList) {
|
|
||||||
loadPids.add(next);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (loadPids.isEmpty()) {
|
|
||||||
return new SimpleBundleProvider();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle sorting if any was provided
|
|
||||||
final List<Long> pids = processSort(theParams, loadPids);
|
|
||||||
|
|
||||||
// Load _revinclude resources
|
|
||||||
final Set<Long> revIncludedPids;
|
|
||||||
if (theParams.getEverythingMode() == null) {
|
|
||||||
if (theParams.getRevIncludes() != null && theParams.getRevIncludes().isEmpty() == false) {
|
|
||||||
revIncludedPids = loadReverseIncludes(pids, theParams.getRevIncludes(), true, null, lu);
|
|
||||||
} else {
|
|
||||||
revIncludedPids = new HashSet<Long>();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
revIncludedPids = new HashSet<Long>();
|
|
||||||
}
|
|
||||||
|
|
||||||
ourLog.debug("Search returned PIDs: {}", pids);
|
|
||||||
|
|
||||||
final int totalCount = pids.size();
|
|
||||||
|
|
||||||
IBundleProvider retVal = new IBundleProvider() {
|
|
||||||
@Override
|
|
||||||
public InstantDt getPublished() {
|
|
||||||
return now;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<IBaseResource> getResources(final int theFromIndex, final int theToIndex) {
|
|
||||||
TransactionTemplate template = new TransactionTemplate(myPlatformTransactionManager);
|
|
||||||
return template.execute(new TransactionCallback<List<IBaseResource>>() {
|
|
||||||
@Override
|
|
||||||
public List<IBaseResource> doInTransaction(TransactionStatus theStatus) {
|
|
||||||
List<Long> pidsSubList = pids.subList(theFromIndex, theToIndex);
|
|
||||||
|
|
||||||
// Load includes
|
|
||||||
pidsSubList = new ArrayList<Long>(pidsSubList);
|
|
||||||
revIncludedPids.addAll(loadReverseIncludes(pidsSubList, theParams.getIncludes(), false, null, theParams.getLastUpdated()));
|
|
||||||
|
|
||||||
// Execute the query and make sure we return distinct results
|
|
||||||
List<IBaseResource> resources = new ArrayList<IBaseResource>();
|
|
||||||
loadResourcesByPid(pidsSubList, resources, revIncludedPids, false);
|
|
||||||
|
|
||||||
return resources;
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Integer preferredPageSize() {
|
|
||||||
return theParams.getCount();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int size() {
|
|
||||||
return totalCount;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
ourLog.info(" {} on {} in {}ms", new Object[] { myResourceName, theParams, w.getMillisAndRestart() });
|
|
||||||
|
|
||||||
return retVal;
|
|
||||||
}
|
|
||||||
|
|
||||||
private List<Long> filterResourceIdsByLastUpdated(Collection<Long> thePids, final DateRangeParam theLastUpdated) {
|
|
||||||
CriteriaBuilder builder = myEntityManager.getCriteriaBuilder();
|
|
||||||
CriteriaQuery<Long> cq = builder.createQuery(Long.class);
|
|
||||||
Root<ResourceTable> from = cq.from(ResourceTable.class);
|
|
||||||
cq.select(from.get("myId").as(Long.class));
|
|
||||||
|
|
||||||
List<Predicate> lastUpdatedPredicates = createLastUpdatedPredicates(theLastUpdated, builder, from);
|
|
||||||
lastUpdatedPredicates.add(0, from.get("myId").in(thePids));
|
|
||||||
|
|
||||||
cq.where(toArray(lastUpdatedPredicates));
|
|
||||||
TypedQuery<Long> query = myEntityManager.createQuery(cq);
|
|
||||||
List<Long> resultList = query.getResultList();
|
|
||||||
return resultList;
|
|
||||||
}
|
|
||||||
|
|
||||||
private List<Predicate> createLastUpdatedPredicates(final DateRangeParam theLastUpdated, CriteriaBuilder builder, From<?, ResourceTable> from) {
|
|
||||||
List<Predicate> lastUpdatedPredicates = new ArrayList<Predicate>();
|
|
||||||
if (theLastUpdated != null) {
|
|
||||||
if (theLastUpdated.getLowerBoundAsInstant() != null) {
|
|
||||||
Predicate predicateLower = builder.greaterThanOrEqualTo(from.<Date> get("myUpdated"), theLastUpdated.getLowerBoundAsInstant());
|
|
||||||
lastUpdatedPredicates.add(predicateLower);
|
|
||||||
}
|
|
||||||
if (theLastUpdated.getUpperBoundAsInstant() != null) {
|
|
||||||
Predicate predicateUpper = builder.lessThanOrEqualTo(from.<Date> get("myUpdated"), theLastUpdated.getUpperBoundAsInstant());
|
|
||||||
lastUpdatedPredicates.add(predicateUpper);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return lastUpdatedPredicates;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private List<Long> toList(Collection<Long> theLoadPids) {
|
|
||||||
final List<Long> pids;
|
|
||||||
if (theLoadPids instanceof List) {
|
|
||||||
pids = (List<Long>) theLoadPids;
|
|
||||||
} else {
|
|
||||||
pids = new ArrayList<Long>(theLoadPids);
|
|
||||||
}
|
|
||||||
return pids;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -1289,145 +883,9 @@ public abstract class BaseHapiFhirResourceDao<T extends IResource> extends BaseH
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Set<Long> searchForIdsWithAndOr(SearchParameterMap theParams, Collection<Long> theInitialPids, DateRangeParam theLastUpdated) {
|
public Set<Long> searchForIdsWithAndOr(SearchParameterMap theParams, Collection<Long> theInitialPids, DateRangeParam theLastUpdated) {
|
||||||
SearchParameterMap params = theParams;
|
SearchBuilder builder = new SearchBuilder(getContext(), myEntityManager, myPlatformTransactionManager, mySearchDao, mySearchResultDao, this);
|
||||||
if (params == null) {
|
builder.setType(getResourceType(), getResourceName());
|
||||||
params = new SearchParameterMap();
|
return builder.searchForIdsWithAndOr(theParams, theInitialPids, theLastUpdated);
|
||||||
}
|
|
||||||
|
|
||||||
RuntimeResourceDefinition resourceDef = getContext().getResourceDefinition(myResourceType);
|
|
||||||
|
|
||||||
Set<Long> pids = new HashSet<Long>();
|
|
||||||
if (theInitialPids != null) {
|
|
||||||
pids.addAll(theInitialPids);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (Entry<String, List<List<? extends IQueryParameterType>>> nextParamEntry : params.entrySet()) {
|
|
||||||
String nextParamName = nextParamEntry.getKey();
|
|
||||||
if (nextParamName.equals(BaseResource.SP_RES_ID)) {
|
|
||||||
|
|
||||||
if (nextParamEntry.getValue().isEmpty()) {
|
|
||||||
continue;
|
|
||||||
} else {
|
|
||||||
for (List<? extends IQueryParameterType> nextValue : nextParamEntry.getValue()) {
|
|
||||||
Set<Long> joinPids = new HashSet<Long>();
|
|
||||||
if (nextValue == null || nextValue.size() == 0) {
|
|
||||||
continue;
|
|
||||||
} else {
|
|
||||||
for (IQueryParameterType next : nextValue) {
|
|
||||||
String value = next.getValueAsQueryToken();
|
|
||||||
IIdType valueId = new IdDt(value);
|
|
||||||
|
|
||||||
try {
|
|
||||||
BaseHasResource entity = readEntity(valueId);
|
|
||||||
if (entity.getDeleted() != null) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
joinPids.add(entity.getId());
|
|
||||||
} catch (ResourceNotFoundException e) {
|
|
||||||
// This isn't an error, just means no result found
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (joinPids.isEmpty()) {
|
|
||||||
return new HashSet<Long>();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pids = addPredicateId(pids, joinPids, theLastUpdated);
|
|
||||||
if (pids.isEmpty()) {
|
|
||||||
return new HashSet<Long>();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pids.isEmpty()) {
|
|
||||||
pids.addAll(joinPids);
|
|
||||||
} else {
|
|
||||||
pids.retainAll(joinPids);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} else if (nextParamName.equals(BaseResource.SP_RES_LANGUAGE)) {
|
|
||||||
|
|
||||||
pids = addPredicateLanguage(pids, nextParamEntry.getValue(), theLastUpdated);
|
|
||||||
|
|
||||||
} else if (nextParamName.equals(Constants.PARAM_TAG) || nextParamName.equals(Constants.PARAM_PROFILE) || nextParamName.equals(Constants.PARAM_SECURITY)) {
|
|
||||||
|
|
||||||
pids = addPredicateTag(pids, nextParamEntry.getValue(), nextParamName, theLastUpdated);
|
|
||||||
|
|
||||||
} else {
|
|
||||||
|
|
||||||
RuntimeSearchParam nextParamDef = resourceDef.getSearchParam(nextParamName);
|
|
||||||
if (nextParamDef != null) {
|
|
||||||
switch (nextParamDef.getParamType()) {
|
|
||||||
case DATE:
|
|
||||||
for (List<? extends IQueryParameterType> nextAnd : nextParamEntry.getValue()) {
|
|
||||||
pids = addPredicateDate(nextParamName, pids, nextAnd);
|
|
||||||
if (pids.isEmpty()) {
|
|
||||||
return new HashSet<Long>();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case QUANTITY:
|
|
||||||
for (List<? extends IQueryParameterType> nextAnd : nextParamEntry.getValue()) {
|
|
||||||
pids = addPredicateQuantity(nextParamName, pids, nextAnd);
|
|
||||||
if (pids.isEmpty()) {
|
|
||||||
return new HashSet<Long>();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case REFERENCE:
|
|
||||||
for (List<? extends IQueryParameterType> nextAnd : nextParamEntry.getValue()) {
|
|
||||||
pids = addPredicateReference(nextParamName, pids, nextAnd);
|
|
||||||
if (pids.isEmpty()) {
|
|
||||||
return new HashSet<Long>();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case STRING:
|
|
||||||
for (List<? extends IQueryParameterType> nextAnd : nextParamEntry.getValue()) {
|
|
||||||
pids = addPredicateString(nextParamName, pids, nextAnd);
|
|
||||||
if (pids.isEmpty()) {
|
|
||||||
return new HashSet<Long>();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case TOKEN:
|
|
||||||
for (List<? extends IQueryParameterType> nextAnd : nextParamEntry.getValue()) {
|
|
||||||
pids = addPredicateToken(nextParamName, pids, nextAnd);
|
|
||||||
if (pids.isEmpty()) {
|
|
||||||
return new HashSet<Long>();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case NUMBER:
|
|
||||||
for (List<? extends IQueryParameterType> nextAnd : nextParamEntry.getValue()) {
|
|
||||||
pids = addPredicateNumber(nextParamName, pids, nextAnd);
|
|
||||||
if (pids.isEmpty()) {
|
|
||||||
return new HashSet<Long>();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case COMPOSITE:
|
|
||||||
for (List<? extends IQueryParameterType> nextAnd : nextParamEntry.getValue()) {
|
|
||||||
pids = addPredicateComposite(nextParamDef, pids, nextAnd);
|
|
||||||
if (pids.isEmpty()) {
|
|
||||||
return new HashSet<Long>();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case URI:
|
|
||||||
for (List<? extends IQueryParameterType> nextAnd : nextParamEntry.getValue()) {
|
|
||||||
pids = addPredicateUri(nextParamName, pids, nextAnd);
|
|
||||||
if (pids.isEmpty()) {
|
|
||||||
return new HashSet<Long>();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return pids;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
|
@ -1437,7 +895,8 @@ public abstract class BaseHapiFhirResourceDao<T extends IResource> extends BaseH
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If set, the given param will be treated as a secondary primary key, and multiple resources will not be able to share the same value.
|
* If set, the given param will be treated as a secondary primary key, and multiple resources will not be able to
|
||||||
|
* share the same value.
|
||||||
*/
|
*/
|
||||||
public void setSecondaryPrimaryKeyParamName(String theSecondaryPrimaryKeyParamName) {
|
public void setSecondaryPrimaryKeyParamName(String theSecondaryPrimaryKeyParamName) {
|
||||||
mySecondaryPrimaryKeyParamName = theSecondaryPrimaryKeyParamName;
|
mySecondaryPrimaryKeyParamName = theSecondaryPrimaryKeyParamName;
|
||||||
|
@ -1460,48 +919,8 @@ public abstract class BaseHapiFhirResourceDao<T extends IResource> extends BaseH
|
||||||
return retVal;
|
return retVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
private IQueryParameterType toParameterType(RuntimeSearchParam theParam) {
|
|
||||||
IQueryParameterType qp;
|
|
||||||
switch (theParam.getParamType()) {
|
|
||||||
case DATE:
|
|
||||||
qp = new DateParam();
|
|
||||||
break;
|
|
||||||
case NUMBER:
|
|
||||||
qp = new NumberParam();
|
|
||||||
break;
|
|
||||||
case QUANTITY:
|
|
||||||
qp = new QuantityParam();
|
|
||||||
break;
|
|
||||||
case STRING:
|
|
||||||
qp = new StringParam();
|
|
||||||
break;
|
|
||||||
case TOKEN:
|
|
||||||
qp = new TokenParam();
|
|
||||||
break;
|
|
||||||
case COMPOSITE:
|
|
||||||
List<RuntimeSearchParam> compositeOf = theParam.getCompositeOf();
|
|
||||||
if (compositeOf.size() != 2) {
|
|
||||||
throw new InternalErrorException("Parameter " + theParam.getName() + " has " + compositeOf.size() + " composite parts. Don't know how handlt this.");
|
|
||||||
}
|
|
||||||
IQueryParameterType leftParam = toParameterType(compositeOf.get(0));
|
|
||||||
IQueryParameterType rightParam = toParameterType(compositeOf.get(1));
|
|
||||||
qp = new CompositeParam<IQueryParameterType, IQueryParameterType>(leftParam, rightParam);
|
|
||||||
break;
|
|
||||||
case REFERENCE:
|
|
||||||
qp = new ReferenceParam();
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw new InternalErrorException("Don't know how to convert param type: " + theParam.getParamType());
|
|
||||||
}
|
|
||||||
return qp;
|
|
||||||
}
|
|
||||||
|
|
||||||
private IQueryParameterType toParameterType(RuntimeSearchParam theParam, String theQualifier, String theValueAsQueryToken) {
|
|
||||||
IQueryParameterType qp = toParameterType(theParam);
|
|
||||||
|
|
||||||
qp.setValueAsQueryToken(theQualifier, theValueAsQueryToken); // aaaa
|
|
||||||
return qp;
|
|
||||||
}
|
|
||||||
|
|
||||||
private ArrayList<TagDefinition> toTagList(MetaDt theMeta) {
|
private ArrayList<TagDefinition> toTagList(MetaDt theMeta) {
|
||||||
ArrayList<TagDefinition> retVal = new ArrayList<TagDefinition>();
|
ArrayList<TagDefinition> retVal = new ArrayList<TagDefinition>();
|
||||||
|
@ -1570,8 +989,7 @@ public abstract class BaseHapiFhirResourceDao<T extends IResource> extends BaseH
|
||||||
}
|
}
|
||||||
|
|
||||||
if (resourceId.hasResourceType() && !resourceId.getResourceType().equals(getResourceName())) {
|
if (resourceId.hasResourceType() && !resourceId.getResourceType().equals(getResourceName())) {
|
||||||
throw new UnprocessableEntityException(
|
throw new UnprocessableEntityException("Invalid resource ID[" + entity.getIdDt().toUnqualifiedVersionless() + "] of type[" + entity.getResourceType() + "] - Does not match expected [" + getResourceName() + "]");
|
||||||
"Invalid resource ID[" + entity.getIdDt().toUnqualifiedVersionless() + "] of type[" + entity.getResourceType() + "] - Does not match expected [" + getResourceName() + "]");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Notify interceptors
|
// Notify interceptors
|
||||||
|
@ -1623,14 +1041,12 @@ public abstract class BaseHapiFhirResourceDao<T extends IResource> extends BaseH
|
||||||
String sourceId = link.getSourceResource().getIdDt().toUnqualifiedVersionless().getValue();
|
String sourceId = link.getSourceResource().getIdDt().toUnqualifiedVersionless().getValue();
|
||||||
String sourcePath = link.getSourcePath();
|
String sourcePath = link.getSourcePath();
|
||||||
|
|
||||||
throw new ResourceVersionConflictException(
|
throw new ResourceVersionConflictException("Unable to delete " + targetId + " because at least one resource has a reference to this resource. First reference found was resource " + sourceId + " in path " + sourcePath);
|
||||||
"Unable to delete " + targetId + " because at least one resource has a reference to this resource. First reference found was resource " + sourceId + " in path " + sourcePath);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void validateResourceType(BaseHasResource entity) {
|
private void validateResourceType(BaseHasResource entity) {
|
||||||
if (!myResourceName.equals(entity.getResourceType())) {
|
if (!myResourceName.equals(entity.getResourceType())) {
|
||||||
throw new ResourceNotFoundException(
|
throw new ResourceNotFoundException("Resource with ID " + entity.getIdDt().getIdPart() + " exists but it is not of type " + myResourceName + ", found resource of type " + entity.getResourceType());
|
||||||
"Resource with ID " + entity.getIdDt().getIdPart() + " exists but it is not of type " + myResourceName + ", found resource of type " + entity.getResourceType());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -40,4 +40,5 @@ public interface IDao {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,8 +45,6 @@ public interface IFhirSystemDao<T> extends IDao {
|
||||||
|
|
||||||
IBundleProvider history(Date theDate);
|
IBundleProvider history(Date theDate);
|
||||||
|
|
||||||
int performReindexingPass(Integer theCount);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Marks all indexes as needing fresh indexing
|
* Marks all indexes as needing fresh indexing
|
||||||
*
|
*
|
||||||
|
@ -59,6 +57,8 @@ public interface IFhirSystemDao<T> extends IDao {
|
||||||
*/
|
*/
|
||||||
MetaDt metaGetOperation();
|
MetaDt metaGetOperation();
|
||||||
|
|
||||||
|
int performReindexingPass(Integer theCount);
|
||||||
|
|
||||||
T transaction(RequestDetails theRequestDetails, T theResources);
|
T transaction(RequestDetails theRequestDetails, T theResources);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,9 +8,13 @@ import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
import java.util.Iterator;
|
||||||
import java.util.LinkedHashSet;
|
import java.util.LinkedHashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Map.Entry;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import javax.persistence.EntityManager;
|
import javax.persistence.EntityManager;
|
||||||
|
@ -20,6 +24,7 @@ import javax.persistence.criteria.CriteriaBuilder;
|
||||||
import javax.persistence.criteria.CriteriaQuery;
|
import javax.persistence.criteria.CriteriaQuery;
|
||||||
import javax.persistence.criteria.Expression;
|
import javax.persistence.criteria.Expression;
|
||||||
import javax.persistence.criteria.From;
|
import javax.persistence.criteria.From;
|
||||||
|
import javax.persistence.criteria.Join;
|
||||||
import javax.persistence.criteria.JoinType;
|
import javax.persistence.criteria.JoinType;
|
||||||
import javax.persistence.criteria.Order;
|
import javax.persistence.criteria.Order;
|
||||||
import javax.persistence.criteria.Path;
|
import javax.persistence.criteria.Path;
|
||||||
|
@ -30,13 +35,21 @@ import javax.persistence.criteria.Subquery;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||||
import org.hl7.fhir.instance.model.api.IIdType;
|
import org.hl7.fhir.instance.model.api.IIdType;
|
||||||
|
import org.springframework.transaction.PlatformTransactionManager;
|
||||||
|
import org.springframework.transaction.TransactionStatus;
|
||||||
|
import org.springframework.transaction.support.TransactionCallback;
|
||||||
|
import org.springframework.transaction.support.TransactionTemplate;
|
||||||
|
|
||||||
import ca.uhn.fhir.context.BaseRuntimeChildDefinition;
|
import ca.uhn.fhir.context.BaseRuntimeChildDefinition;
|
||||||
import ca.uhn.fhir.context.ConfigurationException;
|
import ca.uhn.fhir.context.ConfigurationException;
|
||||||
import ca.uhn.fhir.context.FhirContext;
|
import ca.uhn.fhir.context.FhirContext;
|
||||||
|
import ca.uhn.fhir.context.FhirVersionEnum;
|
||||||
import ca.uhn.fhir.context.RuntimeChildResourceDefinition;
|
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.SearchParameterMap.EverythingModeEnum;
|
||||||
|
import ca.uhn.fhir.jpa.dao.data.ISearchResultDao;
|
||||||
|
import ca.uhn.fhir.jpa.entity.BaseHasResource;
|
||||||
import ca.uhn.fhir.jpa.entity.BaseResourceIndexedSearchParam;
|
import ca.uhn.fhir.jpa.entity.BaseResourceIndexedSearchParam;
|
||||||
import ca.uhn.fhir.jpa.entity.ResourceIndexedSearchParamDate;
|
import ca.uhn.fhir.jpa.entity.ResourceIndexedSearchParamDate;
|
||||||
import ca.uhn.fhir.jpa.entity.ResourceIndexedSearchParamNumber;
|
import ca.uhn.fhir.jpa.entity.ResourceIndexedSearchParamNumber;
|
||||||
|
@ -49,14 +62,20 @@ import ca.uhn.fhir.jpa.entity.ResourceTable;
|
||||||
import ca.uhn.fhir.jpa.entity.ResourceTag;
|
import ca.uhn.fhir.jpa.entity.ResourceTag;
|
||||||
import ca.uhn.fhir.jpa.entity.TagDefinition;
|
import ca.uhn.fhir.jpa.entity.TagDefinition;
|
||||||
import ca.uhn.fhir.jpa.entity.TagTypeEnum;
|
import ca.uhn.fhir.jpa.entity.TagTypeEnum;
|
||||||
|
import ca.uhn.fhir.jpa.util.StopWatch;
|
||||||
import ca.uhn.fhir.model.api.IPrimitiveDatatype;
|
import ca.uhn.fhir.model.api.IPrimitiveDatatype;
|
||||||
import ca.uhn.fhir.model.api.IQueryParameterType;
|
import ca.uhn.fhir.model.api.IQueryParameterType;
|
||||||
|
import ca.uhn.fhir.model.api.IResource;
|
||||||
|
import ca.uhn.fhir.model.api.Include;
|
||||||
|
import ca.uhn.fhir.model.api.ResourceMetadataKeyEnum;
|
||||||
import ca.uhn.fhir.model.base.composite.BaseCodingDt;
|
import ca.uhn.fhir.model.base.composite.BaseCodingDt;
|
||||||
import ca.uhn.fhir.model.base.composite.BaseIdentifierDt;
|
import ca.uhn.fhir.model.base.composite.BaseIdentifierDt;
|
||||||
import ca.uhn.fhir.model.base.composite.BaseQuantityDt;
|
import ca.uhn.fhir.model.base.composite.BaseQuantityDt;
|
||||||
import ca.uhn.fhir.model.dstu.resource.BaseResource;
|
import ca.uhn.fhir.model.dstu.resource.BaseResource;
|
||||||
import ca.uhn.fhir.model.dstu.valueset.QuantityCompararatorEnum;
|
import ca.uhn.fhir.model.dstu.valueset.QuantityCompararatorEnum;
|
||||||
import ca.uhn.fhir.model.primitive.IdDt;
|
import ca.uhn.fhir.model.primitive.IdDt;
|
||||||
|
import ca.uhn.fhir.model.primitive.InstantDt;
|
||||||
|
import ca.uhn.fhir.model.valueset.BundleEntrySearchModeEnum;
|
||||||
import ca.uhn.fhir.rest.api.SortOrderEnum;
|
import ca.uhn.fhir.rest.api.SortOrderEnum;
|
||||||
import ca.uhn.fhir.rest.api.SortSpec;
|
import ca.uhn.fhir.rest.api.SortSpec;
|
||||||
import ca.uhn.fhir.rest.method.RestSearchParameterTypeEnum;
|
import ca.uhn.fhir.rest.method.RestSearchParameterTypeEnum;
|
||||||
|
@ -70,18 +89,31 @@ import ca.uhn.fhir.rest.param.StringParam;
|
||||||
import ca.uhn.fhir.rest.param.TokenParam;
|
import ca.uhn.fhir.rest.param.TokenParam;
|
||||||
import ca.uhn.fhir.rest.param.UriParam;
|
import ca.uhn.fhir.rest.param.UriParam;
|
||||||
import ca.uhn.fhir.rest.server.Constants;
|
import ca.uhn.fhir.rest.server.Constants;
|
||||||
|
import ca.uhn.fhir.rest.server.IBundleProvider;
|
||||||
|
import ca.uhn.fhir.rest.server.SimpleBundleProvider;
|
||||||
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
||||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||||
|
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
|
||||||
|
|
||||||
public class SearchBuilder {
|
public class SearchBuilder {
|
||||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(SearchBuilder.class);
|
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(SearchBuilder.class);
|
||||||
|
|
||||||
private EntityManager myEntityManager;
|
private EntityManager myEntityManager;
|
||||||
private FhirContext myContext;
|
private FhirContext myContext;
|
||||||
|
private Class<? extends IBaseResource> myResourceType;
|
||||||
|
private String myResourceName;
|
||||||
|
private PlatformTransactionManager myPlatformTransactionManager;
|
||||||
|
private ISearchDao mySearchDao;
|
||||||
|
private ISearchResultDao mySearchResultDao;
|
||||||
|
private BaseHapiFhirDao<?> myCallingDao;
|
||||||
|
|
||||||
public SearchBuilder(FhirContext theFhirContext, EntityManager theEntityManager) {
|
public SearchBuilder(FhirContext theFhirContext, EntityManager theEntityManager, PlatformTransactionManager thePlatformTransactionManager, ISearchDao theSearchDao, ISearchResultDao theSearchResultDao, BaseHapiFhirDao theDao) {
|
||||||
myContext = theFhirContext;
|
myContext = theFhirContext;
|
||||||
myEntityManager = theEntityManager;
|
myEntityManager = theEntityManager;
|
||||||
|
myPlatformTransactionManager = thePlatformTransactionManager;
|
||||||
|
mySearchDao = theSearchDao;
|
||||||
|
mySearchResultDao = theSearchResultDao;
|
||||||
|
myCallingDao = theDao;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Predicate createCompositeParamPart(CriteriaBuilder builder, Root<ResourceTable> from, RuntimeSearchParam left, IQueryParameterType leftValue) {
|
private Predicate createCompositeParamPart(CriteriaBuilder builder, Root<ResourceTable> from, RuntimeSearchParam left, IQueryParameterType leftValue) {
|
||||||
|
@ -206,6 +238,149 @@ public class SearchBuilder {
|
||||||
return singleCode;
|
return singleCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Set<Long> searchForIdsWithAndOr(SearchParameterMap theParams, Collection<Long> theInitialPids, DateRangeParam theLastUpdated) {
|
||||||
|
SearchParameterMap params = theParams;
|
||||||
|
if (params == null) {
|
||||||
|
params = new SearchParameterMap();
|
||||||
|
}
|
||||||
|
|
||||||
|
RuntimeResourceDefinition resourceDef = myContext.getResourceDefinition(myResourceType);
|
||||||
|
|
||||||
|
Set<Long> pids = new HashSet<Long>();
|
||||||
|
if (theInitialPids != null) {
|
||||||
|
pids.addAll(theInitialPids);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Entry<String, List<List<? extends IQueryParameterType>>> nextParamEntry : params.entrySet()) {
|
||||||
|
String nextParamName = nextParamEntry.getKey();
|
||||||
|
if (nextParamName.equals(BaseResource.SP_RES_ID)) {
|
||||||
|
|
||||||
|
if (nextParamEntry.getValue().isEmpty()) {
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
for (List<? extends IQueryParameterType> nextValue : nextParamEntry.getValue()) {
|
||||||
|
Set<Long> joinPids = new HashSet<Long>();
|
||||||
|
if (nextValue == null || nextValue.size() == 0) {
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
for (IQueryParameterType next : nextValue) {
|
||||||
|
String value = next.getValueAsQueryToken();
|
||||||
|
IIdType valueId = new IdDt(value);
|
||||||
|
|
||||||
|
try {
|
||||||
|
BaseHasResource entity = myCallingDao.readEntity(valueId);
|
||||||
|
if (entity.getDeleted() != null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
joinPids.add(entity.getId());
|
||||||
|
} catch (ResourceNotFoundException e) {
|
||||||
|
// This isn't an error, just means no result found
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (joinPids.isEmpty()) {
|
||||||
|
return new HashSet<Long>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pids = addPredicateId(pids, joinPids, theLastUpdated);
|
||||||
|
if (pids.isEmpty()) {
|
||||||
|
return new HashSet<Long>();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pids.isEmpty()) {
|
||||||
|
pids.addAll(joinPids);
|
||||||
|
} else {
|
||||||
|
pids.retainAll(joinPids);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if (nextParamName.equals(BaseResource.SP_RES_LANGUAGE)) {
|
||||||
|
|
||||||
|
pids = addPredicateLanguage(pids, nextParamEntry.getValue(), theLastUpdated);
|
||||||
|
|
||||||
|
} else if (nextParamName.equals(Constants.PARAM_TAG) || nextParamName.equals(Constants.PARAM_PROFILE) || nextParamName.equals(Constants.PARAM_SECURITY)) {
|
||||||
|
|
||||||
|
pids = addPredicateTag(pids, nextParamEntry.getValue(), nextParamName, theLastUpdated);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
RuntimeSearchParam nextParamDef = resourceDef.getSearchParam(nextParamName);
|
||||||
|
if (nextParamDef != null) {
|
||||||
|
switch (nextParamDef.getParamType()) {
|
||||||
|
case DATE:
|
||||||
|
for (List<? extends IQueryParameterType> nextAnd : nextParamEntry.getValue()) {
|
||||||
|
pids = addPredicateDate(nextParamName, pids, nextAnd);
|
||||||
|
if (pids.isEmpty()) {
|
||||||
|
return new HashSet<Long>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case QUANTITY:
|
||||||
|
for (List<? extends IQueryParameterType> nextAnd : nextParamEntry.getValue()) {
|
||||||
|
pids = addPredicateQuantity(nextParamName, pids, nextAnd);
|
||||||
|
if (pids.isEmpty()) {
|
||||||
|
return new HashSet<Long>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case REFERENCE:
|
||||||
|
for (List<? extends IQueryParameterType> nextAnd : nextParamEntry.getValue()) {
|
||||||
|
pids = addPredicateReference(nextParamName, pids, nextAnd);
|
||||||
|
if (pids.isEmpty()) {
|
||||||
|
return new HashSet<Long>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case STRING:
|
||||||
|
for (List<? extends IQueryParameterType> nextAnd : nextParamEntry.getValue()) {
|
||||||
|
pids = addPredicateString(nextParamName, pids, nextAnd);
|
||||||
|
if (pids.isEmpty()) {
|
||||||
|
return new HashSet<Long>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case TOKEN:
|
||||||
|
for (List<? extends IQueryParameterType> nextAnd : nextParamEntry.getValue()) {
|
||||||
|
pids = addPredicateToken(nextParamName, pids, nextAnd);
|
||||||
|
if (pids.isEmpty()) {
|
||||||
|
return new HashSet<Long>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case NUMBER:
|
||||||
|
for (List<? extends IQueryParameterType> nextAnd : nextParamEntry.getValue()) {
|
||||||
|
pids = addPredicateNumber(nextParamName, pids, nextAnd);
|
||||||
|
if (pids.isEmpty()) {
|
||||||
|
return new HashSet<Long>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case COMPOSITE:
|
||||||
|
for (List<? extends IQueryParameterType> nextAnd : nextParamEntry.getValue()) {
|
||||||
|
pids = addPredicateComposite(nextParamDef, pids, nextAnd);
|
||||||
|
if (pids.isEmpty()) {
|
||||||
|
return new HashSet<Long>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case URI:
|
||||||
|
for (List<? extends IQueryParameterType> nextAnd : nextParamEntry.getValue()) {
|
||||||
|
pids = addPredicateUri(nextParamName, pids, nextAnd);
|
||||||
|
if (pids.isEmpty()) {
|
||||||
|
return new HashSet<Long>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return pids;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private TypedQuery<Tuple> createSearchAllByTypeQuery(DateRangeParam theLastUpdated) {
|
private TypedQuery<Tuple> createSearchAllByTypeQuery(DateRangeParam theLastUpdated) {
|
||||||
CriteriaBuilder builder = myEntityManager.getCriteriaBuilder();
|
CriteriaBuilder builder = myEntityManager.getCriteriaBuilder();
|
||||||
CriteriaQuery<Tuple> cq = builder.createTupleQuery();
|
CriteriaQuery<Tuple> cq = builder.createTupleQuery();
|
||||||
|
@ -225,6 +400,200 @@ public class SearchBuilder {
|
||||||
return query;
|
return query;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private List<Predicate> createLastUpdatedPredicates(final DateRangeParam theLastUpdated, CriteriaBuilder builder, From<?, ResourceTable> from) {
|
||||||
|
List<Predicate> lastUpdatedPredicates = new ArrayList<Predicate>();
|
||||||
|
if (theLastUpdated != null) {
|
||||||
|
if (theLastUpdated.getLowerBoundAsInstant() != null) {
|
||||||
|
Predicate predicateLower = builder.greaterThanOrEqualTo(from.<Date> get("myUpdated"), theLastUpdated.getLowerBoundAsInstant());
|
||||||
|
lastUpdatedPredicates.add(predicateLower);
|
||||||
|
}
|
||||||
|
if (theLastUpdated.getUpperBoundAsInstant() != null) {
|
||||||
|
Predicate predicateUpper = builder.lessThanOrEqualTo(from.<Date> get("myUpdated"), theLastUpdated.getUpperBoundAsInstant());
|
||||||
|
lastUpdatedPredicates.add(predicateUpper);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return lastUpdatedPredicates;
|
||||||
|
}
|
||||||
|
private List<Long> filterResourceIdsByLastUpdated(Collection<Long> thePids, final DateRangeParam theLastUpdated) {
|
||||||
|
CriteriaBuilder builder = myEntityManager.getCriteriaBuilder();
|
||||||
|
CriteriaQuery<Long> cq = builder.createQuery(Long.class);
|
||||||
|
Root<ResourceTable> from = cq.from(ResourceTable.class);
|
||||||
|
cq.select(from.get("myId").as(Long.class));
|
||||||
|
|
||||||
|
List<Predicate> lastUpdatedPredicates = createLastUpdatedPredicates(theLastUpdated, builder, from);
|
||||||
|
lastUpdatedPredicates.add(0, from.get("myId").in(thePids));
|
||||||
|
|
||||||
|
cq.where(SearchBuilder.toArray(lastUpdatedPredicates));
|
||||||
|
TypedQuery<Long> query = myEntityManager.createQuery(cq);
|
||||||
|
List<Long> resultList = query.getResultList();
|
||||||
|
return resultList;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void loadResourcesByPid(Collection<Long> theIncludePids, List<IBaseResource> theResourceListToPopulate, Set<Long> theRevIncludedPids, boolean theForHistoryOperation) {
|
||||||
|
if (theIncludePids.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<Long, Integer> position = new HashMap<Long, Integer>();
|
||||||
|
for (Long next : theIncludePids) {
|
||||||
|
position.put(next, theResourceListToPopulate.size());
|
||||||
|
theResourceListToPopulate.add(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
CriteriaBuilder builder = myEntityManager.getCriteriaBuilder();
|
||||||
|
CriteriaQuery<ResourceTable> cq = builder.createQuery(ResourceTable.class);
|
||||||
|
Root<ResourceTable> from = cq.from(ResourceTable.class);
|
||||||
|
cq.where(from.get("myId").in(theIncludePids));
|
||||||
|
TypedQuery<ResourceTable> q = myEntityManager.createQuery(cq);
|
||||||
|
|
||||||
|
for (ResourceTable next : q.getResultList()) {
|
||||||
|
Class<? extends IBaseResource> resourceType = myContext.getResourceDefinition(next.getResourceType()).getImplementingClass();
|
||||||
|
IResource resource = (IResource) myCallingDao.toResource(resourceType, next, theForHistoryOperation);
|
||||||
|
Integer index = position.get(next.getId());
|
||||||
|
if (index == null) {
|
||||||
|
ourLog.warn("Got back unexpected resource PID {}", next.getId());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (theRevIncludedPids.contains(next.getId())) {
|
||||||
|
ResourceMetadataKeyEnum.ENTRY_SEARCH_MODE.put(resource, BundleEntrySearchModeEnum.INCLUDE);
|
||||||
|
} else {
|
||||||
|
ResourceMetadataKeyEnum.ENTRY_SEARCH_MODE.put(resource, BundleEntrySearchModeEnum.MATCH);
|
||||||
|
}
|
||||||
|
|
||||||
|
theResourceListToPopulate.set(index, resource);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* THIS SHOULD RETURN HASHSET and not jsut Set because we add to it later (so it can't be Collections.emptySet())
|
||||||
|
* @param theLastUpdated
|
||||||
|
*/
|
||||||
|
private HashSet<Long> loadReverseIncludes(Collection<Long> theMatches, Set<Include> theRevIncludes, boolean theReverseMode, EverythingModeEnum theEverythingModeEnum, DateRangeParam theLastUpdated) {
|
||||||
|
if (theMatches.size() == 0) {
|
||||||
|
return new HashSet<Long>();
|
||||||
|
}
|
||||||
|
if (theRevIncludes == null || theRevIncludes.isEmpty()) {
|
||||||
|
return new HashSet<Long>();
|
||||||
|
}
|
||||||
|
String searchFieldName = theReverseMode ? "myTargetResourcePid" : "mySourceResourcePid";
|
||||||
|
|
||||||
|
Collection<Long> nextRoundMatches = theMatches;
|
||||||
|
HashSet<Long> allAdded = new HashSet<Long>();
|
||||||
|
HashSet<Long> original = new HashSet<Long>(theMatches);
|
||||||
|
ArrayList<Include> includes = new ArrayList<Include>(theRevIncludes);
|
||||||
|
|
||||||
|
int roundCounts = 0;
|
||||||
|
StopWatch w = new StopWatch();
|
||||||
|
|
||||||
|
boolean addedSomeThisRound;
|
||||||
|
do {
|
||||||
|
roundCounts++;
|
||||||
|
|
||||||
|
HashSet<Long> pidsToInclude = new HashSet<Long>();
|
||||||
|
Set<Long> nextRoundOmit = new HashSet<Long>();
|
||||||
|
|
||||||
|
for (Iterator<Include> iter = includes.iterator(); iter.hasNext();) {
|
||||||
|
Include nextInclude = iter.next();
|
||||||
|
if (nextInclude.isRecurse() == false) {
|
||||||
|
iter.remove();
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean matchAll = "*".equals(nextInclude.getValue());
|
||||||
|
if (matchAll) {
|
||||||
|
String sql;
|
||||||
|
sql = "SELECT r FROM ResourceLink r WHERE r." + searchFieldName + " IN (:target_pids)";
|
||||||
|
TypedQuery<ResourceLink> q = myEntityManager.createQuery(sql, ResourceLink.class);
|
||||||
|
q.setParameter("target_pids", nextRoundMatches);
|
||||||
|
List<ResourceLink> results = q.getResultList();
|
||||||
|
for (ResourceLink resourceLink : results) {
|
||||||
|
if (theReverseMode) {
|
||||||
|
// if (theEverythingModeEnum.isEncounter()) {
|
||||||
|
// if (resourceLink.getSourcePath().equals("Encounter.subject") || resourceLink.getSourcePath().equals("Encounter.patient")) {
|
||||||
|
// nextRoundOmit.add(resourceLink.getSourceResourcePid());
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
pidsToInclude.add(resourceLink.getSourceResourcePid());
|
||||||
|
} else {
|
||||||
|
pidsToInclude.add(resourceLink.getTargetResourcePid());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
|
||||||
|
List<String> paths;
|
||||||
|
if (myContext.getVersion().getVersion() == FhirVersionEnum.DSTU1) {
|
||||||
|
paths = Collections.singletonList(nextInclude.getValue());
|
||||||
|
} else {
|
||||||
|
int colonIdx = nextInclude.getValue().indexOf(':');
|
||||||
|
if (colonIdx < 2) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
String resType = nextInclude.getValue().substring(0, colonIdx);
|
||||||
|
RuntimeResourceDefinition def = myContext.getResourceDefinition(resType);
|
||||||
|
if (def == null) {
|
||||||
|
ourLog.warn("Unknown resource type in include/revinclude=" + nextInclude.getValue());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
String paramName = nextInclude.getValue().substring(colonIdx + 1);
|
||||||
|
RuntimeSearchParam param = def.getSearchParam(paramName);
|
||||||
|
if (param == null) {
|
||||||
|
ourLog.warn("Unknown param name in include/revinclude=" + nextInclude.getValue());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
paths = param.getPathsSplit();
|
||||||
|
}
|
||||||
|
|
||||||
|
for (String nextPath : paths) {
|
||||||
|
String sql = "SELECT r FROM ResourceLink r WHERE r.mySourcePath = :src_path AND r." + searchFieldName + " IN (:target_pids)";
|
||||||
|
TypedQuery<ResourceLink> q = myEntityManager.createQuery(sql, ResourceLink.class);
|
||||||
|
q.setParameter("src_path", nextPath);
|
||||||
|
q.setParameter("target_pids", nextRoundMatches);
|
||||||
|
List<ResourceLink> results = q.getResultList();
|
||||||
|
for (ResourceLink resourceLink : results) {
|
||||||
|
if (theReverseMode) {
|
||||||
|
pidsToInclude.add(resourceLink.getSourceResourcePid());
|
||||||
|
} else {
|
||||||
|
pidsToInclude.add(resourceLink.getTargetResourcePid());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (theLastUpdated != null && (theLastUpdated.getLowerBoundAsInstant() != null || theLastUpdated.getUpperBoundAsInstant() != null)) {
|
||||||
|
pidsToInclude = new HashSet<Long>(filterResourceIdsByLastUpdated(pidsToInclude, theLastUpdated));
|
||||||
|
}
|
||||||
|
for (Long next : pidsToInclude) {
|
||||||
|
if (original.contains(next) == false && allAdded.contains(next) == false) {
|
||||||
|
theMatches.add(next);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pidsToInclude.removeAll(nextRoundOmit);
|
||||||
|
|
||||||
|
addedSomeThisRound = allAdded.addAll(pidsToInclude);
|
||||||
|
nextRoundMatches = pidsToInclude;
|
||||||
|
} while (includes.size() > 0 && nextRoundMatches.size() > 0 && addedSomeThisRound);
|
||||||
|
|
||||||
|
ourLog.info("Loaded {} {} in {} rounds and {} ms", new Object[] { allAdded.size(), theReverseMode ? "_revincludes" : "_includes", roundCounts, w.getMillisAndRestart() });
|
||||||
|
|
||||||
|
return allAdded;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private List<Long> toList(Collection<Long> theLoadPids) {
|
||||||
|
final List<Long> pids;
|
||||||
|
if (theLoadPids instanceof List) {
|
||||||
|
pids = (List<Long>) theLoadPids;
|
||||||
|
} else {
|
||||||
|
pids = new ArrayList<Long>(theLoadPids);
|
||||||
|
}
|
||||||
|
return pids;
|
||||||
|
}
|
||||||
|
|
||||||
private List<Long> processSort(final SearchParameterMap theParams, Collection<Long> theLoadPids) {
|
private List<Long> processSort(final SearchParameterMap theParams, Collection<Long> theLoadPids) {
|
||||||
final List<Long> pids;
|
final List<Long> pids;
|
||||||
// Set<Long> loadPids = theLoadPids;
|
// Set<Long> loadPids = theLoadPids;
|
||||||
|
@ -316,7 +685,7 @@ public class SearchBuilder {
|
||||||
}
|
}
|
||||||
|
|
||||||
private Predicate createResourceLinkPathPredicate(String theParamName, CriteriaBuilder builder, Root<? extends ResourceLink> from) {
|
private Predicate createResourceLinkPathPredicate(String theParamName, CriteriaBuilder builder, Root<? extends ResourceLink> from) {
|
||||||
RuntimeSearchParam param = myContext.getResourceDefinition(getResourceType()).getSearchParam(theParamName);
|
RuntimeSearchParam param = myContext.getResourceDefinition(myResourceType).getSearchParam(theParamName);
|
||||||
List<String> path = param.getPathsSplit();
|
List<String> path = param.getPathsSplit();
|
||||||
Predicate type = from.get("mySourcePath").in(path);
|
Predicate type = from.get("mySourcePath").in(path);
|
||||||
return type;
|
return type;
|
||||||
|
@ -682,8 +1051,6 @@ public class SearchBuilder {
|
||||||
}
|
}
|
||||||
|
|
||||||
private Set<Long> addPredicateParamMissing(Set<Long> thePids, String joinName, String theParamName, Class<? extends BaseResourceIndexedSearchParam> theParamTable) {
|
private Set<Long> addPredicateParamMissing(Set<Long> thePids, String joinName, String theParamName, Class<? extends BaseResourceIndexedSearchParam> theParamTable) {
|
||||||
String resourceType = myContext.getResourceDefinition(getResourceType()).getName();
|
|
||||||
|
|
||||||
CriteriaBuilder builder = myEntityManager.getCriteriaBuilder();
|
CriteriaBuilder builder = myEntityManager.getCriteriaBuilder();
|
||||||
CriteriaQuery<Long> cq = builder.createQuery(Long.class);
|
CriteriaQuery<Long> cq = builder.createQuery(Long.class);
|
||||||
Root<ResourceTable> from = cq.from(ResourceTable.class);
|
Root<ResourceTable> from = cq.from(ResourceTable.class);
|
||||||
|
@ -693,11 +1060,11 @@ public class SearchBuilder {
|
||||||
Root<? extends BaseResourceIndexedSearchParam> subQfrom = subQ.from(theParamTable);
|
Root<? extends BaseResourceIndexedSearchParam> subQfrom = subQ.from(theParamTable);
|
||||||
subQ.select(subQfrom.get("myResourcePid").as(Long.class));
|
subQ.select(subQfrom.get("myResourcePid").as(Long.class));
|
||||||
Predicate subQname = builder.equal(subQfrom.get("myParamName"), theParamName);
|
Predicate subQname = builder.equal(subQfrom.get("myParamName"), theParamName);
|
||||||
Predicate subQtype = builder.equal(subQfrom.get("myResourceType"), resourceType);
|
Predicate subQtype = builder.equal(subQfrom.get("myResourceType"), myResourceName);
|
||||||
subQ.where(builder.and(subQtype, subQname));
|
subQ.where(builder.and(subQtype, subQname));
|
||||||
|
|
||||||
Predicate joinPredicate = builder.not(builder.in(from.get("myId")).value(subQ));
|
Predicate joinPredicate = builder.not(builder.in(from.get("myId")).value(subQ));
|
||||||
Predicate typePredicate = builder.equal(from.get("myResourceType"), resourceType);
|
Predicate typePredicate = builder.equal(from.get("myResourceType"), myResourceName);
|
||||||
Predicate notDeletedPredicate = builder.isNull(from.get("myDeleted"));
|
Predicate notDeletedPredicate = builder.isNull(from.get("myDeleted"));
|
||||||
|
|
||||||
if (thePids.size() > 0) {
|
if (thePids.size() > 0) {
|
||||||
|
@ -895,7 +1262,7 @@ public class SearchBuilder {
|
||||||
IIdType dt = new IdDt(resourceId);
|
IIdType dt = new IdDt(resourceId);
|
||||||
resourceId = dt.getIdPart();
|
resourceId = dt.getIdPart();
|
||||||
}
|
}
|
||||||
Long targetPid = translateForcedIdToPid(new IdDt(resourceId));
|
Long targetPid = myCallingDao.translateForcedIdToPid(new IdDt(resourceId));
|
||||||
ourLog.debug("Searching for resource link with target PID: {}", targetPid);
|
ourLog.debug("Searching for resource link with target PID: {}", targetPid);
|
||||||
Predicate eq = builder.equal(from.get("myTargetResourcePid"), targetPid);
|
Predicate eq = builder.equal(from.get("myTargetResourcePid"), targetPid);
|
||||||
|
|
||||||
|
@ -935,7 +1302,7 @@ public class SearchBuilder {
|
||||||
for (Class<? extends IBaseResource> nextType : resourceTypes) {
|
for (Class<? extends IBaseResource> nextType : resourceTypes) {
|
||||||
RuntimeResourceDefinition typeDef = myContext.getResourceDefinition(nextType);
|
RuntimeResourceDefinition typeDef = myContext.getResourceDefinition(nextType);
|
||||||
|
|
||||||
IFhirResourceDao<?> dao = getDao(nextType);
|
IFhirResourceDao<?> dao = myCallingDao.getDao(nextType);
|
||||||
if (dao == null) {
|
if (dao == null) {
|
||||||
ourLog.debug("Don't have a DAO for type {}", nextType.getSimpleName());
|
ourLog.debug("Don't have a DAO for type {}", nextType.getSimpleName());
|
||||||
continue;
|
continue;
|
||||||
|
@ -948,7 +1315,7 @@ public class SearchBuilder {
|
||||||
chain = chain.substring(0, qualifierIndex);
|
chain = chain.substring(0, qualifierIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean isMeta = RESOURCE_META_PARAMS.containsKey(chain);
|
boolean isMeta = BaseHapiFhirDao.RESOURCE_META_PARAMS.containsKey(chain);
|
||||||
RuntimeSearchParam param = null;
|
RuntimeSearchParam param = null;
|
||||||
if (!isMeta) {
|
if (!isMeta) {
|
||||||
param = typeDef.getSearchParam(chain);
|
param = typeDef.getSearchParam(chain);
|
||||||
|
@ -969,7 +1336,7 @@ public class SearchBuilder {
|
||||||
chainValue.setValueAsQueryToken(qualifier, resourceId);
|
chainValue.setValueAsQueryToken(qualifier, resourceId);
|
||||||
((ReferenceParam) chainValue).setChain(remainingChain);
|
((ReferenceParam) chainValue).setChain(remainingChain);
|
||||||
} else if (isMeta) {
|
} else if (isMeta) {
|
||||||
IQueryParameterType type = newInstanceType(chain);
|
IQueryParameterType type = BaseHapiFhirDao.newInstanceType(chain);
|
||||||
type.setValueAsQueryToken(qualifier, resourceId);
|
type.setValueAsQueryToken(qualifier, resourceId);
|
||||||
chainValue = type;
|
chainValue = type;
|
||||||
} else {
|
} else {
|
||||||
|
@ -1013,6 +1380,51 @@ public class SearchBuilder {
|
||||||
return new HashSet<Long>(q.getResultList());
|
return new HashSet<Long>(q.getResultList());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private IQueryParameterType toParameterType(RuntimeSearchParam theParam, String theQualifier, String theValueAsQueryToken) {
|
||||||
|
IQueryParameterType qp = toParameterType(theParam);
|
||||||
|
|
||||||
|
qp.setValueAsQueryToken(theQualifier, theValueAsQueryToken); // aaaa
|
||||||
|
return qp;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private IQueryParameterType toParameterType(RuntimeSearchParam theParam) {
|
||||||
|
IQueryParameterType qp;
|
||||||
|
switch (theParam.getParamType()) {
|
||||||
|
case DATE:
|
||||||
|
qp = new DateParam();
|
||||||
|
break;
|
||||||
|
case NUMBER:
|
||||||
|
qp = new NumberParam();
|
||||||
|
break;
|
||||||
|
case QUANTITY:
|
||||||
|
qp = new QuantityParam();
|
||||||
|
break;
|
||||||
|
case STRING:
|
||||||
|
qp = new StringParam();
|
||||||
|
break;
|
||||||
|
case TOKEN:
|
||||||
|
qp = new TokenParam();
|
||||||
|
break;
|
||||||
|
case COMPOSITE:
|
||||||
|
List<RuntimeSearchParam> compositeOf = theParam.getCompositeOf();
|
||||||
|
if (compositeOf.size() != 2) {
|
||||||
|
throw new InternalErrorException("Parameter " + theParam.getName() + " has " + compositeOf.size() + " composite parts. Don't know how handlt this.");
|
||||||
|
}
|
||||||
|
IQueryParameterType leftParam = toParameterType(compositeOf.get(0));
|
||||||
|
IQueryParameterType rightParam = toParameterType(compositeOf.get(1));
|
||||||
|
qp = new CompositeParam<IQueryParameterType, IQueryParameterType>(leftParam, rightParam);
|
||||||
|
break;
|
||||||
|
case REFERENCE:
|
||||||
|
qp = new ReferenceParam();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new InternalErrorException("Don't know how to convert param type: " + theParam.getParamType());
|
||||||
|
}
|
||||||
|
return qp;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private Set<Long> addPredicateString(String theParamName, Set<Long> thePids, List<? extends IQueryParameterType> theList) {
|
private Set<Long> addPredicateString(String theParamName, Set<Long> thePids, List<? extends IQueryParameterType> theList) {
|
||||||
if (theList == null || theList.isEmpty()) {
|
if (theList == null || theList.isEmpty()) {
|
||||||
return thePids;
|
return thePids;
|
||||||
|
@ -1256,5 +1668,166 @@ public class SearchBuilder {
|
||||||
return new HashSet<Long>(q.getResultList());
|
return new HashSet<Long>(q.getResultList());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setType(Class<? extends IBaseResource> theResourceType, String theResourceName) {
|
||||||
|
myResourceType = theResourceType;
|
||||||
|
myResourceName = theResourceName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IBundleProvider search(final SearchParameterMap theParams) {
|
||||||
|
StopWatch w = new StopWatch();
|
||||||
|
final InstantDt now = InstantDt.withCurrentTime();
|
||||||
|
|
||||||
|
DateRangeParam lu = theParams.getLastUpdated();
|
||||||
|
if (lu != null && lu.isEmpty()) {
|
||||||
|
lu = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
Collection<Long> loadPids;
|
||||||
|
if (theParams.getEverythingMode() != null) {
|
||||||
|
|
||||||
|
CriteriaBuilder builder = myEntityManager.getCriteriaBuilder();
|
||||||
|
CriteriaQuery<Tuple> cq = builder.createTupleQuery();
|
||||||
|
Root<ResourceTable> from = cq.from(ResourceTable.class);
|
||||||
|
List<Predicate> predicates = new ArrayList<Predicate>();
|
||||||
|
if (theParams.get(BaseResource.SP_RES_ID) != null) {
|
||||||
|
StringParam idParm = (StringParam) theParams.get(BaseResource.SP_RES_ID).get(0).get(0);
|
||||||
|
predicates.add(builder.equal(from.get("myId"), idParm.getValue()));
|
||||||
|
}
|
||||||
|
predicates.add(builder.equal(from.get("myResourceType"), myResourceName));
|
||||||
|
predicates.add(builder.isNull(from.get("myDeleted")));
|
||||||
|
cq.where(builder.and(SearchBuilder.toArray(predicates)));
|
||||||
|
|
||||||
|
Join<Object, Object> join = from.join("myIncomingResourceLinks", JoinType.LEFT);
|
||||||
|
cq.multiselect(from.get("myId").as(Long.class), join.get("mySourceResourcePid").as(Long.class));
|
||||||
|
|
||||||
|
TypedQuery<Tuple> query = myEntityManager.createQuery(cq);
|
||||||
|
loadPids = new HashSet<Long>();
|
||||||
|
for (Tuple next : query.getResultList()) {
|
||||||
|
loadPids.add(next.get(0, Long.class));
|
||||||
|
Long nextLong = next.get(1, Long.class);
|
||||||
|
if(nextLong != null) {
|
||||||
|
loadPids.add(nextLong);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if (theParams.isEmpty()) {
|
||||||
|
|
||||||
|
loadPids = new HashSet<Long>();
|
||||||
|
TypedQuery<Tuple> query = createSearchAllByTypeQuery(lu);
|
||||||
|
lu = null;
|
||||||
|
for (Tuple next : query.getResultList()) {
|
||||||
|
loadPids.add(next.get(0, Long.class));
|
||||||
|
}
|
||||||
|
if (loadPids.isEmpty()) {
|
||||||
|
return new SimpleBundleProvider();
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
List<Long> searchResultPids;
|
||||||
|
if (mySearchDao == null) {
|
||||||
|
if (theParams.containsKey(Constants.PARAM_TEXT)) {
|
||||||
|
throw new InvalidRequestException("Fulltext search is not enabled on this service, can not process parameter: " + Constants.PARAM_TEXT);
|
||||||
|
} else if (theParams.containsKey(Constants.PARAM_CONTENT)) {
|
||||||
|
throw new InvalidRequestException("Fulltext search is not enabled on this service, can not process parameter: " + Constants.PARAM_CONTENT);
|
||||||
|
}
|
||||||
|
searchResultPids = null;
|
||||||
|
} else {
|
||||||
|
searchResultPids = mySearchDao.search(myResourceName, theParams);
|
||||||
|
}
|
||||||
|
if (theParams.isEmpty()) {
|
||||||
|
loadPids = searchResultPids;
|
||||||
|
} else {
|
||||||
|
loadPids = searchForIdsWithAndOr(theParams, searchResultPids, lu);
|
||||||
|
}
|
||||||
|
if (loadPids.isEmpty()) {
|
||||||
|
return new SimpleBundleProvider();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// // Load _include and _revinclude before filter and sort in everything mode
|
||||||
|
// if (theParams.getEverythingMode() != null) {
|
||||||
|
// if (theParams.getRevIncludes() != null && theParams.getRevIncludes().isEmpty() == false) {
|
||||||
|
// loadPids.addAll(loadReverseIncludes(loadPids, theParams.getRevIncludes(), true, theParams.getEverythingMode()));
|
||||||
|
// loadPids.addAll(loadReverseIncludes(loadPids, theParams.getIncludes(), false, theParams.getEverythingMode()));
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// Handle _lastUpdated
|
||||||
|
if (lu != null) {
|
||||||
|
List<Long> resultList = filterResourceIdsByLastUpdated(loadPids, lu);
|
||||||
|
loadPids.clear();
|
||||||
|
for (Long next : resultList) {
|
||||||
|
loadPids.add(next);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (loadPids.isEmpty()) {
|
||||||
|
return new SimpleBundleProvider();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle sorting if any was provided
|
||||||
|
final List<Long> pids = processSort(theParams, loadPids);
|
||||||
|
|
||||||
|
// Load _revinclude resources
|
||||||
|
final Set<Long> revIncludedPids;
|
||||||
|
if (theParams.getEverythingMode() == null) {
|
||||||
|
if (theParams.getRevIncludes() != null && theParams.getRevIncludes().isEmpty() == false) {
|
||||||
|
revIncludedPids = loadReverseIncludes(pids, theParams.getRevIncludes(), true, null, lu);
|
||||||
|
} else {
|
||||||
|
revIncludedPids = new HashSet<Long>();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
revIncludedPids = new HashSet<Long>();
|
||||||
|
}
|
||||||
|
|
||||||
|
ourLog.debug("Search returned PIDs: {}", pids);
|
||||||
|
|
||||||
|
final int totalCount = pids.size();
|
||||||
|
|
||||||
|
IBundleProvider retVal = new IBundleProvider() {
|
||||||
|
@Override
|
||||||
|
public InstantDt getPublished() {
|
||||||
|
return now;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<IBaseResource> getResources(final int theFromIndex, final int theToIndex) {
|
||||||
|
TransactionTemplate template = new TransactionTemplate(myPlatformTransactionManager);
|
||||||
|
return template.execute(new TransactionCallback<List<IBaseResource>>() {
|
||||||
|
@Override
|
||||||
|
public List<IBaseResource> doInTransaction(TransactionStatus theStatus) {
|
||||||
|
List<Long> pidsSubList = pids.subList(theFromIndex, theToIndex);
|
||||||
|
|
||||||
|
// Load includes
|
||||||
|
pidsSubList = new ArrayList<Long>(pidsSubList);
|
||||||
|
revIncludedPids.addAll(loadReverseIncludes(pidsSubList, theParams.getIncludes(), false, null, theParams.getLastUpdated()));
|
||||||
|
|
||||||
|
// Execute the query and make sure we return distinct results
|
||||||
|
List<IBaseResource> resources = new ArrayList<IBaseResource>();
|
||||||
|
loadResourcesByPid(pidsSubList, resources, revIncludedPids, false);
|
||||||
|
|
||||||
|
return resources;
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Integer preferredPageSize() {
|
||||||
|
return theParams.getCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int size() {
|
||||||
|
return totalCount;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
ourLog.info(" {} on {} in {}ms", new Object[] { myResourceName, theParams, w.getMillisAndRestart() });
|
||||||
|
return retVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,24 @@
|
||||||
|
package ca.uhn.fhir.jpa.provider;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Required;
|
||||||
|
|
||||||
|
import ca.uhn.fhir.jpa.dao.IFhirSystemDao;
|
||||||
|
|
||||||
|
public class BaseJpaPlainProvider extends BaseJpaProvider {
|
||||||
|
|
||||||
|
private IFhirSystemDao<?> myDao;
|
||||||
|
|
||||||
|
public BaseJpaPlainProvider() {
|
||||||
|
// nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
@Required
|
||||||
|
public void setDao(IFhirSystemDao<?> theDao) {
|
||||||
|
myDao = theDao;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IFhirSystemDao<?> getDao() {
|
||||||
|
return myDao;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -29,15 +29,17 @@ import javax.servlet.http.HttpServletRequest;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.jboss.logging.MDC;
|
import org.jboss.logging.MDC;
|
||||||
|
|
||||||
|
import ca.uhn.fhir.context.FhirContext;
|
||||||
import ca.uhn.fhir.rest.method.RequestDetails;
|
import ca.uhn.fhir.rest.method.RequestDetails;
|
||||||
|
|
||||||
public class BaseJpaProvider {
|
public class BaseJpaProvider {
|
||||||
|
|
||||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(BaseJpaProvider.class);
|
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(BaseJpaProvider.class);
|
||||||
public static final String REMOTE_ADDR = "req.remoteAddr";
|
public static final String REMOTE_ADDR = "req.remoteAddr";
|
||||||
|
|
||||||
public static final String REMOTE_UA = "req.userAgent";
|
public static final String REMOTE_UA = "req.userAgent";
|
||||||
|
|
||||||
|
private FhirContext myContext;
|
||||||
|
|
||||||
public void endRequest(HttpServletRequest theRequest) {
|
public void endRequest(HttpServletRequest theRequest) {
|
||||||
MDC.remove(REMOTE_ADDR);
|
MDC.remove(REMOTE_ADDR);
|
||||||
MDC.remove(REMOTE_UA);
|
MDC.remove(REMOTE_UA);
|
||||||
|
@ -47,6 +49,14 @@ public class BaseJpaProvider {
|
||||||
endRequest(theRequest.getServletRequest());
|
endRequest(theRequest.getServletRequest());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public FhirContext getContext() {
|
||||||
|
return myContext;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setContext(FhirContext theContext) {
|
||||||
|
myContext = theContext;
|
||||||
|
}
|
||||||
|
|
||||||
public void startRequest(HttpServletRequest theRequest) {
|
public void startRequest(HttpServletRequest theRequest) {
|
||||||
if (theRequest == null) {
|
if (theRequest == null) {
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -43,7 +43,6 @@ import ca.uhn.fhir.rest.server.IResourceProvider;
|
||||||
|
|
||||||
public abstract class BaseJpaResourceProvider<T extends IResource> extends BaseJpaProvider implements IResourceProvider {
|
public abstract class BaseJpaResourceProvider<T extends IResource> extends BaseJpaProvider implements IResourceProvider {
|
||||||
|
|
||||||
private FhirContext myContext;
|
|
||||||
private IFhirResourceDao<T> myDao;
|
private IFhirResourceDao<T> myDao;
|
||||||
|
|
||||||
public BaseJpaResourceProvider() {
|
public BaseJpaResourceProvider() {
|
||||||
|
@ -55,10 +54,6 @@ public abstract class BaseJpaResourceProvider<T extends IResource> extends BaseJ
|
||||||
myDao = theDao;
|
myDao = theDao;
|
||||||
}
|
}
|
||||||
|
|
||||||
public FhirContext getContext() {
|
|
||||||
return myContext;
|
|
||||||
}
|
|
||||||
|
|
||||||
public IFhirResourceDao<T> getDao() {
|
public IFhirResourceDao<T> getDao() {
|
||||||
return myDao;
|
return myDao;
|
||||||
}
|
}
|
||||||
|
@ -118,10 +113,6 @@ public abstract class BaseJpaResourceProvider<T extends IResource> extends BaseJ
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setContext(FhirContext theContext) {
|
|
||||||
myContext = theContext;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Required
|
@Required
|
||||||
public void setDao(IFhirResourceDao<T> theDao) {
|
public void setDao(IFhirResourceDao<T> theDao) {
|
||||||
myDao = theDao;
|
myDao = theDao;
|
||||||
|
|
|
@ -0,0 +1,36 @@
|
||||||
|
package ca.uhn.fhir.jpa.dao;
|
||||||
|
|
||||||
|
public class FhirSystemDaoDstu2SearchTest {
|
||||||
|
|
||||||
|
/*//@formatter:off
|
||||||
|
* [ERROR] Search parameter action has conflicting types token and reference
|
||||||
|
* [ERROR] Search parameter source has conflicting types token and reference
|
||||||
|
* [ERROR] Search parameter plan has conflicting types reference and token
|
||||||
|
* [ERROR] Search parameter version has conflicting types token and string
|
||||||
|
* [ERROR] Search parameter source has conflicting types reference and uri
|
||||||
|
* [ERROR] Search parameter location has conflicting types reference and uri
|
||||||
|
* [ERROR] Search parameter title has conflicting types string and token
|
||||||
|
* [ERROR] Search parameter manufacturer has conflicting types string and reference
|
||||||
|
* [ERROR] Search parameter address has conflicting types token and string
|
||||||
|
* [ERROR] Search parameter source has conflicting types reference and string
|
||||||
|
* [ERROR] Search parameter destination has conflicting types reference and string
|
||||||
|
* [ERROR] Search parameter responsible has conflicting types reference and string
|
||||||
|
* [ERROR] Search parameter value has conflicting types token and string
|
||||||
|
* [ERROR] Search parameter address has conflicting types token and string
|
||||||
|
* [ERROR] Search parameter address has conflicting types token and string
|
||||||
|
* [ERROR] Search parameter address has conflicting types token and string
|
||||||
|
* [ERROR] Search parameter address has conflicting types token and string
|
||||||
|
* [ERROR] Search parameter action has conflicting types reference and token
|
||||||
|
* [ERROR] Search parameter version has conflicting types token and string
|
||||||
|
* [ERROR] Search parameter address has conflicting types token and string
|
||||||
|
* [ERROR] Search parameter base has conflicting types reference and token
|
||||||
|
* [ERROR] Search parameter target has conflicting types reference and token
|
||||||
|
* [ERROR] Search parameter base has conflicting types reference and uri
|
||||||
|
* [ERROR] Search parameter contact has conflicting types string and token
|
||||||
|
* [ERROR] Search parameter substance has conflicting types token and reference
|
||||||
|
* [ERROR] Search parameter provider has conflicting types reference and token
|
||||||
|
* [ERROR] Search parameter system has conflicting types token and uri
|
||||||
|
* [ERROR] Search parameter reference has conflicting types reference and uri
|
||||||
|
* //@formatter:off
|
||||||
|
*/
|
||||||
|
}
|
|
@ -55,6 +55,26 @@ public class ServerSearchDstu2Test {
|
||||||
assertEquals("param1value", ourLastRef.getValue());
|
assertEquals("param1value", ourLastRef.getValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSearchParam2() throws Exception {
|
||||||
|
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/?param2=param2value&foo=bar");
|
||||||
|
HttpResponse status = ourClient.execute(httpGet);
|
||||||
|
String responseContent = IOUtils.toString(status.getEntity().getContent());
|
||||||
|
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||||
|
ourLog.info(responseContent);
|
||||||
|
assertEquals("searchParam2", ourLastMethod);
|
||||||
|
assertEquals("param2value", ourLastRef.getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testUnknownSearchParam() throws Exception {
|
||||||
|
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/?foo=bar");
|
||||||
|
HttpResponse status = ourClient.execute(httpGet);
|
||||||
|
String responseContent = IOUtils.toString(status.getEntity().getContent());
|
||||||
|
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||||
|
ourLog.info(responseContent);
|
||||||
|
assertEquals(null, ourLastMethod);
|
||||||
|
}
|
||||||
|
|
||||||
@AfterClass
|
@AfterClass
|
||||||
public static void afterClass() throws Exception {
|
public static void afterClass() throws Exception {
|
||||||
|
@ -86,9 +106,8 @@ public class ServerSearchDstu2Test {
|
||||||
|
|
||||||
public static class DummyPatientResourceProvider {
|
public static class DummyPatientResourceProvider {
|
||||||
|
|
||||||
|
|
||||||
//@formatter:off
|
//@formatter:off
|
||||||
@Search()
|
@Search(allowUnknownParams=true)
|
||||||
public List<IBaseResource> searchParam1(
|
public List<IBaseResource> searchParam1(
|
||||||
@RequiredParam(name = "param1") StringParam theParam) {
|
@RequiredParam(name = "param1") StringParam theParam) {
|
||||||
ourLastMethod = "searchParam1";
|
ourLastMethod = "searchParam1";
|
||||||
|
@ -104,7 +123,7 @@ public class ServerSearchDstu2Test {
|
||||||
//@formatter:on
|
//@formatter:on
|
||||||
|
|
||||||
//@formatter:off
|
//@formatter:off
|
||||||
@Search()
|
@Search(allowUnknownParams=true)
|
||||||
public List<IBaseResource> searchParam2(
|
public List<IBaseResource> searchParam2(
|
||||||
@RequiredParam(name = "param2") StringParam theParam) {
|
@RequiredParam(name = "param2") StringParam theParam) {
|
||||||
ourLastMethod = "searchParam2";
|
ourLastMethod = "searchParam2";
|
||||||
|
|
|
@ -210,9 +210,14 @@ public class TinderJpaRestServerMojo extends AbstractMojo {
|
||||||
// Conformance conformance = new FhirContext(Conformance.class).newXmlParser().parseResource(Conformance.class, metadataString);
|
// Conformance conformance = new FhirContext(Conformance.class).newXmlParser().parseResource(Conformance.class, metadataString);
|
||||||
|
|
||||||
TinderJpaRestServerMojo mojo = new TinderJpaRestServerMojo();
|
TinderJpaRestServerMojo mojo = new TinderJpaRestServerMojo();
|
||||||
|
mojo.myProject = new MavenProject();
|
||||||
|
mojo.version = "dstu2";
|
||||||
mojo.packageBase = "ca.uhn.test";
|
mojo.packageBase = "ca.uhn.test";
|
||||||
mojo.baseResourceNames = java.util.Collections.singletonList("observation");
|
mojo.configPackageBase = "ca.uhn.test";
|
||||||
|
// mojo.baseResourceNames = new ArrayList<String>(Collections.singletonList("observation"));
|
||||||
mojo.targetDirectory = new File("target/generated/valuesets");
|
mojo.targetDirectory = new File("target/generated/valuesets");
|
||||||
|
mojo.targetResourceDirectory = new File("target/generated/valuesets");
|
||||||
|
mojo.targetResourceSpringBeansFile = "tmp_beans.xml";
|
||||||
mojo.execute();
|
mojo.execute();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -60,7 +60,7 @@ public abstract class BaseStructureParser {
|
||||||
private TreeMap<String, String> myNameToDatatypeClass = new TreeMap<String, String>();
|
private TreeMap<String, String> myNameToDatatypeClass = new TreeMap<String, String>();
|
||||||
private TreeMap<String, String> myNameToResourceClass = new TreeMap<String, String>();
|
private TreeMap<String, String> myNameToResourceClass = new TreeMap<String, String>();
|
||||||
private String myPackageBase;
|
private String myPackageBase;
|
||||||
private List<BaseRootType> myResources = new ArrayList<BaseRootType>();
|
protected List<BaseRootType> myResources = new ArrayList<BaseRootType>();
|
||||||
private String myVersion;
|
private String myVersion;
|
||||||
|
|
||||||
public BaseStructureParser(String theVersion, String theBaseDir) {
|
public BaseStructureParser(String theVersion, String theBaseDir) {
|
||||||
|
@ -555,7 +555,7 @@ public abstract class BaseStructureParser {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private FhirVersionEnum determineVersionEnum() throws MojoFailureException {
|
protected FhirVersionEnum determineVersionEnum() throws MojoFailureException {
|
||||||
FhirVersionEnum versionEnum = null;
|
FhirVersionEnum versionEnum = null;
|
||||||
if ("dstu".equals(myVersion)) {
|
if ("dstu".equals(myVersion)) {
|
||||||
versionEnum = FhirVersionEnum.DSTU1;
|
versionEnum = FhirVersionEnum.DSTU1;
|
||||||
|
|
|
@ -16,7 +16,7 @@ public class ResourceGeneratorUsingSpreadsheet extends BaseStructureSpreadsheetP
|
||||||
private List<String> myInputStreamNames;
|
private List<String> myInputStreamNames;
|
||||||
private ArrayList<InputStream> myInputStreams;
|
private ArrayList<InputStream> myInputStreams;
|
||||||
private String myTemplate = null;
|
private String myTemplate = null;
|
||||||
private String myVersion;
|
protected String myVersion;
|
||||||
|
|
||||||
public ResourceGeneratorUsingSpreadsheet(String theVersion, String theBaseDir) {
|
public ResourceGeneratorUsingSpreadsheet(String theVersion, String theBaseDir) {
|
||||||
super(theVersion, theBaseDir);
|
super(theVersion, theBaseDir);
|
||||||
|
|
|
@ -217,6 +217,11 @@
|
||||||
which are part of a bundle when the resource has a UUID/OID
|
which are part of a bundle when the resource has a UUID/OID
|
||||||
ID.
|
ID.
|
||||||
</action>
|
</action>
|
||||||
|
<action type="add">
|
||||||
|
Add ability for a server REST resource provider @Search method
|
||||||
|
to declare that it should allow even parameters it doesn't
|
||||||
|
understand.
|
||||||
|
<action>
|
||||||
</release>
|
</release>
|
||||||
<release version="1.2" date="2015-09-18">
|
<release version="1.2" date="2015-09-18">
|
||||||
<action type="add">
|
<action type="add">
|
||||||
|
|
Loading…
Reference in New Issue