diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/SearchBuilder.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/SearchBuilder.java index c41e24280d4..9ef4a963f48 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/SearchBuilder.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/SearchBuilder.java @@ -46,6 +46,7 @@ import org.springframework.transaction.PlatformTransactionManager; import org.springframework.transaction.TransactionStatus; import org.springframework.transaction.support.TransactionCallback; import org.springframework.transaction.support.TransactionTemplate; +import org.springframework.web.servlet.ThemeResolver; import com.google.common.collect.Lists; import com.google.common.collect.Sets; @@ -117,7 +118,7 @@ public class SearchBuilder { mySearchParamRegistry = theSearchParamRegistry; } - private void addPredicateComposite(RuntimeSearchParam theParamDef, List theNextAnd) { + private void addPredicateComposite(String theResourceName, RuntimeSearchParam theParamDef, List theNextAnd) { // TODO: fail if missing is set for a composite query IQueryParameterType or = theNextAnd.get(0); @@ -128,15 +129,15 @@ public class SearchBuilder { RuntimeSearchParam left = theParamDef.getCompositeOf().get(0); IQueryParameterType leftValue = cp.getLeftValue(); - myPredicates.add(createCompositeParamPart(myResourceTableRoot, left, leftValue)); + myPredicates.add(createCompositeParamPart(theResourceName, myResourceTableRoot, left, leftValue)); RuntimeSearchParam right = theParamDef.getCompositeOf().get(1); IQueryParameterType rightValue = cp.getRightValue(); - myPredicates.add(createCompositeParamPart(myResourceTableRoot, right, rightValue)); + myPredicates.add(createCompositeParamPart(theResourceName, myResourceTableRoot, right, rightValue)); } - private void addPredicateDate(String theParamName, List theList) { + private void addPredicateDate(String theResourceName, String theParamName, List theList) { if (theList.get(0).getMissing() != null) { addPredicateParamMissing(theParamName, theList.get(0).getMissing()); @@ -148,7 +149,7 @@ public class SearchBuilder { List codePredicates = new ArrayList(); for (IQueryParameterType nextOr : theList) { IQueryParameterType params = nextOr; - Predicate p = createPredicateDate(params, theParamName, myBuilder, join); + Predicate p = createPredicateDate(params, theResourceName, theParamName, myBuilder, join); codePredicates.add(p); } @@ -206,8 +207,8 @@ public class SearchBuilder { match = Collections.singleton(-1L); } - Join join = myResourceTableRoot.join("myResourceLinksByTarget", JoinType.LEFT); - + Join join = myResourceTableRoot.join("myIncomingResourceLinks", JoinType.LEFT); + Predicate predicate = join.get("mySourceResourcePid").in(match); myPredicates.add(predicate); } @@ -262,7 +263,7 @@ public class SearchBuilder { return; } - private void addPredicateNumber(String theParamName, List theList) { + private void addPredicateNumber(String theResourceName, String theParamName, List theList) { if (theList.get(0).getMissing() != null) { addPredicateParamMissing(theParamName, theList.get(0).getMissing()); @@ -288,7 +289,7 @@ public class SearchBuilder { String invalidMessageName = "invalidNumberPrefix"; String valueAsString = param.getValue().toPlainString(); - Predicate num = createPredicateNumeric(theParamName, join, myBuilder, params, prefix, value, fromObj, invalidMessageName, valueAsString); + Predicate num = createPredicateNumeric(theResourceName, theParamName, join, myBuilder, params, prefix, value, fromObj, invalidMessageName, valueAsString); codePredicates.add(num); } else { @@ -309,7 +310,7 @@ public class SearchBuilder { myPredicates.add(myBuilder.equal(paramPresentJoin.get("myPresent"), !theMissing)); } - private void addPredicateQuantity(String theParamName, List theList) { + private void addPredicateQuantity(String theResourceName, String theParamName, List theList) { if (theList.get(0).getMissing() != null) { addPredicateParamMissing(theParamName, theList.get(0).getMissing()); return; @@ -320,7 +321,7 @@ public class SearchBuilder { List codePredicates = new ArrayList(); for (IQueryParameterType nextOr : theList) { - Predicate singleCode = createPredicateQuantity(nextOr, theParamName, myBuilder, join); + Predicate singleCode = createPredicateQuantity(nextOr, theResourceName, theParamName, myBuilder, join); codePredicates.add(singleCode); } @@ -371,7 +372,7 @@ public class SearchBuilder { Predicate eq = myBuilder.equal(join.get("myTargetResourcePid"), next); codePredicates.add(eq); } - + } else { List> resourceTypes; @@ -483,7 +484,7 @@ public class SearchBuilder { myPredicates.add(myBuilder.equal(myResourceTableRoot.get("myResourceType"), subResourceName)); myPredicates.add(myBuilder.isNull(myResourceTableRoot.get("myDeleted"))); searchForIdsWithAndOr(subResourceName, chain, andOrParams); - + subQ.where(toArray(myPredicates)); /* @@ -511,7 +512,7 @@ public class SearchBuilder { myPredicates.add(myBuilder.or(toArray(codePredicates))); } - private void addPredicateString(String theParamName, List theList) { + private void addPredicateString(String theResourceName, String theParamName, List theList) { if (theList.get(0).getMissing() != null) { addPredicateParamMissing(theParamName, theList.get(0).getMissing()); return; @@ -522,7 +523,7 @@ public class SearchBuilder { List codePredicates = new ArrayList(); for (IQueryParameterType nextOr : theList) { IQueryParameterType theParameter = nextOr; - Predicate singleCode = createPredicateString(theParameter, theParamName, myBuilder, join); + Predicate singleCode = createPredicateString(theParameter, theResourceName, theParamName, myBuilder, join); codePredicates.add(singleCode); } @@ -658,7 +659,7 @@ public class SearchBuilder { } - private void addPredicateToken(String theParamName, List theList) { + private void addPredicateToken(String theResourceName, String theParamName, List theList) { if (theList.get(0).getMissing() != null) { addPredicateParamMissing(theParamName, theList.get(0).getMissing()); @@ -673,12 +674,12 @@ public class SearchBuilder { if (nextOr instanceof TokenParam) { TokenParam id = (TokenParam) nextOr; if (id.isText()) { - addPredicateString(theParamName, theList); + addPredicateString(theResourceName, theParamName, theList); continue; } } - Predicate singleCode = createPredicateToken(nextOr, theParamName, myBuilder, join); + Predicate singleCode = createPredicateToken(nextOr, theResourceName, theParamName, myBuilder, join); codePredicates.add(singleCode); } @@ -738,12 +739,12 @@ public class SearchBuilder { continue; } - predicate = join.get("myUri").as(String.class).in(toFind); + predicate = join. get("myUri").as(String.class).in(toFind); } else if (param.getQualifier() == UriParamQualifierEnum.BELOW) { - predicate = myBuilder.like(join.get("myUri").as(String.class), createLeftMatchLikeExpression(value)); + predicate = myBuilder.like(join. get("myUri").as(String.class), createLeftMatchLikeExpression(value)); } else { - predicate = myBuilder.equal(join.get("myUri").as(String.class), value); + predicate = myBuilder.equal(join. get("myUri").as(String.class), value); } codePredicates.add(predicate); } else { @@ -757,40 +758,40 @@ public class SearchBuilder { * just add a predicate that can never match */ if (codePredicates.isEmpty()) { - Predicate predicate = myBuilder.isNull(join.get("myUri").as(String.class)); + Predicate predicate = myBuilder.isNull(join. get("myUri").as(String.class)); myPredicates.add(predicate); return; } Predicate orPredicate = myBuilder.or(toArray(codePredicates)); - + Predicate paramNamePredicate = myBuilder.equal(join.get("myParamName"), theParamName); Predicate outerPredicate = myBuilder.and(paramNamePredicate, orPredicate); myPredicates.add(outerPredicate); } - private Predicate createCompositeParamPart(Root theRoot, RuntimeSearchParam theParam, IQueryParameterType leftValue) { + private Predicate createCompositeParamPart(String theResourceName, Root theRoot, RuntimeSearchParam theParam, IQueryParameterType leftValue) { Predicate retVal = null; switch (theParam.getParamType()) { case STRING: { From stringJoin = theRoot.join("myParamsString", JoinType.INNER); - retVal = createPredicateString(leftValue, theParam.getName(), myBuilder, stringJoin); + retVal = createPredicateString(leftValue, theResourceName, theParam.getName(), myBuilder, stringJoin); break; } case TOKEN: { From tokenJoin = theRoot.join("myParamsToken", JoinType.INNER); - retVal = createPredicateToken(leftValue, theParam.getName(), myBuilder, tokenJoin); + retVal = createPredicateToken(leftValue, theResourceName, theParam.getName(), myBuilder, tokenJoin); break; } case DATE: { From dateJoin = theRoot.join("myParamsDate", JoinType.INNER); - retVal = createPredicateDate(leftValue, theParam.getName(), myBuilder, dateJoin); + retVal = createPredicateDate(leftValue, theResourceName, theParam.getName(), myBuilder, dateJoin); break; } case QUANTITY: { From dateJoin = theRoot.join("myParamsQuantity", JoinType.INNER); - retVal = createPredicateQuantity(leftValue, theParam.getName(), myBuilder, dateJoin); + retVal = createPredicateQuantity(leftValue, theResourceName, theParam.getName(), myBuilder, dateJoin); break; } case COMPOSITE: @@ -808,7 +809,7 @@ public class SearchBuilder { return retVal; } - private Predicate createPredicateDate(IQueryParameterType theParam, String theParamName, CriteriaBuilder theBuilder, From theFrom) { + private Predicate createPredicateDate(IQueryParameterType theParam, String theResourceName, String theParamName, CriteriaBuilder theBuilder, From theFrom) { Predicate p; if (theParam instanceof DateParam) { DateParam date = (DateParam) theParam; @@ -825,8 +826,8 @@ public class SearchBuilder { } else { throw new IllegalArgumentException("Invalid token type: " + theParam.getClass()); } - - return combineParamIndexPredicateWithParamNamePredicate(theParamName, theFrom, p); + + return combineParamIndexPredicateWithParamNamePredicate(theResourceName, theParamName, theFrom, p); } private Predicate createPredicateDateFromRange(CriteriaBuilder theBuilder, From theFrom, DateRangeParam theRange) { @@ -886,7 +887,8 @@ public class SearchBuilder { predicates.addAll(createLastUpdatedPredicates(myParams.getLastUpdatedAndRemove(), builder, from)); } - private Predicate createPredicateNumeric(String theParamName, From theFrom, CriteriaBuilder builder, IQueryParameterType theParam, ParamPrefixEnum thePrefix, BigDecimal theValue, final Expression thePath, + private Predicate createPredicateNumeric(String theResourceName, String theParamName, From theFrom, CriteriaBuilder builder, + IQueryParameterType theParam, ParamPrefixEnum thePrefix, BigDecimal theValue, final Expression thePath, String invalidMessageName, String theValueString) { Predicate num; switch (thePrefix) { @@ -926,14 +928,15 @@ public class SearchBuilder { String msg = myContext.getLocalizer().getMessage(SearchBuilder.class, invalidMessageName, thePrefix.getValue(), theParam.getValueAsQueryToken(myContext)); throw new InvalidRequestException(msg); } - + if (theParamName == null) { return num; } - return combineParamIndexPredicateWithParamNamePredicate(theParamName, theFrom, num); + return combineParamIndexPredicateWithParamNamePredicate(theResourceName, theParamName, theFrom, num); } - private Predicate createPredicateQuantity(IQueryParameterType theParam, String theParamName, CriteriaBuilder theBuilder, From theFrom) { + private Predicate createPredicateQuantity(IQueryParameterType theParam, String theResourceName, String theParamName, CriteriaBuilder theBuilder, + From theFrom) { String systemValue; String unitsValue; ParamPrefixEnum cmpValue; @@ -972,7 +975,7 @@ public class SearchBuilder { final Expression path = theFrom.get("myValue"); String invalidMessageName = "invalidQuantityPrefix"; - Predicate num = createPredicateNumeric(null, theFrom, theBuilder, theParam, cmpValue, valueValue, path, invalidMessageName, valueString); + Predicate num = createPredicateNumeric(theResourceName, null, theFrom, theBuilder, theParam, cmpValue, valueValue, path, invalidMessageName, valueString); Predicate singleCode; if (system == null && code == null) { @@ -985,7 +988,7 @@ public class SearchBuilder { singleCode = theBuilder.and(system, code, num); } - return combineParamIndexPredicateWithParamNamePredicate(theParamName, theFrom, singleCode); + return combineParamIndexPredicateWithParamNamePredicate(theResourceName, theParamName, theFrom, singleCode); } private void createPredicateResourceId(CriteriaBuilder builder, AbstractQuery cq, List thePredicates, Expression theExpression) { @@ -1000,7 +1003,7 @@ public class SearchBuilder { } } - private Predicate createPredicateString(IQueryParameterType theParameter, String theParamName, CriteriaBuilder theBuilder, + private Predicate createPredicateString(IQueryParameterType theParameter, String theResourceName, String theParamName, CriteriaBuilder theBuilder, From theFrom) { String rawSearchTerm; if (theParameter instanceof TokenParam) { @@ -1032,12 +1035,12 @@ public class SearchBuilder { Predicate exactCode = theBuilder.equal(theFrom.get("myValueExact"), rawSearchTerm); singleCode = theBuilder.and(singleCode, exactCode); } - - return combineParamIndexPredicateWithParamNamePredicate(theParamName, theFrom, singleCode); + + return combineParamIndexPredicateWithParamNamePredicate(theResourceName, theParamName, theFrom, singleCode); } - private Predicate combineParamIndexPredicateWithParamNamePredicate(String theParamName, From theFrom, Predicate thePredicate) { - Predicate resourceTypePredicate = myBuilder.equal(theFrom.get("myResourceType"), myResourceName); + private Predicate combineParamIndexPredicateWithParamNamePredicate(String theResourceName, String theParamName, From theFrom, Predicate thePredicate) { + Predicate resourceTypePredicate = myBuilder.equal(theFrom.get("myResourceType"), theResourceName); Predicate paramNamePredicate = myBuilder.equal(theFrom.get("myParamName"), theParamName); Predicate outerPredicate = myBuilder.and(resourceTypePredicate, paramNamePredicate, thePredicate); return outerPredicate; @@ -1059,7 +1062,7 @@ public class SearchBuilder { return orPredicates; } - private Predicate createPredicateToken(IQueryParameterType theParameter, String theParamName, CriteriaBuilder theBuilder, + private Predicate createPredicateToken(IQueryParameterType theParameter, String theResourceName, String theParamName, CriteriaBuilder theBuilder, From theFrom) { String code; String system; @@ -1106,16 +1109,16 @@ public class SearchBuilder { codes = myTerminologySvc.findCodesBelow(system, code); } - ArrayList singleCodePredicates = (new ArrayList()); + ArrayList singleCodePredicates = new ArrayList(); if (codes != null) { - + if (codes.isEmpty()) { // This will never match anything Predicate systemPredicate = theBuilder.isNull(theFrom.get("mySystem")); Predicate codePredicate = theBuilder.isNull(theFrom.get("myValue")); singleCodePredicates.add(theBuilder.and(systemPredicate, codePredicate)); - + } else { List orPredicates = new ArrayList(); for (VersionIndependentConcept nextCode : codes) { @@ -1123,40 +1126,40 @@ public class SearchBuilder { Predicate codePredicate = theBuilder.equal(theFrom.get("myValue"), nextCode.getCode()); orPredicates.add(theBuilder.and(systemPredicate, codePredicate)); } - + singleCodePredicates.add(theBuilder.or(orPredicates.toArray(new Predicate[orPredicates.size()]))); } - + } else { - /* - * Ok, this is a normal query - */ - - if (StringUtils.isNotBlank(system)) { - singleCodePredicates.add(theBuilder.equal(theFrom.get("mySystem"), system)); - } else if (system == null) { - // don't check the system - } else { - // If the system is "", we only match on null systems - singleCodePredicates.add(theBuilder.isNull(theFrom.get("mySystem"))); - } - - if (StringUtils.isNotBlank(code)) { - singleCodePredicates.add(theBuilder.equal(theFrom.get("myValue"), code)); - } else { /* - * As of HAPI FHIR 1.5, if the client searched for a token with a system but no specified value this means to - * match all tokens with the given value. - * - * I'm not sure I agree with this, but hey.. FHIR-I voted and this was the result :) + * Ok, this is a normal query */ - // singleCodePredicates.add(theBuilder.isNull(theFrom.get("myValue"))); + + if (StringUtils.isNotBlank(system)) { + singleCodePredicates.add(theBuilder.equal(theFrom.get("mySystem"), system)); + } else if (system == null) { + // don't check the system + } else { + // If the system is "", we only match on null systems + singleCodePredicates.add(theBuilder.isNull(theFrom.get("mySystem"))); + } + + if (StringUtils.isNotBlank(code)) { + singleCodePredicates.add(theBuilder.equal(theFrom.get("myValue"), code)); + } else { + /* + * As of HAPI FHIR 1.5, if the client searched for a token with a system but no specified value this means to + * match all tokens with the given value. + * + * I'm not sure I agree with this, but hey.. FHIR-I voted and this was the result :) + */ + // singleCodePredicates.add(theBuilder.isNull(theFrom.get("myValue"))); + } } - } - + Predicate singleCode = theBuilder.and(toArray(singleCodePredicates)); - return combineParamIndexPredicateWithParamNamePredicate(theParamName, theFrom, singleCode); + return combineParamIndexPredicateWithParamNamePredicate(theResourceName, theParamName, theFrom, singleCode); } private Predicate createResourceLinkPathPredicate(String theParamName, From from) { @@ -1302,7 +1305,6 @@ public class SearchBuilder { return system; } - private boolean doHaveNoResults() { return mySearchEntity.getTotalCount() == 0; } @@ -1395,11 +1397,11 @@ public class SearchBuilder { ArrayList pids = new ArrayList(loadPids); // Any ressources which weren't matched by the sort get added to the bottom -// for (Long next : originalPids) { -// if (loadPids.contains(next) == false) { -// pids.add(next); -// } -// } + // for (Long next : originalPids) { + // if (loadPids.contains(next) == false) { + // pids.add(next); + // } + // } doSetPids(pids); } @@ -1467,7 +1469,7 @@ public class SearchBuilder { } public List loadSearchPage(SearchParameterMap theParams, int theFromIndex, int theToIndex) { - + if (myFulltextSearchSvc == null) { if (theParams.containsKey(Constants.PARAM_TEXT)) { throw new InvalidRequestException("Fulltext search is not enabled on this service, can not process parameter: " + Constants.PARAM_TEXT); @@ -1490,15 +1492,29 @@ public class SearchBuilder { myResourceTableQuery.distinct(true); myResourceTableRoot = myResourceTableQuery.from(ResourceTable.class); myPredicates = new ArrayList(); - myPredicates.add(myBuilder.equal(myResourceTableRoot.get("myResourceType"), myResourceName)); + if (theParams.getEverythingMode() == null) { + myPredicates.add(myBuilder.equal(myResourceTableRoot.get("myResourceType"), myResourceName)); + } myPredicates.add(myBuilder.isNull(myResourceTableRoot.get("myDeleted"))); DateRangeParam lu = theParams.getLastUpdated(); List lastUpdatedPredicates = createLastUpdatedPredicates(lu, myBuilder, myResourceTableRoot); myPredicates.addAll(lastUpdatedPredicates); - searchForIdsWithAndOr(theParams); - + if (theParams.getEverythingMode() != null) { + if (theParams.get(BaseResource.SP_RES_ID) != null) { + StringParam idParm = (StringParam) theParams.get(BaseResource.SP_RES_ID).get(0).get(0); + Long pid = BaseHapiFhirDao.translateForcedIdToPid(myResourceName, idParm.getValue(), myForcedIdDao); + + Join join = myResourceTableRoot.join("myResourceLinks", JoinType.LEFT); + myPredicates.add(myBuilder.equal(join.get("myTargetResourcePid").as(Long.class), pid)); + + } + } else { + // Normal search + searchForIdsWithAndOr(theParams); + } + myResourceTableQuery.where(myBuilder.and(SearchBuilder.toArray(myPredicates))); myResourceTableQuery.multiselect(myResourceTableRoot.get("myId").as(Long.class)); @@ -1649,12 +1665,12 @@ public class SearchBuilder { switch (nextParamDef.getParamType()) { case DATE: for (List nextAnd : theAndOrParams) { - addPredicateDate(theParamName, nextAnd); + addPredicateDate(theResourceName, theParamName, nextAnd); } break; case QUANTITY: for (List nextAnd : theAndOrParams) { - addPredicateQuantity(theParamName, nextAnd); + addPredicateQuantity(theResourceName, theParamName, nextAnd); } break; case REFERENCE: @@ -1664,22 +1680,22 @@ public class SearchBuilder { break; case STRING: for (List nextAnd : theAndOrParams) { - addPredicateString(theParamName, nextAnd); + addPredicateString(theResourceName, theParamName, nextAnd); } break; case TOKEN: for (List nextAnd : theAndOrParams) { - addPredicateToken(theParamName, nextAnd); + addPredicateToken(theResourceName, theParamName, nextAnd); } break; case NUMBER: for (List nextAnd : theAndOrParams) { - addPredicateNumber(theParamName, nextAnd); + addPredicateNumber(theResourceName, theParamName, nextAnd); } break; case COMPOSITE: for (List nextAnd : theAndOrParams) { - addPredicateComposite(nextParamDef, nextAnd); + addPredicateComposite(theResourceName, nextParamDef, nextAnd); } break; case URI: diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/ResourceTable.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/ResourceTable.java index ac73495592d..5757cbb64dd 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/ResourceTable.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/ResourceTable.java @@ -229,9 +229,6 @@ public class ResourceTable extends BaseHasResource implements Serializable { @IndexedEmbedded() private Collection myResourceLinks; - @OneToMany(mappedBy = "myTargetResource", cascade = {}, fetch = FetchType.LAZY, orphanRemoval = false) - private Collection myResourceLinksByTarget; - @Column(name = "RES_TYPE", length = RESTYPE_LEN) @Field private String myResourceType; diff --git a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/dstu3/FhirResourceDaoDstu3SearchNoFtTest.java b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/dstu3/FhirResourceDaoDstu3SearchNoFtTest.java index 31654341b8b..932dd459f94 100644 --- a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/dstu3/FhirResourceDaoDstu3SearchNoFtTest.java +++ b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/dstu3/FhirResourceDaoDstu3SearchNoFtTest.java @@ -9,6 +9,8 @@ import static org.hamcrest.Matchers.hasItem; import static org.hamcrest.Matchers.hasItems; import static org.hamcrest.Matchers.not; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; @@ -29,6 +31,7 @@ import org.hl7.fhir.dstu3.model.Bundle.BundleType; import org.hl7.fhir.dstu3.model.Bundle.HTTPVerb; import org.hl7.fhir.dstu3.model.ContactPoint.ContactPointSystem; import org.hl7.fhir.dstu3.model.Enumerations.AdministrativeGender; +import org.hl7.fhir.dstu3.model.Observation.ObservationStatus; import org.hl7.fhir.dstu3.model.Subscription.SubscriptionChannelType; import org.hl7.fhir.dstu3.model.Subscription.SubscriptionStatus; import org.hl7.fhir.exceptions.FHIRException; @@ -43,12 +46,15 @@ import org.junit.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.transaction.TransactionStatus; import org.springframework.transaction.support.TransactionCallback; +import org.springframework.transaction.support.TransactionCallbackWithoutResult; import org.springframework.transaction.support.TransactionTemplate; import ca.uhn.fhir.jpa.dao.BaseHapiFhirDao; import ca.uhn.fhir.jpa.dao.DaoConfig; +import ca.uhn.fhir.jpa.dao.DaoMethodOutcome; import ca.uhn.fhir.jpa.dao.SearchParameterMap; import ca.uhn.fhir.jpa.dao.SearchParameterMap.EverythingModeEnum; +import ca.uhn.fhir.jpa.dao.data.ISearchDao; import ca.uhn.fhir.jpa.entity.*; import ca.uhn.fhir.jpa.search.IStaleSearchDeletingSvc; import ca.uhn.fhir.model.api.IQueryParameterType; @@ -67,6 +73,9 @@ import ca.uhn.fhir.util.TestUtil; public class FhirResourceDaoDstu3SearchNoFtTest extends BaseJpaDstu3Test { private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(FhirResourceDaoDstu3SearchNoFtTest.class); + @Autowired + protected ISearchDao mySearchEntityDao; + @Autowired protected IStaleSearchDeletingSvc myStaleSearchDeletingSvc; @@ -321,6 +330,44 @@ public class FhirResourceDaoDstu3SearchNoFtTest extends BaseJpaDstu3Test { assertEquals(2, results.size()); } + @SuppressWarnings("unused") + @Test + public void testHasAndHas() { + Patient p1 = new Patient(); + p1.setActive(true); + IIdType p1id = myPatientDao.create(p1).getId().toUnqualifiedVersionless(); + + Patient p2 = new Patient(); + p2.setActive(true); + IIdType p2id = myPatientDao.create(p2).getId().toUnqualifiedVersionless(); + + Observation p1o1 = new Observation(); + p1o1.setStatus(ObservationStatus.FINAL); + p1o1.getSubject().setReferenceElement(p1id); + IIdType p1o1id = myObservationDao.create(p1o1).getId().toUnqualifiedVersionless(); + + Observation p1o2 = new Observation(); + p1o2.setEffective(new DateTimeType("2001-01-01")); + p1o2.getSubject().setReferenceElement(p1id); + IIdType p1o2id = myObservationDao.create(p1o2).getId().toUnqualifiedVersionless(); + + Observation p2o1 = new Observation(); + p2o1.setStatus(ObservationStatus.FINAL); + p2o1.getSubject().setReferenceElement(p2id); + IIdType p2o1id = myObservationDao.create(p2o1).getId().toUnqualifiedVersionless(); + + SearchParameterMap map = new SearchParameterMap(); + + HasAndListParam hasAnd = new HasAndListParam(); + hasAnd.addValue(new HasOrListParam().add(new HasParam("Observation", "subject", "status", "final"))); + hasAnd.addValue(new HasOrListParam().add(new HasParam("Observation", "subject", "date", "2001-01-01"))); + map.add("_has", hasAnd); + List actual = toUnqualifiedVersionlessIdValues(myPatientDao.search(map)); + assertThat(actual, containsInAnyOrder(p1id.getValue())); + + } + + @Test public void testIndexNoDuplicatesNumber() { Immunization res = new Immunization(); @@ -1244,7 +1291,7 @@ public class FhirResourceDaoDstu3SearchNoFtTest extends BaseJpaDstu3Test { } } - + @Test public void testSearchPagesExpiry() throws Exception { IIdType pid1; @@ -1265,16 +1312,29 @@ public class FhirResourceDaoDstu3SearchNoFtTest extends BaseJpaDstu3Test { SearchParameterMap params; params = new SearchParameterMap(); params.add(Patient.SP_FAMILY, new StringParam("EXPIRE")); - IBundleProvider bundleProvider = myPatientDao.search(params); + final IBundleProvider bundleProvider = myPatientDao.search(params); assertThat(toUnqualifiedVersionlessIds(bundleProvider), containsInAnyOrder(pid1, pid2)); assertThat(toUnqualifiedVersionlessIds(bundleProvider), containsInAnyOrder(pid1, pid2)); Thread.sleep(1500); + TransactionTemplate txTemplate = new TransactionTemplate(myTxManager); + txTemplate.execute(new TransactionCallbackWithoutResult() { + @Override + protected void doInTransactionWithoutResult(TransactionStatus theArg0) { + assertNotNull(mySearchEntityDao.findByUuid(bundleProvider.getUuid())); + } + }); + myDaoConfig.setExpireSearchResultsAfterMillis(500); myStaleSearchDeletingSvc.pollForStaleSearchesAndDeleteThem(); - assertThat(toUnqualifiedVersionlessIds(bundleProvider), not(containsInAnyOrder(pid1, pid2))); + txTemplate.execute(new TransactionCallbackWithoutResult() { + @Override + protected void doInTransactionWithoutResult(TransactionStatus theArg0) { + assertNull(mySearchEntityDao.findByUuid(bundleProvider.getUuid())); + } + }); } @Test