Fix #148 - Add _count support to everything operation
This commit is contained in:
parent
8c37973a78
commit
11507ef97c
|
@ -246,12 +246,11 @@ abstract class BaseResourceReturningMethodBinding extends BaseMethodBinding<Obje
|
|||
}
|
||||
}
|
||||
|
||||
Integer count = RestfulServerUtils.extractCountParameter(theRequest.getServletRequest());
|
||||
|
||||
boolean respondGzip = theRequest.isRespondGzip();
|
||||
|
||||
HttpServletResponse response = theRequest.getServletResponse();
|
||||
Object resultObj = invokeServer(theRequest, params);
|
||||
|
||||
Integer count = RestfulServerUtils.extractCountParameter(theRequest.getServletRequest());
|
||||
boolean respondGzip = theRequest.isRespondGzip();
|
||||
HttpServletResponse response = theRequest.getServletResponse();
|
||||
switch (getReturnType()) {
|
||||
case BUNDLE: {
|
||||
|
||||
|
@ -283,12 +282,15 @@ abstract class BaseResourceReturningMethodBinding extends BaseMethodBinding<Obje
|
|||
RestfulServerUtils.streamResponseAsResource(theServer, response, resource, responseEncoding, prettyPrint, requestIsBrowser, narrativeMode, respondGzip, theRequest.getFhirServerBase());
|
||||
break;
|
||||
} else {
|
||||
Set<Include> includes = getRequestIncludesFromParams(params);
|
||||
Set<Include> includes = getRequestIncludesFromParams(params);
|
||||
|
||||
IBundleProvider result = (IBundleProvider) resultObj;
|
||||
if (count == null) {
|
||||
count = result.preferredPageSize();
|
||||
}
|
||||
|
||||
IVersionSpecificBundleFactory bundleFactory = theServer.getFhirContext().newBundleFactory();
|
||||
bundleFactory.initializeBundleFromBundleProvider(theServer, result, responseEncoding, theRequest.getFhirServerBase(), theRequest.getCompleteUrl(), prettyPrint, 0, count, null,
|
||||
getResponseBundleType(), includes);
|
||||
bundleFactory.initializeBundleFromBundleProvider(theServer, result, responseEncoding, theRequest.getFhirServerBase(), theRequest.getCompleteUrl(), prettyPrint, 0, count, null, getResponseBundleType(), includes);
|
||||
Bundle bundle = bundleFactory.getDstu1Bundle();
|
||||
if (bundle != null) {
|
||||
for (int i = theServer.getInterceptors().size() - 1; i >= 0; i--) {
|
||||
|
|
|
@ -208,6 +208,11 @@ public class HistoryMethodBinding extends BaseResourceReturningMethodBinding {
|
|||
public int size() {
|
||||
return resources.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer preferredPageSize() {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -56,6 +56,11 @@ public class BundleProviders {
|
|||
public InstantDt getPublished() {
|
||||
return published;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer preferredPageSize() {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -26,21 +26,24 @@ import java.util.List;
|
|||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
import ca.uhn.fhir.model.api.*;
|
||||
import ca.uhn.fhir.util.ResourceReferenceInfo;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.commons.lang3.Validate;
|
||||
import org.hl7.fhir.instance.model.IBaseResource;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.context.FhirVersionEnum;
|
||||
import ca.uhn.fhir.context.RuntimeResourceDefinition;
|
||||
import ca.uhn.fhir.model.api.Bundle;
|
||||
import ca.uhn.fhir.model.api.BundleEntry;
|
||||
import ca.uhn.fhir.model.api.IResource;
|
||||
import ca.uhn.fhir.model.api.Include;
|
||||
import ca.uhn.fhir.model.api.ResourceMetadataKeyEnum;
|
||||
import ca.uhn.fhir.model.base.composite.BaseResourceReferenceDt;
|
||||
import ca.uhn.fhir.model.base.resource.BaseOperationOutcome;
|
||||
import ca.uhn.fhir.model.primitive.IdDt;
|
||||
import ca.uhn.fhir.model.valueset.BundleEntrySearchModeEnum;
|
||||
import ca.uhn.fhir.model.valueset.BundleTypeEnum;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
||||
import ca.uhn.fhir.util.ResourceReferenceInfo;
|
||||
|
||||
public class Dstu1BundleFactory implements IVersionSpecificBundleFactory {
|
||||
|
||||
|
@ -253,7 +256,7 @@ public class Dstu1BundleFactory implements IVersionSpecificBundleFactory {
|
|||
}
|
||||
|
||||
@Override
|
||||
public IBaseResource getResourceBundle() {
|
||||
public IResource getResourceBundle() {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
|
|
@ -28,14 +28,37 @@ import ca.uhn.fhir.model.primitive.InstantDt;
|
|||
public interface IBundleProvider {
|
||||
|
||||
/**
|
||||
* Load the given collection of resources by index, plus any additional resources per the
|
||||
* server's processing rules (e.g. _include'd resources, OperationOutcome, etc.). For example,
|
||||
* if the method is invoked with index 0,10 the method might return 10 search results, plus an
|
||||
* additional 20 resources which matched a client's _include specification.
|
||||
*
|
||||
* @param theFromIndex The low index (inclusive) to return
|
||||
* @param theToIndex The high index (exclusive) to return
|
||||
* @return A list of resources. The size of this list must be at least <code>theToIndex - theFromIndex</code>.
|
||||
*/
|
||||
List<IResource> getResources(int theFromIndex, int theToIndex);
|
||||
|
||||
/**
|
||||
* Optionally may be used to signal a preferred page size to the server, e.g. because
|
||||
* the implementing code recognizes that the resources which will be returned by this
|
||||
* implementation are expensive to load so a smaller page size should be used. The value
|
||||
* returned by this method will only be used if the client has not explicitly requested
|
||||
* a page size.
|
||||
*
|
||||
* @return Returns the preferred page size or <code>null</code>
|
||||
*/
|
||||
Integer preferredPageSize();
|
||||
|
||||
/**
|
||||
* Returns the total number of results which match the given query (exclusive of any
|
||||
* _include's or OperationOutcome)
|
||||
*/
|
||||
int size();
|
||||
|
||||
/**
|
||||
* Returns the instant as of which this result was valid
|
||||
*/
|
||||
InstantDt getPublished();
|
||||
|
||||
}
|
||||
|
|
|
@ -23,11 +23,9 @@ package ca.uhn.fhir.rest.server;
|
|||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import ca.uhn.fhir.model.api.Include;
|
||||
import org.hl7.fhir.instance.model.IBaseResource;
|
||||
|
||||
import ca.uhn.fhir.model.api.Bundle;
|
||||
import ca.uhn.fhir.model.api.IResource;
|
||||
import ca.uhn.fhir.model.api.Include;
|
||||
import ca.uhn.fhir.model.valueset.BundleTypeEnum;
|
||||
|
||||
/**
|
||||
|
@ -41,11 +39,11 @@ public interface IVersionSpecificBundleFactory {
|
|||
void addRootPropertiesToBundle(String theAuthor, String theServerBase, String theCompleteUrl, Integer theTotalResults, BundleTypeEnum theBundleType);
|
||||
|
||||
void initializeBundleFromBundleProvider(RestfulServer theServer, IBundleProvider theResult, EncodingEnum theResponseEncoding, String theServerBase, String theCompleteUrl, boolean thePrettyPrint,
|
||||
int theOffset, Integer theLimit, String theSearchId, BundleTypeEnum theBundleType, Set<Include> theIncludes);
|
||||
int theOffset, Integer theCount, String theSearchId, BundleTypeEnum theBundleType, Set<Include> theIncludes);
|
||||
|
||||
Bundle getDstu1Bundle();
|
||||
|
||||
IBaseResource getResourceBundle();
|
||||
IResource getResourceBundle();
|
||||
|
||||
void initializeBundleFromResourceList(String theAuthor, List<IResource> theResult, String theServerBase, String theCompleteUrl, int theTotalResults, BundleTypeEnum theBundleType);
|
||||
|
||||
|
|
|
@ -0,0 +1,98 @@
|
|||
package ca.uhn.fhir.rest.server;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.commons.lang3.Validate;
|
||||
import org.hl7.fhir.instance.model.IBaseResource;
|
||||
|
||||
/**
|
||||
* Used by {@link IBundleProvider} to provide a single page worth of results.
|
||||
*
|
||||
* If the server chooses to, it may return a different number of matching results to the number that the user requested.
|
||||
* For example, if the client requested 100 results but the server decided to return only 10 (perhaps because they were
|
||||
* very large), this value should be set to 10. Note that this count refers only to resources which are included in the
|
||||
* indexes provided to {@link IBundleProvider#getResources(int, int)}, so it should not reflect any additional results
|
||||
* added to the response as a result of _include parameters, OperationOutcome's etc.
|
||||
*/
|
||||
public class ResponseResourceList {
|
||||
/**
|
||||
* Singleton unmodifiable empty list
|
||||
*/
|
||||
public static final ResponseResourceList EMPTY = new EmptyResponseResourceList();
|
||||
|
||||
private List<IBaseResource> myIncludeResults;
|
||||
private List<IBaseResource> myMatchResults;
|
||||
|
||||
/**
|
||||
* Adds an "include" results. Include results are results which are added as a result of <code>_include</code>
|
||||
* directives in search requests.
|
||||
*/
|
||||
public void addIncludeResults(IBaseResource theIncludeResult) {
|
||||
if (myIncludeResults == null) {
|
||||
myIncludeResults = new ArrayList<IBaseResource>();
|
||||
}
|
||||
myIncludeResults.add(theIncludeResult);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a "match" result. A match result is a result added as a direct result of the operation in question. E.g. for
|
||||
* a search invocation a match result would be a result which directly matched the search criteria. For a history
|
||||
* invocation it would be a historical version of a resource or the current version.
|
||||
*/
|
||||
public void addMatchResult(IBaseResource theResource) {
|
||||
Validate.notNull(theResource, "theResource must not be null");
|
||||
if (myMatchResults == null) {
|
||||
myMatchResults = new ArrayList<IBaseResource>();
|
||||
}
|
||||
myMatchResults.add(theResource);
|
||||
}
|
||||
|
||||
public List<IBaseResource> getIncludeResults() {
|
||||
return myIncludeResults;
|
||||
}
|
||||
|
||||
public List<IBaseResource> getMatchResults() {
|
||||
return myMatchResults;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the "include" results. Include results are results which are added as a result of <code>_include</code>
|
||||
* directives in search requests.
|
||||
*/
|
||||
public void setIncludeResults(List<IBaseResource> theIncludeResults) {
|
||||
myIncludeResults = theIncludeResults;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the "match" results. A match result is a result added as a direct result of the operation in question. E.g.
|
||||
* for a search invocation a match result would be a result which directly matched the search criteria. For a
|
||||
* history invocation it would be a historical version of a resource or the current version.
|
||||
*/
|
||||
public void setMatchResults(List<IBaseResource> theMatchResults) {
|
||||
myMatchResults = theMatchResults;
|
||||
}
|
||||
|
||||
private static final class EmptyResponseResourceList extends ResponseResourceList {
|
||||
@Override
|
||||
public void addIncludeResults(IBaseResource theIncludeResult) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addMatchResult(IBaseResource theResource) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setIncludeResults(List<IBaseResource> theIncludeResults) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMatchResults(List<IBaseResource> theMatchResults) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -59,5 +59,10 @@ public class SimpleBundleProvider implements IBundleProvider {
|
|||
public InstantDt getPublished() {
|
||||
return InstantDt.withCurrentTime();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer preferredPageSize() {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -494,6 +494,11 @@ public abstract class BaseFhirDao implements IDao {
|
|||
public int size() {
|
||||
return tuples.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer preferredPageSize() {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -659,6 +659,18 @@ public abstract class BaseFhirResourceDao<T extends IResource> extends BaseFhirD
|
|||
return new HashSet<Long>(q.getResultList());
|
||||
}
|
||||
|
||||
private List<IResource> addResourcesAsIncludesById(List<IResource> theListToPopulate, Set<IdDt> includePids, List<IResource> resources) {
|
||||
if (!includePids.isEmpty()) {
|
||||
ourLog.info("Loading {} included resources", includePids.size());
|
||||
resources = loadResourcesById(includePids);
|
||||
for (IResource next : resources) {
|
||||
ResourceMetadataKeyEnum.ENTRY_SEARCH_MODE.put(next, BundleEntrySearchModeEnum.INCLUDE);
|
||||
}
|
||||
theListToPopulate.addAll(resources);
|
||||
}
|
||||
return resources;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addTag(IdDt theId, TagTypeEnum theTagType, String theScheme, String theTerm, String theLabel) {
|
||||
StopWatch w = new StopWatch();
|
||||
|
@ -713,50 +725,6 @@ public abstract class BaseFhirResourceDao<T extends IResource> extends BaseFhirD
|
|||
return doCreate(theResource, theIfNoneExist, thePerformIndexing);
|
||||
}
|
||||
|
||||
private DaoMethodOutcome doCreate(T theResource, String theIfNoneExist, boolean thePerformIndexing) {
|
||||
StopWatch w = new StopWatch();
|
||||
ResourceTable entity = new ResourceTable();
|
||||
entity.setResourceType(toResourceName(theResource));
|
||||
|
||||
if (isNotBlank(theIfNoneExist)) {
|
||||
Set<Long> match = processMatchUrl(theIfNoneExist, myResourceType);
|
||||
if (match.size() > 1) {
|
||||
String msg = getContext().getLocalizer().getMessage(BaseFhirDao.class, "transactionOperationWithMultipleMatchFailure", "CREATE", theIfNoneExist, match.size());
|
||||
throw new PreconditionFailedException(msg);
|
||||
} else if (match.size() == 1) {
|
||||
Long pid = match.iterator().next();
|
||||
entity = myEntityManager.find(ResourceTable.class, pid);
|
||||
return toMethodOutcome(entity, theResource).setCreated(false);
|
||||
}
|
||||
}
|
||||
|
||||
if (theResource.getId().isEmpty() == false) {
|
||||
if (isValidPid(theResource.getId())) {
|
||||
throw new UnprocessableEntityException(
|
||||
"This server cannot create an entity with a user-specified numeric ID - Client should not specify an ID when creating a new resource, or should include at least one letter in the ID to force a client-defined ID");
|
||||
}
|
||||
createForcedIdIfNeeded(entity, theResource.getId());
|
||||
|
||||
if (entity.getForcedId() != null) {
|
||||
try {
|
||||
translateForcedIdToPid(theResource.getId());
|
||||
throw new UnprocessableEntityException(getContext().getLocalizer().getMessage(BaseFhirResourceDao.class, "duplicateCreateForcedId", theResource.getId().getIdPart()));
|
||||
} catch (ResourceNotFoundException e) {
|
||||
// good, this ID doesn't exist so we can create it
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
updateEntity(theResource, entity, false, null, thePerformIndexing, true);
|
||||
|
||||
DaoMethodOutcome outcome = toMethodOutcome(entity, theResource).setCreated(true);
|
||||
|
||||
notifyWriteCompleted();
|
||||
ourLog.info("Processed create on {} in {}ms", myResourceName, w.getMillisAndRestart());
|
||||
return outcome;
|
||||
}
|
||||
|
||||
private Predicate createCompositeParamPart(CriteriaBuilder builder, Root<ResourceTable> from, RuntimeSearchParam left, IQueryParameterType leftValue) {
|
||||
Predicate retVal = null;
|
||||
switch (left.getParamType()) {
|
||||
|
@ -979,6 +947,50 @@ public abstract class BaseFhirResourceDao<T extends IResource> extends BaseFhirD
|
|||
return toMethodOutcome(savedEntity, null);
|
||||
}
|
||||
|
||||
private DaoMethodOutcome doCreate(T theResource, String theIfNoneExist, boolean thePerformIndexing) {
|
||||
StopWatch w = new StopWatch();
|
||||
ResourceTable entity = new ResourceTable();
|
||||
entity.setResourceType(toResourceName(theResource));
|
||||
|
||||
if (isNotBlank(theIfNoneExist)) {
|
||||
Set<Long> match = processMatchUrl(theIfNoneExist, myResourceType);
|
||||
if (match.size() > 1) {
|
||||
String msg = getContext().getLocalizer().getMessage(BaseFhirDao.class, "transactionOperationWithMultipleMatchFailure", "CREATE", theIfNoneExist, match.size());
|
||||
throw new PreconditionFailedException(msg);
|
||||
} else if (match.size() == 1) {
|
||||
Long pid = match.iterator().next();
|
||||
entity = myEntityManager.find(ResourceTable.class, pid);
|
||||
return toMethodOutcome(entity, theResource).setCreated(false);
|
||||
}
|
||||
}
|
||||
|
||||
if (theResource.getId().isEmpty() == false) {
|
||||
if (isValidPid(theResource.getId())) {
|
||||
throw new UnprocessableEntityException(
|
||||
"This server cannot create an entity with a user-specified numeric ID - Client should not specify an ID when creating a new resource, or should include at least one letter in the ID to force a client-defined ID");
|
||||
}
|
||||
createForcedIdIfNeeded(entity, theResource.getId());
|
||||
|
||||
if (entity.getForcedId() != null) {
|
||||
try {
|
||||
translateForcedIdToPid(theResource.getId());
|
||||
throw new UnprocessableEntityException(getContext().getLocalizer().getMessage(BaseFhirResourceDao.class, "duplicateCreateForcedId", theResource.getId().getIdPart()));
|
||||
} catch (ResourceNotFoundException e) {
|
||||
// good, this ID doesn't exist so we can create it
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
updateEntity(theResource, entity, false, null, thePerformIndexing, true);
|
||||
|
||||
DaoMethodOutcome outcome = toMethodOutcome(entity, theResource).setCreated(true);
|
||||
|
||||
notifyWriteCompleted();
|
||||
ourLog.info("Processed create on {} in {}ms", myResourceName, w.getMillisAndRestart());
|
||||
return outcome;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TagList getAllResourceTags() {
|
||||
StopWatch w = new StopWatch();
|
||||
|
@ -987,6 +999,8 @@ public abstract class BaseFhirResourceDao<T extends IResource> extends BaseFhirD
|
|||
return tags;
|
||||
}
|
||||
|
||||
protected abstract List<Object> getIncludeValues(FhirTerser theTerser, Include theInclude, IResource theResource, RuntimeResourceDefinition theResourceDef);
|
||||
|
||||
public Class<T> getResourceType() {
|
||||
return myResourceType;
|
||||
}
|
||||
|
@ -1092,6 +1106,11 @@ public abstract class BaseFhirResourceDao<T extends IResource> extends BaseFhirD
|
|||
return retVal;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer preferredPageSize() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return count;
|
||||
|
@ -1140,6 +1159,159 @@ public abstract class BaseFhirResourceDao<T extends IResource> extends BaseFhirD
|
|||
}
|
||||
}
|
||||
|
||||
protected void loadReverseIncludes(List<Long> theMatches, Set<Include> theRevIncludes) {
|
||||
if (theMatches.size() == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
HashSet<Long> pidsToInclude = new HashSet<Long>();
|
||||
|
||||
for (Include nextInclude : theRevIncludes) {
|
||||
boolean matchAll = "*".equals(nextInclude.getValue());
|
||||
if (matchAll) {
|
||||
String sql = "SELECT r FROM ResourceLink r WHERE r.myTargetResourcePid IN (:target_pids)";
|
||||
TypedQuery<ResourceLink> q = myEntityManager.createQuery(sql, ResourceLink.class);
|
||||
q.setParameter("target_pids", theMatches);
|
||||
List<ResourceLink> results = q.getResultList();
|
||||
for (ResourceLink resourceLink : results) {
|
||||
pidsToInclude.add(resourceLink.getSourceResourcePid());
|
||||
}
|
||||
} else {
|
||||
int colonIdx = nextInclude.getValue().indexOf(':');
|
||||
if (colonIdx < 2) {
|
||||
continue;
|
||||
}
|
||||
String resType = nextInclude.getValue().substring(0, colonIdx);
|
||||
RuntimeResourceDefinition def = getContext().getResourceDefinition(resType);
|
||||
if (def == null) {
|
||||
ourLog.warn("Unknown resource type in _revinclude=" + nextInclude.getValue());
|
||||
continue;
|
||||
}
|
||||
|
||||
String paramName = nextInclude.getValue().substring(colonIdx + 1);
|
||||
RuntimeSearchParam param = def.getSearchParam(paramName);
|
||||
if (param == null) {
|
||||
ourLog.warn("Unknown param name in _revinclude=" + nextInclude.getValue());
|
||||
continue;
|
||||
}
|
||||
|
||||
for (String nextPath : param.getPathsSplit()) {
|
||||
String sql = "SELECT r FROM ResourceLink r WHERE r.mySourcePath = :src_path AND r.myTargetResourcePid IN (:target_pids)";
|
||||
TypedQuery<ResourceLink> q = myEntityManager.createQuery(sql, ResourceLink.class);
|
||||
q.setParameter("src_path", nextPath);
|
||||
q.setParameter("target_pids", theMatches);
|
||||
List<ResourceLink> results = q.getResultList();
|
||||
for (ResourceLink resourceLink : results) {
|
||||
pidsToInclude.add(resourceLink.getSourceResourcePid());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
theMatches.addAll(pidsToInclude);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MetaDt metaAddOperation(IdDt theResourceId, MetaDt theMetaAdd) {
|
||||
StopWatch w = new StopWatch();
|
||||
BaseHasResource entity = readEntity(theResourceId);
|
||||
if (entity == null) {
|
||||
throw new ResourceNotFoundException(theResourceId);
|
||||
}
|
||||
|
||||
List<TagDefinition> tags = toTagList(theMetaAdd);
|
||||
|
||||
//@formatter:off
|
||||
for (TagDefinition nextDef : tags) {
|
||||
|
||||
boolean hasTag = false;
|
||||
for (BaseTag next : new ArrayList<BaseTag>(entity.getTags())) {
|
||||
if (ObjectUtil.equals(next.getTag().getTagType(), nextDef.getTagType()) &&
|
||||
ObjectUtil.equals(next.getTag().getSystem(), nextDef.getSystem()) &&
|
||||
ObjectUtil.equals(next.getTag().getCode(), nextDef.getCode())) {
|
||||
hasTag = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!hasTag) {
|
||||
entity.setHasTags(true);
|
||||
|
||||
TagDefinition def = getTag(nextDef.getTagType(), nextDef.getSystem(), nextDef.getCode(), nextDef.getDisplay());
|
||||
BaseTag newEntity = entity.addTag(def);
|
||||
myEntityManager.persist(newEntity);
|
||||
}
|
||||
}
|
||||
//@formatter:on
|
||||
|
||||
myEntityManager.merge(entity);
|
||||
notifyWriteCompleted();
|
||||
ourLog.info("Processed metaAddOperation on {} in {}ms", new Object[] { theResourceId, w.getMillisAndRestart() });
|
||||
|
||||
return metaGetOperation(theResourceId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MetaDt metaDeleteOperation(IdDt theResourceId, MetaDt theMetaDel) {
|
||||
StopWatch w = new StopWatch();
|
||||
BaseHasResource entity = readEntity(theResourceId);
|
||||
if (entity == null) {
|
||||
throw new ResourceNotFoundException(theResourceId);
|
||||
}
|
||||
|
||||
List<TagDefinition> tags = toTagList(theMetaDel);
|
||||
|
||||
//@formatter:off
|
||||
for (TagDefinition nextDef : tags) {
|
||||
for (BaseTag next : new ArrayList<BaseTag>(entity.getTags())) {
|
||||
if (ObjectUtil.equals(next.getTag().getTagType(), nextDef.getTagType()) &&
|
||||
ObjectUtil.equals(next.getTag().getSystem(), nextDef.getSystem()) &&
|
||||
ObjectUtil.equals(next.getTag().getCode(), nextDef.getCode())) {
|
||||
myEntityManager.remove(next);
|
||||
entity.getTags().remove(next);
|
||||
}
|
||||
}
|
||||
}
|
||||
//@formatter:on
|
||||
|
||||
if (entity.getTags().isEmpty()) {
|
||||
entity.setHasTags(false);
|
||||
}
|
||||
|
||||
myEntityManager.merge(entity);
|
||||
|
||||
ourLog.info("Processed metaDeleteOperation on {} in {}ms", new Object[] { theResourceId.getValue(), w.getMillisAndRestart() });
|
||||
|
||||
return metaGetOperation(theResourceId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MetaDt metaGetOperation() {
|
||||
String sql = "SELECT d FROM TagDefinition d WHERE d.myId IN (SELECT DISTINCT t.myTagId FROM ResourceTag t WHERE t.myResourceType = :res_type)";
|
||||
TypedQuery<TagDefinition> q = myEntityManager.createQuery(sql, TagDefinition.class);
|
||||
q.setParameter("res_type", myResourceName);
|
||||
List<TagDefinition> tagDefinitions = q.getResultList();
|
||||
|
||||
MetaDt retVal = super.toMetaDt(tagDefinitions);
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MetaDt metaGetOperation(IdDt theId) {
|
||||
Long pid = super.translateForcedIdToPid(theId);
|
||||
|
||||
String sql = "SELECT d FROM TagDefinition d WHERE d.myId IN (SELECT DISTINCT t.myTagId FROM ResourceTag t WHERE t.myResourceType = :res_type AND t.myResourceId = :res_id)";
|
||||
TypedQuery<TagDefinition> q = myEntityManager.createQuery(sql, TagDefinition.class);
|
||||
q.setParameter("res_type", myResourceName);
|
||||
q.setParameter("res_id", pid);
|
||||
List<TagDefinition> tagDefinitions = q.getResultList();
|
||||
|
||||
MetaDt retVal = super.toMetaDt(tagDefinitions);
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
@PostConstruct
|
||||
public void postConstruct() {
|
||||
RuntimeResourceDefinition def = getContext().getResourceDefinition(myResourceType);
|
||||
|
@ -1341,7 +1513,6 @@ public abstract class BaseFhirResourceDao<T extends IResource> extends BaseFhirD
|
|||
}
|
||||
|
||||
IBundleProvider retVal = new IBundleProvider() {
|
||||
|
||||
@Override
|
||||
public InstantDt getPublished() {
|
||||
return now;
|
||||
|
@ -1422,6 +1593,11 @@ public abstract class BaseFhirResourceDao<T extends IResource> extends BaseFhirD
|
|||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer preferredPageSize() {
|
||||
return theParams.getCount();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return pids.size();
|
||||
|
@ -1433,77 +1609,11 @@ public abstract class BaseFhirResourceDao<T extends IResource> extends BaseFhirD
|
|||
return retVal;
|
||||
}
|
||||
|
||||
private List<IResource> addResourcesAsIncludesById(List<IResource> theListToPopulate, Set<IdDt> includePids, List<IResource> resources) {
|
||||
if (!includePids.isEmpty()) {
|
||||
ourLog.info("Loading {} included resources", includePids.size());
|
||||
resources = loadResourcesById(includePids);
|
||||
for (IResource next : resources) {
|
||||
ResourceMetadataKeyEnum.ENTRY_SEARCH_MODE.put(next, BundleEntrySearchModeEnum.INCLUDE);
|
||||
}
|
||||
theListToPopulate.addAll(resources);
|
||||
}
|
||||
return resources;
|
||||
}
|
||||
|
||||
protected void loadReverseIncludes(List<Long> theMatches, Set<Include> theRevIncludes) {
|
||||
if (theMatches.size() == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
HashSet<Long> pidsToInclude = new HashSet<Long>();
|
||||
|
||||
for (Include nextInclude : theRevIncludes) {
|
||||
boolean matchAll = "*".equals(nextInclude.getValue());
|
||||
if (matchAll) {
|
||||
String sql = "SELECT r FROM ResourceLink r WHERE r.myTargetResourcePid IN (:target_pids)";
|
||||
TypedQuery<ResourceLink> q = myEntityManager.createQuery(sql, ResourceLink.class);
|
||||
q.setParameter("target_pids", theMatches);
|
||||
List<ResourceLink> results = q.getResultList();
|
||||
for (ResourceLink resourceLink : results) {
|
||||
pidsToInclude.add(resourceLink.getSourceResourcePid());
|
||||
}
|
||||
} else {
|
||||
int colonIdx = nextInclude.getValue().indexOf(':');
|
||||
if (colonIdx < 2) {
|
||||
continue;
|
||||
}
|
||||
String resType = nextInclude.getValue().substring(0, colonIdx);
|
||||
RuntimeResourceDefinition def = getContext().getResourceDefinition(resType);
|
||||
if (def == null) {
|
||||
ourLog.warn("Unknown resource type in _revinclude=" + nextInclude.getValue());
|
||||
continue;
|
||||
}
|
||||
|
||||
String paramName = nextInclude.getValue().substring(colonIdx + 1);
|
||||
RuntimeSearchParam param = def.getSearchParam(paramName);
|
||||
if (param == null) {
|
||||
ourLog.warn("Unknown param name in _revinclude=" + nextInclude.getValue());
|
||||
continue;
|
||||
}
|
||||
|
||||
for (String nextPath : param.getPathsSplit()) {
|
||||
String sql = "SELECT r FROM ResourceLink r WHERE r.mySourcePath = :src_path AND r.myTargetResourcePid IN (:target_pids)";
|
||||
TypedQuery<ResourceLink> q = myEntityManager.createQuery(sql, ResourceLink.class);
|
||||
q.setParameter("src_path", nextPath);
|
||||
q.setParameter("target_pids", theMatches);
|
||||
List<ResourceLink> results = q.getResultList();
|
||||
for (ResourceLink resourceLink : results) {
|
||||
pidsToInclude.add(resourceLink.getSourceResourcePid());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
theMatches.addAll(pidsToInclude);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBundleProvider search(String theParameterName, IQueryParameterType theValue) {
|
||||
return search(Collections.singletonMap(theParameterName, theValue));
|
||||
}
|
||||
|
||||
protected abstract List<Object> getIncludeValues(FhirTerser theTerser, Include theInclude, IResource theResource, RuntimeResourceDefinition theResourceDef);
|
||||
|
||||
@Override
|
||||
public Set<Long> searchForIds(Map<String, IQueryParameterType> theParams) {
|
||||
SearchParameterMap map = new SearchParameterMap();
|
||||
|
@ -1708,6 +1818,22 @@ public abstract class BaseFhirResourceDao<T extends IResource> extends BaseFhirD
|
|||
return qp;
|
||||
}
|
||||
|
||||
private ArrayList<TagDefinition> toTagList(MetaDt theMeta) {
|
||||
ArrayList<TagDefinition> retVal = new ArrayList<TagDefinition>();
|
||||
|
||||
for (CodingDt next : theMeta.getTag()) {
|
||||
retVal.add(new TagDefinition(TagTypeEnum.TAG, next.getSystem(), next.getCode(), next.getDisplay()));
|
||||
}
|
||||
for (CodingDt next : theMeta.getSecurity()) {
|
||||
retVal.add(new TagDefinition(TagTypeEnum.SECURITY_LABEL, next.getSystem(), next.getCode(), next.getDisplay()));
|
||||
}
|
||||
for (UriDt next : theMeta.getProfile()) {
|
||||
retVal.add(new TagDefinition(TagTypeEnum.PROFILE, BaseFhirDao.NS_JPA_PROFILE, next.getValue(), null));
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DaoMethodOutcome update(T theResource) {
|
||||
return update(theResource, null);
|
||||
|
@ -1788,121 +1914,4 @@ public abstract class BaseFhirResourceDao<T extends IResource> extends BaseFhirD
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public MetaDt metaGetOperation() {
|
||||
String sql = "SELECT d FROM TagDefinition d WHERE d.myId IN (SELECT DISTINCT t.myTagId FROM ResourceTag t WHERE t.myResourceType = :res_type)";
|
||||
TypedQuery<TagDefinition> q = myEntityManager.createQuery(sql, TagDefinition.class);
|
||||
q.setParameter("res_type", myResourceName);
|
||||
List<TagDefinition> tagDefinitions = q.getResultList();
|
||||
|
||||
MetaDt retVal = super.toMetaDt(tagDefinitions);
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MetaDt metaGetOperation(IdDt theId) {
|
||||
Long pid = super.translateForcedIdToPid(theId);
|
||||
|
||||
String sql = "SELECT d FROM TagDefinition d WHERE d.myId IN (SELECT DISTINCT t.myTagId FROM ResourceTag t WHERE t.myResourceType = :res_type AND t.myResourceId = :res_id)";
|
||||
TypedQuery<TagDefinition> q = myEntityManager.createQuery(sql, TagDefinition.class);
|
||||
q.setParameter("res_type", myResourceName);
|
||||
q.setParameter("res_id", pid);
|
||||
List<TagDefinition> tagDefinitions = q.getResultList();
|
||||
|
||||
MetaDt retVal = super.toMetaDt(tagDefinitions);
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MetaDt metaDeleteOperation(IdDt theResourceId, MetaDt theMetaDel) {
|
||||
StopWatch w = new StopWatch();
|
||||
BaseHasResource entity = readEntity(theResourceId);
|
||||
if (entity == null) {
|
||||
throw new ResourceNotFoundException(theResourceId);
|
||||
}
|
||||
|
||||
List<TagDefinition> tags = toTagList(theMetaDel);
|
||||
|
||||
//@formatter:off
|
||||
for (TagDefinition nextDef : tags) {
|
||||
for (BaseTag next : new ArrayList<BaseTag>(entity.getTags())) {
|
||||
if (ObjectUtil.equals(next.getTag().getTagType(), nextDef.getTagType()) &&
|
||||
ObjectUtil.equals(next.getTag().getSystem(), nextDef.getSystem()) &&
|
||||
ObjectUtil.equals(next.getTag().getCode(), nextDef.getCode())) {
|
||||
myEntityManager.remove(next);
|
||||
entity.getTags().remove(next);
|
||||
}
|
||||
}
|
||||
}
|
||||
//@formatter:on
|
||||
|
||||
if (entity.getTags().isEmpty()) {
|
||||
entity.setHasTags(false);
|
||||
}
|
||||
|
||||
myEntityManager.merge(entity);
|
||||
|
||||
ourLog.info("Processed metaDeleteOperation on {} in {}ms", new Object[] { theResourceId.getValue(), w.getMillisAndRestart() });
|
||||
|
||||
return metaGetOperation(theResourceId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MetaDt metaAddOperation(IdDt theResourceId, MetaDt theMetaAdd) {
|
||||
StopWatch w = new StopWatch();
|
||||
BaseHasResource entity = readEntity(theResourceId);
|
||||
if (entity == null) {
|
||||
throw new ResourceNotFoundException(theResourceId);
|
||||
}
|
||||
|
||||
List<TagDefinition> tags = toTagList(theMetaAdd);
|
||||
|
||||
//@formatter:off
|
||||
for (TagDefinition nextDef : tags) {
|
||||
|
||||
boolean hasTag = false;
|
||||
for (BaseTag next : new ArrayList<BaseTag>(entity.getTags())) {
|
||||
if (ObjectUtil.equals(next.getTag().getTagType(), nextDef.getTagType()) &&
|
||||
ObjectUtil.equals(next.getTag().getSystem(), nextDef.getSystem()) &&
|
||||
ObjectUtil.equals(next.getTag().getCode(), nextDef.getCode())) {
|
||||
hasTag = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!hasTag) {
|
||||
entity.setHasTags(true);
|
||||
|
||||
TagDefinition def = getTag(nextDef.getTagType(), nextDef.getSystem(), nextDef.getCode(), nextDef.getDisplay());
|
||||
BaseTag newEntity = entity.addTag(def);
|
||||
myEntityManager.persist(newEntity);
|
||||
}
|
||||
}
|
||||
//@formatter:on
|
||||
|
||||
myEntityManager.merge(entity);
|
||||
notifyWriteCompleted();
|
||||
ourLog.info("Processed metaAddOperation on {} in {}ms", new Object[] { theResourceId, w.getMillisAndRestart() });
|
||||
|
||||
return metaGetOperation(theResourceId);
|
||||
}
|
||||
|
||||
private ArrayList<TagDefinition> toTagList(MetaDt theMeta) {
|
||||
ArrayList<TagDefinition> retVal = new ArrayList<TagDefinition>();
|
||||
|
||||
for (CodingDt next : theMeta.getTag()) {
|
||||
retVal.add(new TagDefinition(TagTypeEnum.TAG, next.getSystem(), next.getCode(), next.getDisplay()));
|
||||
}
|
||||
for (CodingDt next : theMeta.getSecurity()) {
|
||||
retVal.add(new TagDefinition(TagTypeEnum.SECURITY_LABEL, next.getSystem(), next.getCode(), next.getDisplay()));
|
||||
}
|
||||
for (UriDt next : theMeta.getProfile()) {
|
||||
retVal.add(new TagDefinition(TagTypeEnum.PROFILE, BaseFhirDao.NS_JPA_PROFILE, next.getValue(), null));
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -15,6 +15,7 @@ import java.util.Date;
|
|||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.TreeSet;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
|
@ -50,6 +51,7 @@ import ca.uhn.fhir.model.dstu.resource.Practitioner;
|
|||
import ca.uhn.fhir.model.dstu2.composite.PeriodDt;
|
||||
import ca.uhn.fhir.model.dstu2.composite.ResourceReferenceDt;
|
||||
import ca.uhn.fhir.model.dstu2.resource.Bundle.Entry;
|
||||
import ca.uhn.fhir.model.dstu2.resource.Condition;
|
||||
import ca.uhn.fhir.model.dstu2.resource.DiagnosticOrder;
|
||||
import ca.uhn.fhir.model.dstu2.resource.DocumentManifest;
|
||||
import ca.uhn.fhir.model.dstu2.resource.DocumentReference;
|
||||
|
@ -62,7 +64,9 @@ import ca.uhn.fhir.model.dstu2.resource.Parameters;
|
|||
import ca.uhn.fhir.model.dstu2.resource.Patient;
|
||||
import ca.uhn.fhir.model.dstu2.valueset.EncounterClassEnum;
|
||||
import ca.uhn.fhir.model.dstu2.valueset.EncounterStateEnum;
|
||||
import ca.uhn.fhir.model.dstu2.valueset.HTTPVerbEnum;
|
||||
import ca.uhn.fhir.model.primitive.IdDt;
|
||||
import ca.uhn.fhir.model.primitive.IntegerDt;
|
||||
import ca.uhn.fhir.model.valueset.BundleEntrySearchModeEnum;
|
||||
import ca.uhn.fhir.model.valueset.BundleTypeEnum;
|
||||
import ca.uhn.fhir.narrative.DefaultThymeleafNarrativeGenerator;
|
||||
|
@ -127,15 +131,15 @@ public class ResourceProviderDstu2Test {
|
|||
|
||||
HttpPost post = new HttpPost(ourServerBase + "/Patient");
|
||||
post.setEntity(new StringEntity(resource, ContentType.create(Constants.CT_FHIR_XML, "UTF-8")));
|
||||
|
||||
|
||||
CloseableHttpResponse response = ourHttpClient.execute(post);
|
||||
try {
|
||||
|
||||
|
||||
assertEquals(201, response.getStatusLine().getStatusCode());
|
||||
assertThat(response.getFirstHeader(Constants.HEADER_LOCATION_LC).getValue(), startsWith(ourServerBase + "/Patient/"));
|
||||
assertThat(response.getFirstHeader(Constants.HEADER_LOCATION_LC).getValue(), endsWith("/_history/1"));
|
||||
assertThat(response.getFirstHeader(Constants.HEADER_LOCATION_LC).getValue(), not(containsString("1777")));
|
||||
|
||||
|
||||
} finally {
|
||||
response.close();
|
||||
}
|
||||
|
@ -144,7 +148,7 @@ public class ResourceProviderDstu2Test {
|
|||
@Test
|
||||
public void testCreateResourceConditional() throws IOException {
|
||||
String methodName = "testCreateResourceConditional";
|
||||
|
||||
|
||||
Patient pt = new Patient();
|
||||
pt.addName().addFamily(methodName);
|
||||
String resource = ourFhirCtx.newXmlParser().encodeResourceToString(pt);
|
||||
|
@ -161,7 +165,7 @@ public class ResourceProviderDstu2Test {
|
|||
} finally {
|
||||
response.close();
|
||||
}
|
||||
|
||||
|
||||
post = new HttpPost(ourServerBase + "/Patient");
|
||||
post.setEntity(new StringEntity(resource, ContentType.create(Constants.CT_FHIR_XML, "UTF-8")));
|
||||
post.addHeader(Constants.HEADER_IF_NONE_EXIST, "Patient?name=" + methodName);
|
||||
|
@ -173,13 +177,13 @@ public class ResourceProviderDstu2Test {
|
|||
} finally {
|
||||
response.close();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateResourceConditional() throws IOException {
|
||||
String methodName = "testUpdateResourceConditional";
|
||||
|
||||
|
||||
Patient pt = new Patient();
|
||||
pt.addName().addFamily(methodName);
|
||||
String resource = ourFhirCtx.newXmlParser().encodeResourceToString(pt);
|
||||
|
@ -196,7 +200,7 @@ public class ResourceProviderDstu2Test {
|
|||
} finally {
|
||||
response.close();
|
||||
}
|
||||
|
||||
|
||||
HttpPut put = new HttpPut(ourServerBase + "/Patient?name=" + methodName);
|
||||
put.setEntity(new StringEntity(resource, ContentType.create(Constants.CT_FHIR_XML, "UTF-8")));
|
||||
response = ourHttpClient.execute(put);
|
||||
|
@ -208,13 +212,13 @@ public class ResourceProviderDstu2Test {
|
|||
} finally {
|
||||
response.close();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testDeleteResourceConditional() throws IOException {
|
||||
String methodName = "testDeleteResourceConditional";
|
||||
|
||||
|
||||
Patient pt = new Patient();
|
||||
pt.addName().addFamily(methodName);
|
||||
String resource = ourFhirCtx.newXmlParser().encodeResourceToString(pt);
|
||||
|
@ -231,7 +235,7 @@ public class ResourceProviderDstu2Test {
|
|||
} finally {
|
||||
response.close();
|
||||
}
|
||||
|
||||
|
||||
HttpDelete delete = new HttpDelete(ourServerBase + "/Patient?name=" + methodName);
|
||||
response = ourHttpClient.execute(delete);
|
||||
try {
|
||||
|
@ -239,7 +243,7 @@ public class ResourceProviderDstu2Test {
|
|||
} finally {
|
||||
response.close();
|
||||
}
|
||||
|
||||
|
||||
HttpGet read = new HttpGet(ourServerBase + "/Patient/" + id.getIdPart());
|
||||
response = ourHttpClient.execute(read);
|
||||
try {
|
||||
|
@ -257,7 +261,7 @@ public class ResourceProviderDstu2Test {
|
|||
@Test
|
||||
public void testReadAllInstancesOfType() throws Exception {
|
||||
Patient pat;
|
||||
|
||||
|
||||
pat = new Patient();
|
||||
pat.addIdentifier().setSystem("urn:system").setValue("testReadAllInstancesOfType_01");
|
||||
ourClient.create().resource(pat).prettyPrint().encodedXml().execute().getId();
|
||||
|
@ -277,11 +281,10 @@ public class ResourceProviderDstu2Test {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testSearchWithInclude() throws Exception {
|
||||
Organization org = new Organization();
|
||||
org.addIdentifier().setSystem("urn:system:rpdstu2").setValue( "testSearchWithInclude01");
|
||||
org.addIdentifier().setSystem("urn:system:rpdstu2").setValue("testSearchWithInclude01");
|
||||
IdDt orgId = ourClient.create().resource(org).prettyPrint().encodedXml().execute().getId();
|
||||
|
||||
Patient pat = new Patient();
|
||||
|
@ -298,7 +301,7 @@ public class ResourceProviderDstu2Test {
|
|||
.prettyPrint()
|
||||
.execute();
|
||||
//@formatter:on
|
||||
|
||||
|
||||
assertEquals(2, found.size());
|
||||
assertEquals(Patient.class, found.getEntries().get(0).getResource().getClass());
|
||||
assertEquals(BundleEntrySearchModeEnum.MATCH, found.getEntries().get(0).getSearchMode().getValueAsEnum());
|
||||
|
@ -311,16 +314,16 @@ public class ResourceProviderDstu2Test {
|
|||
@Test
|
||||
public void testEverythingOperation() throws Exception {
|
||||
String methodName = "testEverythingOperation";
|
||||
|
||||
|
||||
Organization org1 = new Organization();
|
||||
org1.setName(methodName + "1");
|
||||
IdDt orgId1 = ourClient.create().resource(org1).execute().getId();
|
||||
|
||||
|
||||
Patient p = new Patient();
|
||||
p.addName().addFamily(methodName);
|
||||
p.getManagingOrganization().setReference(orgId1);
|
||||
IdDt patientId = ourClient.create().resource(p).execute().getId();
|
||||
|
||||
|
||||
Organization org2 = new Organization();
|
||||
org2.setName(methodName + "1");
|
||||
IdDt orgId2 = ourClient.create().resource(org2).execute().getId();
|
||||
|
@ -328,31 +331,30 @@ public class ResourceProviderDstu2Test {
|
|||
Device dev = new Device();
|
||||
dev.setModel(methodName);
|
||||
dev.getOwner().setReference(orgId2);
|
||||
IdDt devId = ourClient.create().resource(dev).execute().getId();
|
||||
|
||||
IdDt devId = ourClient.create().resource(dev).execute().getId();
|
||||
|
||||
Observation obs = new Observation();
|
||||
obs.getSubject().setReference(patientId);
|
||||
obs.getDevice().setReference(devId);
|
||||
IdDt obsId = ourClient.create().resource(obs).execute().getId();
|
||||
|
||||
|
||||
Encounter enc = new Encounter();
|
||||
enc.getPatient().setReference(patientId);
|
||||
IdDt encId = ourClient.create().resource(enc).execute().getId();
|
||||
|
||||
|
||||
Parameters output = ourClient.operation().onInstance(patientId).named("everything").withNoParameters(Parameters.class).execute();
|
||||
ca.uhn.fhir.model.dstu2.resource.Bundle b = (ca.uhn.fhir.model.dstu2.resource.Bundle) output.getParameterFirstRep().getResource();
|
||||
|
||||
|
||||
Set<IdDt> ids = new HashSet<IdDt>();
|
||||
for (Entry next : b.getEntry()) {
|
||||
ids.add(next.getResource().getId());
|
||||
}
|
||||
|
||||
|
||||
|
||||
assertThat(ids, containsInAnyOrder(patientId, devId, obsId, encId, orgId1, orgId2));
|
||||
|
||||
|
||||
// _revinclude's are counted but not _include's
|
||||
assertEquals(3, b.getTotal().intValue());
|
||||
|
||||
|
||||
ourLog.info(ids.toString());
|
||||
}
|
||||
|
||||
|
@ -360,33 +362,101 @@ public class ResourceProviderDstu2Test {
|
|||
* See #147
|
||||
*/
|
||||
@Test
|
||||
public void testEverythingDoesnRepeatPatient() throws Exception {
|
||||
public void testEverythingDoesntRepeatPatient() throws Exception {
|
||||
ca.uhn.fhir.model.dstu2.resource.Bundle b;
|
||||
b = ourFhirCtx.newJsonParser().parseResource(ca.uhn.fhir.model.dstu2.resource.Bundle.class, new InputStreamReader(ResourceProviderDstu2Test.class.getResourceAsStream("/bug147-bundle.json")));
|
||||
|
||||
|
||||
ca.uhn.fhir.model.dstu2.resource.Bundle resp = ourClient.transaction().withBundle(b).execute();
|
||||
|
||||
ourLog.info(ourFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(resp));
|
||||
|
||||
IdDt patientId = new IdDt(resp.getEntry().get(1).getTransactionResponse().getLocation());
|
||||
assertEquals("Patient", patientId.getResourceType());
|
||||
|
||||
Parameters output = ourClient.operation().onInstance(patientId).named("everything").withNoParameters(Parameters.class).execute();
|
||||
b = (ca.uhn.fhir.model.dstu2.resource.Bundle) output.getParameterFirstRep().getResource();
|
||||
|
||||
List<IdDt> ids = new ArrayList<IdDt>();
|
||||
boolean dupes = false;
|
||||
for (Entry next : b.getEntry()) {
|
||||
IdDt toAdd = next.getResource().getId().toUnqualifiedVersionless();
|
||||
dupes = dupes | ids.contains(toAdd);
|
||||
for (Entry next : resp.getEntry()) {
|
||||
IdDt toAdd = new IdDt(next.getTransactionResponse().getLocation()).toUnqualifiedVersionless();
|
||||
ids.add(toAdd);
|
||||
}
|
||||
|
||||
ourLog.info(ids.toString());
|
||||
|
||||
assertFalse(ids.toString(), dupes);
|
||||
ourLog.info("Created: " + ids.toString());
|
||||
|
||||
IdDt patientId = new IdDt(resp.getEntry().get(1).getTransactionResponse().getLocation());
|
||||
assertEquals("Patient", patientId.getResourceType());
|
||||
|
||||
{
|
||||
Parameters output = ourClient.operation().onInstance(patientId).named("everything").withNoParameters(Parameters.class).execute();
|
||||
b = (ca.uhn.fhir.model.dstu2.resource.Bundle) output.getParameterFirstRep().getResource();
|
||||
|
||||
ids = new ArrayList<IdDt>();
|
||||
boolean dupes = false;
|
||||
for (Entry next : b.getEntry()) {
|
||||
IdDt toAdd = next.getResource().getId().toUnqualifiedVersionless();
|
||||
dupes = dupes | ids.contains(toAdd);
|
||||
ids.add(toAdd);
|
||||
}
|
||||
ourLog.info("$everything: " + ids.toString());
|
||||
|
||||
assertFalse(ids.toString(), dupes);
|
||||
|
||||
/*
|
||||
* Condition/11 is the 11th resource and the default page size is 10 so we don't show the 11th.
|
||||
*/
|
||||
assertThat(ids.toString(), not(containsString("Condition")));
|
||||
}
|
||||
|
||||
/*
|
||||
* Now try with a size specified
|
||||
*/
|
||||
{
|
||||
Parameters input = new Parameters();
|
||||
input.addParameter().setName(Constants.PARAM_COUNT).setValue(new IntegerDt(100));
|
||||
Parameters output = ourClient.operation().onInstance(patientId).named("everything").withParameters(input).execute();
|
||||
b = (ca.uhn.fhir.model.dstu2.resource.Bundle) output.getParameterFirstRep().getResource();
|
||||
|
||||
ids = new ArrayList<IdDt>();
|
||||
boolean dupes = false;
|
||||
for (Entry next : b.getEntry()) {
|
||||
IdDt toAdd = next.getResource().getId().toUnqualifiedVersionless();
|
||||
dupes = dupes | ids.contains(toAdd);
|
||||
ids.add(toAdd);
|
||||
}
|
||||
ourLog.info("$everything: " + ids.toString());
|
||||
|
||||
assertFalse(ids.toString(), dupes);
|
||||
assertThat(ids.toString(), containsString("Condition"));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* See #148
|
||||
*/
|
||||
@Test
|
||||
public void testEverythingIncludesCondition() throws Exception {
|
||||
ca.uhn.fhir.model.dstu2.resource.Bundle b = new ca.uhn.fhir.model.dstu2.resource.Bundle();
|
||||
Patient p = new Patient();
|
||||
p.setId("1");
|
||||
b.addEntry().setResource(p).getTransaction().setMethod(HTTPVerbEnum.POST);
|
||||
|
||||
Condition c = new Condition();
|
||||
c.getPatient().setReference("Patient/1");
|
||||
b.addEntry().setResource(c).getTransaction().setMethod(HTTPVerbEnum.POST);
|
||||
|
||||
ca.uhn.fhir.model.dstu2.resource.Bundle resp = ourClient.transaction().withBundle(b).execute();
|
||||
|
||||
ourLog.info(ourFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(resp));
|
||||
|
||||
IdDt patientId = new IdDt(resp.getEntry().get(1).getTransactionResponse().getLocation());
|
||||
assertEquals("Patient", patientId.getResourceType());
|
||||
|
||||
Parameters output = ourClient.operation().onInstance(patientId).named("everything").withNoParameters(Parameters.class).execute();
|
||||
b = (ca.uhn.fhir.model.dstu2.resource.Bundle) output.getParameterFirstRep().getResource();
|
||||
|
||||
List<IdDt> ids = new ArrayList<IdDt>();
|
||||
for (Entry next : b.getEntry()) {
|
||||
IdDt toAdd = next.getResource().getId().toUnqualifiedVersionless();
|
||||
ids.add(toAdd);
|
||||
}
|
||||
|
||||
assertThat(ids.toString(), containsString("Patient/"));
|
||||
assertThat(ids.toString(), containsString("Condition/"));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCountParam() throws Exception {
|
||||
// NB this does not get used- The paging provider has its own limits built in
|
||||
|
@ -435,7 +505,7 @@ public class ResourceProviderDstu2Test {
|
|||
public void testDocumentManifestResources() throws Exception {
|
||||
ourFhirCtx.getResourceDefinition(Practitioner.class);
|
||||
ourFhirCtx.getResourceDefinition(ca.uhn.fhir.model.dstu.resource.DocumentManifest.class);
|
||||
|
||||
|
||||
IGenericClient client = ourClient;
|
||||
|
||||
int initialSize = client.search().forResource(DocumentManifest.class).execute().size();
|
||||
|
@ -477,7 +547,7 @@ public class ResourceProviderDstu2Test {
|
|||
int initialSize = client.search().forResource(DiagnosticOrder.class).execute().size();
|
||||
|
||||
DiagnosticOrder res = new DiagnosticOrder();
|
||||
res.addIdentifier().setSystem("urn:foo").setValue( "123");
|
||||
res.addIdentifier().setSystem("urn:foo").setValue("123");
|
||||
|
||||
client.create().resource(res).execute();
|
||||
|
||||
|
@ -737,7 +807,7 @@ public class ResourceProviderDstu2Test {
|
|||
RestfulServer restServer = new RestfulServer();
|
||||
ourFhirCtx = FhirContext.forDstu2();
|
||||
restServer.setFhirContext(ourFhirCtx);
|
||||
|
||||
|
||||
ourServerBase = "http://localhost:" + port + "/fhir/context";
|
||||
|
||||
ourAppCtx = new ClassPathXmlApplicationContext("hapi-fhir-server-resourceproviders-dstu2.xml", "fhir-jpabase-spring-test-config.xml");
|
||||
|
@ -771,7 +841,7 @@ public class ResourceProviderDstu2Test {
|
|||
ourFhirCtx.getRestfulClientFactory().setSocketTimeout(1200 * 1000);
|
||||
ourClient = ourFhirCtx.newRestfulGenericClient(ourServerBase);
|
||||
ourClient.registerInterceptor(new LoggingInterceptor(true));
|
||||
|
||||
|
||||
PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(5000, TimeUnit.MILLISECONDS);
|
||||
HttpClientBuilder builder = HttpClientBuilder.create();
|
||||
builder.setConnectionManager(connectionManager);
|
||||
|
|
|
@ -24,7 +24,11 @@
|
|||
"entry":
|
||||
[
|
||||
{
|
||||
"transaction": { "method":"POST" },
|
||||
"transaction":
|
||||
{
|
||||
"method": "POST"
|
||||
},
|
||||
|
||||
"resource":
|
||||
{
|
||||
"resourceType": "Patient",
|
||||
|
@ -114,7 +118,11 @@
|
|||
},
|
||||
|
||||
{
|
||||
"transaction": { "method":"POST" },
|
||||
"transaction":
|
||||
{
|
||||
"method": "POST"
|
||||
},
|
||||
|
||||
"resource":
|
||||
{
|
||||
"resourceType": "Encounter",
|
||||
|
@ -148,7 +156,11 @@
|
|||
},
|
||||
|
||||
{
|
||||
"transaction": { "method":"POST" },
|
||||
"transaction":
|
||||
{
|
||||
"method": "POST"
|
||||
},
|
||||
|
||||
"resource":
|
||||
{
|
||||
"resourceType": "ClinicalImpression",
|
||||
|
@ -193,7 +205,11 @@
|
|||
},
|
||||
|
||||
{
|
||||
"transaction": { "method":"POST" },
|
||||
"transaction":
|
||||
{
|
||||
"method": "POST"
|
||||
},
|
||||
|
||||
"resource":
|
||||
{
|
||||
"resourceType": "ClinicalImpression",
|
||||
|
@ -238,7 +254,11 @@
|
|||
},
|
||||
|
||||
{
|
||||
"transaction": { "method":"POST" },
|
||||
"transaction":
|
||||
{
|
||||
"method": "POST"
|
||||
},
|
||||
|
||||
"resource":
|
||||
{
|
||||
"resourceType": "Encounter",
|
||||
|
@ -267,7 +287,11 @@
|
|||
},
|
||||
|
||||
{
|
||||
"transaction": { "method":"POST" },
|
||||
"transaction":
|
||||
{
|
||||
"method": "POST"
|
||||
},
|
||||
|
||||
"resource":
|
||||
{
|
||||
"resourceType": "ClinicalImpression",
|
||||
|
@ -311,7 +335,11 @@
|
|||
},
|
||||
|
||||
{
|
||||
"transaction": { "method":"POST" },
|
||||
"transaction":
|
||||
{
|
||||
"method": "POST"
|
||||
},
|
||||
|
||||
"resource":
|
||||
{
|
||||
"resourceType": "Encounter",
|
||||
|
@ -340,7 +368,11 @@
|
|||
},
|
||||
|
||||
{
|
||||
"transaction": { "method":"POST" },
|
||||
"transaction":
|
||||
{
|
||||
"method": "POST"
|
||||
},
|
||||
|
||||
"resource":
|
||||
{
|
||||
"resourceType": "ClinicalImpression",
|
||||
|
@ -384,7 +416,11 @@
|
|||
},
|
||||
|
||||
{
|
||||
"transaction": { "method":"POST" },
|
||||
"transaction":
|
||||
{
|
||||
"method": "POST"
|
||||
},
|
||||
|
||||
"resource":
|
||||
{
|
||||
"resourceType": "Observation",
|
||||
|
@ -417,7 +453,11 @@
|
|||
},
|
||||
|
||||
{
|
||||
"transaction": { "method":"POST" },
|
||||
"transaction":
|
||||
{
|
||||
"method": "POST"
|
||||
},
|
||||
|
||||
"resource":
|
||||
{
|
||||
"resourceType": "Observation",
|
||||
|
@ -447,7 +487,50 @@
|
|||
{
|
||||
"mode": "match"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"transaction":
|
||||
{
|
||||
"method": "POST"
|
||||
},
|
||||
|
||||
"resource":
|
||||
{
|
||||
"resourceType": "Condition",
|
||||
"id": "20443",
|
||||
"meta":
|
||||
{
|
||||
"versionId": "1",
|
||||
"lastUpdated": "2015-04-03T22:56:49.886-04:00"
|
||||
},
|
||||
|
||||
"text":
|
||||
{
|
||||
"status": "generated",
|
||||
"div": "<div xmlns=\"http://www.w3.org/1999/xhtml\">pharyngitis working </div>"
|
||||
},
|
||||
|
||||
"patient":
|
||||
{
|
||||
"reference": "Patient/1702",
|
||||
"display": "Eve Everywoman "
|
||||
},
|
||||
|
||||
"code":
|
||||
{
|
||||
"coding":
|
||||
[
|
||||
{
|
||||
"system": "http://loinc.org",
|
||||
"code": "28397-8",
|
||||
"display": "pharyngitis"
|
||||
}
|
||||
],
|
||||
|
||||
"text": "pharyngitis"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
|
@ -35,7 +35,7 @@
|
|||
<property name="persistenceUnitName" value="FHIR_UT" />
|
||||
<property name="jpaVendorAdapter">
|
||||
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
|
||||
<property name="showSql" value="true" />
|
||||
<property name="showSql" value="false" />
|
||||
<property name="generateDdl" value="true" />
|
||||
<!-- <property name="databasePlatform" value="org.hibernate.dialect.HSQLDialect" /> -->
|
||||
<property name="databasePlatform" value="org.hibernate.dialect.DerbyTenSevenDialect" />
|
||||
|
|
|
@ -268,7 +268,7 @@ public class Dstu2BundleFactory implements IVersionSpecificBundleFactory {
|
|||
}
|
||||
|
||||
@Override
|
||||
public IBaseResource getResourceBundle() {
|
||||
public IResource getResourceBundle() {
|
||||
return myBundle;
|
||||
}
|
||||
|
||||
|
|
|
@ -123,6 +123,9 @@
|
|||
the main focus resource if it was referred to in a deep chain. Thanks
|
||||
to David Hay for reporting!
|
||||
</action>
|
||||
<action type="add" issue="148">
|
||||
JPA Server $everything operation now allows a _count parameter
|
||||
</action>
|
||||
</release>
|
||||
<release version="0.9" date="2015-Mar-14">
|
||||
<action type="add">
|
||||
|
|
Loading…
Reference in New Issue