Improve efficiency of JPA queries with _lastUpdated
This commit is contained in:
parent
8c0b665565
commit
b827823004
|
@ -58,20 +58,6 @@ public class DateRangeParam implements IQueryParameterAnd<DateParam> {
|
|||
setRangeFromDatesInclusive(theLowerBound, theUpperBound);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor which takes two Dates representing the lower and upper bounds of the range (inclusive on both ends)
|
||||
*
|
||||
* @param theLowerBound
|
||||
* A qualified date param representing the lower date bound (optionally may include time), e.g.
|
||||
* "2011-02-22" or "2011-02-22T13:12:00Z". Will be treated inclusively. Either theLowerBound or theUpperBound may both be populated, or one may be null, but it is not valid for both to be null.
|
||||
* @param theUpperBound
|
||||
* A qualified date param representing the upper date bound (optionally may include time), e.g.
|
||||
* "2011-02-22" or "2011-02-22T13:12:00Z". Will be treated inclusively. Either theLowerBound or theUpperBound may both be populated, or one may be null, but it is not valid for both to be null.
|
||||
*/
|
||||
public DateRangeParam(DateTimeDt theLowerBound, DateTimeDt theUpperBound) {
|
||||
setRangeFromDatesInclusive(theLowerBound, theUpperBound);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the range from a single date param. If theDateParam has no qualifier, treats it as the lower and upper bound
|
||||
* (e.g. 2011-01-02 would match any time on that day). If theDateParam has a qualifier, treats it as either the
|
||||
|
@ -106,6 +92,20 @@ public class DateRangeParam implements IQueryParameterAnd<DateParam> {
|
|||
validateAndThrowDataFormatExceptionIfInvalid();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor which takes two Dates representing the lower and upper bounds of the range (inclusive on both ends)
|
||||
*
|
||||
* @param theLowerBound
|
||||
* A qualified date param representing the lower date bound (optionally may include time), e.g.
|
||||
* "2011-02-22" or "2011-02-22T13:12:00Z". Will be treated inclusively. Either theLowerBound or theUpperBound may both be populated, or one may be null, but it is not valid for both to be null.
|
||||
* @param theUpperBound
|
||||
* A qualified date param representing the upper date bound (optionally may include time), e.g.
|
||||
* "2011-02-22" or "2011-02-22T13:12:00Z". Will be treated inclusively. Either theLowerBound or theUpperBound may both be populated, or one may be null, but it is not valid for both to be null.
|
||||
*/
|
||||
public DateRangeParam(DateTimeDt theLowerBound, DateTimeDt theUpperBound) {
|
||||
setRangeFromDatesInclusive(theLowerBound, theUpperBound);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor which takes two strings representing the lower and upper bounds of the range (inclusive on both ends)
|
||||
*
|
||||
|
@ -120,6 +120,39 @@ public class DateRangeParam implements IQueryParameterAnd<DateParam> {
|
|||
setRangeFromDatesInclusive(theLowerBound, theUpperBound);
|
||||
}
|
||||
|
||||
private void addParam(DateParam theParsed) throws InvalidRequestException {
|
||||
if (theParsed.getComparator() == null) {
|
||||
if (myLowerBound != null || myUpperBound != null) {
|
||||
throw new InvalidRequestException("Can not have multiple date range parameters for the same param without a qualifier");
|
||||
}
|
||||
|
||||
myLowerBound = new DateParam(QuantityCompararatorEnum.GREATERTHAN_OR_EQUALS, theParsed.getValueAsString());
|
||||
myUpperBound = new DateParam(QuantityCompararatorEnum.LESSTHAN_OR_EQUALS, theParsed.getValueAsString());
|
||||
|
||||
} else {
|
||||
|
||||
switch (theParsed.getComparator()) {
|
||||
case GREATERTHAN:
|
||||
case GREATERTHAN_OR_EQUALS:
|
||||
if (myLowerBound != null) {
|
||||
throw new InvalidRequestException("Can not have multiple date range parameters for the same param that specify a lower bound");
|
||||
}
|
||||
myLowerBound = theParsed;
|
||||
break;
|
||||
case LESSTHAN:
|
||||
case LESSTHAN_OR_EQUALS:
|
||||
if (myUpperBound != null) {
|
||||
throw new InvalidRequestException("Can not have multiple date range parameters for the same param that specify an upper bound");
|
||||
}
|
||||
myUpperBound = theParsed;
|
||||
break;
|
||||
default:
|
||||
throw new InvalidRequestException("Unknown comparator: " + theParsed.getComparator());
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public DateParam getLowerBound() {
|
||||
return myLowerBound;
|
||||
}
|
||||
|
@ -182,6 +215,18 @@ public class DateRangeParam implements IQueryParameterAnd<DateParam> {
|
|||
return retVal;
|
||||
}
|
||||
|
||||
private boolean haveLowerBound() {
|
||||
return myLowerBound != null && myLowerBound.isEmpty() == false;
|
||||
}
|
||||
|
||||
private boolean haveUpperBound() {
|
||||
return myUpperBound != null && myUpperBound.isEmpty() == false;
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
return (getLowerBoundAsInstant() == null) && (getUpperBoundAsInstant() == null);
|
||||
}
|
||||
|
||||
public void setLowerBound(DateParam theLowerBound) {
|
||||
myLowerBound = theLowerBound;
|
||||
validateAndThrowDataFormatExceptionIfInvalid();
|
||||
|
@ -275,37 +320,32 @@ public class DateRangeParam implements IQueryParameterAnd<DateParam> {
|
|||
|
||||
}
|
||||
|
||||
private void addParam(DateParam theParsed) throws InvalidRequestException {
|
||||
if (theParsed.getComparator() == null) {
|
||||
if (myLowerBound != null || myUpperBound != null) {
|
||||
throw new InvalidRequestException("Can not have multiple date range parameters for the same param without a qualifier");
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder b = new StringBuilder();
|
||||
b.append(getClass().getSimpleName());
|
||||
b.append("[");
|
||||
if (haveLowerBound()) {
|
||||
if (myLowerBound.getComparator() != null) {
|
||||
b.append(myLowerBound.getComparator().getCode());
|
||||
}
|
||||
|
||||
myLowerBound = new DateParam(QuantityCompararatorEnum.GREATERTHAN_OR_EQUALS, theParsed.getValueAsString());
|
||||
myUpperBound = new DateParam(QuantityCompararatorEnum.LESSTHAN_OR_EQUALS, theParsed.getValueAsString());
|
||||
|
||||
} else {
|
||||
|
||||
switch (theParsed.getComparator()) {
|
||||
case GREATERTHAN:
|
||||
case GREATERTHAN_OR_EQUALS:
|
||||
if (myLowerBound != null) {
|
||||
throw new InvalidRequestException("Can not have multiple date range parameters for the same param that specify a lower bound");
|
||||
}
|
||||
myLowerBound = theParsed;
|
||||
break;
|
||||
case LESSTHAN:
|
||||
case LESSTHAN_OR_EQUALS:
|
||||
if (myUpperBound != null) {
|
||||
throw new InvalidRequestException("Can not have multiple date range parameters for the same param that specify an upper bound");
|
||||
}
|
||||
myUpperBound = theParsed;
|
||||
break;
|
||||
default:
|
||||
throw new InvalidRequestException("Unknown comparator: " + theParsed.getComparator());
|
||||
}
|
||||
|
||||
b.append(myLowerBound.getValueAsString());
|
||||
}
|
||||
if (haveUpperBound()) {
|
||||
if(haveLowerBound()) {
|
||||
b.append(" ");
|
||||
}
|
||||
if (myUpperBound.getComparator() != null) {
|
||||
b.append(myUpperBound.getComparator().getCode());
|
||||
}
|
||||
b.append(myUpperBound.getValueAsString());
|
||||
} else {
|
||||
if (!haveLowerBound()) {
|
||||
b.append("empty");
|
||||
}
|
||||
}
|
||||
b.append("]");
|
||||
return b.toString();
|
||||
}
|
||||
|
||||
private void validateAndThrowDataFormatExceptionIfInvalid() {
|
||||
|
@ -354,40 +394,4 @@ public class DateRangeParam implements IQueryParameterAnd<DateParam> {
|
|||
|
||||
}
|
||||
|
||||
private boolean haveUpperBound() {
|
||||
return myUpperBound != null && myUpperBound.isEmpty() == false;
|
||||
}
|
||||
|
||||
private boolean haveLowerBound() {
|
||||
return myLowerBound != null && myLowerBound.isEmpty() == false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder b = new StringBuilder();
|
||||
b.append(getClass().getSimpleName());
|
||||
b.append("[");
|
||||
if (haveLowerBound()) {
|
||||
if (myLowerBound.getComparator() != null) {
|
||||
b.append(myLowerBound.getComparator().getCode());
|
||||
}
|
||||
b.append(myLowerBound.getValueAsString());
|
||||
}
|
||||
if (haveUpperBound()) {
|
||||
if(haveLowerBound()) {
|
||||
b.append(" ");
|
||||
}
|
||||
if (myUpperBound.getComparator() != null) {
|
||||
b.append(myUpperBound.getComparator().getCode());
|
||||
}
|
||||
b.append(myUpperBound.getValueAsString());
|
||||
} else {
|
||||
if (!haveLowerBound()) {
|
||||
b.append("empty");
|
||||
}
|
||||
}
|
||||
b.append("]");
|
||||
return b.toString();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -772,7 +772,7 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
|
|||
}
|
||||
|
||||
IFhirResourceDao<R> dao = getDao(theResourceType);
|
||||
Set<Long> ids = dao.searchForIdsWithAndOr(paramMap, new HashSet<Long>());
|
||||
Set<Long> ids = dao.searchForIdsWithAndOr(paramMap, new HashSet<Long>(), paramMap.getLastUpdated());
|
||||
|
||||
return ids;
|
||||
}
|
||||
|
|
|
@ -228,7 +228,7 @@ public abstract class BaseHapiFhirResourceDao<T extends IResource> extends BaseH
|
|||
codePredicates.add(p);
|
||||
}
|
||||
|
||||
Predicate masterCodePredicate = builder.or(codePredicates.toArray(new Predicate[0]));
|
||||
Predicate masterCodePredicate = builder.or(toArray(codePredicates));
|
||||
|
||||
Predicate type = builder.equal(from.get("myResourceType"), myResourceName);
|
||||
Predicate name = builder.equal(from.get("myParamName"), theParamName);
|
||||
|
@ -243,7 +243,7 @@ public abstract class BaseHapiFhirResourceDao<T extends IResource> extends BaseH
|
|||
return new HashSet<Long>(q.getResultList());
|
||||
}
|
||||
|
||||
private Set<Long> addPredicateId(Set<Long> theExistingPids, Set<Long> thePids) {
|
||||
private Set<Long> addPredicateId(Set<Long> theExistingPids, Set<Long> thePids, DateRangeParam theLastUpdated) {
|
||||
if (thePids == null || thePids.isEmpty()) {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
|
@ -253,10 +253,12 @@ public abstract class BaseHapiFhirResourceDao<T extends IResource> extends BaseH
|
|||
Root<ResourceTable> from = cq.from(ResourceTable.class);
|
||||
cq.select(from.get("myId").as(Long.class));
|
||||
|
||||
Predicate typePredicate = builder.equal(from.get("myResourceType"), myResourceName);
|
||||
Predicate idPrecidate = from.get("myId").in(thePids);
|
||||
|
||||
cq.where(builder.and(typePredicate, idPrecidate));
|
||||
List<Predicate> predicates = new ArrayList<Predicate>();
|
||||
predicates.add(builder.equal(from.get("myResourceType"), myResourceName));
|
||||
predicates.add(from.get("myId").in(thePids));
|
||||
predicates.addAll(createLastUpdatedPredicates(theLastUpdated, builder, from));
|
||||
|
||||
cq.where(toArray(predicates));
|
||||
|
||||
TypedQuery<Long> q = myEntityManager.createQuery(cq);
|
||||
HashSet<Long> found = new HashSet<Long>(q.getResultList());
|
||||
|
@ -272,7 +274,7 @@ public abstract class BaseHapiFhirResourceDao<T extends IResource> extends BaseH
|
|||
// IQueryParameterType> theList) {
|
||||
// }
|
||||
|
||||
private Set<Long> addPredicateLanguage(Set<Long> thePids, List<List<? extends IQueryParameterType>> theList) {
|
||||
private Set<Long> addPredicateLanguage(Set<Long> thePids, List<List<? extends IQueryParameterType>> theList, DateRangeParam theLastUpdated) {
|
||||
Set<Long> retVal = thePids;
|
||||
if (theList == null || theList.isEmpty()) {
|
||||
return retVal;
|
||||
|
@ -301,17 +303,18 @@ public abstract class BaseHapiFhirResourceDao<T extends IResource> extends BaseH
|
|||
return retVal;
|
||||
}
|
||||
|
||||
Predicate typePredicate = builder.equal(from.get("myResourceType"), myResourceName);
|
||||
Predicate langPredicate = from.get("myLanguage").as(String.class).in(values);
|
||||
Predicate masterCodePredicate = builder.and(typePredicate, langPredicate);
|
||||
Predicate notDeletedPredicate = builder.isNull(from.get("myDeleted"));
|
||||
List<Predicate> predicates = new ArrayList<Predicate>();
|
||||
predicates.add(builder.equal(from.get("myResourceType"), myResourceName));
|
||||
predicates.add(from.get("myLanguage").as(String.class).in(values));
|
||||
|
||||
if (retVal.size() > 0) {
|
||||
Predicate inPids = (from.get("myId").in(retVal));
|
||||
cq.where(builder.and(masterCodePredicate, inPids, notDeletedPredicate));
|
||||
} else {
|
||||
cq.where(builder.and(masterCodePredicate, notDeletedPredicate));
|
||||
}
|
||||
predicates.add(inPids);
|
||||
}
|
||||
|
||||
predicates.add(builder.isNull(from.get("myDeleted")));
|
||||
|
||||
cq.where(toArray(predicates));
|
||||
|
||||
TypedQuery<Long> q = myEntityManager.createQuery(cq);
|
||||
retVal = new HashSet<Long>(q.getResultList());
|
||||
|
@ -413,7 +416,7 @@ public abstract class BaseHapiFhirResourceDao<T extends IResource> extends BaseH
|
|||
|
||||
}
|
||||
|
||||
Predicate masterCodePredicate = builder.or(codePredicates.toArray(new Predicate[0]));
|
||||
Predicate masterCodePredicate = builder.or(toArray(codePredicates));
|
||||
|
||||
Predicate type = builder.equal(from.get("myResourceType"), myResourceName);
|
||||
Predicate name = builder.equal(from.get("myParamName"), theParamName);
|
||||
|
@ -592,7 +595,7 @@ public abstract class BaseHapiFhirResourceDao<T extends IResource> extends BaseH
|
|||
}
|
||||
}
|
||||
|
||||
Predicate masterCodePredicate = builder.or(codePredicates.toArray(new Predicate[0]));
|
||||
Predicate masterCodePredicate = builder.or(toArray(codePredicates));
|
||||
|
||||
Predicate type = builder.equal(from.get("myResourceType"), myResourceName);
|
||||
Predicate name = builder.equal(from.get("myParamName"), theParamName);
|
||||
|
@ -746,7 +749,7 @@ public abstract class BaseHapiFhirResourceDao<T extends IResource> extends BaseH
|
|||
|
||||
}
|
||||
|
||||
Predicate masterCodePredicate = builder.or(codePredicates.toArray(new Predicate[0]));
|
||||
Predicate masterCodePredicate = builder.or(toArray(codePredicates));
|
||||
|
||||
Predicate type = createResourceLinkPathPredicate(theParamName, builder, from);
|
||||
if (pidsToRetain.size() > 0) {
|
||||
|
@ -785,7 +788,7 @@ public abstract class BaseHapiFhirResourceDao<T extends IResource> extends BaseH
|
|||
codePredicates.add(singleCode);
|
||||
}
|
||||
|
||||
Predicate masterCodePredicate = builder.or(codePredicates.toArray(new Predicate[0]));
|
||||
Predicate masterCodePredicate = builder.or(toArray(codePredicates));
|
||||
|
||||
Predicate type = builder.equal(from.get("myResourceType"), myResourceName);
|
||||
Predicate name = builder.equal(from.get("myParamName"), theParamName);
|
||||
|
@ -800,7 +803,7 @@ public abstract class BaseHapiFhirResourceDao<T extends IResource> extends BaseH
|
|||
return new HashSet<Long>(q.getResultList());
|
||||
}
|
||||
|
||||
private Set<Long> addPredicateTag(Set<Long> thePids, List<List<? extends IQueryParameterType>> theList, String theParamName) {
|
||||
private Set<Long> addPredicateTag(Set<Long> thePids, List<List<? extends IQueryParameterType>> theList, String theParamName, DateRangeParam theLastUpdated) {
|
||||
Set<Long> pids = thePids;
|
||||
if (theList == null || theList.isEmpty()) {
|
||||
return pids;
|
||||
|
@ -874,14 +877,17 @@ public abstract class BaseHapiFhirResourceDao<T extends IResource> extends BaseH
|
|||
|
||||
}
|
||||
if (orPredicates.isEmpty() == false) {
|
||||
andPredicates.add(builder.or(orPredicates.toArray(new Predicate[0])));
|
||||
andPredicates.add(builder.or(toArray(orPredicates)));
|
||||
}
|
||||
|
||||
From<ResourceTag, ResourceTable> defJoin = from.join("myResource");
|
||||
Predicate notDeletedPredicatePrediate = builder.isNull(defJoin.get("myDeleted"));
|
||||
andPredicates.add(notDeletedPredicatePrediate);
|
||||
|
||||
Predicate masterCodePredicate = builder.and(andPredicates.toArray(new Predicate[0]));
|
||||
if (theLastUpdated != null) {
|
||||
andPredicates.addAll(createLastUpdatedPredicates(theLastUpdated, builder, defJoin));
|
||||
}
|
||||
|
||||
Predicate masterCodePredicate = builder.and(toArray(andPredicates));
|
||||
|
||||
if (pids.size() > 0) {
|
||||
Predicate inPids = (from.get("myResourceId").in(pids));
|
||||
|
@ -928,7 +934,7 @@ public abstract class BaseHapiFhirResourceDao<T extends IResource> extends BaseH
|
|||
codePredicates.add(singleCode);
|
||||
}
|
||||
|
||||
Predicate masterCodePredicate = builder.or(codePredicates.toArray(new Predicate[0]));
|
||||
Predicate masterCodePredicate = builder.or(toArray(codePredicates));
|
||||
|
||||
Predicate type = builder.equal(from.get("myResourceType"), myResourceName);
|
||||
Predicate name = builder.equal(from.get("myParamName"), theParamName);
|
||||
|
@ -943,6 +949,10 @@ public abstract class BaseHapiFhirResourceDao<T extends IResource> extends BaseH
|
|||
return new HashSet<Long>(q.getResultList());
|
||||
}
|
||||
|
||||
private static Predicate[] toArray(List<Predicate> thePredicates) {
|
||||
return thePredicates.toArray(new Predicate[thePredicates.size()]);
|
||||
}
|
||||
|
||||
private Set<Long> addPredicateUri(String theParamName, Set<Long> thePids, List<? extends IQueryParameterType> theList) {
|
||||
if (theList == null || theList.isEmpty()) {
|
||||
return thePids;
|
||||
|
@ -981,7 +991,7 @@ public abstract class BaseHapiFhirResourceDao<T extends IResource> extends BaseH
|
|||
|
||||
}
|
||||
|
||||
Predicate masterCodePredicate = builder.or(codePredicates.toArray(new Predicate[0]));
|
||||
Predicate masterCodePredicate = builder.or(toArray(codePredicates));
|
||||
|
||||
Predicate type = builder.equal(from.get("myResourceType"), myResourceName);
|
||||
Predicate name = builder.equal(from.get("myParamName"), theParamName);
|
||||
|
@ -1227,7 +1237,7 @@ public abstract class BaseHapiFhirResourceDao<T extends IResource> extends BaseH
|
|||
} else {
|
||||
singleCodePredicates.add(theBuilder.isNull(theFrom.get("myValue")));
|
||||
}
|
||||
Predicate singleCode = theBuilder.and(singleCodePredicates.toArray(new Predicate[0]));
|
||||
Predicate singleCode = theBuilder.and(toArray(singleCodePredicates));
|
||||
return singleCode;
|
||||
}
|
||||
|
||||
|
@ -1662,87 +1672,87 @@ public abstract class BaseHapiFhirResourceDao<T extends IResource> extends BaseH
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBundleProvider everything(IIdType theId) {
|
||||
Search search = new Search();
|
||||
search.setUuid(UUID.randomUUID().toString());
|
||||
search.setCreated(new Date());
|
||||
myEntityManager.persist(search);
|
||||
|
||||
List<SearchResult> results = new ArrayList<SearchResult>();
|
||||
if (theId != null) {
|
||||
Long pid = translateForcedIdToPid(theId);
|
||||
ResourceTable entity = myEntityManager.find(ResourceTable.class, pid);
|
||||
validateGivenIdIsAppropriateToRetrieveResource(theId, entity);
|
||||
SearchResult res = new SearchResult(search);
|
||||
res.setResourcePid(pid);
|
||||
results.add(res);
|
||||
} else {
|
||||
TypedQuery<Tuple> query = createSearchAllByTypeQuery();
|
||||
for (Tuple next : query.getResultList()) {
|
||||
SearchResult res = new SearchResult(search);
|
||||
res.setResourcePid(next.get(0, Long.class));
|
||||
results.add(res);
|
||||
}
|
||||
}
|
||||
|
||||
int totalCount = results.size();
|
||||
mySearchResultDao.save(results);
|
||||
mySearchResultDao.flush();
|
||||
|
||||
CriteriaBuilder builder = myEntityManager.getCriteriaBuilder();
|
||||
|
||||
// Load _revincludes
|
||||
CriteriaQuery<Long> cq = builder.createQuery(Long.class);
|
||||
Root<ResourceLink> from = cq.from(ResourceLink.class);
|
||||
cq.select(from.get("mySourceResourcePid").as(Long.class));
|
||||
|
||||
Subquery<Long> pidsSubquery = cq.subquery(Long.class);
|
||||
Root<SearchResult> pidsSubqueryFrom = pidsSubquery.from(SearchResult.class);
|
||||
pidsSubquery.select(pidsSubqueryFrom.get("myResourcePid").as(Long.class));
|
||||
pidsSubquery.where(pidsSubqueryFrom.get("mySearch").in(search));
|
||||
|
||||
cq.where(from.get("myTargetResourceId").in(pidsSubquery));
|
||||
TypedQuery<Long> query = myEntityManager.createQuery(cq);
|
||||
|
||||
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;
|
||||
}
|
||||
};
|
||||
}
|
||||
// @Override
|
||||
// public IBundleProvider everything(IIdType theId) {
|
||||
// Search search = new Search();
|
||||
// search.setUuid(UUID.randomUUID().toString());
|
||||
// search.setCreated(new Date());
|
||||
// myEntityManager.persist(search);
|
||||
//
|
||||
// List<SearchResult> results = new ArrayList<SearchResult>();
|
||||
// if (theId != null) {
|
||||
// Long pid = translateForcedIdToPid(theId);
|
||||
// ResourceTable entity = myEntityManager.find(ResourceTable.class, pid);
|
||||
// validateGivenIdIsAppropriateToRetrieveResource(theId, entity);
|
||||
// SearchResult res = new SearchResult(search);
|
||||
// res.setResourcePid(pid);
|
||||
// results.add(res);
|
||||
// } else {
|
||||
// TypedQuery<Tuple> query = createSearchAllByTypeQuery();
|
||||
// for (Tuple next : query.getResultList()) {
|
||||
// SearchResult res = new SearchResult(search);
|
||||
// res.setResourcePid(next.get(0, Long.class));
|
||||
// results.add(res);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// int totalCount = results.size();
|
||||
// mySearchResultDao.save(results);
|
||||
// mySearchResultDao.flush();
|
||||
//
|
||||
// CriteriaBuilder builder = myEntityManager.getCriteriaBuilder();
|
||||
//
|
||||
// // Load _revincludes
|
||||
// CriteriaQuery<Long> cq = builder.createQuery(Long.class);
|
||||
// Root<ResourceLink> from = cq.from(ResourceLink.class);
|
||||
// cq.select(from.get("mySourceResourcePid").as(Long.class));
|
||||
//
|
||||
// Subquery<Long> pidsSubquery = cq.subquery(Long.class);
|
||||
// Root<SearchResult> pidsSubqueryFrom = pidsSubquery.from(SearchResult.class);
|
||||
// pidsSubquery.select(pidsSubqueryFrom.get("myResourcePid").as(Long.class));
|
||||
// pidsSubquery.where(pidsSubqueryFrom.get("mySearch").in(search));
|
||||
//
|
||||
// cq.where(from.get("myTargetResourceId").in(pidsSubquery));
|
||||
// TypedQuery<Long> query = myEntityManager.createQuery(cq);
|
||||
//
|
||||
// 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())
|
||||
|
@ -2150,6 +2160,11 @@ public abstract class BaseHapiFhirResourceDao<T extends IResource> extends BaseH
|
|||
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) {
|
||||
|
||||
|
@ -2163,7 +2178,7 @@ public abstract class BaseHapiFhirResourceDao<T extends IResource> extends BaseH
|
|||
}
|
||||
predicates.add(builder.equal(from.get("myResourceType"), myResourceName));
|
||||
predicates.add(builder.isNull(from.get("myDeleted")));
|
||||
cq.where(builder.and(predicates.toArray(new Predicate[predicates.size()])));
|
||||
cq.where(builder.and(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));
|
||||
|
@ -2181,7 +2196,8 @@ public abstract class BaseHapiFhirResourceDao<T extends IResource> extends BaseH
|
|||
} else if (theParams.isEmpty()) {
|
||||
|
||||
loadPids = new HashSet<Long>();
|
||||
TypedQuery<Tuple> query = createSearchAllByTypeQuery();
|
||||
TypedQuery<Tuple> query = createSearchAllByTypeQuery(lu);
|
||||
lu = null;
|
||||
for (Tuple next : query.getResultList()) {
|
||||
loadPids.add(next.get(0, Long.class));
|
||||
}
|
||||
|
@ -2205,7 +2221,7 @@ public abstract class BaseHapiFhirResourceDao<T extends IResource> extends BaseH
|
|||
if (theParams.isEmpty()) {
|
||||
loadPids = searchResultPids;
|
||||
} else {
|
||||
loadPids = searchForIdsWithAndOr(theParams, searchResultPids);
|
||||
loadPids = searchForIdsWithAndOr(theParams, searchResultPids, lu);
|
||||
}
|
||||
if (loadPids.isEmpty()) {
|
||||
return new SimpleBundleProvider();
|
||||
|
@ -2222,9 +2238,7 @@ public abstract class BaseHapiFhirResourceDao<T extends IResource> extends BaseH
|
|||
// }
|
||||
|
||||
// Handle _lastUpdated
|
||||
final DateRangeParam lu = theParams.getLastUpdated();
|
||||
if (lu != null && (lu.getLowerBoundAsInstant() != null || lu.getUpperBoundAsInstant() != null)) {
|
||||
|
||||
if (lu != null) {
|
||||
List<Long> resultList = filterResourceIdsByLastUpdated(loadPids, lu);
|
||||
loadPids.clear();
|
||||
for (Long next : resultList) {
|
||||
|
@ -2271,7 +2285,7 @@ public abstract class BaseHapiFhirResourceDao<T extends IResource> extends BaseH
|
|||
|
||||
// Load includes
|
||||
pidsSubList = new ArrayList<Long>(pidsSubList);
|
||||
revIncludedPids.addAll(loadReverseIncludes(pidsSubList, theParams.getIncludes(), false, null, lu));
|
||||
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>();
|
||||
|
@ -2305,29 +2319,44 @@ public abstract class BaseHapiFhirResourceDao<T extends IResource> extends BaseH
|
|||
Root<ResourceTable> from = cq.from(ResourceTable.class);
|
||||
cq.select(from.get("myId").as(Long.class));
|
||||
|
||||
Predicate predicateIds = (from.get("myId").in(thePids));
|
||||
Predicate predicateLower = theLastUpdated.getLowerBoundAsInstant() != null ? builder.greaterThanOrEqualTo(from.<Date> get("myUpdated"), theLastUpdated.getLowerBoundAsInstant()) : null;
|
||||
Predicate predicateUpper = theLastUpdated.getUpperBoundAsInstant() != null ? builder.lessThanOrEqualTo(from.<Date> get("myUpdated"), theLastUpdated.getUpperBoundAsInstant()) : null;
|
||||
if (predicateLower != null && predicateUpper != null) {
|
||||
cq.where(predicateIds, predicateLower, predicateUpper);
|
||||
} else if (predicateLower != null) {
|
||||
cq.where(predicateIds, predicateLower);
|
||||
} else {
|
||||
cq.where(predicateIds, predicateUpper);
|
||||
}
|
||||
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 TypedQuery<Tuple> createSearchAllByTypeQuery() {
|
||||
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 TypedQuery<Tuple> createSearchAllByTypeQuery(DateRangeParam theLastUpdated) {
|
||||
CriteriaBuilder builder = myEntityManager.getCriteriaBuilder();
|
||||
CriteriaQuery<Tuple> cq = builder.createTupleQuery();
|
||||
Root<ResourceTable> from = cq.from(ResourceTable.class);
|
||||
cq.multiselect(from.get("myId").as(Long.class));
|
||||
Predicate typeEquals = builder.equal(from.get("myResourceType"), myResourceName);
|
||||
Predicate notDeleted = builder.isNull(from.get("myDeleted"));
|
||||
cq.where(builder.and(typeEquals, notDeleted));
|
||||
List<Predicate> predicates = new ArrayList<Predicate>();
|
||||
predicates.add(builder.equal(from.get("myResourceType"), myResourceName));
|
||||
predicates.add(builder.isNull(from.get("myDeleted")));
|
||||
|
||||
if (theLastUpdated != null) {
|
||||
predicates.addAll(createLastUpdatedPredicates(theLastUpdated, builder, from));
|
||||
}
|
||||
|
||||
cq.where(toArray(predicates));
|
||||
|
||||
TypedQuery<Tuple> query = myEntityManager.createQuery(cq);
|
||||
return query;
|
||||
|
@ -2348,7 +2377,7 @@ public abstract class BaseHapiFhirResourceDao<T extends IResource> extends BaseH
|
|||
Collection<Long> originalPids = theLoadPids;
|
||||
LinkedHashSet<Long> loadPids = new LinkedHashSet<Long>();
|
||||
cq.multiselect(from.get("myId").as(Long.class));
|
||||
cq.where(predicates.toArray(new Predicate[0]));
|
||||
cq.where(toArray(predicates));
|
||||
cq.orderBy(orders);
|
||||
|
||||
TypedQuery<Tuple> query = myEntityManager.createQuery(cq);
|
||||
|
@ -2398,7 +2427,7 @@ public abstract class BaseHapiFhirResourceDao<T extends IResource> extends BaseH
|
|||
for (Entry<String, IQueryParameterType> nextEntry : theParams.entrySet()) {
|
||||
map.add(nextEntry.getKey(), (nextEntry.getValue()));
|
||||
}
|
||||
return searchForIdsWithAndOr(map, null);
|
||||
return searchForIdsWithAndOr(map, null, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -2407,7 +2436,7 @@ public abstract class BaseHapiFhirResourceDao<T extends IResource> extends BaseH
|
|||
}
|
||||
|
||||
@Override
|
||||
public Set<Long> searchForIdsWithAndOr(SearchParameterMap theParams, Collection<Long> theInitialPids) {
|
||||
public Set<Long> searchForIdsWithAndOr(SearchParameterMap theParams, Collection<Long> theInitialPids, DateRangeParam theLastUpdated) {
|
||||
SearchParameterMap params = theParams;
|
||||
if (params == null) {
|
||||
params = new SearchParameterMap();
|
||||
|
@ -2451,7 +2480,7 @@ public abstract class BaseHapiFhirResourceDao<T extends IResource> extends BaseH
|
|||
}
|
||||
}
|
||||
|
||||
pids = addPredicateId(pids, joinPids);
|
||||
pids = addPredicateId(pids, joinPids, theLastUpdated);
|
||||
if (pids.isEmpty()) {
|
||||
return new HashSet<Long>();
|
||||
}
|
||||
|
@ -2466,11 +2495,11 @@ public abstract class BaseHapiFhirResourceDao<T extends IResource> extends BaseH
|
|||
|
||||
} else if (nextParamName.equals(BaseResource.SP_RES_LANGUAGE)) {
|
||||
|
||||
pids = addPredicateLanguage(pids, nextParamEntry.getValue());
|
||||
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);
|
||||
pids = addPredicateTag(pids, nextParamEntry.getValue(), nextParamName, theLastUpdated);
|
||||
|
||||
} else {
|
||||
|
||||
|
|
|
@ -28,7 +28,6 @@ import java.util.Date;
|
|||
import java.util.List;
|
||||
|
||||
import javax.persistence.Query;
|
||||
import javax.persistence.TypedQuery;
|
||||
|
||||
import org.apache.commons.lang3.time.DateUtils;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
|
@ -77,6 +76,9 @@ public class FhirResourceDaoSubscriptionDstu2 extends FhirResourceDaoDstu2<Subsc
|
|||
@Autowired
|
||||
private ISubscriptionTableDao mySubscriptionTableDao;
|
||||
|
||||
@Autowired
|
||||
private PlatformTransactionManager myTxManager;
|
||||
|
||||
private void createSubscriptionTable(ResourceTable theEntity, Subscription theSubscription) {
|
||||
SubscriptionTable subscriptionEntity = new SubscriptionTable();
|
||||
subscriptionEntity.setCreated(new Date());
|
||||
|
@ -87,15 +89,32 @@ public class FhirResourceDaoSubscriptionDstu2 extends FhirResourceDaoDstu2<Subsc
|
|||
myEntityManager.persist(subscriptionEntity);
|
||||
}
|
||||
|
||||
@Autowired
|
||||
private PlatformTransactionManager myTxManager;
|
||||
|
||||
@Scheduled(fixedDelay = 10 * DateUtils.MILLIS_PER_SECOND)
|
||||
@Transactional(propagation = Propagation.NOT_SUPPORTED)
|
||||
public synchronized void pollForNewUndeliveredResourcesScheduler() {
|
||||
pollForNewUndeliveredResources();
|
||||
@Override
|
||||
public Long getSubscriptionTablePidForSubscriptionResource(IIdType theId) {
|
||||
ResourceTable entity = readEntityLatestVersion(theId);
|
||||
SubscriptionTable table = mySubscriptionTableDao.findOneByResourcePid(entity.getId());
|
||||
if (table == null) {
|
||||
return null;
|
||||
}
|
||||
return table.getId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized List<IBaseResource> getUndeliveredResourcesAndPurge(Long theSubscriptionPid) {
|
||||
List<IBaseResource> retVal = new ArrayList<IBaseResource>();
|
||||
Page<SubscriptionFlaggedResource> flaggedResources = mySubscriptionFlaggedResourceDataDao.findAllBySubscriptionId(theSubscriptionPid, new PageRequest(0, 100));
|
||||
for (SubscriptionFlaggedResource nextFlaggedResource : flaggedResources) {
|
||||
retVal.add(toResource(nextFlaggedResource.getResource(), false));
|
||||
}
|
||||
|
||||
mySubscriptionFlaggedResourceDataDao.delete(flaggedResources);
|
||||
mySubscriptionFlaggedResourceDataDao.flush();
|
||||
|
||||
mySubscriptionTableDao.updateLastClientPoll(new Date());
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(propagation = Propagation.NOT_SUPPORTED)
|
||||
public synchronized int pollForNewUndeliveredResources() {
|
||||
|
@ -189,6 +208,12 @@ public class FhirResourceDaoSubscriptionDstu2 extends FhirResourceDaoDstu2<Subsc
|
|||
return results.size();
|
||||
}
|
||||
|
||||
@Scheduled(fixedDelay = 10 * DateUtils.MILLIS_PER_SECOND)
|
||||
@Transactional(propagation = Propagation.NOT_SUPPORTED)
|
||||
public synchronized void pollForNewUndeliveredResourcesScheduler() {
|
||||
pollForNewUndeliveredResources();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void postPersist(ResourceTable theEntity, Subscription theSubscription) {
|
||||
super.postPersist(theEntity, theSubscription);
|
||||
|
@ -196,105 +221,6 @@ public class FhirResourceDaoSubscriptionDstu2 extends FhirResourceDaoDstu2<Subsc
|
|||
createSubscriptionTable(theEntity, theSubscription);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ResourceTable updateEntity(IResource theResource, ResourceTable theEntity, boolean theUpdateHistory, Date theDeletedTimestampOrNull, boolean thePerformIndexing, boolean theUpdateVersion,
|
||||
Date theUpdateTime) {
|
||||
ResourceTable retVal = super.updateEntity(theResource, theEntity, theUpdateHistory, theDeletedTimestampOrNull, thePerformIndexing, theUpdateVersion, theUpdateTime);
|
||||
|
||||
Subscription resource = (Subscription) theResource;
|
||||
Long resourceId = theEntity.getId();
|
||||
if (theDeletedTimestampOrNull != null) {
|
||||
Long subscriptionId = getSubscriptionTablePidForSubscriptionResource(theEntity.getIdDt());
|
||||
if (subscriptionId != null) {
|
||||
mySubscriptionFlaggedResourceDataDao.deleteAllForSubscription(subscriptionId);
|
||||
mySubscriptionTableDao.deleteAllForSubscription(subscriptionId);
|
||||
}
|
||||
} else {
|
||||
Query q = myEntityManager.createNamedQuery("Q_HFJ_SUBSCRIPTION_SET_STATUS");
|
||||
q.setParameter("res_id", resourceId);
|
||||
q.setParameter("status", resource.getStatusElement().getValueAsEnum());
|
||||
if (q.executeUpdate() > 0) {
|
||||
ourLog.info("Updated subscription status for subscription {} to {}", resourceId, resource.getStatusElement().getValueAsEnum());
|
||||
} else {
|
||||
createSubscriptionTable(retVal, resource);
|
||||
}
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void validateResourceForStorage(Subscription theResource, ResourceTable theEntityToSave) {
|
||||
super.validateResourceForStorage(theResource, theEntityToSave);
|
||||
|
||||
RuntimeResourceDefinition resDef = validateCriteriaAndReturnResourceDefinition(theResource);
|
||||
|
||||
IFhirResourceDao<? extends IBaseResource> dao = getDao(resDef.getImplementingClass());
|
||||
if (dao == null) {
|
||||
throw new UnprocessableEntityException("Subscription.criteria contains invalid/unsupported resource type: " + resDef);
|
||||
}
|
||||
|
||||
if (theResource.getChannel().getType() == null) {
|
||||
throw new UnprocessableEntityException("Subscription.channel.type must be populated on this server");
|
||||
}
|
||||
|
||||
SubscriptionStatusEnum status = theResource.getStatusElement().getValueAsEnum();
|
||||
if (status == null) {
|
||||
throw new UnprocessableEntityException("Subscription.status must be populated on this server");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private RuntimeResourceDefinition validateCriteriaAndReturnResourceDefinition(Subscription theResource) {
|
||||
String query = theResource.getCriteria();
|
||||
if (isBlank(query)) {
|
||||
throw new UnprocessableEntityException("Subscription.criteria must be populated");
|
||||
}
|
||||
|
||||
int sep = query.indexOf('?');
|
||||
if (sep <= 1) {
|
||||
throw new UnprocessableEntityException("Subscription.criteria must be in the form \"{Resource Type}?[params]\"");
|
||||
}
|
||||
|
||||
String resType = query.substring(0, sep);
|
||||
if (resType.contains("/")) {
|
||||
throw new UnprocessableEntityException("Subscription.criteria must be in the form \"{Resource Type}?[params]\"");
|
||||
}
|
||||
|
||||
RuntimeResourceDefinition resDef;
|
||||
try {
|
||||
resDef = getContext().getResourceDefinition(resType);
|
||||
} catch (DataFormatException e) {
|
||||
throw new UnprocessableEntityException("Subscription.criteria contains invalid/unsupported resource type: " + resType);
|
||||
}
|
||||
return resDef;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized List<IBaseResource> getUndeliveredResourcesAndPurge(Long theSubscriptionPid) {
|
||||
List<IBaseResource> retVal = new ArrayList<IBaseResource>();
|
||||
Page<SubscriptionFlaggedResource> flaggedResources = mySubscriptionFlaggedResourceDataDao.findAllBySubscriptionId(theSubscriptionPid, new PageRequest(0, 100));
|
||||
for (SubscriptionFlaggedResource nextFlaggedResource : flaggedResources) {
|
||||
retVal.add(toResource(nextFlaggedResource.getResource(), false));
|
||||
}
|
||||
|
||||
mySubscriptionFlaggedResourceDataDao.delete(flaggedResources);
|
||||
mySubscriptionFlaggedResourceDataDao.flush();
|
||||
|
||||
mySubscriptionTableDao.updateLastClientPoll(new Date());
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long getSubscriptionTablePidForSubscriptionResource(IIdType theId) {
|
||||
ResourceTable entity = readEntityLatestVersion(theId);
|
||||
SubscriptionTable table = mySubscriptionTableDao.findOneByResourcePid(entity.getId());
|
||||
if (table == null) {
|
||||
return null;
|
||||
}
|
||||
return table.getId();
|
||||
}
|
||||
|
||||
@Scheduled(fixedDelay = DateUtils.MILLIS_PER_MINUTE)
|
||||
@Transactional(propagation = Propagation.NOT_SUPPORTED)
|
||||
@Override
|
||||
|
@ -323,4 +249,77 @@ public class FhirResourceDaoSubscriptionDstu2 extends FhirResourceDaoDstu2<Subsc
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ResourceTable updateEntity(IResource theResource, ResourceTable theEntity, boolean theUpdateHistory, Date theDeletedTimestampOrNull, boolean thePerformIndexing, boolean theUpdateVersion,
|
||||
Date theUpdateTime) {
|
||||
ResourceTable retVal = super.updateEntity(theResource, theEntity, theUpdateHistory, theDeletedTimestampOrNull, thePerformIndexing, theUpdateVersion, theUpdateTime);
|
||||
|
||||
Subscription resource = (Subscription) theResource;
|
||||
Long resourceId = theEntity.getId();
|
||||
if (theDeletedTimestampOrNull != null) {
|
||||
Long subscriptionId = getSubscriptionTablePidForSubscriptionResource(theEntity.getIdDt());
|
||||
if (subscriptionId != null) {
|
||||
mySubscriptionFlaggedResourceDataDao.deleteAllForSubscription(subscriptionId);
|
||||
mySubscriptionTableDao.deleteAllForSubscription(subscriptionId);
|
||||
}
|
||||
} else {
|
||||
Query q = myEntityManager.createNamedQuery("Q_HFJ_SUBSCRIPTION_SET_STATUS");
|
||||
q.setParameter("res_id", resourceId);
|
||||
q.setParameter("status", resource.getStatusElement().getValueAsEnum());
|
||||
if (q.executeUpdate() > 0) {
|
||||
ourLog.info("Updated subscription status for subscription {} to {}", resourceId, resource.getStatusElement().getValueAsEnum());
|
||||
} else {
|
||||
createSubscriptionTable(retVal, resource);
|
||||
}
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
||||
private RuntimeResourceDefinition validateCriteriaAndReturnResourceDefinition(Subscription theResource) {
|
||||
String query = theResource.getCriteria();
|
||||
if (isBlank(query)) {
|
||||
throw new UnprocessableEntityException("Subscription.criteria must be populated");
|
||||
}
|
||||
|
||||
int sep = query.indexOf('?');
|
||||
if (sep <= 1) {
|
||||
throw new UnprocessableEntityException("Subscription.criteria must be in the form \"{Resource Type}?[params]\"");
|
||||
}
|
||||
|
||||
String resType = query.substring(0, sep);
|
||||
if (resType.contains("/")) {
|
||||
throw new UnprocessableEntityException("Subscription.criteria must be in the form \"{Resource Type}?[params]\"");
|
||||
}
|
||||
|
||||
RuntimeResourceDefinition resDef;
|
||||
try {
|
||||
resDef = getContext().getResourceDefinition(resType);
|
||||
} catch (DataFormatException e) {
|
||||
throw new UnprocessableEntityException("Subscription.criteria contains invalid/unsupported resource type: " + resType);
|
||||
}
|
||||
return resDef;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void validateResourceForStorage(Subscription theResource, ResourceTable theEntityToSave) {
|
||||
super.validateResourceForStorage(theResource, theEntityToSave);
|
||||
|
||||
RuntimeResourceDefinition resDef = validateCriteriaAndReturnResourceDefinition(theResource);
|
||||
|
||||
IFhirResourceDao<? extends IBaseResource> dao = getDao(resDef.getImplementingClass());
|
||||
if (dao == null) {
|
||||
throw new UnprocessableEntityException("Subscription.criteria contains invalid/unsupported resource type: " + resDef);
|
||||
}
|
||||
|
||||
if (theResource.getChannel().getType() == null) {
|
||||
throw new UnprocessableEntityException("Subscription.channel.type must be populated on this server");
|
||||
}
|
||||
|
||||
SubscriptionStatusEnum status = theResource.getStatusElement().getValueAsEnum();
|
||||
if (status == null) {
|
||||
throw new UnprocessableEntityException("Subscription.status must be populated on this server");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -36,6 +36,7 @@ import ca.uhn.fhir.model.api.TagList;
|
|||
import ca.uhn.fhir.model.dstu2.composite.MetaDt;
|
||||
import ca.uhn.fhir.rest.api.MethodOutcome;
|
||||
import ca.uhn.fhir.rest.api.ValidationModeEnum;
|
||||
import ca.uhn.fhir.rest.param.DateRangeParam;
|
||||
import ca.uhn.fhir.rest.server.EncodingEnum;
|
||||
import ca.uhn.fhir.rest.server.IBundleProvider;
|
||||
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
|
||||
|
@ -123,7 +124,7 @@ public interface IFhirResourceDao<T extends IBaseResource> extends IDao {
|
|||
|
||||
Set<Long> searchForIds(String theParameterName, IQueryParameterType theValue);
|
||||
|
||||
Set<Long> searchForIdsWithAndOr(SearchParameterMap theParams, Collection<Long> theInitialPids);
|
||||
Set<Long> searchForIdsWithAndOr(SearchParameterMap theParams, Collection<Long> theInitialPids, DateRangeParam theLastUpdated);
|
||||
|
||||
DaoMethodOutcome update(T theResource);
|
||||
|
||||
|
@ -146,9 +147,9 @@ public interface IFhirResourceDao<T extends IBaseResource> extends IDao {
|
|||
*/
|
||||
DaoMethodOutcome deleteByUrl(String theUrl, boolean theTransaction);
|
||||
|
||||
/**
|
||||
* Invoke the everything operation
|
||||
*/
|
||||
IBundleProvider everything(IIdType theId);
|
||||
// /**
|
||||
// * Invoke the everything operation
|
||||
// */
|
||||
// IBundleProvider everything(IIdType theId);
|
||||
|
||||
}
|
||||
|
|
|
@ -399,6 +399,7 @@ public class FhirResourceDaoDstu2SearchNoFtTest extends BaseJpaDstu2Test {
|
|||
patient.addIdentifier().setSystem("urn:system").setValue("001");
|
||||
id1 = myPatientDao.create(patient).getId().toUnqualifiedVersionless();
|
||||
}
|
||||
long betweenTime = System.currentTimeMillis();
|
||||
IIdType id2;
|
||||
{
|
||||
Patient patient = new Patient();
|
||||
|
@ -418,6 +419,13 @@ public class FhirResourceDaoDstu2SearchNoFtTest extends BaseJpaDstu2Test {
|
|||
params.add("_id", new StringOrListParam().addOr(new StringParam(id1.getIdPart())).addOr(new StringParam("999999999999")));
|
||||
assertThat(toUnqualifiedVersionlessIds(myPatientDao.search(params)), containsInAnyOrder(id1));
|
||||
|
||||
// With lastupdated
|
||||
|
||||
params = new SearchParameterMap();
|
||||
params.add("_id", new StringOrListParam().addOr(new StringParam(id1.getIdPart())).addOr(new StringParam(id2.getIdPart())));
|
||||
params.setLastUpdated(new DateRangeParam(new Date(betweenTime), null));
|
||||
assertThat(toUnqualifiedVersionlessIds(myPatientDao.search(params)), containsInAnyOrder(id2));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -610,6 +618,9 @@ public class FhirResourceDaoDstu2SearchNoFtTest extends BaseJpaDstu2Test {
|
|||
patient.addName().addFamily("testSearchLanguageParam").addGiven("Joe");
|
||||
id1 = myPatientDao.create(patient).getId().toUnqualifiedVersionless();
|
||||
}
|
||||
|
||||
Date betweenTime = new Date();
|
||||
|
||||
IIdType id2;
|
||||
{
|
||||
Patient patient = new Patient();
|
||||
|
@ -623,6 +634,12 @@ public class FhirResourceDaoDstu2SearchNoFtTest extends BaseJpaDstu2Test {
|
|||
params.add(BaseResource.SP_RES_LANGUAGE, new StringOrListParam().addOr(new StringParam("en_CA")).addOr(new StringParam("en_US")));
|
||||
assertThat(toUnqualifiedVersionlessIds(myPatientDao.search(params)), containsInAnyOrder(id1, id2));
|
||||
}
|
||||
{
|
||||
SearchParameterMap params = new SearchParameterMap();
|
||||
params.add(BaseResource.SP_RES_LANGUAGE, new StringOrListParam().addOr(new StringParam("en_CA")).addOr(new StringParam("en_US")));
|
||||
params.setLastUpdated(new DateRangeParam(betweenTime, null));
|
||||
assertThat(toUnqualifiedVersionlessIds(myPatientDao.search(params)), containsInAnyOrder(id2));
|
||||
}
|
||||
{
|
||||
SearchParameterMap params = new SearchParameterMap();
|
||||
params.add(BaseResource.SP_RES_LANGUAGE, new StringOrListParam().addOr(new StringParam("en_CA")).addOr(new StringParam("ZZZZ")));
|
||||
|
@ -1943,6 +1960,9 @@ public class FhirResourceDaoDstu2SearchNoFtTest extends BaseJpaDstu2Test {
|
|||
ResourceMetadataKeyEnum.TAG_LIST.put(org, tagList);
|
||||
tag1id = myOrganizationDao.create(org).getId().toUnqualifiedVersionless();
|
||||
}
|
||||
|
||||
Date betweenDate = new Date();
|
||||
|
||||
IIdType tag2id;
|
||||
{
|
||||
Organization org = new Organization();
|
||||
|
@ -1978,6 +1998,17 @@ public class FhirResourceDaoDstu2SearchNoFtTest extends BaseJpaDstu2Test {
|
|||
List<IIdType> patients = toUnqualifiedVersionlessIds(myOrganizationDao.search(params));
|
||||
assertThat(patients, containsInAnyOrder(tag1id, tag2id));
|
||||
}
|
||||
{
|
||||
// Or tags with lastupdated
|
||||
SearchParameterMap params = new SearchParameterMap();
|
||||
TokenOrListParam orListParam = new TokenOrListParam();
|
||||
orListParam.add(new TokenParam("urn:taglist", methodName + "1a"));
|
||||
orListParam.add(new TokenParam("urn:taglist", methodName + "2a"));
|
||||
params.add("_tag", orListParam);
|
||||
params.setLastUpdated(new DateRangeParam(betweenDate, null));
|
||||
List<IIdType> patients = toUnqualifiedVersionlessIds(myOrganizationDao.search(params));
|
||||
assertThat(patients, containsInAnyOrder(tag2id));
|
||||
}
|
||||
// TODO: get multiple/AND working
|
||||
{
|
||||
// And tags
|
||||
|
|
|
@ -162,6 +162,9 @@
|
|||
meaning that the same operation can also be invoked
|
||||
at the type level.
|
||||
</action>
|
||||
<action type="add">
|
||||
Make JPA search queries with _lastUpdated parameter a bit more efficient
|
||||
</action>
|
||||
</release>
|
||||
<release version="1.2" date="2015-09-18">
|
||||
<action type="add">
|
||||
|
|
Loading…
Reference in New Issue