Merge branch 'master' into issue-2786-upload-terminology-command-add-explicit-current-version-control
This commit is contained in:
commit
264dfee099
|
@ -21,20 +21,29 @@ package ca.uhn.fhir.interceptor.model;
|
|||
*/
|
||||
|
||||
import ca.uhn.fhir.rest.api.RestOperationTypeEnum;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.hl7.fhir.instance.model.api.IIdType;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public class ReadPartitionIdRequestDetails {
|
||||
|
||||
private final String myResourceType;
|
||||
private final RestOperationTypeEnum myRestOperationType;
|
||||
private final IIdType myReadResourceId;
|
||||
private final Object mySearchParams;
|
||||
private final IBaseResource myConditionalTargetOrNull;
|
||||
|
||||
public ReadPartitionIdRequestDetails(String theResourceType, RestOperationTypeEnum theRestOperationType, IIdType theReadResourceId, Object theSearchParams) {
|
||||
public ReadPartitionIdRequestDetails(String theResourceType, RestOperationTypeEnum theRestOperationType, IIdType theReadResourceId, Object theSearchParams, @Nullable IBaseResource theConditionalTargetOrNull) {
|
||||
myResourceType = theResourceType;
|
||||
myRestOperationType = theRestOperationType;
|
||||
myReadResourceId = theReadResourceId;
|
||||
mySearchParams = theSearchParams;
|
||||
myConditionalTargetOrNull = theConditionalTargetOrNull;
|
||||
}
|
||||
|
||||
public IBaseResource getConditionalTargetOrNull() {
|
||||
return myConditionalTargetOrNull;
|
||||
}
|
||||
|
||||
public String getResourceType() {
|
||||
|
@ -55,11 +64,11 @@ public class ReadPartitionIdRequestDetails {
|
|||
|
||||
public static ReadPartitionIdRequestDetails forRead(String theResourceType, IIdType theId, boolean theIsVread) {
|
||||
RestOperationTypeEnum op = theIsVread ? RestOperationTypeEnum.VREAD : RestOperationTypeEnum.READ;
|
||||
return new ReadPartitionIdRequestDetails(theResourceType, op, theId.withResourceType(theResourceType), null);
|
||||
return new ReadPartitionIdRequestDetails(theResourceType, op, theId.withResourceType(theResourceType), null, null);
|
||||
}
|
||||
|
||||
public static ReadPartitionIdRequestDetails forSearchType(String theResourceType, Object theParams) {
|
||||
return new ReadPartitionIdRequestDetails(theResourceType, RestOperationTypeEnum.SEARCH_TYPE, null, theParams);
|
||||
public static ReadPartitionIdRequestDetails forSearchType(String theResourceType, Object theParams, IBaseResource theConditionalOperationTargetOrNull) {
|
||||
return new ReadPartitionIdRequestDetails(theResourceType, RestOperationTypeEnum.SEARCH_TYPE, null, theParams, theConditionalOperationTargetOrNull);
|
||||
}
|
||||
|
||||
public static ReadPartitionIdRequestDetails forHistory(String theResourceType, IIdType theIdType) {
|
||||
|
@ -71,6 +80,6 @@ public class ReadPartitionIdRequestDetails {
|
|||
} else {
|
||||
restOperationTypeEnum = RestOperationTypeEnum.HISTORY_SYSTEM;
|
||||
}
|
||||
return new ReadPartitionIdRequestDetails(theResourceType, restOperationTypeEnum, theIdType, null);
|
||||
return new ReadPartitionIdRequestDetails(theResourceType, restOperationTypeEnum, theIdType, null, null);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
type: add
|
||||
issue: 2828
|
||||
title: "PatientIdPartitionInterceptor now supports conditional creates of resources where the resource is in
|
||||
the patient compartment but the conditional URL does not contain a patietn reference."
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
type: fix
|
||||
issue: 2823
|
||||
title: "Mdm failed to load if any mdm subscription had been deleted, e.g. if $expunge expungeEverything had been run
|
||||
on the server. This has been corrected."
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
type: fix
|
||||
issue: 2826
|
||||
title: "When Client Id Strategy is set to NOT_ALLOWED, permit system requests to create resources, e.g. SearchParameter
|
||||
and Subscription resources required by the system."
|
|
@ -0,0 +1,3 @@
|
|||
---
|
||||
type: add
|
||||
title: "Upgrade net.java.dev.jna to run docker tests on Mac arm64 M1 machines"
|
|
@ -0,0 +1,9 @@
|
|||
---
|
||||
type: security
|
||||
issue: 2835
|
||||
title: "Addressed the following CVE report by bumping the minor version for Jetty in the root POM:
|
||||
<ul>
|
||||
<li>
|
||||
[CVE-2021-34429](https://github.com/advisories/GHSA-vjv5-gp2w-65vm)
|
||||
</li>
|
||||
</ul>"
|
|
@ -47,6 +47,7 @@ import org.hl7.fhir.instance.model.api.IBaseResource;
|
|||
import org.hl7.fhir.instance.model.api.IIdType;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.util.Collection;
|
||||
import java.util.Date;
|
||||
|
@ -80,7 +81,7 @@ public interface IFhirResourceDao<T extends IBaseResource> extends IDao {
|
|||
* won't be indexed and searches won't work.
|
||||
* @param theRequestDetails TODO
|
||||
*/
|
||||
DaoMethodOutcome create(T theResource, String theIfNoneExist, boolean thePerformIndexing, @Nonnull TransactionDetails theTransactionDetails, RequestDetails theRequestDetails);
|
||||
DaoMethodOutcome create(T theResource, String theIfNoneExist, boolean thePerformIndexing, @Nonnull TransactionDetails theTransactionDetails, RequestDetails theRequestDetails);
|
||||
|
||||
DaoMethodOutcome create(T theResource, String theIfNoneExist, RequestDetails theRequestDetails);
|
||||
|
||||
|
@ -211,7 +212,21 @@ public interface IFhirResourceDao<T extends IBaseResource> extends IDao {
|
|||
/**
|
||||
* Search for IDs for processing a match URLs, etc.
|
||||
*/
|
||||
Set<ResourcePersistentId> searchForIds(SearchParameterMap theParams, RequestDetails theRequest);
|
||||
default Set<ResourcePersistentId> searchForIds(SearchParameterMap theParams, RequestDetails theRequest) {
|
||||
return searchForIds(theParams, theRequest, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Search for IDs for processing a match URLs, etc.
|
||||
*
|
||||
* @param theConditionalOperationTargetOrNull If we're searching for IDs in order to satisfy a conditional
|
||||
* create/update, this is the resource being searched for
|
||||
* @since 5.5.0
|
||||
*/
|
||||
default Set<ResourcePersistentId> searchForIds(SearchParameterMap theParams, RequestDetails theRequest, @Nullable IBaseResource theConditionalOperationTargetOrNull) {
|
||||
return searchForIds(theParams, theRequest);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Takes a map of incoming raw search parameters and translates/parses them into
|
||||
|
@ -249,7 +264,7 @@ public interface IFhirResourceDao<T extends IBaseResource> extends IDao {
|
|||
* @param theForceUpdateVersion Create a new version with the same contents as the current version even if the content hasn't changed (this is mostly useful for
|
||||
* resources mapping to external content such as external code systems)
|
||||
*/
|
||||
DaoMethodOutcome update(T theResource, String theMatchUrl, boolean thePerformIndexing, boolean theForceUpdateVersion, RequestDetails theRequestDetails, @Nonnull TransactionDetails theTransactionDetails);
|
||||
DaoMethodOutcome update(T theResource, String theMatchUrl, boolean thePerformIndexing, boolean theForceUpdateVersion, RequestDetails theRequestDetails, @Nonnull TransactionDetails theTransactionDetails);
|
||||
|
||||
/**
|
||||
* Not supported in DSTU1!
|
||||
|
@ -262,10 +277,11 @@ public interface IFhirResourceDao<T extends IBaseResource> extends IDao {
|
|||
|
||||
/**
|
||||
* Delete a list of resource Pids
|
||||
* @param theUrl the original URL that triggered the delete
|
||||
* @param theResourceIds the ids of the resources to be deleted
|
||||
*
|
||||
* @param theUrl the original URL that triggered the delete
|
||||
* @param theResourceIds the ids of the resources to be deleted
|
||||
* @param theDeleteConflicts out parameter of conflicts preventing deletion
|
||||
* @param theRequest the request that initiated the request
|
||||
* @param theRequest the request that initiated the request
|
||||
* @return response back to the client
|
||||
*/
|
||||
DeleteMethodOutcome deletePidList(String theUrl, Collection<ResourcePersistentId> theResourceIds, DeleteConflictList theDeleteConflicts, RequestDetails theRequest);
|
||||
|
@ -273,8 +289,8 @@ public interface IFhirResourceDao<T extends IBaseResource> extends IDao {
|
|||
/**
|
||||
* Returns the current version ID for the given resource
|
||||
*/
|
||||
default String getCurrentVersionId(IIdType theReferenceElement) {
|
||||
return read(theReferenceElement.toVersionless()).getIdElement().getVersionIdPart();
|
||||
}
|
||||
default String getCurrentVersionId(IIdType theReferenceElement) {
|
||||
return read(theReferenceElement.toVersionless()).getIdElement().getVersionIdPart();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -21,6 +21,7 @@ package ca.uhn.fhir.jpa.bulk.export.job;
|
|||
*/
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.interceptor.model.RequestPartitionId;
|
||||
import ca.uhn.fhir.jpa.api.dao.DaoRegistry;
|
||||
import ca.uhn.fhir.jpa.api.dao.IFhirResourceDao;
|
||||
import ca.uhn.fhir.jpa.api.model.DaoMethodOutcome;
|
||||
|
@ -101,7 +102,7 @@ public class ResourceToFileWriter implements ItemWriter<List<IBaseResource>> {
|
|||
IBaseBinary binary = BinaryUtil.newBinary(myFhirContext);
|
||||
binary.setContentType(Constants.CT_FHIR_NDJSON);
|
||||
binary.setContent(myOutputStream.toByteArray());
|
||||
DaoMethodOutcome outcome = myBinaryDao.create(binary, new SystemRequestDetails());
|
||||
DaoMethodOutcome outcome = myBinaryDao.create(binary, new SystemRequestDetails().setRequestPartitionId(RequestPartitionId.defaultPartition()));
|
||||
return outcome.getResource().getIdElement();
|
||||
}
|
||||
|
||||
|
|
|
@ -47,6 +47,7 @@ import ca.uhn.fhir.jpa.model.entity.TagTypeEnum;
|
|||
import ca.uhn.fhir.jpa.model.search.SearchRuntimeDetails;
|
||||
import ca.uhn.fhir.jpa.model.util.JpaConstants;
|
||||
import ca.uhn.fhir.jpa.partition.IRequestPartitionHelperSvc;
|
||||
import ca.uhn.fhir.jpa.partition.SystemRequestDetails;
|
||||
import ca.uhn.fhir.jpa.patch.FhirPatch;
|
||||
import ca.uhn.fhir.jpa.patch.JsonPatchUtils;
|
||||
import ca.uhn.fhir.jpa.patch.XmlPatchUtils;
|
||||
|
@ -125,8 +126,8 @@ import org.springframework.transaction.support.TransactionSynchronizationAdapter
|
|||
import org.springframework.transaction.support.TransactionSynchronizationManager;
|
||||
import org.springframework.transaction.support.TransactionTemplate;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.PostConstruct;
|
||||
import javax.persistence.NoResultException;
|
||||
import javax.persistence.TypedQuery;
|
||||
|
@ -228,7 +229,7 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
|
|||
|
||||
if (isNotBlank(theResource.getIdElement().getIdPart())) {
|
||||
if (getContext().getVersion().getVersion().isOlderThan(FhirVersionEnum.DSTU3)) {
|
||||
String message = getContext().getLocalizer().getMessageSanitized(BaseHapiFhirResourceDao.class, "failedToCreateWithClientAssignedId", theResource.getIdElement().getIdPart());
|
||||
String message = getMessageSanitized("failedToCreateWithClientAssignedId", theResource.getIdElement().getIdPart());
|
||||
throw new InvalidRequestException(message, createErrorOperationOutcome(message, "processing"));
|
||||
} else {
|
||||
// As of DSTU3, ID and version in the body should be ignored for a create/update
|
||||
|
@ -305,21 +306,9 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
|
|||
createForcedIdIfNeeded(entity, theResource.getIdElement(), true);
|
||||
serverAssignedId = true;
|
||||
} else {
|
||||
switch (getConfig().getResourceClientIdStrategy()) {
|
||||
case NOT_ALLOWED:
|
||||
throw new ResourceNotFoundException(
|
||||
getContext().getLocalizer().getMessageSanitized(BaseHapiFhirResourceDao.class, "failedToCreateWithClientAssignedIdNotAllowed", theResource.getIdElement().getIdPart()));
|
||||
case ALPHANUMERIC:
|
||||
if (theResource.getIdElement().isIdPartValidLong()) {
|
||||
throw new InvalidRequestException(
|
||||
getContext().getLocalizer().getMessageSanitized(BaseHapiFhirResourceDao.class, "failedToCreateWithClientAssignedNumericId", theResource.getIdElement().getIdPart()));
|
||||
}
|
||||
createForcedIdIfNeeded(entity, theResource.getIdElement(), false);
|
||||
break;
|
||||
case ANY:
|
||||
createForcedIdIfNeeded(entity, theResource.getIdElement(), true);
|
||||
break;
|
||||
}
|
||||
validateResourceIdCreation(theResource, theRequest);
|
||||
boolean createForPureNumericIds = getConfig().getResourceClientIdStrategy() != DaoConfig.ClientIdStrategyEnum.ALPHANUMERIC;
|
||||
createForcedIdIfNeeded(entity, theResource.getIdElement(), createForPureNumericIds);
|
||||
serverAssignedId = false;
|
||||
}
|
||||
} else {
|
||||
|
@ -407,6 +396,32 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
|
|||
return outcome;
|
||||
}
|
||||
|
||||
void validateResourceIdCreation(T theResource, RequestDetails theRequest) {
|
||||
DaoConfig.ClientIdStrategyEnum strategy = getConfig().getResourceClientIdStrategy();
|
||||
|
||||
if (strategy == DaoConfig.ClientIdStrategyEnum.NOT_ALLOWED) {
|
||||
if (!isSystemRequest(theRequest)) {
|
||||
throw new ResourceNotFoundException(
|
||||
getMessageSanitized("failedToCreateWithClientAssignedIdNotAllowed", theResource.getIdElement().getIdPart()));
|
||||
}
|
||||
}
|
||||
|
||||
if (strategy == DaoConfig.ClientIdStrategyEnum.ALPHANUMERIC) {
|
||||
if (theResource.getIdElement().isIdPartValidLong()) {
|
||||
throw new InvalidRequestException(
|
||||
getMessageSanitized("failedToCreateWithClientAssignedNumericId", theResource.getIdElement().getIdPart()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected String getMessageSanitized(String theKey, String theIdPart) {
|
||||
return getContext().getLocalizer().getMessageSanitized(BaseHapiFhirResourceDao.class, theKey, theIdPart);
|
||||
}
|
||||
|
||||
private boolean isSystemRequest(RequestDetails theRequest) {
|
||||
return theRequest instanceof SystemRequestDetails;
|
||||
}
|
||||
|
||||
private IInstanceValidatorModule getInstanceValidator() {
|
||||
return myInstanceValidator;
|
||||
}
|
||||
|
@ -555,7 +570,7 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
|
|||
SearchParameterMap paramMap = resourceSearch.getSearchParameterMap();
|
||||
paramMap.setLoadSynchronous(true);
|
||||
|
||||
Set<ResourcePersistentId> resourceIds = myMatchResourceUrlService.search(paramMap, myResourceType, theRequest);
|
||||
Set<ResourcePersistentId> resourceIds = myMatchResourceUrlService.search(paramMap, myResourceType, theRequest, null);
|
||||
|
||||
if (resourceIds.size() > 1) {
|
||||
if (!getConfig().isAllowMultipleDelete()) {
|
||||
|
@ -632,7 +647,7 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
|
|||
IBaseOperationOutcome oo;
|
||||
if (deletedResources.isEmpty()) {
|
||||
oo = OperationOutcomeUtil.newInstance(getContext());
|
||||
String message = getContext().getLocalizer().getMessageSanitized(BaseHapiFhirResourceDao.class, "unableToDeleteNotFound", theUrl);
|
||||
String message = getMessageSanitized("unableToDeleteNotFound", theUrl);
|
||||
String severity = "warning";
|
||||
String code = "not-found";
|
||||
OperationOutcomeUtil.addIssue(getContext(), oo, severity, message, null, code);
|
||||
|
@ -1401,7 +1416,7 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
|
|||
cacheControlDirective.parse(theRequest.getHeaders(Constants.HEADER_CACHE_CONTROL));
|
||||
}
|
||||
|
||||
RequestPartitionId requestPartitionId = myRequestPartitionHelperService.determineReadPartitionForRequestForSearchType(theRequest, getResourceName(), theParams);
|
||||
RequestPartitionId requestPartitionId = myRequestPartitionHelperService.determineReadPartitionForRequestForSearchType(theRequest, getResourceName(), theParams, null);
|
||||
IBundleProvider retVal = mySearchCoordinatorSvc.registerSearch(this, theParams, getResourceName(), cacheControlDirective, theRequest, requestPartitionId);
|
||||
|
||||
if (retVal instanceof PersistedJpaBundleProvider) {
|
||||
|
@ -1476,7 +1491,7 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
|
|||
}
|
||||
|
||||
@Override
|
||||
public Set<ResourcePersistentId> searchForIds(SearchParameterMap theParams, RequestDetails theRequest) {
|
||||
public Set<ResourcePersistentId> searchForIds(SearchParameterMap theParams, RequestDetails theRequest, @Nullable IBaseResource theConditionalOperationTargetOrNull) {
|
||||
TransactionDetails transactionDetails = new TransactionDetails();
|
||||
|
||||
return myTransactionService.execute(theRequest, transactionDetails, tx -> {
|
||||
|
@ -1492,9 +1507,9 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
|
|||
HashSet<ResourcePersistentId> retVal = new HashSet<>();
|
||||
|
||||
String uuid = UUID.randomUUID().toString();
|
||||
SearchRuntimeDetails searchRuntimeDetails = new SearchRuntimeDetails(theRequest, uuid);
|
||||
RequestPartitionId requestPartitionId = myRequestPartitionHelperService.determineReadPartitionForRequestForSearchType(theRequest, getResourceName(), theParams, theConditionalOperationTargetOrNull);
|
||||
|
||||
RequestPartitionId requestPartitionId = myRequestPartitionHelperService.determineReadPartitionForRequestForSearchType(theRequest, getResourceName(), theParams);
|
||||
SearchRuntimeDetails searchRuntimeDetails = new SearchRuntimeDetails(theRequest, uuid);
|
||||
try (IResultIterator iter = builder.createQuery(theParams, searchRuntimeDetails, theRequest, requestPartitionId)) {
|
||||
while (iter.hasNext()) {
|
||||
retVal.add(iter.next());
|
||||
|
@ -1602,7 +1617,7 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
|
|||
|
||||
IIdType resourceId;
|
||||
if (isNotBlank(theMatchUrl)) {
|
||||
Set<ResourcePersistentId> match = myMatchResourceUrlService.processMatchUrl(theMatchUrl, myResourceType, theTransactionDetails, theRequest);
|
||||
Set<ResourcePersistentId> match = myMatchResourceUrlService.processMatchUrl(theMatchUrl, myResourceType, theTransactionDetails, theRequest, theResource);
|
||||
if (match.size() > 1) {
|
||||
String msg = getContext().getLocalizer().getMessageSanitized(BaseHapiFhirDao.class, "transactionOperationWithMultipleMatchFailure", "UPDATE", theMatchUrl, match.size());
|
||||
throw new PreconditionFailedException(msg);
|
||||
|
|
|
@ -91,7 +91,7 @@ public abstract class BaseHapiFhirResourceDaoObservation<T extends IBaseResource
|
|||
TreeMap<Long, IQueryParameterType> orderedSubjectReferenceMap = new TreeMap<>();
|
||||
if(theSearchParameterMap.containsKey(getSubjectParamName())) {
|
||||
|
||||
RequestPartitionId requestPartitionId = myRequestPartitionHelperService.determineReadPartitionForRequestForSearchType(theRequestDetails, getResourceName(), theSearchParameterMap);
|
||||
RequestPartitionId requestPartitionId = myRequestPartitionHelperService.determineReadPartitionForRequestForSearchType(theRequestDetails, getResourceName(), theSearchParameterMap, null);
|
||||
|
||||
List<List<IQueryParameterType>> patientParams = new ArrayList<>();
|
||||
if (theSearchParameterMap.get(getPatientParamName()) != null) {
|
||||
|
|
|
@ -79,7 +79,7 @@ public class FhirResourceDaoPatientDstu2 extends BaseHapiFhirResourceDao<Patient
|
|||
paramMap.setLoadSynchronous(true);
|
||||
}
|
||||
|
||||
RequestPartitionId requestPartitionId = myPartitionHelperSvc.determineReadPartitionForRequestForSearchType(theRequest, getResourceName(), paramMap);
|
||||
RequestPartitionId requestPartitionId = myPartitionHelperSvc.determineReadPartitionForRequestForSearchType(theRequest, getResourceName(), paramMap, null);
|
||||
return mySearchCoordinatorSvc.registerSearch(this, paramMap, getResourceName(), new CacheControlDirective().parse(theRequest.getHeaders(Constants.HEADER_CACHE_CONTROL)), theRequest, requestPartitionId);
|
||||
}
|
||||
|
||||
|
|
|
@ -68,6 +68,13 @@ public class MatchResourceUrlService {
|
|||
* Note that this will only return a maximum of 2 results!!
|
||||
*/
|
||||
public <R extends IBaseResource> Set<ResourcePersistentId> processMatchUrl(String theMatchUrl, Class<R> theResourceType, TransactionDetails theTransactionDetails, RequestDetails theRequest) {
|
||||
return processMatchUrl(theMatchUrl, theResourceType, theTransactionDetails, theRequest, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Note that this will only return a maximum of 2 results!!
|
||||
*/
|
||||
public <R extends IBaseResource> Set<ResourcePersistentId> processMatchUrl(String theMatchUrl, Class<R> theResourceType, TransactionDetails theTransactionDetails, RequestDetails theRequest, IBaseResource theConditionalOperationTargetOrNull) {
|
||||
String resourceType = myContext.getResourceType(theResourceType);
|
||||
String matchUrl = massageForStorage(resourceType, theMatchUrl);
|
||||
|
||||
|
@ -92,7 +99,7 @@ public class MatchResourceUrlService {
|
|||
}
|
||||
paramMap.setLoadSynchronousUpTo(2);
|
||||
|
||||
Set<ResourcePersistentId> retVal = search(paramMap, theResourceType, theRequest);
|
||||
Set<ResourcePersistentId> retVal = search(paramMap, theResourceType, theRequest, theConditionalOperationTargetOrNull);
|
||||
|
||||
if (myDaoConfig.isMatchUrlCacheEnabled() && retVal.size() == 1) {
|
||||
ResourcePersistentId pid = retVal.iterator().next();
|
||||
|
@ -124,14 +131,14 @@ public class MatchResourceUrlService {
|
|||
return existing;
|
||||
}
|
||||
|
||||
public <R extends IBaseResource> Set<ResourcePersistentId> search(SearchParameterMap theParamMap, Class<R> theResourceType, RequestDetails theRequest) {
|
||||
public <R extends IBaseResource> Set<ResourcePersistentId> search(SearchParameterMap theParamMap, Class<R> theResourceType, RequestDetails theRequest, @Nullable IBaseResource theConditionalOperationTargetOrNull) {
|
||||
StopWatch sw = new StopWatch();
|
||||
IFhirResourceDao<R> dao = myDaoRegistry.getResourceDao(theResourceType);
|
||||
if (dao == null) {
|
||||
throw new InternalErrorException("No DAO for resource type: " + theResourceType.getName());
|
||||
}
|
||||
|
||||
Set<ResourcePersistentId> retVal = dao.searchForIds(theParamMap, theRequest);
|
||||
Set<ResourcePersistentId> retVal = dao.searchForIds(theParamMap, theRequest, theConditionalOperationTargetOrNull);
|
||||
|
||||
// Interceptor broadcast: JPA_PERFTRACE_INFO
|
||||
if (CompositeInterceptorBroadcaster.hasHooks(Pointcut.JPA_PERFTRACE_INFO, myInterceptorBroadcaster, theRequest)) {
|
||||
|
|
|
@ -48,7 +48,7 @@ public class FhirResourceDaoObservationDstu3 extends BaseHapiFhirResourceDaoObse
|
|||
|
||||
updateSearchParamsForLastn(theSearchParameterMap, theRequestDetails);
|
||||
|
||||
RequestPartitionId requestPartitionId = myPartitionHelperSvc.determineReadPartitionForRequestForSearchType(theRequestDetails, getResourceName(), theSearchParameterMap);
|
||||
RequestPartitionId requestPartitionId = myPartitionHelperSvc.determineReadPartitionForRequestForSearchType(theRequestDetails, getResourceName(), theSearchParameterMap, null);
|
||||
return mySearchCoordinatorSvc.registerSearch(this, theSearchParameterMap, getResourceName(), new CacheControlDirective().parse(theRequestDetails.getHeaders(Constants.HEADER_CACHE_CONTROL)), theRequestDetails, requestPartitionId);
|
||||
}
|
||||
|
||||
|
|
|
@ -74,7 +74,7 @@ public class FhirResourceDaoPatientDstu3 extends BaseHapiFhirResourceDao<Patient
|
|||
paramMap.setLoadSynchronous(true);
|
||||
}
|
||||
|
||||
RequestPartitionId requestPartitionId = myPartitionHelperSvc.determineReadPartitionForRequestForSearchType(theRequest, getResourceName(), paramMap);
|
||||
RequestPartitionId requestPartitionId = myPartitionHelperSvc.determineReadPartitionForRequestForSearchType(theRequest, getResourceName(), paramMap, null);
|
||||
return mySearchCoordinatorSvc.registerSearch(this, paramMap, getResourceName(), new CacheControlDirective().parse(theRequest.getHeaders(Constants.HEADER_CACHE_CONTROL)), theRequest, requestPartitionId);
|
||||
}
|
||||
|
||||
|
|
|
@ -53,7 +53,7 @@ public class FhirResourceDaoObservationR4 extends BaseHapiFhirResourceDaoObserva
|
|||
public IBundleProvider observationsLastN(SearchParameterMap theSearchParameterMap, RequestDetails theRequestDetails, HttpServletResponse theServletResponse) {
|
||||
updateSearchParamsForLastn(theSearchParameterMap, theRequestDetails);
|
||||
|
||||
RequestPartitionId requestPartitionId = myRequestPartitionHelperService.determineReadPartitionForRequestForSearchType(theRequestDetails, getResourceName(), theSearchParameterMap);
|
||||
RequestPartitionId requestPartitionId = myRequestPartitionHelperService.determineReadPartitionForRequestForSearchType(theRequestDetails, getResourceName(), theSearchParameterMap, null);
|
||||
return mySearchCoordinatorSvc.registerSearch(this, theSearchParameterMap, getResourceName(), new CacheControlDirective().parse(theRequestDetails.getHeaders(Constants.HEADER_CACHE_CONTROL)), theRequestDetails, requestPartitionId);
|
||||
}
|
||||
|
||||
|
|
|
@ -74,7 +74,7 @@ public class FhirResourceDaoPatientR4 extends BaseHapiFhirResourceDao<Patient>im
|
|||
paramMap.setLoadSynchronous(true);
|
||||
}
|
||||
|
||||
RequestPartitionId requestPartitionId = myPartitionHelperSvc.determineReadPartitionForRequestForSearchType(theRequest, getResourceName(), paramMap);
|
||||
RequestPartitionId requestPartitionId = myPartitionHelperSvc.determineReadPartitionForRequestForSearchType(theRequest, getResourceName(), paramMap, null);
|
||||
return mySearchCoordinatorSvc.registerSearch(this, paramMap, getResourceName(), new CacheControlDirective().parse(theRequest.getHeaders(Constants.HEADER_CACHE_CONTROL)), theRequest, requestPartitionId);
|
||||
}
|
||||
|
||||
|
|
|
@ -48,7 +48,7 @@ public class FhirResourceDaoObservationR5 extends BaseHapiFhirResourceDaoObserva
|
|||
|
||||
updateSearchParamsForLastn(theSearchParameterMap, theRequestDetails);
|
||||
|
||||
RequestPartitionId requestPartitionId = myPartitionHelperSvc.determineReadPartitionForRequestForSearchType(theRequestDetails, getResourceName(), theSearchParameterMap);
|
||||
RequestPartitionId requestPartitionId = myPartitionHelperSvc.determineReadPartitionForRequestForSearchType(theRequestDetails, getResourceName(), theSearchParameterMap, null);
|
||||
return mySearchCoordinatorSvc.registerSearch(this, theSearchParameterMap, getResourceName(), new CacheControlDirective().parse(theRequestDetails.getHeaders(Constants.HEADER_CACHE_CONTROL)), theRequestDetails, requestPartitionId);
|
||||
}
|
||||
|
||||
|
|
|
@ -74,7 +74,7 @@ public class FhirResourceDaoPatientR5 extends BaseHapiFhirResourceDao<Patient> i
|
|||
paramMap.setLoadSynchronous(true);
|
||||
}
|
||||
|
||||
RequestPartitionId requestPartitionId = myPartitionHelperSvc.determineReadPartitionForRequestForSearchType(theRequest, getResourceName(), paramMap);
|
||||
RequestPartitionId requestPartitionId = myPartitionHelperSvc.determineReadPartitionForRequestForSearchType(theRequest, getResourceName(), paramMap, null);
|
||||
return mySearchCoordinatorSvc.registerSearch(this, paramMap, getResourceName(), new CacheControlDirective().parse(theRequest.getHeaders(Constants.HEADER_CACHE_CONTROL)), theRequest, requestPartitionId);
|
||||
}
|
||||
|
||||
|
|
|
@ -92,7 +92,7 @@ public class DeleteExpungeJobSubmitterImpl implements IDeleteExpungeJobSubmitter
|
|||
List<RequestPartitionId> retval = new ArrayList<>();
|
||||
for (String url : theUrlsToDeleteExpunge) {
|
||||
ResourceSearch resourceSearch = myMatchUrlService.getResourceSearch(url);
|
||||
RequestPartitionId requestPartitionId = myRequestPartitionHelperSvc.determineReadPartitionForRequestForSearchType(theRequest, resourceSearch.getResourceName(), null);
|
||||
RequestPartitionId requestPartitionId = myRequestPartitionHelperSvc.determineReadPartitionForRequestForSearchType(theRequest, resourceSearch.getResourceName(), null, null);
|
||||
retval.add(requestPartitionId);
|
||||
}
|
||||
return retval;
|
||||
|
|
|
@ -118,17 +118,6 @@ public class PatientIdPartitionInterceptor {
|
|||
return provideCompartmentMemberInstanceResponse(theRequestDetails, compartmentIdentity);
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
private List<RuntimeSearchParam> getCompartmentSearchParams(RuntimeResourceDefinition resourceDef) {
|
||||
return resourceDef
|
||||
.getSearchParams()
|
||||
.stream()
|
||||
.filter(param -> param.getParamType() == RestSearchParameterTypeEnum.REFERENCE)
|
||||
.filter(param -> param.getProvidesMembershipInCompartments() != null && param.getProvidesMembershipInCompartments().contains("Patient"))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
|
||||
@Hook(Pointcut.STORAGE_PARTITION_IDENTIFY_READ)
|
||||
public RequestPartitionId identifyForRead(ReadPartitionIdRequestDetails theReadDetails, RequestDetails theRequestDetails) {
|
||||
RuntimeResourceDefinition resourceDef = myFhirContext.getResourceDefinition(theReadDetails.getResourceType());
|
||||
|
@ -169,7 +158,23 @@ public class PatientIdPartitionInterceptor {
|
|||
// nothing
|
||||
}
|
||||
|
||||
return provideUnsupportedQueryResponse(theReadDetails);
|
||||
// If we couldn't identify a patient ID by the URL, let's try using the
|
||||
// conditional target if we have one
|
||||
if (theReadDetails.getConditionalTargetOrNull() != null) {
|
||||
return identifyForCreate(theReadDetails.getConditionalTargetOrNull(), theRequestDetails);
|
||||
}
|
||||
|
||||
return provideNonPatientSpecificQueryResponse(theReadDetails);
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
private List<RuntimeSearchParam> getCompartmentSearchParams(RuntimeResourceDefinition resourceDef) {
|
||||
return resourceDef
|
||||
.getSearchParams()
|
||||
.stream()
|
||||
.filter(param -> param.getParamType() == RestSearchParameterTypeEnum.REFERENCE)
|
||||
.filter(param -> param.getProvidesMembershipInCompartments() != null && param.getProvidesMembershipInCompartments().contains("Patient"))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private String getSingleResourceIdValueOrNull(SearchParameterMap theParams, String theParamName, String theResourceType) {
|
||||
|
@ -206,8 +211,8 @@ public class PatientIdPartitionInterceptor {
|
|||
/**
|
||||
* Return a partition or throw an error for FHIR operations that can not be used with this interceptor
|
||||
*/
|
||||
protected RequestPartitionId provideUnsupportedQueryResponse(ReadPartitionIdRequestDetails theRequestDetails) {
|
||||
throw new MethodNotAllowedException("This server is not able to handle this request of type " + theRequestDetails.getRestOperationType());
|
||||
protected RequestPartitionId provideNonPatientSpecificQueryResponse(ReadPartitionIdRequestDetails theRequestDetails) {
|
||||
return RequestPartitionId.allPartitions();
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -27,13 +27,13 @@ import ca.uhn.fhir.context.FhirContext;
|
|||
import ca.uhn.fhir.context.FhirVersionEnum;
|
||||
import ca.uhn.fhir.context.support.IValidationSupport;
|
||||
import ca.uhn.fhir.context.support.ValidationSupportContext;
|
||||
import ca.uhn.fhir.interceptor.model.RequestPartitionId;
|
||||
import ca.uhn.fhir.jpa.api.dao.DaoRegistry;
|
||||
import ca.uhn.fhir.jpa.api.dao.IFhirResourceDao;
|
||||
import ca.uhn.fhir.jpa.api.model.DaoMethodOutcome;
|
||||
import ca.uhn.fhir.jpa.dao.data.INpmPackageVersionDao;
|
||||
import ca.uhn.fhir.jpa.model.config.PartitionSettings;
|
||||
import ca.uhn.fhir.jpa.model.entity.NpmPackageVersionEntity;
|
||||
import ca.uhn.fhir.jpa.model.util.JpaConstants;
|
||||
import ca.uhn.fhir.jpa.partition.SystemRequestDetails;
|
||||
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
||||
import ca.uhn.fhir.jpa.searchparam.registry.ISearchParamRegistryController;
|
||||
|
@ -63,6 +63,7 @@ import org.springframework.transaction.PlatformTransactionManager;
|
|||
import org.springframework.transaction.support.TransactionTemplate;
|
||||
import org.hl7.fhir.utilities.npm.NpmPackage;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.PostConstruct;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
|
@ -358,16 +359,23 @@ public class PackageInstallerSvcImpl implements IPackageInstallerSvc {
|
|||
|
||||
private IBundleProvider searchResource(IFhirResourceDao theDao, SearchParameterMap theMap) {
|
||||
if (myPartitionSettings.isPartitioningEnabled()) {
|
||||
SystemRequestDetails requestDetails = new SystemRequestDetails();
|
||||
SystemRequestDetails requestDetails = newSystemRequestDetails();
|
||||
return theDao.search(theMap, requestDetails);
|
||||
} else {
|
||||
return theDao.search(theMap);
|
||||
}
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
private SystemRequestDetails newSystemRequestDetails() {
|
||||
return
|
||||
new SystemRequestDetails()
|
||||
.setRequestPartitionId(RequestPartitionId.defaultPartition());
|
||||
}
|
||||
|
||||
private void createResource(IFhirResourceDao theDao, IBaseResource theResource) {
|
||||
if (myPartitionSettings.isPartitioningEnabled()) {
|
||||
SystemRequestDetails requestDetails = new SystemRequestDetails();
|
||||
SystemRequestDetails requestDetails = newSystemRequestDetails();
|
||||
theDao.create(theResource, requestDetails);
|
||||
} else {
|
||||
theDao.create(theResource);
|
||||
|
@ -376,7 +384,7 @@ public class PackageInstallerSvcImpl implements IPackageInstallerSvc {
|
|||
|
||||
private DaoMethodOutcome updateResource(IFhirResourceDao theDao, IBaseResource theResource) {
|
||||
if (myPartitionSettings.isPartitioningEnabled()) {
|
||||
SystemRequestDetails requestDetails = new SystemRequestDetails();
|
||||
SystemRequestDetails requestDetails = newSystemRequestDetails();
|
||||
return theDao.update(theResource, requestDetails);
|
||||
} else {
|
||||
return theDao.update(theResource);
|
||||
|
|
|
@ -23,6 +23,7 @@ package ca.uhn.fhir.jpa.partition;
|
|||
import ca.uhn.fhir.interceptor.model.ReadPartitionIdRequestDetails;
|
||||
import ca.uhn.fhir.interceptor.model.RequestPartitionId;
|
||||
import ca.uhn.fhir.jpa.model.entity.PartitionablePartitionId;
|
||||
import ca.uhn.fhir.jpa.model.search.SearchRuntimeDetails;
|
||||
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
||||
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
|
@ -44,8 +45,8 @@ public interface IRequestPartitionHelperSvc {
|
|||
}
|
||||
|
||||
@Nonnull
|
||||
default RequestPartitionId determineReadPartitionForRequestForSearchType(RequestDetails theRequest, String theResourceType, SearchParameterMap theParams) {
|
||||
ReadPartitionIdRequestDetails details = ReadPartitionIdRequestDetails.forSearchType(theResourceType, theParams);
|
||||
default RequestPartitionId determineReadPartitionForRequestForSearchType(RequestDetails theRequest, String theResourceType, SearchParameterMap theParams, IBaseResource theConditionalOperationTargetOrNull) {
|
||||
ReadPartitionIdRequestDetails details = ReadPartitionIdRequestDetails.forSearchType(theResourceType, theParams, theConditionalOperationTargetOrNull);
|
||||
return determineReadPartitionForRequest(theRequest, theResourceType, details);
|
||||
}
|
||||
|
||||
|
|
|
@ -109,14 +109,14 @@ public class RequestPartitionHelperSvc implements IRequestPartitionHelperSvc {
|
|||
if (myPartitionSettings.isPartitioningEnabled()) {
|
||||
// Handle system requests
|
||||
//TODO GGG eventually, theRequest will not be allowed to be null here, and we will pass through SystemRequestDetails instead.
|
||||
if (theRequest == null && nonPartitionableResource) {
|
||||
if ((theRequest == null || theRequest instanceof SystemRequestDetails) && nonPartitionableResource) {
|
||||
return RequestPartitionId.defaultPartition();
|
||||
}
|
||||
|
||||
if (theRequest instanceof SystemRequestDetails) {
|
||||
if (theRequest instanceof SystemRequestDetails && systemRequestHasExplicitPartition((SystemRequestDetails) theRequest)) {
|
||||
requestPartitionId = getSystemRequestPartitionId((SystemRequestDetails) theRequest, nonPartitionableResource);
|
||||
// Interceptor call: STORAGE_PARTITION_IDENTIFY_READ
|
||||
} else if (hasHooks(Pointcut.STORAGE_PARTITION_IDENTIFY_READ, myInterceptorBroadcaster, theRequest)) {
|
||||
// Interceptor call: STORAGE_PARTITION_IDENTIFY_READ
|
||||
HookParams params = new HookParams()
|
||||
.add(RequestDetails.class, theRequest)
|
||||
.addIfMatchesType(ServletRequestDetails.class, theRequest)
|
||||
|
@ -186,15 +186,16 @@ public class RequestPartitionHelperSvc implements IRequestPartitionHelperSvc {
|
|||
boolean nonPartitionableResource = myNonPartitionableResourceNames.contains(theResourceType);
|
||||
|
||||
//TODO GGG eventually, theRequest will not be allowed to be null here, and we will pass through SystemRequestDetails instead.
|
||||
if (theRequest == null && nonPartitionableResource) {
|
||||
if ((theRequest == null || theRequest instanceof SystemRequestDetails) && nonPartitionableResource) {
|
||||
return RequestPartitionId.defaultPartition();
|
||||
}
|
||||
|
||||
if (theRequest instanceof SystemRequestDetails) {
|
||||
if (theRequest instanceof SystemRequestDetails && systemRequestHasExplicitPartition((SystemRequestDetails) theRequest)) {
|
||||
requestPartitionId = getSystemRequestPartitionId((SystemRequestDetails) theRequest, nonPartitionableResource);
|
||||
} else {
|
||||
//This is an external Request (e.g. ServletRequestDetails) so we want to figure out the partition via interceptor.
|
||||
HookParams params = new HookParams()// Interceptor call: STORAGE_PARTITION_IDENTIFY_CREATE
|
||||
// Interceptor call: STORAGE_PARTITION_IDENTIFY_CREATE
|
||||
HookParams params = new HookParams()
|
||||
.add(IBaseResource.class, theResource)
|
||||
.add(RequestDetails.class, theRequest)
|
||||
.addIfMatchesType(ServletRequestDetails.class, theRequest);
|
||||
|
@ -215,6 +216,10 @@ public class RequestPartitionHelperSvc implements IRequestPartitionHelperSvc {
|
|||
return RequestPartitionId.allPartitions();
|
||||
}
|
||||
|
||||
private boolean systemRequestHasExplicitPartition(@Nonnull SystemRequestDetails theRequest) {
|
||||
return theRequest.getRequestPartitionId() != null || theRequest.getTenantId() != null;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public PartitionablePartitionId toStoragePartition(@Nonnull RequestPartitionId theRequestPartitionId) {
|
||||
|
|
|
@ -72,8 +72,9 @@ public class SystemRequestDetails extends RequestDetails {
|
|||
return myRequestPartitionId;
|
||||
}
|
||||
|
||||
public void setRequestPartitionId(RequestPartitionId theRequestPartitionId) {
|
||||
public SystemRequestDetails setRequestPartitionId(RequestPartitionId theRequestPartitionId) {
|
||||
myRequestPartitionId = theRequestPartitionId;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -271,7 +271,7 @@ public class SearchCoordinatorSvcImpl implements ISearchCoordinatorSvc {
|
|||
String resourceType = search.getResourceType();
|
||||
SearchParameterMap params = search.getSearchParameterMap().orElseThrow(() -> new IllegalStateException("No map in PASSCOMPLET search"));
|
||||
IFhirResourceDao<?> resourceDao = myDaoRegistry.getResourceDao(resourceType);
|
||||
RequestPartitionId requestPartitionId = myRequestPartitionHelperService.determineReadPartitionForRequestForSearchType(theRequestDetails, resourceType, params);
|
||||
RequestPartitionId requestPartitionId = myRequestPartitionHelperService.determineReadPartitionForRequestForSearchType(theRequestDetails, resourceType, params, null);
|
||||
SearchContinuationTask task = new SearchContinuationTask(search, resourceDao, params, resourceType, theRequestDetails, requestPartitionId);
|
||||
myIdToSearchTask.put(search.getUuid(), task);
|
||||
myExecutor.submit(task);
|
||||
|
|
|
@ -814,7 +814,9 @@ public class SearchBuilder implements ISearchBuilder {
|
|||
if (findVersionFieldName != null) {
|
||||
sqlBuilder.append(", r." + findVersionFieldName);
|
||||
}
|
||||
sqlBuilder.append(" FROM ResourceLink r WHERE r.");
|
||||
sqlBuilder.append(" FROM ResourceLink r WHERE ");
|
||||
|
||||
sqlBuilder.append("r.");
|
||||
sqlBuilder.append(searchPidFieldName);
|
||||
sqlBuilder.append(" IN (:target_pids)");
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@ package ca.uhn.fhir.jpa.bulk;
|
|||
import ca.uhn.fhir.interceptor.api.HookParams;
|
||||
import ca.uhn.fhir.interceptor.api.IAnonymousInterceptor;
|
||||
import ca.uhn.fhir.interceptor.api.Pointcut;
|
||||
import ca.uhn.fhir.interceptor.model.RequestPartitionId;
|
||||
import ca.uhn.fhir.jpa.api.config.DaoConfig;
|
||||
import ca.uhn.fhir.jpa.api.model.DaoMethodOutcome;
|
||||
import ca.uhn.fhir.jpa.batch.BatchJobsConfig;
|
||||
|
@ -944,7 +945,7 @@ public class BulkDataExportSvcImplR4Test extends BaseJpaR4Test {
|
|||
|
||||
public String getBinaryContents(IBulkDataExportSvc.JobInfo theJobInfo, int theIndex) {
|
||||
// Iterate over the files
|
||||
Binary nextBinary = myBinaryDao.read(theJobInfo.getFiles().get(theIndex).getResourceId(), new SystemRequestDetails());
|
||||
Binary nextBinary = myBinaryDao.read(theJobInfo.getFiles().get(theIndex).getResourceId(), new SystemRequestDetails().setRequestPartitionId(RequestPartitionId.defaultPartition()));
|
||||
assertEquals(Constants.CT_FHIR_NDJSON, nextBinary.getContentType());
|
||||
String nextContents = new String(nextBinary.getContent(), Constants.CHARSET_UTF8);
|
||||
ourLog.info("Next contents for type {}:\n{}", nextBinary.getResourceType(), nextContents);
|
||||
|
@ -1238,12 +1239,12 @@ public class BulkDataExportSvcImplR4Test extends BaseJpaR4Test {
|
|||
createCareTeamWithIndex(i, patId);
|
||||
}
|
||||
|
||||
myPatientGroupId = myGroupDao.update(group, new SystemRequestDetails()).getId();
|
||||
myPatientGroupId = myGroupDao.update(group, new SystemRequestDetails().setRequestPartitionId(RequestPartitionId.defaultPartition())).getId();
|
||||
|
||||
//Manually create another golden record
|
||||
Patient goldenPatient2 = new Patient();
|
||||
goldenPatient2.setId("PAT888");
|
||||
DaoMethodOutcome g2Outcome = myPatientDao.update(goldenPatient2, new SystemRequestDetails());
|
||||
DaoMethodOutcome g2Outcome = myPatientDao.update(goldenPatient2, new SystemRequestDetails().setRequestPartitionId(RequestPartitionId.defaultPartition()));
|
||||
Long goldenPid2 = myIdHelperService.getPidOrNull(g2Outcome.getResource());
|
||||
|
||||
//Create some nongroup patients MDM linked to a different golden resource. They shouldnt be included in the query.
|
||||
|
@ -1272,14 +1273,14 @@ public class BulkDataExportSvcImplR4Test extends BaseJpaR4Test {
|
|||
patient.setGender(i % 2 == 0 ? Enumerations.AdministrativeGender.MALE : Enumerations.AdministrativeGender.FEMALE);
|
||||
patient.addName().setFamily("FAM" + i);
|
||||
patient.addIdentifier().setSystem("http://mrns").setValue("PAT" + i);
|
||||
return myPatientDao.update(patient, new SystemRequestDetails());
|
||||
return myPatientDao.update(patient, new SystemRequestDetails().setRequestPartitionId(RequestPartitionId.defaultPartition()));
|
||||
}
|
||||
|
||||
private void createCareTeamWithIndex(int i, IIdType patId) {
|
||||
CareTeam careTeam = new CareTeam();
|
||||
careTeam.setId("CT" + i);
|
||||
careTeam.setSubject(new Reference(patId)); // This maps to the "patient" search parameter on CareTeam
|
||||
myCareTeamDao.update(careTeam, new SystemRequestDetails());
|
||||
myCareTeamDao.update(careTeam, new SystemRequestDetails().setRequestPartitionId(RequestPartitionId.defaultPartition()));
|
||||
}
|
||||
|
||||
private void createImmunizationWithIndex(int i, IIdType patId) {
|
||||
|
@ -1297,7 +1298,7 @@ public class BulkDataExportSvcImplR4Test extends BaseJpaR4Test {
|
|||
cc.addCoding().setSystem("vaccines").setCode("COVID-19");
|
||||
immunization.setVaccineCode(cc);
|
||||
}
|
||||
myImmunizationDao.update(immunization, new SystemRequestDetails());
|
||||
myImmunizationDao.update(immunization, new SystemRequestDetails().setRequestPartitionId(RequestPartitionId.defaultPartition()));
|
||||
}
|
||||
|
||||
private void createObservationWithIndex(int i, IIdType patId) {
|
||||
|
@ -1308,7 +1309,7 @@ public class BulkDataExportSvcImplR4Test extends BaseJpaR4Test {
|
|||
if (patId != null) {
|
||||
obs.getSubject().setReference(patId.getValue());
|
||||
}
|
||||
myObservationDao.update(obs, new SystemRequestDetails());
|
||||
myObservationDao.update(obs, new SystemRequestDetails().setRequestPartitionId(RequestPartitionId.defaultPartition()));
|
||||
}
|
||||
|
||||
public void linkToGoldenResource(Long theGoldenPid, Long theSourcePid) {
|
||||
|
|
|
@ -0,0 +1,77 @@
|
|||
package ca.uhn.fhir.jpa.dao;
|
||||
|
||||
import ca.uhn.fhir.jpa.api.config.DaoConfig;
|
||||
import ca.uhn.fhir.jpa.partition.SystemRequestDetails;
|
||||
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
|
||||
import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails;
|
||||
import org.hl7.fhir.r4.model.Patient;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.fail;
|
||||
|
||||
class BaseHapiFhirResourceDaoTest {
|
||||
TestResourceDao mySvc = new TestResourceDao();
|
||||
|
||||
@Test
|
||||
public void validateResourceIdCreation_asSystem() {
|
||||
Patient patient = new Patient();
|
||||
RequestDetails sysRequest = new SystemRequestDetails();
|
||||
mySvc.getConfig().setResourceClientIdStrategy(DaoConfig.ClientIdStrategyEnum.NOT_ALLOWED);
|
||||
mySvc.validateResourceIdCreation(patient, sysRequest);
|
||||
// no exception is thrown
|
||||
}
|
||||
|
||||
@Test
|
||||
public void validateResourceIdCreation_asUser() {
|
||||
Patient patient = new Patient();
|
||||
RequestDetails sysRequest = new ServletRequestDetails();
|
||||
mySvc.getConfig().setResourceClientIdStrategy(DaoConfig.ClientIdStrategyEnum.NOT_ALLOWED);
|
||||
try {
|
||||
mySvc.validateResourceIdCreation(patient, sysRequest);
|
||||
fail();
|
||||
} catch (ResourceNotFoundException e) {
|
||||
assertEquals("failedToCreateWithClientAssignedIdNotAllowed", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void validateResourceIdCreationAlpha_withNumber() {
|
||||
Patient patient = new Patient();
|
||||
patient.setId("2401");
|
||||
RequestDetails sysRequest = new ServletRequestDetails();
|
||||
mySvc.getConfig().setResourceClientIdStrategy(DaoConfig.ClientIdStrategyEnum.ALPHANUMERIC);
|
||||
try {
|
||||
mySvc.validateResourceIdCreation(patient, sysRequest);
|
||||
fail();
|
||||
} catch (InvalidRequestException e) {
|
||||
assertEquals("failedToCreateWithClientAssignedNumericId", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void validateResourceIdCreationAlpha_withAlpha() {
|
||||
Patient patient = new Patient();
|
||||
patient.setId("P2401");
|
||||
RequestDetails sysRequest = new ServletRequestDetails();
|
||||
mySvc.getConfig().setResourceClientIdStrategy(DaoConfig.ClientIdStrategyEnum.ALPHANUMERIC);
|
||||
mySvc.validateResourceIdCreation(patient, sysRequest);
|
||||
// no exception is thrown
|
||||
}
|
||||
|
||||
static class TestResourceDao extends BaseHapiFhirResourceDao<Patient> {
|
||||
private final DaoConfig myDaoConfig = new DaoConfig();
|
||||
|
||||
@Override
|
||||
public DaoConfig getConfig() {
|
||||
return myDaoConfig;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getMessageSanitized(String theKey, String theIdPart) {
|
||||
return theKey;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -506,6 +506,8 @@ public abstract class BaseJpaR4Test extends BaseJpaTest implements ITestDataBuil
|
|||
|
||||
myPagingProvider.setDefaultPageSize(BasePagingProvider.DEFAULT_DEFAULT_PAGE_SIZE);
|
||||
myPagingProvider.setMaximumPageSize(BasePagingProvider.DEFAULT_MAX_PAGE_SIZE);
|
||||
|
||||
myPartitionSettings.setPartitioningEnabled(false);
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
|
|
|
@ -49,6 +49,7 @@ import static org.awaitility.Awaitility.await;
|
|||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.hamcrest.Matchers.empty;
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.hamcrest.Matchers.hasSize;
|
||||
import static org.hamcrest.Matchers.matchesPattern;
|
||||
import static org.hamcrest.Matchers.not;
|
||||
|
@ -566,12 +567,10 @@ public class FhirResourceDaoR4SearchOptimizedTest extends BaseJpaR4Test {
|
|||
/*
|
||||
* 20 should be prefetched since that's the initial page size
|
||||
*/
|
||||
await().until(() -> {
|
||||
return runInTransaction(() -> {
|
||||
Search search = mySearchEntityDao.findByUuidAndFetchIncludes(uuid).orElseThrow(() -> new InternalErrorException(""));
|
||||
return search.getNumFound() == 20;
|
||||
});
|
||||
});
|
||||
await().until(() -> runInTransaction(() -> {
|
||||
Search search = mySearchEntityDao.findByUuidAndFetchIncludes(uuid).orElseThrow(() -> new InternalErrorException(""));
|
||||
return search.getNumFound();
|
||||
}), equalTo(20));
|
||||
runInTransaction(() -> {
|
||||
Search search = mySearchEntityDao.findByUuidAndFetchIncludes(uuid).orElseThrow(() -> new InternalErrorException(""));
|
||||
assertEquals(20, search.getNumFound());
|
||||
|
|
|
@ -4,15 +4,24 @@ import ca.uhn.fhir.jpa.api.model.DaoMethodOutcome;
|
|||
import ca.uhn.fhir.jpa.dao.r4.BaseJpaR4SystemTest;
|
||||
import ca.uhn.fhir.jpa.model.config.PartitionSettings;
|
||||
import ca.uhn.fhir.jpa.model.entity.ResourceTable;
|
||||
import ca.uhn.fhir.jpa.partition.SystemRequestDetails;
|
||||
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
||||
import ca.uhn.fhir.jpa.searchparam.extractor.ISearchParamExtractor;
|
||||
import ca.uhn.fhir.jpa.util.MultimapCollector;
|
||||
import ca.uhn.fhir.jpa.util.SqlQuery;
|
||||
import ca.uhn.fhir.model.api.Include;
|
||||
import ca.uhn.fhir.rest.api.server.IBundleProvider;
|
||||
import ca.uhn.fhir.rest.param.ReferenceParam;
|
||||
import ca.uhn.fhir.rest.param.TokenOrListParam;
|
||||
import ca.uhn.fhir.rest.param.TokenParam;
|
||||
import ca.uhn.fhir.rest.server.exceptions.MethodNotAllowedException;
|
||||
import com.google.common.collect.ListMultimap;
|
||||
import com.google.common.collect.Multimap;
|
||||
import org.hl7.fhir.instance.model.api.IIdType;
|
||||
import org.hl7.fhir.r4.model.Bundle;
|
||||
import org.hl7.fhir.r4.model.Encounter;
|
||||
import org.hl7.fhir.r4.model.Enumerations;
|
||||
import org.hl7.fhir.r4.model.ExplanationOfBenefit;
|
||||
import org.hl7.fhir.r4.model.IdType;
|
||||
import org.hl7.fhir.r4.model.Observation;
|
||||
import org.hl7.fhir.r4.model.Organization;
|
||||
|
@ -22,8 +31,18 @@ import org.junit.jupiter.api.BeforeEach;
|
|||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.contains;
|
||||
import static org.hamcrest.Matchers.containsInAnyOrder;
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.hamcrest.Matchers.either;
|
||||
import static org.hamcrest.Matchers.matchesPattern;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import static org.junit.jupiter.api.Assertions.fail;
|
||||
|
@ -225,11 +244,9 @@ public class PatientIdPartitionInterceptorTest extends BaseJpaR4SystemTest {
|
|||
createObservationB();
|
||||
|
||||
myCaptureQueriesListener.clear();
|
||||
try {
|
||||
myObservationDao.search(SearchParameterMap.newSynchronous(), mySrd);
|
||||
} catch (MethodNotAllowedException e) {
|
||||
assertEquals("This server is not able to handle this request of type SEARCH_TYPE", e.getMessage());
|
||||
}
|
||||
myObservationDao.search(SearchParameterMap.newSynchronous(), mySrd);
|
||||
myCaptureQueriesListener.logSelectQueries();
|
||||
assertEquals("SELECT t0.RES_ID FROM HFJ_RESOURCE t0 WHERE ((t0.RES_TYPE = 'Observation') AND (t0.RES_DELETED_AT IS NULL)) limit '10'", myCaptureQueriesListener.getSelectQueries().get(0).getSql(true, false));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -314,6 +331,139 @@ public class PatientIdPartitionInterceptorTest extends BaseJpaR4SystemTest {
|
|||
assertThat(myCaptureQueriesListener.getSelectQueries().get(1).getSql(false, false), containsString("PARTITION_ID="));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testTransaction_NoRequestDetails() throws IOException {
|
||||
Bundle input = loadResourceFromClasspath(Bundle.class, "/r4/load_bundle.json");
|
||||
|
||||
// Maybe in the future we'll make request details mandatory and if that
|
||||
// causes this to fail that's ok
|
||||
Bundle outcome = mySystemDao.transaction(null, input);
|
||||
|
||||
ListMultimap<String, String> resourceIds = outcome
|
||||
.getEntry()
|
||||
.stream()
|
||||
.collect(MultimapCollector.toMultimap(t -> new IdType(t.getResponse().getLocation()).toUnqualifiedVersionless().getResourceType(), t -> new IdType(t.getResponse().getLocation()).toUnqualifiedVersionless().getValue()));
|
||||
|
||||
Multimap<String, Integer> resourcesByType = runInTransaction(() -> {
|
||||
logAllResources();
|
||||
return myResourceTableDao.findAll().stream().collect(MultimapCollector.toMultimap(t->t.getResourceType(), t->t.getPartitionId().getPartitionId()));
|
||||
});
|
||||
|
||||
assertThat(resourcesByType.get("Patient"), contains(4267));
|
||||
assertThat(resourcesByType.get("ExplanationOfBenefit"), contains(4267));
|
||||
assertThat(resourcesByType.get("Coverage"), contains(4267));
|
||||
assertThat(resourcesByType.get("Organization"), contains(-1, -1));
|
||||
assertThat(resourcesByType.get("Practitioner"), contains(-1, -1, -1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTransaction_SystemRequestDetails() throws IOException {
|
||||
Bundle input = loadResourceFromClasspath(Bundle.class, "/r4/load_bundle.json");
|
||||
myCaptureQueriesListener.clear();
|
||||
Bundle outcome = mySystemDao.transaction(new SystemRequestDetails(), input);
|
||||
myCaptureQueriesListener.logSelectQueries();
|
||||
List<String> selectQueryStrings = myCaptureQueriesListener
|
||||
.getSelectQueries()
|
||||
.stream()
|
||||
.map(t -> t.getSql(false, false).toUpperCase(Locale.US))
|
||||
.filter(t -> !t.contains("FROM HFJ_TAG_DEF"))
|
||||
.collect(Collectors.toList());
|
||||
for (String next : selectQueryStrings) {
|
||||
assertThat(next, either(containsString("PARTITION_ID =")).or(containsString("PARTITION_ID IN")));
|
||||
}
|
||||
|
||||
ListMultimap<String, String> resourceIds = outcome
|
||||
.getEntry()
|
||||
.stream()
|
||||
.collect(MultimapCollector.toMultimap(t -> new IdType(t.getResponse().getLocation()).toUnqualifiedVersionless().getResourceType(), t -> new IdType(t.getResponse().getLocation()).toUnqualifiedVersionless().getValue()));
|
||||
|
||||
String patientId = resourceIds.get("Patient").get(0);
|
||||
|
||||
Multimap<String, Integer> resourcesByType = runInTransaction(() -> {
|
||||
logAllResources();
|
||||
return myResourceTableDao.findAll().stream().collect(MultimapCollector.toMultimap(t->t.getResourceType(), t->t.getPartitionId().getPartitionId()));
|
||||
});
|
||||
|
||||
assertThat(resourcesByType.get("Patient"), contains(4267));
|
||||
assertThat(resourcesByType.get("ExplanationOfBenefit"), contains(4267));
|
||||
assertThat(resourcesByType.get("Coverage"), contains(4267));
|
||||
assertThat(resourcesByType.get("Organization"), contains(-1, -1));
|
||||
assertThat(resourcesByType.get("Practitioner"), contains(-1, -1, -1));
|
||||
|
||||
// Try Searching
|
||||
SearchParameterMap map = new SearchParameterMap();
|
||||
map.add(ExplanationOfBenefit.SP_PATIENT, new ReferenceParam(patientId));
|
||||
map.addInclude(new Include("*"));
|
||||
myCaptureQueriesListener.clear();
|
||||
IBundleProvider result = myExplanationOfBenefitDao.search(map);
|
||||
List<String> resultIds = toUnqualifiedVersionlessIdValues(result);
|
||||
assertThat(resultIds.toString(), resultIds, containsInAnyOrder(
|
||||
resourceIds.get("Coverage").get(0),
|
||||
resourceIds.get("Organization").get(0),
|
||||
resourceIds.get("ExplanationOfBenefit").get(0),
|
||||
resourceIds.get("Patient").get(0),
|
||||
resourceIds.get("Practitioner").get(0),
|
||||
resourceIds.get("Practitioner").get(1),
|
||||
resourceIds.get("Practitioner").get(2)
|
||||
));
|
||||
|
||||
myCaptureQueriesListener.logSelectQueries();
|
||||
|
||||
List<SqlQuery> selectQueries = myCaptureQueriesListener.getSelectQueries();
|
||||
assertThat(selectQueries.get(0).getSql(true, false).toUpperCase(Locale.US), matchesPattern("SELECT.*FROM HFJ_RES_LINK.*WHERE.*PARTITION_ID = '4267'.*"));
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testSearch() throws IOException {
|
||||
Bundle input = loadResourceFromClasspath(Bundle.class, "/r4/load_bundle.json");
|
||||
Bundle outcome = mySystemDao.transaction(new SystemRequestDetails(), input);
|
||||
|
||||
ListMultimap<String, String> resourceIds = outcome
|
||||
.getEntry()
|
||||
.stream()
|
||||
.collect(MultimapCollector.toMultimap(t -> new IdType(t.getResponse().getLocation()).toUnqualifiedVersionless().getResourceType(), t -> new IdType(t.getResponse().getLocation()).toUnqualifiedVersionless().getValue()));
|
||||
|
||||
String patientId = resourceIds.get("Patient").get(0);
|
||||
|
||||
Multimap<String, Integer> resourcesByType = runInTransaction(() -> {
|
||||
logAllResources();
|
||||
return myResourceTableDao.findAll().stream().collect(MultimapCollector.toMultimap(t->t.getResourceType(), t->t.getPartitionId().getPartitionId()));
|
||||
});
|
||||
|
||||
assertThat(resourcesByType.get("Patient"), contains(4267));
|
||||
assertThat(resourcesByType.get("ExplanationOfBenefit"), contains(4267));
|
||||
assertThat(resourcesByType.get("Coverage"), contains(4267));
|
||||
assertThat(resourcesByType.get("Organization"), contains(-1, -1));
|
||||
assertThat(resourcesByType.get("Practitioner"), contains(-1, -1, -1));
|
||||
|
||||
// Try Searching
|
||||
SearchParameterMap map = new SearchParameterMap();
|
||||
map.add(ExplanationOfBenefit.SP_PATIENT, new ReferenceParam(patientId));
|
||||
map.addInclude(new Include("*"));
|
||||
myCaptureQueriesListener.clear();
|
||||
IBundleProvider result = myExplanationOfBenefitDao.search(map);
|
||||
List<String> resultIds = toUnqualifiedVersionlessIdValues(result);
|
||||
assertThat(resultIds.toString(), resultIds, containsInAnyOrder(
|
||||
resourceIds.get("Coverage").get(0),
|
||||
resourceIds.get("Organization").get(0),
|
||||
resourceIds.get("ExplanationOfBenefit").get(0),
|
||||
resourceIds.get("Patient").get(0),
|
||||
resourceIds.get("Practitioner").get(0),
|
||||
resourceIds.get("Practitioner").get(1),
|
||||
resourceIds.get("Practitioner").get(2)
|
||||
));
|
||||
|
||||
myCaptureQueriesListener.logSelectQueries();
|
||||
|
||||
List<SqlQuery> selectQueries = myCaptureQueriesListener.getSelectQueries();
|
||||
assertThat(selectQueries.get(0).getSql(true, false).toUpperCase(Locale.US), matchesPattern("SELECT.*FROM HFJ_RES_LINK.*WHERE.*PARTITION_ID = '4267'.*"));
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testHistory_Type() {
|
||||
myOrganizationDao.history(null, null, null, mySrd);
|
||||
|
|
|
@ -6,6 +6,7 @@ import ca.uhn.fhir.jpa.dao.data.INpmPackageVersionDao;
|
|||
import ca.uhn.fhir.jpa.dao.r4.BaseJpaR4Test;
|
||||
import ca.uhn.fhir.jpa.interceptor.PatientIdPartitionInterceptor;
|
||||
import ca.uhn.fhir.jpa.model.config.PartitionSettings;
|
||||
import ca.uhn.fhir.jpa.searchparam.extractor.ISearchParamExtractor;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
|
||||
import ca.uhn.fhir.rest.server.interceptor.partition.RequestTenantPartitionInterceptor;
|
||||
|
@ -40,6 +41,8 @@ public class JpaPackageCacheTest extends BaseJpaR4Test {
|
|||
private IInterceptorService myInterceptorService;
|
||||
@Autowired
|
||||
private RequestTenantPartitionInterceptor myRequestTenantPartitionInterceptor;
|
||||
@Autowired
|
||||
private ISearchParamExtractor mySearchParamExtractor;
|
||||
|
||||
@AfterEach
|
||||
public void disablePartitioning() {
|
||||
|
@ -75,7 +78,7 @@ public class JpaPackageCacheTest extends BaseJpaR4Test {
|
|||
public void testSaveAndDeletePackagePartitionsEnabled() throws IOException {
|
||||
myPartitionSettings.setPartitioningEnabled(true);
|
||||
myPartitionSettings.setDefaultPartitionId(1);
|
||||
myInterceptorService.registerInterceptor(new PatientIdPartitionInterceptor());
|
||||
myInterceptorService.registerInterceptor(new PatientIdPartitionInterceptor(myFhirCtx, mySearchParamExtractor));
|
||||
myInterceptorService.registerInterceptor(myRequestTenantPartitionInterceptor);
|
||||
|
||||
try (InputStream stream = ClasspathUtil.loadResourceAsStream("/packages/basisprofil.de.tar.gz")) {
|
||||
|
@ -109,7 +112,7 @@ public class JpaPackageCacheTest extends BaseJpaR4Test {
|
|||
myPartitionSettings.setPartitioningEnabled(true);
|
||||
myPartitionSettings.setDefaultPartitionId(0);
|
||||
myPartitionSettings.setUnnamedPartitionMode(true);
|
||||
myInterceptorService.registerInterceptor(new PatientIdPartitionInterceptor());
|
||||
myInterceptorService.registerInterceptor(new PatientIdPartitionInterceptor(myFhirCtx, mySearchParamExtractor));
|
||||
myInterceptorService.registerInterceptor(myRequestTenantPartitionInterceptor);
|
||||
|
||||
try (InputStream stream = ClasspathUtil.loadResourceAsStream("/packages/hl7.fhir.uv.shorthand-0.12.0.tgz")) {
|
||||
|
|
|
@ -423,9 +423,9 @@ public class NpmR4Test extends BaseJpaR4Test {
|
|||
myDaoConfig.setAllowExternalReferences(true);
|
||||
|
||||
byte[] bytes = loadClasspathBytes("/packages/test-draft-sample.tgz");
|
||||
myFakeNpmServlet.myResponses.put("/hl7.fhir.uv.shorthand/0.11.1", bytes);
|
||||
myFakeNpmServlet.myResponses.put("/hl7.fhir.uv.onlydrafts/0.11.1", bytes);
|
||||
|
||||
PackageInstallationSpec spec = new PackageInstallationSpec().setName("hl7.fhir.uv.shorthand").setVersion("0.11.1").setInstallMode(PackageInstallationSpec.InstallModeEnum.STORE_AND_INSTALL);
|
||||
PackageInstallationSpec spec = new PackageInstallationSpec().setName("hl7.fhir.uv.onlydrafts").setVersion("0.11.1").setInstallMode(PackageInstallationSpec.InstallModeEnum.STORE_AND_INSTALL);
|
||||
PackageInstallOutcomeJson outcome = myPackageInstallerSvc.install(spec);
|
||||
assertEquals(0, outcome.getResourcesInstalled().size(), outcome.getResourcesInstalled().toString());
|
||||
|
||||
|
|
|
@ -0,0 +1,64 @@
|
|||
package ca.uhn.fhir.jpa.util;
|
||||
|
||||
import com.google.common.collect.ArrayListMultimap;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.ListMultimap;
|
||||
import com.google.common.collect.Multimap;
|
||||
|
||||
import java.util.Set;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.BinaryOperator;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Collector;
|
||||
|
||||
/**
|
||||
* Copied from https://stackoverflow.com/questions/23003542/cleanest-way-to-create-a-guava-multimap-from-a-java-8-stream
|
||||
*/
|
||||
public class MultimapCollector<T, K, V> implements
|
||||
Collector<T, ListMultimap<K, V>, ListMultimap<K, V>> {
|
||||
|
||||
private final Function<T, K> keyGetter;
|
||||
private final Function<T, V> valueGetter;
|
||||
|
||||
public MultimapCollector(Function<T, K> keyGetter, Function<T, V> valueGetter) {
|
||||
this.keyGetter = keyGetter;
|
||||
this.valueGetter = valueGetter;
|
||||
}
|
||||
|
||||
public static <T, K, V> MultimapCollector<T, K, V> toMultimap(Function<T, K> keyGetter, Function<T, V> valueGetter) {
|
||||
return new MultimapCollector<>(keyGetter, valueGetter);
|
||||
}
|
||||
|
||||
public static <T, K, V> MultimapCollector<T, K, T> toMultimap(Function<T, K> keyGetter) {
|
||||
return new MultimapCollector<>(keyGetter, v -> v);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Supplier<ListMultimap<K, V>> supplier() {
|
||||
return ArrayListMultimap::create;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BiConsumer<ListMultimap<K, V>, T> accumulator() {
|
||||
return (map, element) -> map.put(keyGetter.apply(element), valueGetter.apply(element));
|
||||
}
|
||||
|
||||
@Override
|
||||
public BinaryOperator<ListMultimap<K, V>> combiner() {
|
||||
return (map1, map2) -> {
|
||||
map1.putAll(map2);
|
||||
return map1;
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public Function<ListMultimap<K, V>, ListMultimap<K, V>> finisher() {
|
||||
return map -> map;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Characteristics> characteristics() {
|
||||
return ImmutableSet.of(Characteristics.IDENTITY_FINISH);
|
||||
}
|
||||
}
|
Binary file not shown.
|
@ -0,0 +1,986 @@
|
|||
{
|
||||
"resourceType": "Bundle",
|
||||
"type": "transaction",
|
||||
"entry": [
|
||||
{
|
||||
"resource": {
|
||||
"resourceType": "ExplanationOfBenefit",
|
||||
"meta": {
|
||||
"lastUpdated": "2021-06-30",
|
||||
"profile": [
|
||||
"http://hl7.org/fhir/us/carin-bb/StructureDefinition/C4BB-ExplanationOfBenefit-Professional-NonClinician"
|
||||
]
|
||||
},
|
||||
"identifier": [
|
||||
{
|
||||
"type": {
|
||||
"coding": [
|
||||
{
|
||||
"system": "http://hl7.org/fhir/us/carin-bb/CodeSystem/C4BBIdentifierType",
|
||||
"code": "payerid"
|
||||
}
|
||||
]
|
||||
},
|
||||
"system": "https://hl7.org/fhir/sid/payerid",
|
||||
"value": "5824473976"
|
||||
},
|
||||
{
|
||||
"type": {
|
||||
"coding": [
|
||||
{
|
||||
"system": "http://hl7.org/fhir/us/carin-bb/CodeSystem/C4BBIdentifierType",
|
||||
"code": "uc"
|
||||
}
|
||||
]
|
||||
},
|
||||
"system": "https://hl7.org/fhir/sid/claimid",
|
||||
"value": "1234094"
|
||||
}
|
||||
],
|
||||
"status": "active",
|
||||
"type": {
|
||||
"coding": [
|
||||
{
|
||||
"system": "http://terminology.hl7.org/CodeSystem/claim-type",
|
||||
"code": "professional"
|
||||
}
|
||||
]
|
||||
},
|
||||
"use": "claim",
|
||||
"patient": {
|
||||
"reference": "Patient/d1a47e2c-509b-e326-deab-597e3f598ca5"
|
||||
},
|
||||
"billablePeriod": {
|
||||
"start": "2017-01-08",
|
||||
"end": "2017-01-08"
|
||||
},
|
||||
"created": "2017-01-11T00:00:00-08:00",
|
||||
"insurer": {
|
||||
"reference": "Organization/5954a17b-0779-334c-4f1c-e894e45d15fb"
|
||||
},
|
||||
"provider": {
|
||||
"reference": "Organization/68ae4f74-afdc-6242-c50e-02ef776d8e5d"
|
||||
},
|
||||
"payee": {
|
||||
"type": {
|
||||
"coding": [
|
||||
{
|
||||
"system": "http://terminology.hl7.org/CodeSystem/payeetype",
|
||||
"code": "provider"
|
||||
}
|
||||
],
|
||||
"text": "Claim paid to VENDOR"
|
||||
},
|
||||
"party": {
|
||||
"reference": "Organization/68ae4f74-afdc-6242-c50e-02ef776d8e5d"
|
||||
}
|
||||
},
|
||||
"outcome": "complete",
|
||||
"disposition": "PAID",
|
||||
"careTeam": [
|
||||
{
|
||||
"sequence": 1,
|
||||
"provider": {
|
||||
"reference": "Practitioner/23eccc61-ab67-bf8a-e464-6260f7989556"
|
||||
},
|
||||
"responsible": false,
|
||||
"role": {
|
||||
"coding": [
|
||||
{
|
||||
"system": "http://terminology.hl7.org/CodeSystem/claimcareteamrole",
|
||||
"code": "primary"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"sequence": 2,
|
||||
"provider": {
|
||||
"reference": "Practitioner/dbbc9a06-f685-b481-d739-133755af138e"
|
||||
},
|
||||
"responsible": false,
|
||||
"role": {
|
||||
"coding": [
|
||||
{
|
||||
"system": "http://hl7.org/fhir/us/carin-bb/CodeSystem/C4BBClaimCareTeamRole",
|
||||
"code": "referring"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"sequence": 3,
|
||||
"provider": {
|
||||
"reference": "Practitioner/39b9250c-0d01-cbb0-ea89-0de9c74af511"
|
||||
},
|
||||
"responsible": true,
|
||||
"role": {
|
||||
"coding": [
|
||||
{
|
||||
"system": "http://hl7.org/fhir/us/carin-bb/CodeSystem/C4BBClaimCareTeamRole",
|
||||
"code": "performing"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
"supportingInfo": [
|
||||
{
|
||||
"sequence": 1,
|
||||
"category": {
|
||||
"coding": [
|
||||
{
|
||||
"system": "http://hl7.org/fhir/us/carin-bb/CodeSystem/C4BBSupportingInfoType",
|
||||
"code": "clmrecvddate"
|
||||
}
|
||||
]
|
||||
},
|
||||
"timingDate": "2017-01-11"
|
||||
},
|
||||
{
|
||||
"sequence": 2,
|
||||
"category": {
|
||||
"coding": [
|
||||
{
|
||||
"system": "http://hl7.org/fhir/us/carin-bb/CodeSystem/C4BBSupportingInfoType",
|
||||
"code": "billingnetworkcontractingstatus"
|
||||
}
|
||||
]
|
||||
},
|
||||
"code": {
|
||||
"coding": [
|
||||
{
|
||||
"system": "http://hl7.org/fhir/us/carin-bb/CodeSystem/C4BBPayerAdjudicationStatus",
|
||||
"code": "other"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
"diagnosis": [
|
||||
{
|
||||
"sequence": 4,
|
||||
"diagnosisCodeableConcept": {
|
||||
"coding": [
|
||||
{
|
||||
"system": "http://hl7.org/fhir/sid/icd-10-cm",
|
||||
"code": "I27.2",
|
||||
"display": "Other secondary pulmonary hypertension"
|
||||
}
|
||||
],
|
||||
"text": "Other secondary pulmonary hypertension"
|
||||
}
|
||||
}
|
||||
],
|
||||
"procedure": [
|
||||
{
|
||||
"sequence": 1,
|
||||
"date": "2017-01-08T00:00:00-08:00",
|
||||
"procedureCodeableConcept": {
|
||||
"coding": [
|
||||
{
|
||||
"system": "http://www.ama-assn.org/go/cpt",
|
||||
"code": "99233",
|
||||
"display": "Subsequent hospital care for severe problem"
|
||||
}
|
||||
],
|
||||
"text": "SBSQ HOSPITAL CARE/DAY 35 MINUTES"
|
||||
}
|
||||
}
|
||||
],
|
||||
"insurance": [
|
||||
{
|
||||
"focal": true,
|
||||
"coverage": {
|
||||
"reference": "urn:uuid:175dbf4a-7ee2-446d-9938-82eea27871a7"
|
||||
}
|
||||
}
|
||||
],
|
||||
"item": [
|
||||
{
|
||||
"sequence": 1,
|
||||
"diagnosisSequence": [
|
||||
4
|
||||
],
|
||||
"procedureSequence": [
|
||||
1
|
||||
],
|
||||
"productOrService": {
|
||||
"coding": [
|
||||
{
|
||||
"system": "http://www.ama-assn.org/go/cpt",
|
||||
"code": "99233",
|
||||
"display": "Subsequent hospital care for severe problem"
|
||||
}
|
||||
],
|
||||
"text": "SBSQ HOSPITAL CARE/DAY 35 MINUTES"
|
||||
},
|
||||
"servicedPeriod": {
|
||||
"start": "2017-01-08",
|
||||
"end": "2017-01-08"
|
||||
},
|
||||
"locationCodeableConcept": {
|
||||
"coding": [
|
||||
{
|
||||
"system": "https://www.cms.gov/Medicare/Coding/place-of-service-codes/Place_of_Service_Code_Set",
|
||||
"code": "99"
|
||||
}
|
||||
]
|
||||
},
|
||||
"quantity": {
|
||||
"value": 1,
|
||||
"unit": "Units",
|
||||
"system": "http://unitsofmeasure.org",
|
||||
"code": "[arb'U]"
|
||||
},
|
||||
"net": {
|
||||
"value": 317.00,
|
||||
"currency": "USD"
|
||||
},
|
||||
"adjudication": [
|
||||
{
|
||||
"category": {
|
||||
"coding": [
|
||||
{
|
||||
"system": "http://terminology.hl7.org/CodeSystem/adjudication",
|
||||
"code": "submitted"
|
||||
}
|
||||
]
|
||||
},
|
||||
"amount": {
|
||||
"value": 317.00,
|
||||
"currency": "USD"
|
||||
}
|
||||
},
|
||||
{
|
||||
"category": {
|
||||
"coding": [
|
||||
{
|
||||
"system": "http://terminology.hl7.org/CodeSystem/adjudication",
|
||||
"code": "benefit"
|
||||
}
|
||||
]
|
||||
},
|
||||
"amount": {
|
||||
"value": 124.69,
|
||||
"currency": "USD"
|
||||
}
|
||||
},
|
||||
{
|
||||
"category": {
|
||||
"coding": [
|
||||
{
|
||||
"system": "http://terminology.hl7.org/CodeSystem/adjudication",
|
||||
"code": "copay"
|
||||
}
|
||||
]
|
||||
},
|
||||
"amount": {
|
||||
"value": 0.00,
|
||||
"currency": "USD"
|
||||
}
|
||||
},
|
||||
{
|
||||
"category": {
|
||||
"coding": [
|
||||
{
|
||||
"system": "http://terminology.hl7.org/CodeSystem/adjudication",
|
||||
"code": "deductible"
|
||||
}
|
||||
]
|
||||
},
|
||||
"amount": {
|
||||
"value": 124.69,
|
||||
"currency": "USD"
|
||||
}
|
||||
},
|
||||
{
|
||||
"category": {
|
||||
"coding": [
|
||||
{
|
||||
"system": "http://hl7.org/fhir/us/carin-bb/CodeSystem/C4BBAdjudication",
|
||||
"code": "coinsurance"
|
||||
}
|
||||
]
|
||||
},
|
||||
"amount": {
|
||||
"value": 0.00,
|
||||
"currency": "USD"
|
||||
}
|
||||
},
|
||||
{
|
||||
"category": {
|
||||
"coding": [
|
||||
{
|
||||
"system": "http://hl7.org/fhir/us/carin-bb/CodeSystem/C4BBAdjudication",
|
||||
"code": "memberliability"
|
||||
}
|
||||
]
|
||||
},
|
||||
"amount": {
|
||||
"value": 124.69,
|
||||
"currency": "USD"
|
||||
}
|
||||
},
|
||||
{
|
||||
"category": {
|
||||
"coding": [
|
||||
{
|
||||
"system": "http://hl7.org/fhir/us/carin-bb/CodeSystem/C4BBAdjudication",
|
||||
"code": "noncovered"
|
||||
}
|
||||
]
|
||||
},
|
||||
"amount": {
|
||||
"value": 0.00,
|
||||
"currency": "USD"
|
||||
}
|
||||
},
|
||||
{
|
||||
"category": {
|
||||
"coding": [
|
||||
{
|
||||
"system": "http://hl7.org/fhir/us/carin-bb/CodeSystem/C4BBAdjudication",
|
||||
"code": "priorpayerpaid"
|
||||
}
|
||||
]
|
||||
},
|
||||
"amount": {
|
||||
"value": 0.00,
|
||||
"currency": "USD"
|
||||
}
|
||||
},
|
||||
{
|
||||
"category": {
|
||||
"coding": [
|
||||
{
|
||||
"system": "http://hl7.org/fhir/us/carin-bb/CodeSystem/C4BBAdjudication",
|
||||
"code": "paidtoprovider"
|
||||
}
|
||||
]
|
||||
},
|
||||
"amount": {
|
||||
"value": 0.00,
|
||||
"currency": "USD"
|
||||
}
|
||||
},
|
||||
{
|
||||
"category": {
|
||||
"coding": [
|
||||
{
|
||||
"system": "http://hl7.org/fhir/us/carin-bb/CodeSystem/C4BBPayerAdjudicationStatus",
|
||||
"code": "outofnetwork"
|
||||
}
|
||||
]
|
||||
},
|
||||
"amount": {
|
||||
"value": 0.00,
|
||||
"currency": "USD"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"total": [
|
||||
{
|
||||
"category": {
|
||||
"coding": [
|
||||
{
|
||||
"system": "http://terminology.hl7.org/CodeSystem/adjudication",
|
||||
"code": "submitted"
|
||||
}
|
||||
]
|
||||
},
|
||||
"amount": {
|
||||
"value": 317.00,
|
||||
"currency": "USD"
|
||||
}
|
||||
},
|
||||
{
|
||||
"category": {
|
||||
"coding": [
|
||||
{
|
||||
"system": "http://terminology.hl7.org/CodeSystem/adjudication",
|
||||
"code": "benefit"
|
||||
}
|
||||
]
|
||||
},
|
||||
"amount": {
|
||||
"value": 124.69,
|
||||
"currency": "USD"
|
||||
}
|
||||
},
|
||||
{
|
||||
"category": {
|
||||
"coding": [
|
||||
{
|
||||
"system": "http://terminology.hl7.org/CodeSystem/adjudication",
|
||||
"code": "copay"
|
||||
}
|
||||
]
|
||||
},
|
||||
"amount": {
|
||||
"value": 0.00,
|
||||
"currency": "USD"
|
||||
}
|
||||
},
|
||||
{
|
||||
"category": {
|
||||
"coding": [
|
||||
{
|
||||
"system": "http://terminology.hl7.org/CodeSystem/adjudication",
|
||||
"code": "deductible"
|
||||
}
|
||||
]
|
||||
},
|
||||
"amount": {
|
||||
"value": 124.69,
|
||||
"currency": "USD"
|
||||
}
|
||||
},
|
||||
{
|
||||
"category": {
|
||||
"coding": [
|
||||
{
|
||||
"system": "http://hl7.org/fhir/us/carin-bb/CodeSystem/C4BBAdjudication",
|
||||
"code": "coinsurance"
|
||||
}
|
||||
]
|
||||
},
|
||||
"amount": {
|
||||
"value": 0.00,
|
||||
"currency": "USD"
|
||||
}
|
||||
},
|
||||
{
|
||||
"category": {
|
||||
"coding": [
|
||||
{
|
||||
"system": "http://hl7.org/fhir/us/carin-bb/CodeSystem/C4BBAdjudication",
|
||||
"code": "memberliability"
|
||||
}
|
||||
]
|
||||
},
|
||||
"amount": {
|
||||
"value": 124.69,
|
||||
"currency": "USD"
|
||||
}
|
||||
},
|
||||
{
|
||||
"category": {
|
||||
"coding": [
|
||||
{
|
||||
"system": "http://hl7.org/fhir/us/carin-bb/CodeSystem/C4BBAdjudication",
|
||||
"code": "noncovered"
|
||||
}
|
||||
]
|
||||
},
|
||||
"amount": {
|
||||
"value": 0.00,
|
||||
"currency": "USD"
|
||||
}
|
||||
},
|
||||
{
|
||||
"category": {
|
||||
"coding": [
|
||||
{
|
||||
"system": "http://hl7.org/fhir/us/carin-bb/CodeSystem/C4BBAdjudication",
|
||||
"code": "priorpayerpaid"
|
||||
}
|
||||
]
|
||||
},
|
||||
"amount": {
|
||||
"value": 0.00,
|
||||
"currency": "USD"
|
||||
}
|
||||
},
|
||||
{
|
||||
"category": {
|
||||
"coding": [
|
||||
{
|
||||
"system": "http://hl7.org/fhir/us/carin-bb/CodeSystem/C4BBAdjudication",
|
||||
"code": "paidtoprovider"
|
||||
}
|
||||
]
|
||||
},
|
||||
"amount": {
|
||||
"value": 0.00,
|
||||
"currency": "USD"
|
||||
}
|
||||
}
|
||||
],
|
||||
"payment": {
|
||||
"date": "2017-02-02",
|
||||
"amount": {
|
||||
"value": 0.00,
|
||||
"currency": "USD"
|
||||
}
|
||||
}
|
||||
},
|
||||
"request": {
|
||||
"method": "PUT",
|
||||
"url": "ExplanationOfBenefit?identifier=5824473976"
|
||||
}
|
||||
},
|
||||
{
|
||||
"resource": {
|
||||
"resourceType": "Patient",
|
||||
"id": "d1a47e2c-509b-e326-deab-597e3f598ca5",
|
||||
"meta": {
|
||||
"lastUpdated": "2021-06-30",
|
||||
"profile": [
|
||||
"http://hl7.org/fhir/us/core/StructureDefinition/us-core-patient"
|
||||
]
|
||||
},
|
||||
"identifier": [
|
||||
{
|
||||
"type": {
|
||||
"coding": [
|
||||
{
|
||||
"system": "http://terminology.hl7.org/CodeSystem/v2-0203",
|
||||
"code": "MR"
|
||||
}
|
||||
]
|
||||
},
|
||||
"system": "https://example.org/front-door",
|
||||
"value": "412563524-CO"
|
||||
}
|
||||
],
|
||||
"name": [
|
||||
{
|
||||
"use": "usual",
|
||||
"text": "HYOHWAN MGUIRRE",
|
||||
"family": "MGUIRRE",
|
||||
"given": [
|
||||
"HYOHWAN"
|
||||
]
|
||||
}
|
||||
],
|
||||
"telecom": [
|
||||
{
|
||||
"system": "phone",
|
||||
"value": "719-654-0220",
|
||||
"use": "home"
|
||||
}
|
||||
],
|
||||
"gender": "unknown",
|
||||
"birthDate": "1958-05-12",
|
||||
"address": [
|
||||
{
|
||||
"use": "home",
|
||||
"type": "postal",
|
||||
"line": [
|
||||
"20360 East 45Th Court",
|
||||
"PO Box 523"
|
||||
],
|
||||
"city": "COLORADO SPRINGS",
|
||||
"postalCode": "80922-4166"
|
||||
}
|
||||
]
|
||||
},
|
||||
"request": {
|
||||
"method": "PUT",
|
||||
"url": "Patient/d1a47e2c-509b-e326-deab-597e3f598ca5"
|
||||
}
|
||||
},
|
||||
{
|
||||
"fullUrl": "urn:uuid:175dbf4a-7ee2-446d-9938-82eea27871a7",
|
||||
"resource": {
|
||||
"resourceType": "Coverage",
|
||||
"meta": {
|
||||
"lastUpdated": "2021-06-30",
|
||||
"profile": [
|
||||
"http://hl7.org/fhir/us/carin-bb/StructureDefinition/C4BB-Coverage"
|
||||
]
|
||||
},
|
||||
"identifier": [
|
||||
{
|
||||
"type": {
|
||||
"coding": [
|
||||
{
|
||||
"system": "http://terminology.hl7.org/CodeSystem/v2-0203",
|
||||
"code": "FILL"
|
||||
}
|
||||
]
|
||||
},
|
||||
"system": "https://hl7.org/fhir/sid/coverageid",
|
||||
"value": "412563524-CO-80001"
|
||||
}
|
||||
],
|
||||
"status": "active",
|
||||
"type": {
|
||||
"coding": [
|
||||
{
|
||||
"system": "http://terminology.hl7.org/CodeSystem/v3-ActCode",
|
||||
"code": "HMO",
|
||||
"display": "health maintenance organization policy"
|
||||
}
|
||||
],
|
||||
"text": "HMO - HMO COMMERCIAL-HDHP-Signature"
|
||||
},
|
||||
"subscriberId": "412563524",
|
||||
"beneficiary": {
|
||||
"reference": "Patient/d1a47e2c-509b-e326-deab-597e3f598ca5"
|
||||
},
|
||||
"relationship": {
|
||||
"coding": [
|
||||
{
|
||||
"system": "http://terminology.hl7.org/CodeSystem/subscriber-relationship",
|
||||
"code": "self",
|
||||
"display": "Self"
|
||||
}
|
||||
],
|
||||
"text": "The Beneficiary is the Subscriber"
|
||||
},
|
||||
"period": {
|
||||
"start": "2016-01-01",
|
||||
"end": "2017-07-01"
|
||||
},
|
||||
"payor": [
|
||||
{
|
||||
"reference": "Organization/5954a17b-0779-334c-4f1c-e894e45d15fb"
|
||||
}
|
||||
],
|
||||
"class": [
|
||||
{
|
||||
"type": {
|
||||
"coding": [
|
||||
{
|
||||
"system": "http://terminology.hl7.org/CodeSystem/coverage-class",
|
||||
"code": "group",
|
||||
"display": "Group"
|
||||
}
|
||||
],
|
||||
"text": "An employee group"
|
||||
},
|
||||
"value": "80001",
|
||||
"name": "CS BRZ HDHP 5500/30%/0 ONX S-NON-MEDICARE"
|
||||
}
|
||||
]
|
||||
},
|
||||
"request": {
|
||||
"method": "PUT",
|
||||
"url": "Coverage?identifier=412563524-CO-80001"
|
||||
}
|
||||
},
|
||||
{
|
||||
"resource": {
|
||||
"resourceType": "Organization",
|
||||
"id": "68ae4f74-afdc-6242-c50e-02ef776d8e5d",
|
||||
"meta": {
|
||||
"lastUpdated": "2021-06-30",
|
||||
"profile": [
|
||||
"http://hl7.org/fhir/us/carin-bb/StructureDefinition/C4BB-Organization"
|
||||
]
|
||||
},
|
||||
"identifier": [
|
||||
{
|
||||
"type": {
|
||||
"coding": [
|
||||
{
|
||||
"system": "http://hl7.org/fhir/us/carin-bb/CodeSystem/C4BBIdentifierType",
|
||||
"code": "npi"
|
||||
}
|
||||
]
|
||||
},
|
||||
"system": "http://hl7.org/fhir/sid/us-npi",
|
||||
"value": "1407833767"
|
||||
},
|
||||
{
|
||||
"type": {
|
||||
"coding": [
|
||||
{
|
||||
"system": "http://terminology.hl7.org/CodeSystem/v2-0203",
|
||||
"code": "TAX"
|
||||
}
|
||||
]
|
||||
},
|
||||
"system": "urn:oid:2.16.840.1.113883.4.4"
|
||||
}
|
||||
],
|
||||
"active": true,
|
||||
"type": [
|
||||
{
|
||||
"coding": [
|
||||
{
|
||||
"system": "http://terminology.hl7.org/CodeSystem/organization-type",
|
||||
"code": "prov"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"name": "PIKES PEAK NEPHROLOGY ASSOCIATES PC",
|
||||
"address": [
|
||||
{
|
||||
"use": "work",
|
||||
"type": "physical",
|
||||
"line": [
|
||||
"1914 LELARAY STREET"
|
||||
],
|
||||
"city": "COLORADO SPRINGS",
|
||||
"postalCode": "80909",
|
||||
"country": "USA"
|
||||
}
|
||||
]
|
||||
},
|
||||
"request": {
|
||||
"method": "PUT",
|
||||
"url": "Organization/68ae4f74-afdc-6242-c50e-02ef776d8e5d"
|
||||
}
|
||||
},
|
||||
{
|
||||
"resource": {
|
||||
"resourceType": "Organization",
|
||||
"id": "5954a17b-0779-334c-4f1c-e894e45d15fb",
|
||||
"meta": {
|
||||
"lastUpdated": "2021-06-30",
|
||||
"profile": [
|
||||
"http://hl7.org/fhir/us/carin-bb/StructureDefinition/C4BB-Organization"
|
||||
]
|
||||
},
|
||||
"identifier": [
|
||||
{
|
||||
"use": "usual",
|
||||
"type": {
|
||||
"coding": [
|
||||
{
|
||||
"system": "http://terminology.hl7.org/CodeSystem/v2-0203",
|
||||
"code": "FILL"
|
||||
}
|
||||
]
|
||||
},
|
||||
"system": "https://hl7.org/fhir/sid/organizationid",
|
||||
"value": "NATLTAP CO-KFHP-PAY-CO"
|
||||
}
|
||||
],
|
||||
"active": true,
|
||||
"type": [
|
||||
{
|
||||
"coding": [
|
||||
{
|
||||
"system": "http://terminology.hl7.org/CodeSystem/organization-type",
|
||||
"code": "pay",
|
||||
"display": "Payer"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"name": "KAISER FOUNDATION HEALTHPLAN, INC",
|
||||
"telecom": [
|
||||
{
|
||||
"system": "phone",
|
||||
"value": "1-800-382-4661",
|
||||
"use": "work"
|
||||
}
|
||||
],
|
||||
"address": [
|
||||
{
|
||||
"use": "work",
|
||||
"type": "postal",
|
||||
"line": [
|
||||
"NATIONAL CLAIMS ADMINISTRATION COLORADO",
|
||||
"PO Box 629028"
|
||||
],
|
||||
"city": "El Dorado Hills",
|
||||
"state": "CA",
|
||||
"postalCode": "95762-9028"
|
||||
}
|
||||
]
|
||||
},
|
||||
"request": {
|
||||
"method": "PUT",
|
||||
"url": "Organization/5954a17b-0779-334c-4f1c-e894e45d15fb"
|
||||
}
|
||||
},
|
||||
{
|
||||
"resource": {
|
||||
"resourceType": "Practitioner",
|
||||
"id": "23eccc61-ab67-bf8a-e464-6260f7989556",
|
||||
"meta": {
|
||||
"lastUpdated": "2021-06-30",
|
||||
"profile": [
|
||||
"http://hl7.org/fhir/us/core/StructureDefinition/us-core-practitioner"
|
||||
]
|
||||
},
|
||||
"identifier": [
|
||||
{
|
||||
"use": "usual",
|
||||
"type": {
|
||||
"coding": [
|
||||
{
|
||||
"system": "http://terminology.hl7.org/CodeSystem/v2-0203",
|
||||
"code": "NPI"
|
||||
}
|
||||
]
|
||||
},
|
||||
"system": "http://hl7.org/fhir/sid/us-npi",
|
||||
"value": "1497983654"
|
||||
}
|
||||
],
|
||||
"name": [
|
||||
{
|
||||
"use": "usual",
|
||||
"text": "CASSIDY, HEATHER M (MD)",
|
||||
"family": "CASSIDY",
|
||||
"given": [
|
||||
"HEATHER"
|
||||
],
|
||||
"suffix": [
|
||||
"MD"
|
||||
]
|
||||
}
|
||||
],
|
||||
"address": [
|
||||
{
|
||||
"use": "work",
|
||||
"line": [
|
||||
"Briargate",
|
||||
"1405 Briargate Pkwy #141"
|
||||
],
|
||||
"city": "Colorado Springs",
|
||||
"postalCode": "80920"
|
||||
}
|
||||
]
|
||||
},
|
||||
"request": {
|
||||
"method": "PUT",
|
||||
"url": "Practitioner/23eccc61-ab67-bf8a-e464-6260f7989556"
|
||||
}
|
||||
},
|
||||
{
|
||||
"resource": {
|
||||
"resourceType": "Practitioner",
|
||||
"id": "dbbc9a06-f685-b481-d739-133755af138e",
|
||||
"meta": {
|
||||
"lastUpdated": "2021-06-30",
|
||||
"profile": [
|
||||
"http://hl7.org/fhir/us/core/StructureDefinition/us-core-practitioner"
|
||||
]
|
||||
},
|
||||
"identifier": [
|
||||
{
|
||||
"use": "usual",
|
||||
"type": {
|
||||
"coding": [
|
||||
{
|
||||
"system": "http://terminology.hl7.org/CodeSystem/v2-0203",
|
||||
"code": "NPI"
|
||||
}
|
||||
]
|
||||
},
|
||||
"system": "http://hl7.org/fhir/sid/us-npi",
|
||||
"value": "1568467280"
|
||||
},
|
||||
{
|
||||
"use": "usual",
|
||||
"type": {
|
||||
"coding": [
|
||||
{
|
||||
"system": "http://terminology.hl7.org/CodeSystem/v2-0203",
|
||||
"code": "TAX"
|
||||
}
|
||||
]
|
||||
},
|
||||
"system": "urn:oid:2.16.840.1.113883.4.4",
|
||||
"value": "311669909"
|
||||
}
|
||||
],
|
||||
"name": [
|
||||
{
|
||||
"use": "usual",
|
||||
"text": "MOHNSSEN, STEVEN R (MD)",
|
||||
"family": "MOHNSSEN",
|
||||
"given": [
|
||||
"STEVEN"
|
||||
],
|
||||
"suffix": [
|
||||
"MD"
|
||||
]
|
||||
}
|
||||
],
|
||||
"address": [
|
||||
{
|
||||
"use": "work",
|
||||
"line": [
|
||||
"1725 E Boulder St",
|
||||
"Ste 204"
|
||||
],
|
||||
"city": "Colorado Springs",
|
||||
"postalCode": "80909"
|
||||
}
|
||||
]
|
||||
},
|
||||
"request": {
|
||||
"method": "PUT",
|
||||
"url": "Practitioner/dbbc9a06-f685-b481-d739-133755af138e"
|
||||
}
|
||||
},
|
||||
{
|
||||
"resource": {
|
||||
"resourceType": "Practitioner",
|
||||
"id": "39b9250c-0d01-cbb0-ea89-0de9c74af511",
|
||||
"meta": {
|
||||
"lastUpdated": "2021-06-30",
|
||||
"profile": [
|
||||
"http://hl7.org/fhir/us/core/StructureDefinition/us-core-practitioner"
|
||||
]
|
||||
},
|
||||
"identifier": [
|
||||
{
|
||||
"use": "usual",
|
||||
"type": {
|
||||
"coding": [
|
||||
{
|
||||
"system": "http://terminology.hl7.org/CodeSystem/v2-0203",
|
||||
"code": "NPI"
|
||||
}
|
||||
]
|
||||
},
|
||||
"system": "http://hl7.org/fhir/sid/us-npi",
|
||||
"value": "1679605265"
|
||||
},
|
||||
{
|
||||
"use": "usual",
|
||||
"type": {
|
||||
"coding": [
|
||||
{
|
||||
"system": "http://terminology.hl7.org/CodeSystem/v2-0203",
|
||||
"code": "TAX"
|
||||
}
|
||||
]
|
||||
},
|
||||
"system": "urn:oid:2.16.840.1.113883.4.4",
|
||||
"value": "840629252"
|
||||
}
|
||||
],
|
||||
"name": [
|
||||
{
|
||||
"use": "usual",
|
||||
"text": "ROSS, MICHAEL D (MD)",
|
||||
"family": "ROSS",
|
||||
"given": [
|
||||
"MICHAEL"
|
||||
],
|
||||
"suffix": [
|
||||
"MD"
|
||||
]
|
||||
}
|
||||
],
|
||||
"address": [
|
||||
{
|
||||
"use": "work",
|
||||
"line": [
|
||||
"1914 Lelaray St"
|
||||
],
|
||||
"city": "Colorado Springs",
|
||||
"postalCode": "80909"
|
||||
}
|
||||
]
|
||||
},
|
||||
"request": {
|
||||
"method": "PUT",
|
||||
"url": "Practitioner/39b9250c-0d01-cbb0-ea89-0de9c74af511"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
|
@ -550,7 +550,7 @@
|
|||
}
|
||||
]
|
||||
},
|
||||
"system": "https://healthy.kaiserpermanente.org/front-door",
|
||||
"system": "https://example.org/front-door",
|
||||
"value": "1000116-GA"
|
||||
}
|
||||
],
|
||||
|
|
|
@ -550,7 +550,7 @@
|
|||
}
|
||||
]
|
||||
},
|
||||
"system": "https://healthy.kaiserpermanente.org/front-door",
|
||||
"system": "https://example.org/front-door",
|
||||
"value": "1000116-GA"
|
||||
}
|
||||
],
|
||||
|
|
|
@ -5,7 +5,7 @@ import ca.uhn.fhir.interceptor.api.IInterceptorService;
|
|||
import ca.uhn.fhir.interceptor.api.Pointcut;
|
||||
import ca.uhn.fhir.interceptor.model.RequestPartitionId;
|
||||
import ca.uhn.fhir.jpa.model.config.PartitionSettings;
|
||||
import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails;
|
||||
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
||||
import org.junit.jupiter.api.extension.AfterEachCallback;
|
||||
import org.junit.jupiter.api.extension.BeforeEachCallback;
|
||||
import org.junit.jupiter.api.extension.ExtensionContext;
|
||||
|
@ -49,7 +49,7 @@ public class PartitionHelper implements BeforeEachCallback, AfterEachCallback {
|
|||
private boolean myCalled = false;
|
||||
|
||||
@Hook(Pointcut.STORAGE_PARTITION_IDENTIFY_READ)
|
||||
RequestPartitionId partitionIdentifyRead(ServletRequestDetails theRequestDetails) {
|
||||
RequestPartitionId partitionIdentifyRead(RequestDetails theRequestDetails) {
|
||||
myCalled = true;
|
||||
if (theRequestDetails == null) {
|
||||
ourLog.info("useful breakpoint :-)");
|
||||
|
@ -67,7 +67,7 @@ public class PartitionHelper implements BeforeEachCallback, AfterEachCallback {
|
|||
}
|
||||
|
||||
@Hook(Pointcut.STORAGE_PARTITION_IDENTIFY_CREATE)
|
||||
RequestPartitionId partitionIdentifyCreate(ServletRequestDetails theRequestDetails) {
|
||||
RequestPartitionId partitionIdentifyCreate(RequestDetails theRequestDetails) {
|
||||
return RequestPartitionId.defaultPartition();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,7 +29,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
|
|||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
|
||||
public class CqlMeasureEvaluationDstu3Test extends BaseCqlDstu3Test {
|
||||
Logger ourLog = LoggerFactory.getLogger(CqlMeasureEvaluationDstu3Test.class);
|
||||
private static final Logger ourLog = LoggerFactory.getLogger(CqlMeasureEvaluationDstu3Test.class);
|
||||
|
||||
@Autowired
|
||||
MeasureOperationsProvider myMeasureOperationsProvider;
|
||||
|
@ -60,7 +60,7 @@ public class CqlMeasureEvaluationDstu3Test extends BaseCqlDstu3Test {
|
|||
String periodStart = this.getPeriodStart(expected);
|
||||
String periodEnd = this.getPeriodEnd(expected);
|
||||
|
||||
this.ourLog.info("Measure: %s, Patient: %s, Start: %s, End: %s", measureId, patientId, periodStart, periodEnd);
|
||||
ourLog.info("Measure: {}, Patient: {}, Start: {}, End: {}", measureId, patientId, periodStart, periodEnd);
|
||||
|
||||
MeasureReport actual = this.myMeasureOperationsProvider.evaluateMeasure(new IdType("Measure", measureId),
|
||||
periodStart, periodEnd, null,
|
||||
|
|
|
@ -22,14 +22,15 @@ package ca.uhn.fhir.jpa.mdm.config;
|
|||
|
||||
import ca.uhn.fhir.context.ConfigurationException;
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.mdm.api.MdmConstants;
|
||||
import ca.uhn.fhir.mdm.api.IMdmSettings;
|
||||
import ca.uhn.fhir.mdm.log.Logs;
|
||||
import ca.uhn.fhir.jpa.api.dao.DaoRegistry;
|
||||
import ca.uhn.fhir.jpa.api.dao.IFhirResourceDao;
|
||||
import ca.uhn.fhir.jpa.dao.index.IdHelperService;
|
||||
import ca.uhn.fhir.jpa.subscription.channel.api.ChannelProducerSettings;
|
||||
import ca.uhn.fhir.jpa.subscription.channel.subscription.IChannelNamer;
|
||||
import ca.uhn.fhir.mdm.api.IMdmSettings;
|
||||
import ca.uhn.fhir.mdm.api.MdmConstants;
|
||||
import ca.uhn.fhir.mdm.log.Logs;
|
||||
import ca.uhn.fhir.rest.server.exceptions.ResourceGoneException;
|
||||
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.hl7.fhir.r4.model.Subscription;
|
||||
|
@ -86,10 +87,10 @@ public class MdmSubscriptionLoader {
|
|||
}
|
||||
}
|
||||
|
||||
private synchronized void updateIfNotPresent(IBaseResource theSubscription) {
|
||||
synchronized void updateIfNotPresent(IBaseResource theSubscription) {
|
||||
try {
|
||||
mySubscriptionDao.read(theSubscription.getIdElement());
|
||||
} catch (ResourceNotFoundException e) {
|
||||
} catch (ResourceNotFoundException | ResourceGoneException e) {
|
||||
ourLog.info("Creating subsription " + theSubscription.getIdElement());
|
||||
mySubscriptionDao.update(theSubscription);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,64 @@
|
|||
package ca.uhn.fhir.jpa.mdm.config;
|
||||
|
||||
import ca.uhn.fhir.jpa.api.dao.IFhirResourceDao;
|
||||
import ca.uhn.fhir.rest.server.exceptions.ResourceGoneException;
|
||||
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.hl7.fhir.r4.model.IdType;
|
||||
import org.hl7.fhir.r4.model.Subscription;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.verifyNoMoreInteractions;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
class MdmSubscriptionLoaderTest {
|
||||
@Mock
|
||||
IFhirResourceDao<IBaseResource> mySubscriptionDao;
|
||||
|
||||
@InjectMocks
|
||||
MdmSubscriptionLoader mySvc = new MdmSubscriptionLoader();
|
||||
|
||||
@AfterEach
|
||||
public void after() {
|
||||
verifyNoMoreInteractions(mySubscriptionDao);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void updateIfNotPresent_createSubscriptionIfItWasDeleted() {
|
||||
Subscription subscription = new Subscription();
|
||||
IdType id = new IdType("2401");
|
||||
subscription.setIdElement(id);
|
||||
when(mySubscriptionDao.read(id)).thenThrow(new ResourceGoneException(""));
|
||||
mySvc.updateIfNotPresent(subscription);
|
||||
verify(mySubscriptionDao).update(subscription);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void updateIfNotPresent_createSubscriptionIfItDoesNotExist() {
|
||||
Subscription subscription = new Subscription();
|
||||
IdType id = new IdType("2401");
|
||||
subscription.setIdElement(id);
|
||||
when(mySubscriptionDao.read(id)).thenThrow(new ResourceNotFoundException(""));
|
||||
mySvc.updateIfNotPresent(subscription);
|
||||
verify(mySubscriptionDao).update(subscription);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void updateIfNotPresent_createSubscriptionExists() {
|
||||
Subscription subscription = new Subscription();
|
||||
IdType id = new IdType("2401");
|
||||
subscription.setIdElement(id);
|
||||
when(mySubscriptionDao.read(id)).thenReturn(subscription);
|
||||
mySvc.updateIfNotPresent(subscription);
|
||||
verify(mySubscriptionDao, never()).update(any());
|
||||
}
|
||||
}
|
|
@ -39,7 +39,6 @@ import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamToken;
|
|||
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamUri;
|
||||
import ca.uhn.fhir.jpa.model.entity.SearchParamPresent;
|
||||
import ca.uhn.fhir.util.VersionEnum;
|
||||
import org.checkerframework.checker.units.qual.C;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
@ -117,6 +116,12 @@ public class HapiFhirJpaMigrationTasks extends BaseMigrationTasks<VersionEnum> {
|
|||
cmpToks.addForeignKey("20210720.4", "FK_IDXCMBTOKNU_RES_ID").toColumn("RES_ID").references("HFJ_RESOURCE", "RES_ID");
|
||||
cmpToks.addIndex("20210720.5", "IDX_IDXCMBTOKNU_STR").unique(false).withColumns("IDX_STRING");
|
||||
cmpToks.addIndex("20210720.6", "IDX_IDXCMBTOKNU_RES").unique(false).withColumns("RES_ID");
|
||||
|
||||
Builder.BuilderWithTableName cmbTokNuTable = version.onTable("HFJ_IDX_CMB_TOK_NU");
|
||||
|
||||
cmbTokNuTable.addColumn("20210722.1", "PARTITION_ID").nullable().type(ColumnTypeEnum.INT);
|
||||
cmbTokNuTable.addColumn("20210722.2", "PARTITION_DATE").nullable().type(ColumnTypeEnum.DATE_ONLY);
|
||||
cmbTokNuTable.modifyColumn("20210722.3", "RES_ID").nullable().withType(ColumnTypeEnum.LONG);
|
||||
}
|
||||
|
||||
private void init540() {
|
||||
|
|
|
@ -38,6 +38,7 @@ public class SearchRuntimeDetails {
|
|||
private String myQueryString;
|
||||
private SearchStatusEnum mySearchStatus;
|
||||
private int myFoundIndexMatchesCount;
|
||||
|
||||
public SearchRuntimeDetails(RequestDetails theRequestDetails, String theSearchUuid) {
|
||||
myRequestDetails = theRequestDetails;
|
||||
mySearchUuid = theSearchUuid;
|
||||
|
|
25
pom.xml
25
pom.xml
|
@ -767,7 +767,7 @@
|
|||
<aries_spifly_version>1.2</aries_spifly_version>
|
||||
<caffeine_version>2.9.1</caffeine_version>
|
||||
<commons_codec_version>1.15</commons_codec_version>
|
||||
<commons_compress_version>1.20</commons_compress_version>
|
||||
<commons_compress_version>1.21</commons_compress_version>
|
||||
<commons_text_version>1.9</commons_text_version>
|
||||
<commons_io_version>2.8.0</commons_io_version>
|
||||
<commons_lang3_version>3.12.0</commons_lang3_version>
|
||||
|
@ -786,8 +786,7 @@
|
|||
<jaxb_runtime_version>3.0.0</jaxb_runtime_version>
|
||||
<jena_version>3.17.0</jena_version>
|
||||
<jersey_version>3.0.0</jersey_version>
|
||||
<!-- 9.4.17 seems to have issues -->
|
||||
<jetty_version>9.4.42.v20210604</jetty_version>
|
||||
<jetty_version>9.4.43.v20210629</jetty_version>
|
||||
<jsr305_version>3.0.2</jsr305_version>
|
||||
<junit_version>5.7.1</junit_version>
|
||||
<flexmark_version>0.50.40</flexmark_version>
|
||||
|
@ -822,6 +821,7 @@
|
|||
<spring_retry_version>1.2.2.RELEASE</spring_retry_version>
|
||||
|
||||
<stax2_api_version>3.1.4</stax2_api_version>
|
||||
<testcontainers_version>1.15.3</testcontainers_version>
|
||||
<thymeleaf-version>3.0.12.RELEASE</thymeleaf-version>
|
||||
<woodstox_core_asl_version>4.4.1</woodstox_core_asl_version>
|
||||
|
||||
|
@ -1593,8 +1593,21 @@
|
|||
<groupId>org.yaml</groupId>
|
||||
<artifactId>*</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<!-- Elastic have repackaged net.java.dev.jna, but we need a newer version to support Mac ARM. Managed below. -->
|
||||
<groupId>org.elasticsearch</groupId>
|
||||
<artifactId>jna</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<!-- Upgrade testcontainers and elasticsearch dependency for Mac M1 ARM64 support.
|
||||
We can delete this once testcontainers and elasticsearch upgrade. -->
|
||||
<dependency>
|
||||
<groupId>net.java.dev.jna</groupId>
|
||||
<artifactId>jna</artifactId>
|
||||
<version>5.8.0</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.hibernate.search</groupId>
|
||||
<artifactId>hibernate-search-backend-elasticsearch</artifactId>
|
||||
|
@ -1876,19 +1889,19 @@
|
|||
<dependency>
|
||||
<groupId>org.testcontainers</groupId>
|
||||
<artifactId>testcontainers</artifactId>
|
||||
<version>1.15.3</version>
|
||||
<version>${testcontainers_version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.testcontainers</groupId>
|
||||
<artifactId>elasticsearch</artifactId>
|
||||
<version>1.15.3</version>
|
||||
<version>${testcontainers_version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.testcontainers</groupId>
|
||||
<artifactId>junit-jupiter</artifactId>
|
||||
<version>1.15.3</version>
|
||||
<version>${testcontainers_version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
|
|
Loading…
Reference in New Issue