diff --git a/hapi-fhir-jpaserver-base/pom.xml b/hapi-fhir-jpaserver-base/pom.xml index 52e8c123781..573510eed59 100644 --- a/hapi-fhir-jpaserver-base/pom.xml +++ b/hapi-fhir-jpaserver-base/pom.xml @@ -238,7 +238,6 @@ org.hibernate hibernate-search-orm - 5.5.0.Final diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/BaseHapiFhirDao.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/BaseHapiFhirDao.java index ee93f087537..36ab5668941 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/BaseHapiFhirDao.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/BaseHapiFhirDao.java @@ -632,7 +632,7 @@ public abstract class BaseHapiFhirDao implements IDao { }; } - protected boolean isValidPid(IIdType theId) { + protected static boolean isValidPid(IIdType theId) { if (theId == null || theId.getIdPart() == null) { return false; } @@ -1186,10 +1186,14 @@ public abstract class BaseHapiFhirDao implements IDao { } protected Long translateForcedIdToPid(IIdType theId) { + return translateForcedIdToPid(theId, myEntityManager); + } + + static Long translateForcedIdToPid(IIdType theId, EntityManager entityManager) { if (isValidPid(theId)) { return theId.getIdPartAsLong(); } else { - TypedQuery q = myEntityManager.createNamedQuery("Q_GET_FORCED_ID", ForcedId.class); + TypedQuery q = entityManager.createNamedQuery("Q_GET_FORCED_ID", ForcedId.class); q.setParameter("ID", theId.getIdPart()); try { return q.getSingleResult().getResourcePid(); @@ -1356,7 +1360,7 @@ public abstract class BaseHapiFhirDao implements IDao { } } - + if (theEntity.getId() == null) { myEntityManager.persist(theEntity); @@ -1426,6 +1430,7 @@ public abstract class BaseHapiFhirDao implements IDao { myEntityManager.persist(next); } + // Store resource links for (ResourceLink next : resourceLinks) { myEntityManager.remove(next); } diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/FhirResourceDaoPatientDstu2.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/FhirResourceDaoPatientDstu2.java index 0e0593867ec..ec78f8ac67d 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/FhirResourceDaoPatientDstu2.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/FhirResourceDaoPatientDstu2.java @@ -33,18 +33,25 @@ import ca.uhn.fhir.model.primitive.UnsignedIntDt; import ca.uhn.fhir.rest.api.RestOperationTypeEnum; import ca.uhn.fhir.rest.api.SortSpec; import ca.uhn.fhir.rest.param.DateRangeParam; +import ca.uhn.fhir.rest.param.StringAndListParam; import ca.uhn.fhir.rest.param.StringParam; +import ca.uhn.fhir.rest.server.Constants; import ca.uhn.fhir.rest.server.IBundleProvider; import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor.ActionRequestDetails; public class FhirResourceDaoPatientDstu2 extends FhirResourceDaoDstu2implements IFhirResourceDaoPatient { - private IBundleProvider doEverythingOperation(IIdType theId, UnsignedIntDt theCount, DateRangeParam theLastUpdated, SortSpec theSort) { + private IBundleProvider doEverythingOperation(IIdType theId, UnsignedIntDt theCount, DateRangeParam theLastUpdated, SortSpec theSort, StringAndListParam theContent, StringAndListParam theNarrative) { SearchParameterMap paramMap = new SearchParameterMap(); if (theCount != null) { paramMap.setCount(theCount.getValue()); } - + if (theContent != null) { + paramMap.add(Constants.PARAM_CONTENT, theContent); + } + if (theNarrative != null) { + paramMap.add(Constants.PARAM_TEXT, theNarrative); + } paramMap.setIncludes(Collections.singleton(IResource.INCLUDE_ALL.asRecursive())); paramMap.setEverythingMode(theId != null ? EverythingModeEnum.PATIENT_INSTANCE : EverythingModeEnum.PATIENT_TYPE); paramMap.setSort(theSort); @@ -59,21 +66,21 @@ public class FhirResourceDaoPatientDstu2 extends FhirResourceDaoDstu2im } @Override - public IBundleProvider patientInstanceEverything(HttpServletRequest theServletRequest, IIdType theId, UnsignedIntDt theCount, DateRangeParam theLastUpdated, SortSpec theSort) { + public IBundleProvider patientInstanceEverything(HttpServletRequest theServletRequest, IIdType theId, UnsignedIntDt theCount, DateRangeParam theLastUpdated, SortSpec theSort, StringAndListParam theContent, StringAndListParam theNarrative) { // Notify interceptors ActionRequestDetails requestDetails = new ActionRequestDetails(null, getResourceName()); notifyInterceptors(RestOperationTypeEnum.EXTENDED_OPERATION_INSTANCE, requestDetails); - return doEverythingOperation(theId, theCount, theLastUpdated, theSort); + return doEverythingOperation(theId, theCount, theLastUpdated, theSort, theContent, theNarrative); } @Override - public IBundleProvider patientTypeEverything(HttpServletRequest theServletRequest, UnsignedIntDt theCount, DateRangeParam theLastUpdated, SortSpec theSort) { + public IBundleProvider patientTypeEverything(HttpServletRequest theServletRequest, UnsignedIntDt theCount, DateRangeParam theLastUpdated, SortSpec theSort, StringAndListParam theContent, StringAndListParam theNarrative) { // Notify interceptors ActionRequestDetails requestDetails = new ActionRequestDetails(null, getResourceName()); notifyInterceptors(RestOperationTypeEnum.EXTENDED_OPERATION_TYPE, requestDetails); - return doEverythingOperation(null, theCount, theLastUpdated, theSort); + return doEverythingOperation(null, theCount, theLastUpdated, theSort, theContent, theNarrative); } } diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/FhirSearchDao.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/FhirSearchDao.java index 53707a0a4c8..ae760f56460 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/FhirSearchDao.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/FhirSearchDao.java @@ -45,6 +45,8 @@ import org.springframework.transaction.annotation.Transactional; import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.jpa.entity.ResourceTable; import ca.uhn.fhir.model.api.IQueryParameterType; +import ca.uhn.fhir.model.dstu.resource.BaseResource; +import ca.uhn.fhir.model.primitive.IdDt; import ca.uhn.fhir.rest.param.StringParam; import ca.uhn.fhir.rest.server.Constants; @@ -57,6 +59,10 @@ public class FhirSearchDao extends BaseHapiFhirDao implements ISe @Transactional() @Override public List search(String theResourceName, SearchParameterMap theParams) { + return doSearch(theResourceName, theParams, null); + } + + private List doSearch(String theResourceName, SearchParameterMap theParams, Long theReferencingPid) { FullTextEntityManager em = org.hibernate.search.jpa.Search.getFullTextEntityManager(myEntityManager); QueryBuilder qb = em @@ -72,6 +78,10 @@ public class FhirSearchDao extends BaseHapiFhirDao implements ISe List> textAndTerms = theParams.remove(Constants.PARAM_TEXT); addTextSearch(qb, bool, textAndTerms, "myNarrativeText"); + if (theReferencingPid != null) { + bool.must(qb.keyword().onField("myResourceLinks.myTargetResourcePid").matching(theReferencingPid).createQuery()); + } + if (bool.isEmpty()) { return null; } @@ -92,7 +102,10 @@ public class FhirSearchDao extends BaseHapiFhirDao implements ISe ArrayList retVal = new ArrayList(); for (Object object : result) { Object[] nextArray = (Object[]) object; - retVal.add((Long)nextArray[0]); + Long next = (Long)nextArray[0]; + if (next != null) { + retVal.add(next); + } } return retVal; @@ -118,4 +131,23 @@ public class FhirSearchDao extends BaseHapiFhirDao implements ISe } } + @Override + public List everything(String theResourceName, SearchParameterMap theParams) { + + Long pid = null; + if (theParams.get(BaseResource.SP_RES_ID) != null) { + StringParam idParm = (StringParam) theParams.get(BaseResource.SP_RES_ID).get(0).get(0); + pid = BaseHapiFhirDao.translateForcedIdToPid(new IdDt(idParm.getValue()), myEntityManager); + } + + Long referencingPid = pid; + List retVal = doSearch(null, theParams, referencingPid); + if (referencingPid != null) { + retVal.add(referencingPid); + } + return retVal; + } + + + } diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/IFhirResourceDaoPatient.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/IFhirResourceDaoPatient.java index efd8480cf51..a34d56d2251 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/IFhirResourceDaoPatient.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/IFhirResourceDaoPatient.java @@ -28,12 +28,13 @@ import org.hl7.fhir.instance.model.api.IIdType; import ca.uhn.fhir.model.primitive.UnsignedIntDt; import ca.uhn.fhir.rest.api.SortSpec; import ca.uhn.fhir.rest.param.DateRangeParam; +import ca.uhn.fhir.rest.param.StringAndListParam; import ca.uhn.fhir.rest.server.IBundleProvider; public interface IFhirResourceDaoPatient extends IFhirResourceDao { - IBundleProvider patientInstanceEverything(HttpServletRequest theServletRequest, IIdType theId, UnsignedIntDt theCount, DateRangeParam theLastUpdate, SortSpec theSort); + IBundleProvider patientInstanceEverything(HttpServletRequest theServletRequest, IIdType theId, UnsignedIntDt theCount, DateRangeParam theLastUpdate, SortSpec theSort, StringAndListParam theContent, StringAndListParam theNarrative); - IBundleProvider patientTypeEverything(HttpServletRequest theServletRequest, UnsignedIntDt theCount, DateRangeParam theLastUpdated, SortSpec theSortSpec); + IBundleProvider patientTypeEverything(HttpServletRequest theServletRequest, UnsignedIntDt theCount, DateRangeParam theLastUpdated, SortSpec theSortSpec, StringAndListParam theContent, StringAndListParam theNarrative); } diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/ISearchDao.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/ISearchDao.java index 9b52fa3c561..e8a66b6f8a7 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/ISearchDao.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/ISearchDao.java @@ -25,5 +25,7 @@ import java.util.List; public interface ISearchDao { List search(String theResourceName, SearchParameterMap theParams); - + + List everything(String theResourceName, SearchParameterMap theParams); + } 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 03c220ee000..baacd661955 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 @@ -117,7 +117,7 @@ import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException; public class SearchBuilder { private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(SearchBuilder.class); - + private BaseHapiFhirDao myCallingDao; private FhirContext myContext; private EntityManager myEntityManager; @@ -135,7 +135,7 @@ public class SearchBuilder { mySearchResultDao = theSearchResultDao; myCallingDao = theDao; } - + private Set addPredicateComposite(RuntimeSearchParam theParamDef, Set thePids, List theNextAnd) { // TODO: fail if missing is set for a composite query @@ -170,7 +170,7 @@ public class SearchBuilder { return new HashSet(q.getResultList()); } - + private Set addPredicateDate(String theParamName, Set thePids, List theList) { if (theList == null || theList.isEmpty()) { return thePids; @@ -225,7 +225,7 @@ public class SearchBuilder { 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 q = myEntityManager.createQuery(cq); @@ -274,8 +274,8 @@ public class SearchBuilder { if (retVal.size() > 0) { Predicate inPids = (from.get("myId").in(retVal)); predicates.add(inPids); - } - + } + predicates.add(builder.isNull(from.get("myDeleted"))); cq.where(toArray(predicates)); @@ -289,9 +289,8 @@ public class SearchBuilder { return retVal; } - - private boolean addPredicateMissingFalseIfPresent(CriteriaBuilder theBuilder, String theParamName, Root from, List codePredicates, - IQueryParameterType nextOr) { + + private boolean addPredicateMissingFalseIfPresent(CriteriaBuilder theBuilder, String theParamName, Root from, List codePredicates, IQueryParameterType nextOr) { boolean missingFalse = false; if (nextOr.getMissing() != null) { if (nextOr.getMissing().booleanValue() == true) { @@ -305,9 +304,7 @@ public class SearchBuilder { return missingFalse; } - - private boolean addPredicateMissingFalseIfPresentForResourceLink(CriteriaBuilder theBuilder, String theParamName, Root from, List codePredicates, - IQueryParameterType nextOr) { + private boolean addPredicateMissingFalseIfPresentForResourceLink(CriteriaBuilder theBuilder, String theParamName, Root from, List codePredicates, IQueryParameterType nextOr) { boolean missingFalse = false; if (nextOr.getMissing() != null) { if (nextOr.getMissing().booleanValue() == true) { @@ -395,6 +392,7 @@ public class SearchBuilder { TypedQuery q = myEntityManager.createQuery(cq); return new HashSet(q.getResultList()); } + private Set addPredicateParamMissing(Set thePids, String joinName, String theParamName, Class theParamTable) { CriteriaBuilder builder = myEntityManager.getCriteriaBuilder(); CriteriaQuery cq = builder.createQuery(Long.class); @@ -427,7 +425,6 @@ public class SearchBuilder { return retVal; } - private Set addPredicateParamMissingResourceLink(Set thePids, String joinName, String theParamName) { CriteriaBuilder builder = myEntityManager.getCriteriaBuilder(); CriteriaQuery cq = builder.createQuery(Long.class); @@ -457,7 +454,7 @@ public class SearchBuilder { HashSet retVal = new HashSet(resultList); return retVal; } - + private Set addPredicateQuantity(String theParamName, Set thePids, List theList) { if (theList == null || theList.isEmpty()) { return thePids; @@ -572,8 +569,7 @@ public class SearchBuilder { TypedQuery q = myEntityManager.createQuery(cq); return new HashSet(q.getResultList()); } - - + private Set addPredicateReference(String theParamName, Set thePids, List theList) { assert theParamName.contains(".") == false; @@ -766,6 +762,7 @@ public class SearchBuilder { TypedQuery q = myEntityManager.createQuery(cq); return new HashSet(q.getResultList()); } + private Set addPredicateTag(Set thePids, List> theList, String theParamName, DateRangeParam theLastUpdated) { Set pids = thePids; if (theList == null || theList.isEmpty()) { @@ -849,7 +846,7 @@ public class SearchBuilder { if (theLastUpdated != null) { andPredicates.addAll(createLastUpdatedPredicates(theLastUpdated, builder, defJoin)); } - + Predicate masterCodePredicate = builder.and(toArray(andPredicates)); if (pids.size() > 0) { @@ -965,7 +962,6 @@ public class SearchBuilder { return new HashSet(q.getResultList()); } - private Predicate createCompositeParamPart(CriteriaBuilder builder, Root from, RuntimeSearchParam left, IQueryParameterType leftValue) { Predicate retVal = null; switch (left.getParamType()) { @@ -1072,8 +1068,7 @@ public class SearchBuilder { } } - private Predicate createPredicateString(IQueryParameterType theParameter, String theParamName, CriteriaBuilder theBuilder, - From theFrom) { + private Predicate createPredicateString(IQueryParameterType theParameter, String theParamName, CriteriaBuilder theBuilder, From theFrom) { String rawSearchTerm; if (theParameter instanceof TokenParam) { TokenParam id = (TokenParam) theParameter; @@ -1092,8 +1087,7 @@ public class SearchBuilder { } if (rawSearchTerm.length() > ResourceIndexedSearchParamString.MAX_LENGTH) { - throw new InvalidRequestException("Parameter[" + theParamName + "] has length (" + rawSearchTerm.length() + ") that is longer than maximum allowed (" - + ResourceIndexedSearchParamString.MAX_LENGTH + "): " + rawSearchTerm); + throw new InvalidRequestException("Parameter[" + theParamName + "] has length (" + rawSearchTerm.length() + ") that is longer than maximum allowed (" + ResourceIndexedSearchParamString.MAX_LENGTH + "): " + rawSearchTerm); } String likeExpression = BaseHapiFhirDao.normalizeString(rawSearchTerm); @@ -1107,8 +1101,7 @@ public class SearchBuilder { return singleCode; } - private Predicate createPredicateToken(IQueryParameterType theParameter, String theParamName, CriteriaBuilder theBuilder, - From theFrom) { + private Predicate createPredicateToken(IQueryParameterType theParameter, String theParamName, CriteriaBuilder theBuilder, From theFrom) { String code; String system; if (theParameter instanceof TokenParam) { @@ -1128,12 +1121,10 @@ public class SearchBuilder { } if (system != null && system.length() > ResourceIndexedSearchParamToken.MAX_LENGTH) { - throw new InvalidRequestException( - "Parameter[" + theParamName + "] has system (" + system.length() + ") that is longer than maximum allowed (" + ResourceIndexedSearchParamToken.MAX_LENGTH + "): " + system); + throw new InvalidRequestException("Parameter[" + theParamName + "] has system (" + system.length() + ") that is longer than maximum allowed (" + ResourceIndexedSearchParamToken.MAX_LENGTH + "): " + system); } if (code != null && code.length() > ResourceIndexedSearchParamToken.MAX_LENGTH) { - throw new InvalidRequestException( - "Parameter[" + theParamName + "] has code (" + code.length() + ") that is longer than maximum allowed (" + ResourceIndexedSearchParamToken.MAX_LENGTH + "): " + code); + throw new InvalidRequestException("Parameter[" + theParamName + "] has code (" + code.length() + ") that is longer than maximum allowed (" + ResourceIndexedSearchParamToken.MAX_LENGTH + "): " + code); } ArrayList singleCodePredicates = (new ArrayList()); @@ -1169,11 +1160,11 @@ public class SearchBuilder { List predicates = new ArrayList(); 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 query = myEntityManager.createQuery(cq); @@ -1281,9 +1272,9 @@ public class SearchBuilder { Root from = cq.from(ResourceTable.class); cq.select(from.get("myId").as(Long.class)); - List lastUpdatedPredicates = createLastUpdatedPredicates(theLastUpdated, builder, from); + List lastUpdatedPredicates = createLastUpdatedPredicates(theLastUpdated, builder, from); lastUpdatedPredicates.add(0, from.get("myId").in(thePids)); - + cq.where(SearchBuilder.toArray(lastUpdatedPredicates)); TypedQuery query = myEntityManager.createQuery(cq); List resultList = query.getResultList(); @@ -1325,10 +1316,11 @@ public class SearchBuilder { 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 + * + * @param theLastUpdated */ private HashSet loadReverseIncludes(Collection theMatches, Set theRevIncludes, boolean theReverseMode, EverythingModeEnum theEverythingModeEnum, DateRangeParam theLastUpdated) { if (theMatches.size() == 0) { @@ -1369,11 +1361,12 @@ public class SearchBuilder { List 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()); -// } -// } + // 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()); @@ -1443,10 +1436,9 @@ public class SearchBuilder { return allAdded; } - private List processSort(final SearchParameterMap theParams, Collection theLoadPids) { final List pids; -// Set loadPids = theLoadPids; + // Set loadPids = theLoadPids; if (theParams.getSort() != null && isNotBlank(theParams.getSort().getParamName())) { List orders = new ArrayList(); List predicates = new ArrayList(); @@ -1487,8 +1479,7 @@ public class SearchBuilder { } return pids; } - - + public IBundleProvider search(final SearchParameterMap theParams) { StopWatch w = new StopWatch(); final InstantDt now = InstantDt.withCurrentTime(); @@ -1501,28 +1492,41 @@ public class SearchBuilder { Collection loadPids; if (theParams.getEverythingMode() != null) { - CriteriaBuilder builder = myEntityManager.getCriteriaBuilder(); - CriteriaQuery cq = builder.createTupleQuery(); - Root from = cq.from(ResourceTable.class); - List predicates = new ArrayList(); + Long pid = null; 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())); + pid = BaseHapiFhirDao.translateForcedIdToPid(new IdDt(idParm.getValue()), myEntityManager); } - predicates.add(builder.equal(from.get("myResourceType"), myResourceName)); - predicates.add(builder.isNull(from.get("myDeleted"))); - cq.where(builder.and(SearchBuilder.toArray(predicates))); - Join join = from.join("myIncomingResourceLinks", JoinType.LEFT); - cq.multiselect(from.get("myId").as(Long.class), join.get("mySourceResourcePid").as(Long.class)); - - TypedQuery query = myEntityManager.createQuery(cq); loadPids = new HashSet(); - 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); + if (theParams.containsKey(Constants.PARAM_CONTENT) || theParams.containsKey(Constants.PARAM_TEXT)) { + List pids = mySearchDao.everything(myResourceName, theParams); +// if (pid != null) { +// loadPids.add(pid); +// } + loadPids.addAll(pids); + } else { + CriteriaBuilder builder = myEntityManager.getCriteriaBuilder(); + CriteriaQuery cq = builder.createTupleQuery(); + Root from = cq.from(ResourceTable.class); + List predicates = new ArrayList(); + if (pid != null) { + predicates.add(builder.equal(from.get("myId"), pid)); + } + predicates.add(builder.equal(from.get("myResourceType"), myResourceName)); + predicates.add(builder.isNull(from.get("myDeleted"))); + cq.where(builder.and(SearchBuilder.toArray(predicates))); + + Join join = from.join("myIncomingResourceLinks", JoinType.LEFT); + cq.multiselect(from.get("myId").as(Long.class), join.get("mySourceResourcePid").as(Long.class)); + + TypedQuery query = myEntityManager.createQuery(cq); + 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); + } } } @@ -1539,7 +1543,7 @@ public class SearchBuilder { } } else { - + List searchResultPids; if (mySearchDao == null) { if (theParams.containsKey(Constants.PARAM_TEXT)) { @@ -1565,7 +1569,8 @@ public class SearchBuilder { // // 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.getRevIncludes(), true, + // theParams.getEverythingMode())); // loadPids.addAll(loadReverseIncludes(loadPids, theParams.getIncludes(), false, theParams.getEverythingMode())); // } // } @@ -1849,5 +1854,4 @@ public class SearchBuilder { return thePredicates.toArray(new Predicate[thePredicates.size()]); } - } diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/ResourceLink.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/ResourceLink.java index c2ec3dfd29c..d9836afe2df 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/ResourceLink.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/ResourceLink.java @@ -36,6 +36,8 @@ import javax.persistence.Table; import org.apache.commons.lang3.Validate; import org.apache.commons.lang3.builder.EqualsBuilder; import org.apache.commons.lang3.builder.HashCodeBuilder; +import org.hibernate.search.annotations.ContainedIn; +import org.hibernate.search.annotations.Field; @Entity @Table(name = "HFJ_RES_LINK" , indexes= { @@ -57,6 +59,7 @@ public class ResourceLink implements Serializable { @ManyToOne(optional = false, fetch=FetchType.LAZY) @JoinColumn(name = "SRC_RESOURCE_ID", referencedColumnName = "RES_ID", nullable = false) +// @ContainedIn() private ResourceTable mySourceResource; @Column(name = "SRC_RESOURCE_ID", insertable = false, updatable = false, nullable = false) @@ -67,6 +70,7 @@ public class ResourceLink implements Serializable { private ResourceTable myTargetResource; @Column(name = "TARGET_RESOURCE_ID", insertable = false, updatable = false, nullable = false) + @Field() private Long myTargetResourcePid; public ResourceLink() { @@ -77,7 +81,9 @@ public class ResourceLink implements Serializable { super(); mySourcePath = theSourcePath; mySourceResource = theSourceResource; + mySourceResourcePid = theSourceResource.getId(); myTargetResource = theTargetResource; + myTargetResourcePid = theTargetResource.getId(); } @Override @@ -134,11 +140,13 @@ public class ResourceLink implements Serializable { public void setSourceResource(ResourceTable theSourceResource) { mySourceResource = theSourceResource; + mySourceResourcePid = theSourceResource.getId(); } public void setTargetResource(ResourceTable theTargetResource) { Validate.notNull(theTargetResource); myTargetResource = theTargetResource; + myTargetResourcePid = theTargetResource.getId(); } @Override 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 f82a7c0320c..04a53f9210e 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 @@ -29,6 +29,7 @@ import java.util.Set; import javax.persistence.CascadeType; import javax.persistence.Column; +import javax.persistence.Embedded; import javax.persistence.Entity; import javax.persistence.FetchType; import javax.persistence.GeneratedValue; @@ -39,8 +40,11 @@ import javax.persistence.OneToMany; import javax.persistence.Table; import javax.persistence.Transient; +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; import org.hibernate.search.annotations.Field; import org.hibernate.search.annotations.Indexed; +import org.hibernate.search.annotations.IndexedEmbedded; import ca.uhn.fhir.jpa.search.IndexNonDeletedInterceptor; import ca.uhn.fhir.model.primitive.IdDt; @@ -65,6 +69,13 @@ public class ResourceTable extends BaseHasResource implements Serializable { private static final long serialVersionUID = 1L; + /** + * Holds the narrative text only - Used for Fulltext searching but not directly stored in the DB + */ + @Transient() + @Field() + private String myContentText; + @Column(name = "SP_HAS_LINKS") private boolean myHasLinks; @@ -85,27 +96,16 @@ public class ResourceTable extends BaseHasResource implements Serializable { /** * Holds the narrative text only - Used for Fulltext searching but not directly stored in the DB */ -// @Column(name = "SP_NARRATIVE_TEXT", length = Integer.MAX_VALUE - 1, nullable=true) -// @Lob - @Transient + @Transient() @Field() private String myNarrativeText; - /** - * Holds the narrative text only - Used for Fulltext searching but not directly stored in the DB - */ -// @Column(name = "SP_CONTENT_TEXT", length = Integer.MAX_VALUE - 1, nullable=true) -// @Lob - @Transient - @Field() - private String myContentText; - @OneToMany(mappedBy = "myResource", cascade = {}, fetch = FetchType.LAZY, orphanRemoval = false) private Collection myParamsCoords; @Column(name = "SP_COORDS_PRESENT") private boolean myParamsCoordsPopulated; - + @OneToMany(mappedBy = "myResource", cascade = {}, fetch = FetchType.LAZY, orphanRemoval = false) private Collection myParamsDate; @@ -146,6 +146,7 @@ public class ResourceTable extends BaseHasResource implements Serializable { private String myProfile; @OneToMany(mappedBy = "mySourceResource", cascade = {}, fetch = FetchType.LAZY, orphanRemoval = false) + @IndexedEmbedded() private Collection myResourceLinks; @Column(name = "RES_TYPE", length = RESTYPE_LEN) @@ -303,6 +304,10 @@ public class ResourceTable extends BaseHasResource implements Serializable { return myParamsUriPopulated; } + public void setContentTextParsedIntoWords(String theContentText) { + myContentText = theContentText; + } + public void setHasLinks(boolean theHasLinks) { myHasLinks = theHasLinks; } @@ -326,10 +331,6 @@ public class ResourceTable extends BaseHasResource implements Serializable { myNarrativeText = theNarrativeText; } - public void setContentTextParsedIntoWords(String theContentText) { - myContentText = theContentText; - } - public void setParamsCoords(Collection theParamsCoords) { if (!isParamsTokenPopulated() && theParamsCoords.isEmpty()) { return; @@ -462,4 +463,12 @@ public class ResourceTable extends BaseHasResource implements Serializable { return retVal; } + @Override + public String toString() { + ToStringBuilder b = new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE); + b.append("resourceType", myResourceType); + b.append("pid", myId); + return b.build(); + } + } diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/provider/BaseJpaResourceProviderPatientDstu2.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/provider/BaseJpaResourceProviderPatientDstu2.java index 47d4e712b98..fdcf21d3f6f 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/provider/BaseJpaResourceProviderPatientDstu2.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/provider/BaseJpaResourceProviderPatientDstu2.java @@ -1,5 +1,9 @@ package ca.uhn.fhir.jpa.provider; +import static org.apache.commons.lang3.StringUtils.isNotBlank; + +import java.util.List; + /* * #%L * HAPI FHIR JPA Server @@ -23,17 +27,20 @@ package ca.uhn.fhir.jpa.provider; import ca.uhn.fhir.jpa.dao.IFhirResourceDaoPatient; import ca.uhn.fhir.model.api.annotation.Description; import ca.uhn.fhir.model.dstu2.resource.Patient; +import ca.uhn.fhir.model.primitive.StringDt; import ca.uhn.fhir.rest.annotation.IdParam; import ca.uhn.fhir.rest.annotation.Operation; import ca.uhn.fhir.rest.annotation.OperationParam; import ca.uhn.fhir.rest.annotation.Sort; import ca.uhn.fhir.rest.api.SortSpec; import ca.uhn.fhir.rest.param.DateRangeParam; +import ca.uhn.fhir.rest.param.StringAndListParam; +import ca.uhn.fhir.rest.param.StringOrListParam; +import ca.uhn.fhir.rest.param.StringParam; import ca.uhn.fhir.rest.server.Constants; public class BaseJpaResourceProviderPatientDstu2 extends JpaResourceProviderDstu2 { - /** * Patient/123/$everything */ @@ -53,7 +60,15 @@ public class BaseJpaResourceProviderPatientDstu2 extends JpaResourceProviderDstu @Description(shortDefinition="Only return resources which were last updated as specified by the given range") @OperationParam(name = Constants.PARAM_LASTUPDATED, min=0, max=1) DateRangeParam theLastUpdated, - + + @Description(shortDefinition="Filter the resources to return only resources matching the given _content filter (note that this filter is applied only to results which link to the given patient, not to the patient itself or to supporting resources linked to by the matched resources)") + @OperationParam(name = Constants.PARAM_CONTENT, min=0, max=OperationParam.MAX_UNLIMITED) + List theContent, + + @Description(shortDefinition="Filter the resources to return only resources matching the given _text filter (note that this filter is applied only to results which link to the given patient, not to the patient itself or to supporting resources linked to by the matched resources)") + @OperationParam(name = Constants.PARAM_TEXT, min=0, max=OperationParam.MAX_UNLIMITED) + List theNarrative, + @Sort SortSpec theSortSpec ) { @@ -61,15 +76,16 @@ public class BaseJpaResourceProviderPatientDstu2 extends JpaResourceProviderDstu startRequest(theServletRequest); try { - return ((IFhirResourceDaoPatient)getDao()).patientInstanceEverything(theServletRequest, theId, theCount, theLastUpdated, theSortSpec); + return ((IFhirResourceDaoPatient) getDao()).patientInstanceEverything(theServletRequest, theId, theCount, theLastUpdated, theSortSpec, toStringAndList(theContent), toStringAndList(theNarrative)); } finally { endRequest(theServletRequest); - }} + } + } - /** - * /Patient/$everything - */ - //@formatter:off + /** + * /Patient/$everything + */ + //@formatter:off @Operation(name = "everything", idempotent = true) public ca.uhn.fhir.rest.server.IBundleProvider patientTypeEverything( @@ -82,19 +98,42 @@ public class BaseJpaResourceProviderPatientDstu2 extends JpaResourceProviderDstu @Description(shortDefinition="Only return resources which were last updated as specified by the given range") @OperationParam(name = Constants.PARAM_LASTUPDATED, min=0, max=1) DateRangeParam theLastUpdated, - + + @Description(shortDefinition="Filter the resources to return only resources matching the given _content filter (note that this filter is applied only to results which link to the given patient, not to the patient itself or to supporting resources linked to by the matched resources)") + @OperationParam(name = Constants.PARAM_CONTENT, min=0, max=OperationParam.MAX_UNLIMITED) + List theContent, + + @Description(shortDefinition="Filter the resources to return only resources matching the given _text filter (note that this filter is applied only to results which link to the given patient, not to the patient itself or to supporting resources linked to by the matched resources)") + @OperationParam(name = Constants.PARAM_TEXT, min=0, max=OperationParam.MAX_UNLIMITED) + List theNarrative, + @Sort SortSpec theSortSpec ) { //@formatter:on - startRequest(theServletRequest); - try { - return ((IFhirResourceDaoPatient)getDao()).patientTypeEverything(theServletRequest, theCount, theLastUpdated, theSortSpec); - } finally { - endRequest(theServletRequest); - } + startRequest(theServletRequest); + try { + return ((IFhirResourceDaoPatient) getDao()).patientTypeEverything(theServletRequest, theCount, theLastUpdated, theSortSpec, toStringAndList(theContent), toStringAndList(theNarrative)); + } finally { + endRequest(theServletRequest); + } } + private StringAndListParam toStringAndList(List theNarrative) { + StringAndListParam retVal = new StringAndListParam(); + if (theNarrative != null) { + for (StringDt next : theNarrative) { + if (isNotBlank(next.getValue())) { + retVal.addAnd(new StringOrListParam().addOr(new StringParam(next.getValue()))); + } + } + } + if (retVal.getValuesAsQueryTokens().isEmpty()) { + return null; + } + return retVal; + } + } diff --git a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/BaseJpaDstu2SystemTest.java b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/BaseJpaDstu2SystemTest.java new file mode 100644 index 00000000000..758e1b09722 --- /dev/null +++ b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/BaseJpaDstu2SystemTest.java @@ -0,0 +1,43 @@ +package ca.uhn.fhir.jpa.dao; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import java.util.Enumeration; + +import javax.servlet.ServletConfig; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; + +import org.junit.Before; + +import ca.uhn.fhir.jpa.rp.dstu2.PatientResourceProvider; +import ca.uhn.fhir.rest.method.RequestDetails; +import ca.uhn.fhir.rest.server.RestfulServer; + +public abstract class BaseJpaDstu2SystemTest extends BaseJpaDstu2Test { + protected RequestDetails myRequestDetails; + private RestfulServer myServer; + + @SuppressWarnings("unchecked") + @Before + public void before() throws ServletException { + myRequestDetails = mock(RequestDetails.class); + + if (myServer == null) { + myServer = new RestfulServer(myFhirCtx); + + PatientResourceProvider patientRp = new PatientResourceProvider(); + patientRp.setDao(myPatientDao); + myServer.setResourceProviders(patientRp); + myServer.init(mock(ServletConfig.class)); + } + + when(myRequestDetails.getServer()).thenReturn(myServer); + HttpServletRequest servletRequest = mock(HttpServletRequest.class); + when(myRequestDetails.getServletRequest()).thenReturn(servletRequest); + when(servletRequest.getHeaderNames()).thenReturn(mock(Enumeration.class)); + when(servletRequest.getRequestURL()).thenReturn(new StringBuffer("/Patient")); + } + +} diff --git a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/BaseJpaDstu2Test.java b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/BaseJpaDstu2Test.java index d9a8917f5e0..fda5f522fad 100644 --- a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/BaseJpaDstu2Test.java +++ b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/BaseJpaDstu2Test.java @@ -10,6 +10,8 @@ import javax.persistence.EntityManager; import javax.persistence.PersistenceContext; import org.apache.commons.io.IOUtils; +import org.hibernate.search.jpa.FullTextEntityManager; +import org.hibernate.search.jpa.Search; import org.hl7.fhir.instance.model.api.IBaseResource; import org.junit.Before; import org.junit.runner.RunWith; @@ -75,7 +77,7 @@ public abstract class BaseJpaDstu2Test extends BaseJpaTest { @Autowired protected ApplicationContext myAppCtx; - + @Autowired @Qualifier("myConceptMapDaoDstu2") protected IFhirResourceDao myConceptMapDao; @@ -162,6 +164,16 @@ public abstract class BaseJpaDstu2Test extends BaseJpaTest { myDaoConfig.setInterceptors(myInterceptor); } + @Before + @Transactional + public void beforeFlushFT() { + FullTextEntityManager ftem = Search.getFullTextEntityManager(myEntityManager); + ftem.purgeAll(ResourceTable.class); + ftem.flushToIndexes(); + + myDaoConfig.setSchedulingDisabled(true); + } + @Before @Transactional() public void beforePurgeDatabase() { diff --git a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/FhirResourceDaoDstu2SearchFtTest.java b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/FhirResourceDaoDstu2SearchFtTest.java index fbaa485b80c..b8d34f294f8 100644 --- a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/FhirResourceDaoDstu2SearchFtTest.java +++ b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/FhirResourceDaoDstu2SearchFtTest.java @@ -4,48 +4,40 @@ import static org.hamcrest.Matchers.contains; import static org.hamcrest.Matchers.containsInAnyOrder; import static org.hamcrest.Matchers.empty; import static org.hamcrest.Matchers.not; +import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertThat; +import static org.mockito.Mockito.mock; import java.util.List; -import org.hibernate.search.jpa.FullTextEntityManager; -import org.hibernate.search.jpa.Search; -import org.hl7.fhir.instance.model.api.IIdType; -import org.junit.Before; -import org.junit.Test; -import org.springframework.test.context.ContextConfiguration; -import org.springframework.transaction.annotation.Transactional; +import javax.servlet.http.HttpServletRequest; -import ca.uhn.fhir.jpa.entity.ResourceTable; +import org.hl7.fhir.instance.model.api.IIdType; +import org.junit.Test; + +import ca.uhn.fhir.model.dstu2.resource.Device; import ca.uhn.fhir.model.dstu2.resource.Observation; import ca.uhn.fhir.model.dstu2.resource.Patient; import ca.uhn.fhir.model.primitive.StringDt; +import ca.uhn.fhir.rest.param.StringAndListParam; +import ca.uhn.fhir.rest.param.StringOrListParam; import ca.uhn.fhir.rest.param.StringParam; import ca.uhn.fhir.rest.server.Constants; public class FhirResourceDaoDstu2SearchFtTest extends BaseJpaDstu2Test { + private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(FhirResourceDaoDstu2SearchFtTest.class); - - @Before - @Transactional - public void beforeFlushFT() { - FullTextEntityManager ftem = Search.getFullTextEntityManager(myEntityManager); - ftem.purgeAll(ResourceTable.class); - ftem.flushToIndexes(); - - myDaoConfig.setSchedulingDisabled(true); - } - + @Test public void testSearchAndReindex() { Patient patient; SearchParameterMap map; - + patient = new Patient(); patient.getText().setDiv("
DIVAAA
"); patient.addName().addGiven("NAMEAAA"); IIdType pId1 = myPatientDao.create(patient).getId().toUnqualifiedVersionless(); - + map = new SearchParameterMap(); map.add(Constants.PARAM_CONTENT, new StringParam("NAMEAAA")); assertThat(toUnqualifiedVersionlessIds(myPatientDao.search(map)), contains(pId1)); @@ -53,11 +45,11 @@ public class FhirResourceDaoDstu2SearchFtTest extends BaseJpaDstu2Test { map = new SearchParameterMap(); map.add(Constants.PARAM_TEXT, new StringParam("DIVAAA")); assertThat(toUnqualifiedVersionlessIds(myPatientDao.search(map)), contains(pId1)); - + /* * Reindex */ - + patient = new Patient(); patient.setId(pId1); patient.getText().setDiv("
DIVBBB
"); @@ -79,24 +71,204 @@ public class FhirResourceDaoDstu2SearchFtTest extends BaseJpaDstu2Test { map = new SearchParameterMap(); map.add(Constants.PARAM_TEXT, new StringParam("DIVBBB")); assertThat(toUnqualifiedVersionlessIds(myPatientDao.search(map)), contains(pId1)); - } + @Test + public void testEverythingInstanceWithContentFilter() { + Patient pt1 = new Patient(); + pt1.addName().addFamily("Everything").addGiven("Arthur"); + IIdType ptId1 = myPatientDao.create(pt1).getId().toUnqualifiedVersionless(); + + Patient pt2 = new Patient(); + pt2.addName().addFamily("Everything").addGiven("Arthur"); + IIdType ptId2 = myPatientDao.create(pt2).getId().toUnqualifiedVersionless(); + + Device dev1 = new Device(); + dev1.setManufacturer("Some Manufacturer"); + IIdType devId1 = myDeviceDao.create(dev1).getId().toUnqualifiedVersionless(); + + Device dev2 = new Device(); + dev2.setManufacturer("Some Manufacturer 2"); + myDeviceDao.create(dev2).getId().toUnqualifiedVersionless(); + + Observation obs1 = new Observation(); + obs1.getText().setDiv("
OBSTEXT1
"); + obs1.getSubject().setReference(ptId1); + obs1.getCode().addCoding().setCode("CODE1"); + obs1.setValue(new StringDt("obsvalue1")); + obs1.getDevice().setReference(devId1); + IIdType obsId1 = myObservationDao.create(obs1).getId().toUnqualifiedVersionless(); + + Observation obs2 = new Observation(); + obs2.getSubject().setReference(ptId1); + obs2.getCode().addCoding().setCode("CODE2"); + obs2.setValue(new StringDt("obsvalue2")); + IIdType obsId2 = myObservationDao.create(obs2).getId().toUnqualifiedVersionless(); + + Observation obs3 = new Observation(); + obs3.getSubject().setReference(ptId2); + obs3.getCode().addCoding().setCode("CODE3"); + obs3.setValue(new StringDt("obsvalue3")); + IIdType obsId3 = myObservationDao.create(obs3).getId().toUnqualifiedVersionless(); + + HttpServletRequest request; + List actual; + request = mock(HttpServletRequest.class); + StringAndListParam param; + + ourLog.info("Pt1:{} Pt2:{} Obs1:{} Obs2:{} Obs3:{}", new Object[] {ptId1.getIdPart(), ptId2.getIdPart(), obsId1.getIdPart(), obsId2.getIdPart(), obsId3.getIdPart()}); + + param = new StringAndListParam(); + param.addAnd(new StringOrListParam().addOr(new StringParam("obsvalue1"))); + actual = toUnqualifiedVersionlessIds(myPatientDao.patientInstanceEverything(request, ptId1, null, null, null, param, null)); + assertThat(actual, containsInAnyOrder(ptId1, obsId1, devId1)); + + param = new StringAndListParam(); + param.addAnd(new StringOrListParam().addOr(new StringParam("obstext1"))); + actual = toUnqualifiedVersionlessIds(myPatientDao.patientInstanceEverything(request, ptId1, null, null, null, null, param)); + assertThat(actual, containsInAnyOrder(ptId1, obsId1, devId1)); + + request = mock(HttpServletRequest.class); + actual = toUnqualifiedVersionlessIds(myPatientDao.patientInstanceEverything(request, ptId1, null, null, null, null, null)); + assertThat(actual, containsInAnyOrder(ptId1, obsId1, obsId2, devId1)); + + /* + * Add another match + */ + + Observation obs4 = new Observation(); + obs4.getSubject().setReference(ptId1); + obs4.getCode().addCoding().setCode("CODE1"); + obs4.setValue(new StringDt("obsvalue1")); + IIdType obsId4 = myObservationDao.create(obs4).getId().toUnqualifiedVersionless(); + assertNotEquals(obsId1.getIdPart(), obsId4.getIdPart(), devId1); + + param = new StringAndListParam(); + param.addAnd(new StringOrListParam().addOr(new StringParam("obsvalue1"))); + actual = toUnqualifiedVersionlessIds(myPatientDao.patientInstanceEverything(request, ptId1, null, null, null, param, null)); + assertThat(actual, containsInAnyOrder(ptId1, obsId1, obsId4, devId1)); + + /* + * Make one previous match no longer match + */ + + obs1 = new Observation(); + obs1.setId(obsId1); + obs1.getSubject().setReference(ptId1); + obs1.getCode().addCoding().setCode("CODE2"); + obs1.setValue(new StringDt("obsvalue2")); + myObservationDao.update(obs1); + + param = new StringAndListParam(); + param.addAnd(new StringOrListParam().addOr(new StringParam("obsvalue1"))); + actual = toUnqualifiedVersionlessIds(myPatientDao.patientInstanceEverything(request, ptId1, null, null, null, param, null)); + assertThat(actual, containsInAnyOrder(ptId1, obsId4)); + + } + + @Test + public void testEverythingTypeWithContentFilter() { + Patient pt1 = new Patient(); + pt1.addName().addFamily("Everything").addGiven("Arthur"); + IIdType ptId1 = myPatientDao.create(pt1).getId().toUnqualifiedVersionless(); + + Patient pt2 = new Patient(); + pt2.addName().addFamily("Everything").addGiven("Arthur"); + IIdType ptId2 = myPatientDao.create(pt2).getId().toUnqualifiedVersionless(); + + Device dev1 = new Device(); + dev1.setManufacturer("Some Manufacturer"); + IIdType devId1 = myDeviceDao.create(dev1).getId().toUnqualifiedVersionless(); + + Device dev2 = new Device(); + dev2.setManufacturer("Some Manufacturer 2"); + IIdType devId2 = myDeviceDao.create(dev2).getId().toUnqualifiedVersionless(); + + Observation obs1 = new Observation(); + obs1.getSubject().setReference(ptId1); + obs1.getCode().addCoding().setCode("CODE1"); + obs1.setValue(new StringDt("obsvalue1")); + obs1.getDevice().setReference(devId1); + IIdType obsId1 = myObservationDao.create(obs1).getId().toUnqualifiedVersionless(); + + Observation obs2 = new Observation(); + obs2.getSubject().setReference(ptId1); + obs2.getCode().addCoding().setCode("CODE2"); + obs2.setValue(new StringDt("obsvalue2")); + IIdType obsId2 = myObservationDao.create(obs2).getId().toUnqualifiedVersionless(); + + Observation obs3 = new Observation(); + obs3.getSubject().setReference(ptId2); + obs3.getCode().addCoding().setCode("CODE3"); + obs3.setValue(new StringDt("obsvalue3")); + IIdType obsId3 = myObservationDao.create(obs3).getId().toUnqualifiedVersionless(); + + HttpServletRequest request; + List actual; + request = mock(HttpServletRequest.class); + StringAndListParam param; + + ourLog.info("Pt1:{} Pt2:{} Obs1:{} Obs2:{} Obs3:{}", new Object[] {ptId1.getIdPart(), ptId2.getIdPart(), obsId1.getIdPart(), obsId2.getIdPart(), obsId3.getIdPart()}); + + param = new StringAndListParam(); + param.addAnd(new StringOrListParam().addOr(new StringParam("obsvalue1"))); + actual = toUnqualifiedVersionlessIds(myPatientDao.patientTypeEverything(request, null, null, null, param, null)); + assertThat(actual, containsInAnyOrder(ptId1, obsId1, devId1)); + + request = mock(HttpServletRequest.class); + actual = toUnqualifiedVersionlessIds(myPatientDao.patientTypeEverything(request, null, null, null, null, null)); + assertThat(actual, containsInAnyOrder(ptId1, obsId1, obsId2, devId1, ptId2, obsId3)); + + /* + * Add another match + */ + + Observation obs4 = new Observation(); + obs4.getSubject().setReference(ptId1); + obs4.getCode().addCoding().setCode("CODE1"); + obs4.setValue(new StringDt("obsvalue1")); + IIdType obsId4 = myObservationDao.create(obs4).getId().toUnqualifiedVersionless(); + assertNotEquals(obsId1.getIdPart(), obsId4.getIdPart(), devId1); + + param = new StringAndListParam(); + param.addAnd(new StringOrListParam().addOr(new StringParam("obsvalue1"))); + actual = toUnqualifiedVersionlessIds(myPatientDao.patientTypeEverything(request, null, null, null, param, null)); + assertThat(actual, containsInAnyOrder(ptId1, obsId1, obsId4, devId1)); + + /* + * Make one previous match no longer match + */ + + obs1 = new Observation(); + obs1.setId(obsId1); + obs1.getSubject().setReference(ptId1); + obs1.getCode().addCoding().setCode("CODE2"); + obs1.setValue(new StringDt("obsvalue2")); + myObservationDao.update(obs1); + + param = new StringAndListParam(); + param.addAnd(new StringOrListParam().addOr(new StringParam("obsvalue1"))); + actual = toUnqualifiedVersionlessIds(myPatientDao.patientTypeEverything(request, null, null, null, param, null)); + assertThat(actual, containsInAnyOrder(ptId1, obsId4)); + + } + + /** - * When processing transactions, we do two passes. Make sure we don't update the - * lucene index twice since that would be inefficient + * When processing transactions, we do two passes. Make sure we don't update the lucene index twice since that would + * be inefficient */ @Test public void testSearchDontReindexForUpdateWithIndexDisabled() { Patient patient; SearchParameterMap map; - + patient = new Patient(); patient.getText().setDiv("
DIVAAA
"); patient.addName().addGiven("NAMEAAA"); IIdType pId1 = myPatientDao.create(patient).getId().toUnqualifiedVersionless(); - + map = new SearchParameterMap(); map.add(Constants.PARAM_CONTENT, new StringParam("NAMEAAA")); assertThat(toUnqualifiedVersionlessIds(myPatientDao.search(map)), contains(pId1)); @@ -104,11 +276,11 @@ public class FhirResourceDaoDstu2SearchFtTest extends BaseJpaDstu2Test { map = new SearchParameterMap(); map.add(Constants.PARAM_TEXT, new StringParam("DIVAAA")); assertThat(toUnqualifiedVersionlessIds(myPatientDao.search(map)), contains(pId1)); - + /* * Update but don't reindex */ - + patient = new Patient(); patient.setId(pId1); patient.getText().setDiv("
DIVBBB
"); @@ -122,8 +294,8 @@ public class FhirResourceDaoDstu2SearchFtTest extends BaseJpaDstu2Test { map.add(Constants.PARAM_CONTENT, new StringParam("NAMEBBB")); assertThat(toUnqualifiedVersionlessIds(myPatientDao.search(map)), not(contains(pId1))); - myPatientDao.update(patient, null, true); - + myPatientDao.update(patient, null, true); + map = new SearchParameterMap(); map.add(Constants.PARAM_CONTENT, new StringParam("NAMEAAA")); assertThat(toUnqualifiedVersionlessIds(myPatientDao.search(map)), empty()); @@ -139,12 +311,9 @@ public class FhirResourceDaoDstu2SearchFtTest extends BaseJpaDstu2Test { map = new SearchParameterMap(); map.add(Constants.PARAM_TEXT, new StringParam("DIVBBB")); assertThat(toUnqualifiedVersionlessIds(myPatientDao.search(map)), contains(pId1)); - } - - @Test public void testSearchWithChainedParams() { String methodName = "testSearchWithChainedParams"; diff --git a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/FhirResourceDaoDstu2SearchNoFtTest.java b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/FhirResourceDaoDstu2SearchNoFtTest.java index 82651ad5889..21081fa3aee 100644 --- a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/FhirResourceDaoDstu2SearchNoFtTest.java +++ b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/FhirResourceDaoDstu2SearchNoFtTest.java @@ -8,6 +8,7 @@ import static org.hamcrest.Matchers.endsWith; import static org.hamcrest.Matchers.hasItems; import static org.hamcrest.Matchers.not; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; @@ -141,14 +142,14 @@ public class FhirResourceDaoDstu2SearchNoFtTest extends BaseJpaDstu2Test { IIdType moId = myMedicationOrderDao.create(mo).getId().toUnqualifiedVersionless(); HttpServletRequest request = mock(HttpServletRequest.class); - IBundleProvider resp = myPatientDao.patientTypeEverything(request, null, null, null); + IBundleProvider resp = myPatientDao.patientTypeEverything(request, null, null, null, null, null); assertThat(toUnqualifiedVersionlessIds(resp), containsInAnyOrder(orgId, medId, patId, moId, patId2)); request = mock(HttpServletRequest.class); - resp = myPatientDao.patientInstanceEverything(request, patId, null, null, null); + resp = myPatientDao.patientInstanceEverything(request, patId, null, null, null, null, null); assertThat(toUnqualifiedVersionlessIds(resp), containsInAnyOrder(orgId, medId, patId, moId)); } - + @Test public void testIndexNoDuplicatesDate() { DiagnosticOrder order = new DiagnosticOrder(); diff --git a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/FhirSystemDaoDstu2SearchTest.java b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/FhirSystemDaoDstu2SearchTest.java index 878db8d0c25..7e497a5e6a5 100644 --- a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/FhirSystemDaoDstu2SearchTest.java +++ b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/FhirSystemDaoDstu2SearchTest.java @@ -1,7 +1,14 @@ package ca.uhn.fhir.jpa.dao; -public class FhirSystemDaoDstu2SearchTest { +import org.junit.Test; +public class FhirSystemDaoDstu2SearchTest extends BaseJpaDstu2SystemTest { + + @Test + public void testSearchByParans() { + // code to come.. just here to prevent a failure + } + /*//@formatter:off * [ERROR] Search parameter action has conflicting types token and reference * [ERROR] Search parameter source has conflicting types token and reference diff --git a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/FhirSystemDaoDstu2Test.java b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/FhirSystemDaoDstu2Test.java index e8692018115..cb5836ecc38 100644 --- a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/FhirSystemDaoDstu2Test.java +++ b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/FhirSystemDaoDstu2Test.java @@ -14,25 +14,16 @@ import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import static org.mockito.Matchers.eq; -import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; import java.io.InputStream; import java.io.UnsupportedEncodingException; import java.util.ArrayList; -import java.util.Collection; -import java.util.Enumeration; import java.util.List; -import javax.servlet.ServletConfig; -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; - import org.apache.commons.io.IOUtils; import org.hl7.fhir.instance.model.api.IIdType; -import org.junit.Before; import org.junit.Test; import org.mockito.ArgumentCaptor; import org.springframework.transaction.TransactionStatus; @@ -43,7 +34,6 @@ import ca.uhn.fhir.jpa.entity.ResourceEncodingEnum; import ca.uhn.fhir.jpa.entity.ResourceTable; import ca.uhn.fhir.jpa.entity.TagTypeEnum; import ca.uhn.fhir.jpa.provider.SystemProviderDstu2Test; -import ca.uhn.fhir.jpa.rp.dstu2.PatientResourceProvider; import ca.uhn.fhir.model.api.IResource; import ca.uhn.fhir.model.api.ResourceMetadataKeyEnum; import ca.uhn.fhir.model.api.TagList; @@ -67,81 +57,61 @@ import ca.uhn.fhir.model.dstu2.valueset.IssueSeverityEnum; import ca.uhn.fhir.model.primitive.IdDt; import ca.uhn.fhir.model.primitive.UriDt; import ca.uhn.fhir.rest.api.RestOperationTypeEnum; -import ca.uhn.fhir.rest.method.RequestDetails; import ca.uhn.fhir.rest.server.Constants; import ca.uhn.fhir.rest.server.IBundleProvider; -import ca.uhn.fhir.rest.server.IResourceProvider; -import ca.uhn.fhir.rest.server.RestfulServer; import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException; import ca.uhn.fhir.rest.server.exceptions.PreconditionFailedException; import ca.uhn.fhir.rest.server.exceptions.ResourceGoneException; import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException; import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor.ActionRequestDetails; -public class FhirSystemDaoDstu2Test extends BaseJpaDstu2Test { +public class FhirSystemDaoDstu2Test extends BaseJpaDstu2SystemTest { private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(FhirSystemDaoDstu2Test.class); - private RequestDetails myRequestDetails; - private RestfulServer myServer; - @Test - public void testTransactionFromBundle6() throws Exception { - InputStream bundleRes = SystemProviderDstu2Test.class.getResourceAsStream("/simone_bundle3.xml"); - String bundle = IOUtils.toString(bundleRes); - Bundle output = mySystemDao.transaction(myRequestDetails, myFhirCtx.newXmlParser().parseResource(Bundle.class, bundle)); - ourLog.info(myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(output)); - } - - - @Test - public void testNestedCount() { - Patient p = new Patient(); - p.addName().addFamily("family"); - final IIdType id = myPatientDao.create(p).getId().toUnqualifiedVersionless(); - - } - - @Test public void testRendexing() { Patient p = new Patient(); p.addName().addFamily("family"); final IIdType id = myPatientDao.create(p).getId().toUnqualifiedVersionless(); - + ValueSet vs = new ValueSet(); vs.setUrl("http://foo"); myValueSetDao.create(vs); - + ResourceTable entity = new TransactionTemplate(myTxManager).execute(new TransactionCallback() { @Override public ResourceTable doInTransaction(TransactionStatus theStatus) { return myEntityManager.find(ResourceTable.class, id.getIdPartAsLong()); - }}); + } + }); assertEquals(Long.valueOf(1), entity.getIndexStatus()); - + mySystemDao.markAllResourcesForReindexing(); entity = new TransactionTemplate(myTxManager).execute(new TransactionCallback() { @Override public ResourceTable doInTransaction(TransactionStatus theStatus) { return myEntityManager.find(ResourceTable.class, id.getIdPartAsLong()); - }}); + } + }); assertEquals(null, entity.getIndexStatus()); mySystemDao.performReindexingPass(null); - + entity = new TransactionTemplate(myTxManager).execute(new TransactionCallback() { @Override public ResourceTable doInTransaction(TransactionStatus theStatus) { return myEntityManager.find(ResourceTable.class, id.getIdPartAsLong()); - }}); + } + }); assertEquals(Long.valueOf(1), entity.getIndexStatus()); // Just make sure this doesn't cause a choke mySystemDao.performReindexingPass(100000); - + // Try making the resource unparseable - + TransactionTemplate template = new TransactionTemplate(myTxManager); template.setPropagationBehavior(TransactionTemplate.PROPAGATION_REQUIRES_NEW); template.execute(new TransactionCallback() { @@ -157,21 +127,21 @@ public class FhirSystemDaoDstu2Test extends BaseJpaDstu2Test { } myEntityManager.merge(table); return null; - }}); + } + }); mySystemDao.performReindexingPass(null); - + entity = new TransactionTemplate(myTxManager).execute(new TransactionCallback() { @Override public ResourceTable doInTransaction(TransactionStatus theStatus) { return myEntityManager.find(ResourceTable.class, id.getIdPartAsLong()); - }}); + } + }); assertEquals(Long.valueOf(2), entity.getIndexStatus()); - } - - + @Test public void testSystemMetaOperation() { @@ -261,6 +231,53 @@ public class FhirSystemDaoDstu2Test extends BaseJpaDstu2Test { } + @Test + public void testTransactionBatchWithFailingRead() { + String methodName = "testTransactionBatchWithFailingRead"; + Bundle request = new Bundle(); + request.setType(BundleTypeEnum.BATCH); + + Patient p = new Patient(); + p.addName().addFamily(methodName); + request.addEntry().setResource(p).getRequest().setMethod(HTTPVerbEnum.POST); + + request.addEntry().getRequest().setMethod(HTTPVerbEnum.GET).setUrl("Patient/THIS_ID_DOESNT_EXIST"); + + Bundle resp = mySystemDao.transaction(myRequestDetails, request); + assertEquals(3, resp.getEntry().size()); + assertEquals(BundleTypeEnum.BATCH_RESPONSE, resp.getTypeElement().getValueAsEnum()); + + ourLog.info(myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(resp)); + EntryResponse respEntry; + + // Bundle.entry[0] is operation outcome + assertEquals(OperationOutcome.class, resp.getEntry().get(0).getResource().getClass()); + assertEquals(IssueSeverityEnum.INFORMATION, ((OperationOutcome) resp.getEntry().get(0).getResource()).getIssue().get(0).getSeverityElement().getValueAsEnum()); + assertThat(((OperationOutcome) resp.getEntry().get(0).getResource()).getIssue().get(0).getDiagnostics(), startsWith("Batch completed in ")); + + // Bundle.entry[1] is create response + assertEquals("201 Created", resp.getEntry().get(1).getResponse().getStatus()); + assertThat(resp.getEntry().get(1).getResponse().getLocation(), startsWith("Patient/")); + + // Bundle.entry[2] is failed read response + assertEquals(OperationOutcome.class, resp.getEntry().get(2).getResource().getClass()); + assertEquals(IssueSeverityEnum.ERROR, ((OperationOutcome) resp.getEntry().get(2).getResource()).getIssue().get(0).getSeverityElement().getValueAsEnum()); + assertEquals("Resource Patient/THIS_ID_DOESNT_EXIST is not known", ((OperationOutcome) resp.getEntry().get(2).getResource()).getIssue().get(0).getDiagnostics()); + assertEquals("404 Not Found", resp.getEntry().get(2).getResponse().getStatus()); + + // Check POST + respEntry = resp.getEntry().get(1).getResponse(); + assertEquals("201 Created", respEntry.getStatus()); + IdDt createdId = new IdDt(respEntry.getLocation()); + assertEquals("Patient", createdId.getResourceType()); + myPatientDao.read(createdId); // shouldn't fail + + // Check GET + respEntry = resp.getEntry().get(2).getResponse(); + assertThat(respEntry.getStatus(), startsWith("404")); + + } + @Test public void testTransactionCreateMatchUrlWithOneMatch() { String methodName = "testTransactionCreateMatchUrlWithOneMatch"; @@ -303,188 +320,6 @@ public class FhirSystemDaoDstu2Test extends BaseJpaDstu2Test { } - @Test - public void testTransactionWithInvalidType() { - Bundle request = new Bundle(); - request.setType(BundleTypeEnum.SEARCH_RESULTS); - Patient p = new Patient(); - request.addEntry().setResource(p).getRequest().setMethod(HTTPVerbEnum.POST); - - try { - mySystemDao.transaction(myRequestDetails, request); - fail(); - } catch (InvalidRequestException e) { - assertEquals("Unable to process transaction where incoming Bundle.type = searchset", e.getMessage()); - } - - } - - @SuppressWarnings("unchecked") - @Before - public void before() throws ServletException { - myRequestDetails = mock(RequestDetails.class); - - if (myServer == null) { - myServer = new RestfulServer(myFhirCtx); - - PatientResourceProvider patientRp = new PatientResourceProvider(); - patientRp.setDao(myPatientDao); - myServer.setResourceProviders(patientRp); - myServer.init(mock(ServletConfig.class)); - } - - when(myRequestDetails.getServer()).thenReturn(myServer); - HttpServletRequest servletRequest = mock(HttpServletRequest.class); - when(myRequestDetails.getServletRequest()).thenReturn(servletRequest); - when(servletRequest.getHeaderNames()).thenReturn(mock(Enumeration.class)); - when(servletRequest.getRequestURL()).thenReturn(new StringBuffer("/Patient")); - } - - @Test - public void testTransactionSingleEmptyResource() { - - Bundle request = new Bundle(); - request.setType(BundleTypeEnum.SEARCH_RESULTS); - Patient p = new Patient(); - request.addEntry().setResource(p).getRequest().setMethod(HTTPVerbEnum.POST); - - try { - mySystemDao.transaction(myRequestDetails, request); - fail(); - } catch (InvalidRequestException e) { - assertEquals("Unable to process transaction where incoming Bundle.type = searchset", e.getMessage()); - } - - } - - @Test - public void testTransactionBatchWithFailingRead() { - String methodName = "testTransactionBatchWithFailingRead"; - Bundle request = new Bundle(); - request.setType(BundleTypeEnum.BATCH); - - Patient p = new Patient(); - p.addName().addFamily(methodName); - request.addEntry().setResource(p).getRequest().setMethod(HTTPVerbEnum.POST); - - request.addEntry().getRequest().setMethod(HTTPVerbEnum.GET).setUrl("Patient/THIS_ID_DOESNT_EXIST"); - - Bundle resp = mySystemDao.transaction(myRequestDetails, request); - assertEquals(3, resp.getEntry().size()); - assertEquals(BundleTypeEnum.BATCH_RESPONSE, resp.getTypeElement().getValueAsEnum()); - - ourLog.info(myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(resp)); - EntryResponse respEntry; - - // Bundle.entry[0] is operation outcome - assertEquals(OperationOutcome.class, resp.getEntry().get(0).getResource().getClass()); - assertEquals(IssueSeverityEnum.INFORMATION, ((OperationOutcome)resp.getEntry().get(0).getResource()).getIssue().get(0).getSeverityElement().getValueAsEnum()); - assertThat(((OperationOutcome)resp.getEntry().get(0).getResource()).getIssue().get(0).getDiagnostics(), startsWith("Batch completed in ")); - - // Bundle.entry[1] is create response - assertEquals("201 Created", resp.getEntry().get(1).getResponse().getStatus()); - assertThat(resp.getEntry().get(1).getResponse().getLocation(), startsWith("Patient/")); - - // Bundle.entry[2] is failed read response - assertEquals(OperationOutcome.class, resp.getEntry().get(2).getResource().getClass()); - assertEquals(IssueSeverityEnum.ERROR, ((OperationOutcome)resp.getEntry().get(2).getResource()).getIssue().get(0).getSeverityElement().getValueAsEnum()); - assertEquals("Resource Patient/THIS_ID_DOESNT_EXIST is not known", ((OperationOutcome)resp.getEntry().get(2).getResource()).getIssue().get(0).getDiagnostics()); - assertEquals("404 Not Found", resp.getEntry().get(2).getResponse().getStatus()); - - // Check POST - respEntry = resp.getEntry().get(1).getResponse(); - assertEquals("201 Created", respEntry.getStatus()); - IdDt createdId = new IdDt(respEntry.getLocation()); - assertEquals("Patient", createdId.getResourceType()); - myPatientDao.read(createdId); // shouldn't fail - - // Check GET - respEntry = resp.getEntry().get(2).getResponse(); - assertThat(respEntry.getStatus(), startsWith("404")); - - } - - @Test - public void testTransactionCreateWithDuplicateMatchUrl01() { - String methodName = "testTransactionCreateWithDuplicateMatchUrl01"; - Bundle request = new Bundle(); - - Patient p; - p = new Patient(); - p.addIdentifier().setSystem("urn:system").setValue(methodName); - request.addEntry().setResource(p).getRequest().setMethod(HTTPVerbEnum.POST).setIfNoneExist("Patient?identifier=urn%3Asystem%7C" + methodName); - - p = new Patient(); - p.addIdentifier().setSystem("urn:system").setValue(methodName); - request.addEntry().setResource(p).getRequest().setMethod(HTTPVerbEnum.POST).setIfNoneExist("Patient?identifier=urn%3Asystem%7C" + methodName); - - try { - mySystemDao.transaction(myRequestDetails, request); - fail(); - } catch (InvalidRequestException e) { - assertEquals(e.getMessage(), - "Unable to process Transaction - Request would cause multiple resources to match URL: \"Patient?identifier=urn%3Asystem%7CtestTransactionCreateWithDuplicateMatchUrl01\". Does transaction request contain duplicates?"); - } - } - - @Test - public void testTransactionCreateWithInvalidMatchUrl() { - String methodName = "testTransactionCreateWithInvalidMatchUrl"; - Bundle request = new Bundle(); - - Patient p; - p = new Patient(); - p.addIdentifier().setSystem("urn:system").setValue(methodName); - EntryRequest entry = request.addEntry().setResource(p).getRequest().setMethod(HTTPVerbEnum.POST); - - try { - entry.setIfNoneExist("Patient?identifier identifier" + methodName); - mySystemDao.transaction(myRequestDetails, request); - fail(); - } catch (InvalidRequestException e) { - assertEquals("Failed to parse match URL[Patient?identifier identifiertestTransactionCreateWithInvalidMatchUrl] - URL is invalid (must not contain spaces)", e.getMessage()); - } - - try { - entry.setIfNoneExist("Patient?identifier="); - mySystemDao.transaction(myRequestDetails, request); - fail(); - } catch (InvalidRequestException e) { - assertEquals("Invalid match URL[Patient?identifier=] - URL has no search parameters", e.getMessage()); - } - - try { - entry.setIfNoneExist("Patient?foo=bar"); - mySystemDao.transaction(myRequestDetails, request); - fail(); - } catch (InvalidRequestException e) { - assertEquals("Failed to parse match URL[Patient?foo=bar] - Resource type Patient does not have a parameter with name: foo", e.getMessage()); - } - } - - - public void testTransactionCreateWithDuplicateMatchUrl02() { - String methodName = "testTransactionCreateWithDuplicateMatchUrl02"; - Bundle request = new Bundle(); - - Patient p; - p = new Patient(); - p.addIdentifier().setSystem("urn:system").setValue(methodName); - request.addEntry().setResource(p).getRequest().setMethod(HTTPVerbEnum.POST).setIfNoneExist("Patient?identifier=urn%3Asystem%7C" + methodName); - - p = new Patient(); - p.addIdentifier().setSystem("urn:system").setValue(methodName); - request.addEntry().setResource(p).getRequest().setMethod(HTTPVerbEnum.POST); - - try { - mySystemDao.transaction(myRequestDetails, request); - fail(); - } catch (InvalidRequestException e) { - assertEquals(e.getMessage(), - "Unable to process Transaction - Request would cause multiple resources to match URL: \"Patient?identifier=urn%3Asystem%7CtestTransactionCreateWithDuplicateMatchUrl02\". Does transaction request contain duplicates?"); - } - } - @Test public void testTransactionCreateMatchUrlWithTwoMatch() { String methodName = "testTransactionCreateMatchUrlWithTwoMatch"; @@ -576,8 +411,7 @@ public class FhirSystemDaoDstu2Test extends BaseJpaDstu2Test { assertThat(patientId, not(containsString("test"))); /* - * Interceptor should have been called once for the transaction, and once for the - * embedded operation + * Interceptor should have been called once for the transaction, and once for the embedded operation */ ArgumentCaptor detailsCapt = ArgumentCaptor.forClass(ActionRequestDetails.class); verify(myInterceptor).incomingRequestPreHandled(eq(RestOperationTypeEnum.TRANSACTION), detailsCapt.capture()); @@ -591,7 +425,85 @@ public class FhirSystemDaoDstu2Test extends BaseJpaDstu2Test { assertNotNull(details.getId()); assertEquals("Patient", details.getResourceType()); assertEquals(Patient.class, details.getResource().getClass()); - + + } + + @Test + public void testTransactionCreateWithDuplicateMatchUrl01() { + String methodName = "testTransactionCreateWithDuplicateMatchUrl01"; + Bundle request = new Bundle(); + + Patient p; + p = new Patient(); + p.addIdentifier().setSystem("urn:system").setValue(methodName); + request.addEntry().setResource(p).getRequest().setMethod(HTTPVerbEnum.POST).setIfNoneExist("Patient?identifier=urn%3Asystem%7C" + methodName); + + p = new Patient(); + p.addIdentifier().setSystem("urn:system").setValue(methodName); + request.addEntry().setResource(p).getRequest().setMethod(HTTPVerbEnum.POST).setIfNoneExist("Patient?identifier=urn%3Asystem%7C" + methodName); + + try { + mySystemDao.transaction(myRequestDetails, request); + fail(); + } catch (InvalidRequestException e) { + assertEquals(e.getMessage(), "Unable to process Transaction - Request would cause multiple resources to match URL: \"Patient?identifier=urn%3Asystem%7CtestTransactionCreateWithDuplicateMatchUrl01\". Does transaction request contain duplicates?"); + } + } + + public void testTransactionCreateWithDuplicateMatchUrl02() { + String methodName = "testTransactionCreateWithDuplicateMatchUrl02"; + Bundle request = new Bundle(); + + Patient p; + p = new Patient(); + p.addIdentifier().setSystem("urn:system").setValue(methodName); + request.addEntry().setResource(p).getRequest().setMethod(HTTPVerbEnum.POST).setIfNoneExist("Patient?identifier=urn%3Asystem%7C" + methodName); + + p = new Patient(); + p.addIdentifier().setSystem("urn:system").setValue(methodName); + request.addEntry().setResource(p).getRequest().setMethod(HTTPVerbEnum.POST); + + try { + mySystemDao.transaction(myRequestDetails, request); + fail(); + } catch (InvalidRequestException e) { + assertEquals(e.getMessage(), "Unable to process Transaction - Request would cause multiple resources to match URL: \"Patient?identifier=urn%3Asystem%7CtestTransactionCreateWithDuplicateMatchUrl02\". Does transaction request contain duplicates?"); + } + } + + @Test + public void testTransactionCreateWithInvalidMatchUrl() { + String methodName = "testTransactionCreateWithInvalidMatchUrl"; + Bundle request = new Bundle(); + + Patient p; + p = new Patient(); + p.addIdentifier().setSystem("urn:system").setValue(methodName); + EntryRequest entry = request.addEntry().setResource(p).getRequest().setMethod(HTTPVerbEnum.POST); + + try { + entry.setIfNoneExist("Patient?identifier identifier" + methodName); + mySystemDao.transaction(myRequestDetails, request); + fail(); + } catch (InvalidRequestException e) { + assertEquals("Failed to parse match URL[Patient?identifier identifiertestTransactionCreateWithInvalidMatchUrl] - URL is invalid (must not contain spaces)", e.getMessage()); + } + + try { + entry.setIfNoneExist("Patient?identifier="); + mySystemDao.transaction(myRequestDetails, request); + fail(); + } catch (InvalidRequestException e) { + assertEquals("Invalid match URL[Patient?identifier=] - URL has no search parameters", e.getMessage()); + } + + try { + entry.setIfNoneExist("Patient?foo=bar"); + mySystemDao.transaction(myRequestDetails, request); + fail(); + } catch (InvalidRequestException e) { + assertEquals("Failed to parse match URL[Patient?foo=bar] - Resource type Patient does not have a parameter with name: foo", e.getMessage()); + } } @Test @@ -721,7 +633,7 @@ public class FhirSystemDaoDstu2Test extends BaseJpaDstu2Test { @Test public void testTransactionDeleteMatchUrlWithTwoMatch() { myDaoConfig.setAllowMultipleDelete(false); - + String methodName = "testTransactionDeleteMatchUrlWithTwoMatch"; Patient p = new Patient(); @@ -757,12 +669,12 @@ public class FhirSystemDaoDstu2Test extends BaseJpaDstu2Test { Bundle request = new Bundle(); request.addEntry().getRequest().setMethod(HTTPVerbEnum.DELETE).setUrl("Patient?identifier=urn%3Asystem%7C" + methodName); -// try { - mySystemDao.transaction(myRequestDetails, request); -// fail(); -// } catch (ResourceNotFoundException e) { -// assertThat(e.getMessage(), containsString("resource matching URL \"Patient?")); -// } + // try { + mySystemDao.transaction(myRequestDetails, request); + // fail(); + // } catch (ResourceNotFoundException e) { + // assertThat(e.getMessage(), containsString("resource matching URL \"Patient?")); + // } } @Test @@ -827,6 +739,14 @@ public class FhirSystemDaoDstu2Test extends BaseJpaDstu2Test { assertEquals("Patient/temp6789", p.getLink().get(0).getOther().getReference().getValue()); } + @Test + public void testTransactionFromBundle6() throws Exception { + InputStream bundleRes = SystemProviderDstu2Test.class.getResourceAsStream("/simone_bundle3.xml"); + String bundle = IOUtils.toString(bundleRes); + Bundle output = mySystemDao.transaction(myRequestDetails, myFhirCtx.newXmlParser().parseResource(Bundle.class, bundle)); + ourLog.info(myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(output)); + } + @Test public void testTransactionFromBundleJosh() throws Exception { @@ -842,59 +762,6 @@ public class FhirSystemDaoDstu2Test extends BaseJpaDstu2Test { assertEquals("201 Created", resp.getEntry().get(1).getResponse().getStatus()); } - @Test - public void testTransactionWithReferenceToCreateIfNoneExist() { - Bundle bundle = new Bundle(); - bundle.setType(BundleTypeEnum.TRANSACTION); - - Medication med = new Medication(); - IdDt medId = IdDt.newRandomUuid(); - med.setId(medId); - med.getCode().addCoding().setSystem("billscodes").setCode("theCode"); - bundle.addEntry().setResource(med).setFullUrl(medId.getValue()).getRequest().setMethod(HTTPVerbEnum.POST).setIfNoneExist("Medication?code=billscodes|theCode"); - - MedicationOrder mo = new MedicationOrder(); - mo.setMedication(new ResourceReferenceDt(medId)); - bundle.addEntry().setResource(mo).setFullUrl(mo.getId().getValue()).getRequest().setMethod(HTTPVerbEnum.POST); - - ourLog.info("Request:\n"+myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(bundle)); - - Bundle outcome = mySystemDao.transaction(myRequestDetails, bundle); - ourLog.info("Response:\n"+myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(outcome)); - - IdDt medId1 = new IdDt(outcome.getEntry().get(0).getResponse().getLocation()); - IdDt medOrderId1 = new IdDt( outcome.getEntry().get(1).getResponse().getLocation()); - - /* - * Again! - */ - - bundle = new Bundle(); - bundle.setType(BundleTypeEnum.TRANSACTION); - - med = new Medication(); - medId = IdDt.newRandomUuid(); - med.getCode().addCoding().setSystem("billscodes").setCode("theCode"); - bundle.addEntry().setResource(med).setFullUrl(medId.getValue()).getRequest().setMethod(HTTPVerbEnum.POST).setIfNoneExist("Medication?code=billscodes|theCode"); - - mo = new MedicationOrder(); - mo.setMedication(new ResourceReferenceDt(medId)); - bundle.addEntry().setResource(mo).setFullUrl(mo.getId().getValue()).getRequest().setMethod(HTTPVerbEnum.POST); - - outcome = mySystemDao.transaction(myRequestDetails, bundle); - - IdDt medId2 = new IdDt(outcome.getEntry().get(0).getResponse().getLocation()); - IdDt medOrderId2 = new IdDt(outcome.getEntry().get(1).getResponse().getLocation()); - - assertTrue(medId1.isIdPartValidLong()); - assertTrue(medId2.isIdPartValidLong()); - assertTrue(medOrderId1.isIdPartValidLong()); - assertTrue(medOrderId2.isIdPartValidLong()); - - assertEquals(medId1, medId2); - assertNotEquals(medOrderId1, medOrderId2); - } - @Test public void testTransactionReadAndSearch() { String methodName = "testTransactionReadAndSearch"; @@ -935,10 +802,9 @@ public class FhirSystemDaoDstu2Test extends BaseJpaDstu2Test { assertEquals(Bundle.class, nextEntry.getResource().getClass()); Bundle respBundle = (Bundle) nextEntry.getResource(); assertEquals(1, respBundle.getTotal().intValue()); - + /* - * Interceptor should have been called once for the transaction, and once for the - * embedded operation + * Interceptor should have been called once for the transaction, and once for the embedded operation */ ArgumentCaptor detailsCapt = ArgumentCaptor.forClass(ActionRequestDetails.class); verify(myInterceptor, times(1)).incomingRequestPreHandled(eq(RestOperationTypeEnum.TRANSACTION), detailsCapt.capture()); @@ -963,7 +829,51 @@ public class FhirSystemDaoDstu2Test extends BaseJpaDstu2Test { details = detailsCapt.getValue(); assertEquals("Patient", details.getResourceType()); - + } + + @Test + public void testTransactionReadWithIfNoneMatch() { + String methodName = "testTransactionReadWithIfNoneMatch"; + + Patient p = new Patient(); + p.addIdentifier().setSystem("urn:system").setValue(methodName); + p.setId("Patient/" + methodName); + IIdType idv1 = myPatientDao.update(p).getId(); + ourLog.info("Created patient, got id: {}", idv1); + + p = new Patient(); + p.addIdentifier().setSystem("urn:system").setValue(methodName); + p.addName().addFamily("Family Name"); + p.setId("Patient/" + methodName); + IIdType idv2 = myPatientDao.update(p).getId(); + ourLog.info("Updated patient, got id: {}", idv2); + + Bundle request = new Bundle(); + request.addEntry().getRequest().setMethod(HTTPVerbEnum.GET).setUrl(idv1.toUnqualifiedVersionless().getValue()); + request.addEntry().getRequest().setMethod(HTTPVerbEnum.GET).setUrl(idv1.toUnqualifiedVersionless().getValue()).setIfNoneMatch("W/\"" + idv1.getVersionIdPart() + "\""); + request.addEntry().getRequest().setMethod(HTTPVerbEnum.GET).setUrl(idv1.toUnqualifiedVersionless().getValue()).setIfNoneMatch("W/\"" + idv2.getVersionIdPart() + "\""); + + Bundle resp = mySystemDao.transaction(myRequestDetails, request); + + assertEquals(3, resp.getEntry().size()); + + Entry nextEntry; + + nextEntry = resp.getEntry().get(0); + assertNotNull(nextEntry.getResource()); + assertEquals(Patient.class, nextEntry.getResource().getClass()); + assertEquals(idv2.toUnqualified(), nextEntry.getResource().getId().toUnqualified()); + assertEquals("200 OK", nextEntry.getResponse().getStatus()); + + nextEntry = resp.getEntry().get(1); + assertNotNull(nextEntry.getResource()); + assertEquals(Patient.class, nextEntry.getResource().getClass()); + assertEquals(idv2.toUnqualified(), nextEntry.getResource().getId().toUnqualified()); + assertEquals("200 OK", nextEntry.getResponse().getStatus()); + + nextEntry = resp.getEntry().get(2); + assertEquals("304 Not Modified", nextEntry.getResponse().getStatus()); + assertNull(nextEntry.getResource()); } @Test @@ -1013,48 +923,20 @@ public class FhirSystemDaoDstu2Test extends BaseJpaDstu2Test { } @Test - public void testTransactionReadWithIfNoneMatch() { - String methodName = "testTransactionReadWithIfNoneMatch"; - - Patient p = new Patient(); - p.addIdentifier().setSystem("urn:system").setValue(methodName); - p.setId("Patient/" + methodName); - IIdType idv1 = myPatientDao.update(p).getId(); - ourLog.info("Created patient, got id: {}", idv1); - - p = new Patient(); - p.addIdentifier().setSystem("urn:system").setValue(methodName); - p.addName().addFamily("Family Name"); - p.setId("Patient/" + methodName); - IIdType idv2 = myPatientDao.update(p).getId(); - ourLog.info("Updated patient, got id: {}", idv2); + public void testTransactionSingleEmptyResource() { Bundle request = new Bundle(); - request.addEntry().getRequest().setMethod(HTTPVerbEnum.GET).setUrl(idv1.toUnqualifiedVersionless().getValue()); - request.addEntry().getRequest().setMethod(HTTPVerbEnum.GET).setUrl(idv1.toUnqualifiedVersionless().getValue()).setIfNoneMatch("W/\"" + idv1.getVersionIdPart() + "\""); - request.addEntry().getRequest().setMethod(HTTPVerbEnum.GET).setUrl(idv1.toUnqualifiedVersionless().getValue()).setIfNoneMatch("W/\"" + idv2.getVersionIdPart() + "\""); + request.setType(BundleTypeEnum.SEARCH_RESULTS); + Patient p = new Patient(); + request.addEntry().setResource(p).getRequest().setMethod(HTTPVerbEnum.POST); - Bundle resp = mySystemDao.transaction(myRequestDetails, request); + try { + mySystemDao.transaction(myRequestDetails, request); + fail(); + } catch (InvalidRequestException e) { + assertEquals("Unable to process transaction where incoming Bundle.type = searchset", e.getMessage()); + } - assertEquals(3, resp.getEntry().size()); - - Entry nextEntry; - - nextEntry = resp.getEntry().get(0); - assertNotNull(nextEntry.getResource()); - assertEquals(Patient.class, nextEntry.getResource().getClass()); - assertEquals(idv2.toUnqualified(), nextEntry.getResource().getId().toUnqualified()); - assertEquals("200 OK", nextEntry.getResponse().getStatus()); - - nextEntry = resp.getEntry().get(1); - assertNotNull(nextEntry.getResource()); - assertEquals(Patient.class, nextEntry.getResource().getClass()); - assertEquals(idv2.toUnqualified(), nextEntry.getResource().getId().toUnqualified()); - assertEquals("200 OK", nextEntry.getResponse().getStatus()); - - nextEntry = resp.getEntry().get(2); - assertEquals("304 Not Modified", nextEntry.getResponse().getStatus()); - assertNull(nextEntry.getResource()); } @Test @@ -1211,6 +1093,75 @@ public class FhirSystemDaoDstu2Test extends BaseJpaDstu2Test { } + @Test + public void testTransactionWithInvalidType() { + Bundle request = new Bundle(); + request.setType(BundleTypeEnum.SEARCH_RESULTS); + Patient p = new Patient(); + request.addEntry().setResource(p).getRequest().setMethod(HTTPVerbEnum.POST); + + try { + mySystemDao.transaction(myRequestDetails, request); + fail(); + } catch (InvalidRequestException e) { + assertEquals("Unable to process transaction where incoming Bundle.type = searchset", e.getMessage()); + } + + } + + @Test + public void testTransactionWithReferenceToCreateIfNoneExist() { + Bundle bundle = new Bundle(); + bundle.setType(BundleTypeEnum.TRANSACTION); + + Medication med = new Medication(); + IdDt medId = IdDt.newRandomUuid(); + med.setId(medId); + med.getCode().addCoding().setSystem("billscodes").setCode("theCode"); + bundle.addEntry().setResource(med).setFullUrl(medId.getValue()).getRequest().setMethod(HTTPVerbEnum.POST).setIfNoneExist("Medication?code=billscodes|theCode"); + + MedicationOrder mo = new MedicationOrder(); + mo.setMedication(new ResourceReferenceDt(medId)); + bundle.addEntry().setResource(mo).setFullUrl(mo.getId().getValue()).getRequest().setMethod(HTTPVerbEnum.POST); + + ourLog.info("Request:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(bundle)); + + Bundle outcome = mySystemDao.transaction(myRequestDetails, bundle); + ourLog.info("Response:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(outcome)); + + IdDt medId1 = new IdDt(outcome.getEntry().get(0).getResponse().getLocation()); + IdDt medOrderId1 = new IdDt(outcome.getEntry().get(1).getResponse().getLocation()); + + /* + * Again! + */ + + bundle = new Bundle(); + bundle.setType(BundleTypeEnum.TRANSACTION); + + med = new Medication(); + medId = IdDt.newRandomUuid(); + med.getCode().addCoding().setSystem("billscodes").setCode("theCode"); + bundle.addEntry().setResource(med).setFullUrl(medId.getValue()).getRequest().setMethod(HTTPVerbEnum.POST).setIfNoneExist("Medication?code=billscodes|theCode"); + + mo = new MedicationOrder(); + mo.setMedication(new ResourceReferenceDt(medId)); + bundle.addEntry().setResource(mo).setFullUrl(mo.getId().getValue()).getRequest().setMethod(HTTPVerbEnum.POST); + + outcome = mySystemDao.transaction(myRequestDetails, bundle); + + IdDt medId2 = new IdDt(outcome.getEntry().get(0).getResponse().getLocation()); + IdDt medOrderId2 = new IdDt(outcome.getEntry().get(1).getResponse().getLocation()); + + assertTrue(medId1.isIdPartValidLong()); + assertTrue(medId2.isIdPartValidLong()); + assertTrue(medOrderId1.isIdPartValidLong()); + assertTrue(medOrderId2.isIdPartValidLong()); + + assertEquals(medId1, medId2); + assertNotEquals(medOrderId1, medOrderId2); + } + // // // /** @@ -1396,5 +1347,4 @@ public class FhirSystemDaoDstu2Test extends BaseJpaDstu2Test { } - } diff --git a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/BaseResourceProviderDstu2Test.java b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/BaseResourceProviderDstu2Test.java index 199fddc8cc2..e84210343ae 100644 --- a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/BaseResourceProviderDstu2Test.java +++ b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/BaseResourceProviderDstu2Test.java @@ -1,14 +1,11 @@ package ca.uhn.fhir.jpa.provider; import static org.apache.commons.lang3.StringUtils.isNotBlank; -import static org.mockito.Mockito.mock; import java.util.ArrayList; import java.util.List; import java.util.concurrent.TimeUnit; -import javax.servlet.ServletContext; - import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClientBuilder; import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; @@ -18,15 +15,11 @@ import org.eclipse.jetty.servlet.ServletHolder; import org.junit.After; import org.junit.AfterClass; import org.junit.Before; -import org.springframework.web.context.ContextLoaderListener; import org.springframework.web.context.WebApplicationContext; import org.springframework.web.context.support.AnnotationConfigWebApplicationContext; import org.springframework.web.context.support.GenericWebApplicationContext; -import org.springframework.web.context.support.WebApplicationContextUtils; import org.springframework.web.servlet.DispatcherServlet; -import ca.uhn.fhir.jpa.config.DispatcherServletConfig; -import ca.uhn.fhir.jpa.config.TestDstu2Config; import ca.uhn.fhir.jpa.dao.BaseJpaDstu2Test; import ca.uhn.fhir.jpa.testutil.RandomServerPortProvider; import ca.uhn.fhir.model.api.Bundle; diff --git a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/ResourceProviderDstu2Test.java b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/ResourceProviderDstu2Test.java index a2b469cfe35..3e6489cd653 100644 --- a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/ResourceProviderDstu2Test.java +++ b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/ResourceProviderDstu2Test.java @@ -46,8 +46,6 @@ import ca.uhn.fhir.model.api.Bundle; import ca.uhn.fhir.model.api.IResource; import ca.uhn.fhir.model.api.ResourceMetadataKeyEnum; import ca.uhn.fhir.model.api.TemporalPrecisionEnum; -import ca.uhn.fhir.model.dstu.resource.Device; -import ca.uhn.fhir.model.dstu.resource.Practitioner; import ca.uhn.fhir.model.dstu2.composite.CodingDt; import ca.uhn.fhir.model.dstu2.composite.MetaDt; import ca.uhn.fhir.model.dstu2.composite.PeriodDt; @@ -55,6 +53,7 @@ import ca.uhn.fhir.model.dstu2.composite.ResourceReferenceDt; import ca.uhn.fhir.model.dstu2.resource.BaseResource; import ca.uhn.fhir.model.dstu2.resource.Bundle.Entry; import ca.uhn.fhir.model.dstu2.resource.Condition; +import ca.uhn.fhir.model.dstu2.resource.Device; import ca.uhn.fhir.model.dstu2.resource.DiagnosticOrder; import ca.uhn.fhir.model.dstu2.resource.DocumentManifest; import ca.uhn.fhir.model.dstu2.resource.DocumentReference; @@ -67,6 +66,7 @@ import ca.uhn.fhir.model.dstu2.resource.Observation; import ca.uhn.fhir.model.dstu2.resource.Organization; import ca.uhn.fhir.model.dstu2.resource.Parameters; import ca.uhn.fhir.model.dstu2.resource.Patient; +import ca.uhn.fhir.model.dstu2.resource.Practitioner; import ca.uhn.fhir.model.dstu2.resource.Questionnaire; import ca.uhn.fhir.model.dstu2.resource.QuestionnaireResponse; import ca.uhn.fhir.model.dstu2.resource.Subscription; @@ -82,6 +82,7 @@ import ca.uhn.fhir.model.primitive.DateDt; import ca.uhn.fhir.model.primitive.DateTimeDt; import ca.uhn.fhir.model.primitive.IdDt; import ca.uhn.fhir.model.primitive.InstantDt; +import ca.uhn.fhir.model.primitive.StringDt; import ca.uhn.fhir.model.primitive.UnsignedIntDt; import ca.uhn.fhir.model.primitive.UriDt; import ca.uhn.fhir.model.valueset.BundleEntrySearchModeEnum; @@ -90,6 +91,9 @@ import ca.uhn.fhir.rest.api.MethodOutcome; import ca.uhn.fhir.rest.api.SummaryEnum; import ca.uhn.fhir.rest.client.IGenericClient; import ca.uhn.fhir.rest.param.DateRangeParam; +import ca.uhn.fhir.rest.param.StringAndListParam; +import ca.uhn.fhir.rest.param.StringOrListParam; +import ca.uhn.fhir.rest.param.StringParam; import ca.uhn.fhir.rest.server.Constants; import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException; import ca.uhn.fhir.rest.server.exceptions.PreconditionFailedException; @@ -101,8 +105,6 @@ public class ResourceProviderDstu2Test extends BaseResourceProviderDstu2Test { private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ResourceProviderDstu2Test.class); - // private static JpaConformanceProvider ourConfProvider; - @Override public void before() throws Exception { super.before(); @@ -117,6 +119,67 @@ public class ResourceProviderDstu2Test extends BaseResourceProviderDstu2Test { assertEquals(200, resp.getStatusLine().getStatusCode()); } + @Test + public void testEverythingInstanceWithContentFilter() { + Patient pt1 = new Patient(); + pt1.addName().addFamily("Everything").addGiven("Arthur"); + IIdType ptId1 = myPatientDao.create(pt1).getId().toUnqualifiedVersionless(); + + Patient pt2 = new Patient(); + pt2.addName().addFamily("Everything").addGiven("Arthur"); + IIdType ptId2 = myPatientDao.create(pt2).getId().toUnqualifiedVersionless(); + + Device dev1 = new Device(); + dev1.setManufacturer("Some Manufacturer"); + IIdType devId1 = myDeviceDao.create(dev1).getId().toUnqualifiedVersionless(); + + Device dev2 = new Device(); + dev2.setManufacturer("Some Manufacturer 2"); + myDeviceDao.create(dev2).getId().toUnqualifiedVersionless(); + + Observation obs1 = new Observation(); + obs1.getText().setDiv("
OBSTEXT1
"); + obs1.getSubject().setReference(ptId1); + obs1.getCode().addCoding().setCode("CODE1"); + obs1.setValue(new StringDt("obsvalue1")); + obs1.getDevice().setReference(devId1); + IIdType obsId1 = myObservationDao.create(obs1).getId().toUnqualifiedVersionless(); + + Observation obs2 = new Observation(); + obs2.getSubject().setReference(ptId1); + obs2.getCode().addCoding().setCode("CODE2"); + obs2.setValue(new StringDt("obsvalue2")); + IIdType obsId2 = myObservationDao.create(obs2).getId().toUnqualifiedVersionless(); + + Observation obs3 = new Observation(); + obs3.getSubject().setReference(ptId2); + obs3.getCode().addCoding().setCode("CODE3"); + obs3.setValue(new StringDt("obsvalue3")); + IIdType obsId3 = myObservationDao.create(obs3).getId().toUnqualifiedVersionless(); + + List actual; + StringAndListParam param; + + ourLog.info("Pt1:{} Pt2:{} Obs1:{} Obs2:{} Obs3:{}", new Object[] {ptId1.getIdPart(), ptId2.getIdPart(), obsId1.getIdPart(), obsId2.getIdPart(), obsId3.getIdPart()}); + + param = new StringAndListParam(); + param.addAnd(new StringOrListParam().addOr(new StringParam("obsvalue1"))); + + //@formatter:off + Parameters response = ourClient + .operation() + .onInstance(ptId1) + .named("everything") + .withParameter(Parameters.class, Constants.PARAM_CONTENT, new StringDt("obsvalue1")) + .execute(); + //@formatter:on + + actual = toUnqualifiedVersionlessIds((ca.uhn.fhir.model.dstu2.resource.Bundle)response.getParameter().get(0).getResource()); + assertThat(actual, containsInAnyOrder(ptId1, obsId1, devId1)); + + } + + @Test public void testBundleCreate() throws Exception { IGenericClient client = ourClient; diff --git a/pom.xml b/pom.xml index 7ba71727cf4..c5088dbf5d4 100644 --- a/pom.xml +++ b/pom.xml @@ -226,8 +226,8 @@ 10.12.1.1 - 5.0.2.Final - 5.2.1.Final + 5.0.3.Final + 5.2.2.Final 9.3.4.v20151007 2.5.3 2.18.1 @@ -497,6 +497,11 @@ hibernate-validator ${hibernate_validator_version} + + org.hibernate + hibernate-search-orm + 5.5.0.Final + org.javassist javassist diff --git a/src/changes/changes.xml b/src/changes/changes.xml index 1da6d8f9a10..3ace717cb3f 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -15,7 +15,7 @@
  • Commons-lang3 (Core): 3.3.2 -> 3.4
  • Logback (Core): 1.1.2 -> 1.1.3
  • Springframework (JPA, Web Tester): 4.1.5 -> 4.2.2
  • -
  • Hibernate (JPA, Web Tester): 4.2.17 -> 5.0.2
  • +
  • Hibernate (JPA, Web Tester): 4.2.17 -> 5.0.3
  • Hibernate Validator (JPA, Web Tester): 5.2.1 -> 5.2.2
  • Derby (JPA, CLI, Public Server): 10.11.1.1 -> 10.12.1.1
  • Jetty (JPA, CLI, Public Server): 9.2.6.v20141205 -> 9.3.4.v20151007
  • @@ -227,6 +227,12 @@ the server, and correcltly set the same value in JPA server $everything results. + + JPA $everything operations now support new parameters _content + and _text, which work the same way as the same parameters on a + search. This is experimental, since it is not a part of the core + FHIR specification. +