mirror of
https://github.com/hapifhir/hapi-fhir.git
synced 2025-02-18 02:45:07 +00:00
Enable mass ingestion mode (#2681)
* Work on fixes * Work on counts * Enable mass ingestion mode * Add changelog * Test fix * Test fix * Test fixes * Fixes * Test fix * Test fix
This commit is contained in:
parent
d70bbad6f1
commit
24b3f0f30d
@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
type: add
|
||||||
|
issue: 2681
|
||||||
|
title: "A new DaoConfig setting called Mass Ingestion Mode has been added. This mode enables rapid
|
||||||
|
data ingestion by skipping a number of unnecessary checks during backloading."
|
@ -240,6 +240,7 @@ public class DaoConfig {
|
|||||||
* @since 5.5.0
|
* @since 5.5.0
|
||||||
*/
|
*/
|
||||||
private boolean myEnableTaskBulkExportJobExecution;
|
private boolean myEnableTaskBulkExportJobExecution;
|
||||||
|
private boolean myMassIngestionMode;
|
||||||
private boolean myAccountForDateIndexNulls;
|
private boolean myAccountForDateIndexNulls;
|
||||||
private boolean myTriggerSubscriptionsForNonVersioningChanges;
|
private boolean myTriggerSubscriptionsForNonVersioningChanges;
|
||||||
|
|
||||||
@ -2365,6 +2366,40 @@ public class DaoConfig {
|
|||||||
return myEnableTaskResourceReindexing;
|
return myEnableTaskResourceReindexing;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If this is enabled (disabled by default), Mass Ingestion Mode is enabled. In this mode, a number of
|
||||||
|
* runtime checks are disabled. This mode is designed for rapid backloading of data while the system is not
|
||||||
|
* being otherwise used.
|
||||||
|
*
|
||||||
|
* In this mode:
|
||||||
|
*
|
||||||
|
* - Tags/Profiles/Security Labels will not be updated on existing resources that already have them
|
||||||
|
* - Resources modification checks will be skipped in favour of a simple hash check
|
||||||
|
* - Extra resource ID caching is enabled
|
||||||
|
*
|
||||||
|
* @since 5.5.0
|
||||||
|
*/
|
||||||
|
public void setMassIngestionMode(boolean theMassIngestionMode) {
|
||||||
|
myMassIngestionMode = theMassIngestionMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If this is enabled (disabled by default), Mass Ingestion Mode is enabled. In this mode, a number of
|
||||||
|
* runtime checks are disabled. This mode is designed for rapid backloading of data while the system is not
|
||||||
|
* being otherwise used.
|
||||||
|
*
|
||||||
|
* In this mode:
|
||||||
|
*
|
||||||
|
* - Tags/Profiles/Security Labels will not be updated on existing resources that already have them
|
||||||
|
* - Resources modification checks will be skipped in favour of a simple hash check
|
||||||
|
* - Extra resource ID caching is enabled
|
||||||
|
*
|
||||||
|
* @since 5.5.0
|
||||||
|
*/
|
||||||
|
public boolean isMassIngestionMode() {
|
||||||
|
return myMassIngestionMode;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If this is enabled (this is the default), this server will attempt to run resource reindexing jobs.
|
* If this is enabled (this is the default), this server will attempt to run resource reindexing jobs.
|
||||||
* Otherwise, this server will not.
|
* Otherwise, this server will not.
|
||||||
|
@ -387,10 +387,6 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> extends BaseStora
|
|||||||
return myConfig;
|
return myConfig;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setConfig(DaoConfig theConfig) {
|
|
||||||
myConfig = theConfig;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public FhirContext getContext() {
|
public FhirContext getContext() {
|
||||||
return myContext;
|
return myContext;
|
||||||
@ -608,6 +604,12 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> extends BaseStora
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
boolean skipUpdatingTags = false;
|
||||||
|
if (myConfig.isMassIngestionMode() && theEntity.isHasTags()) {
|
||||||
|
skipUpdatingTags = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!skipUpdatingTags) {
|
||||||
Set<ResourceTag> allDefs = new HashSet<>();
|
Set<ResourceTag> allDefs = new HashSet<>();
|
||||||
Set<ResourceTag> allTagsOld = getAllTagDefinitions(theEntity);
|
Set<ResourceTag> allTagsOld = getAllTagDefinitions(theEntity);
|
||||||
|
|
||||||
@ -651,6 +653,7 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> extends BaseStora
|
|||||||
changed = true;
|
changed = true;
|
||||||
}
|
}
|
||||||
theEntity.setHasTags(!allTagsNew.isEmpty());
|
theEntity.setHasTags(!allTagsNew.isEmpty());
|
||||||
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
theEntity.setHashSha256(null);
|
theEntity.setHashSha256(null);
|
||||||
@ -661,6 +664,10 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> extends BaseStora
|
|||||||
if (thePerformIndexing && changed == false) {
|
if (thePerformIndexing && changed == false) {
|
||||||
if (theEntity.getId() == null) {
|
if (theEntity.getId() == null) {
|
||||||
changed = true;
|
changed = true;
|
||||||
|
} else if (myConfig.isMassIngestionMode()) {
|
||||||
|
|
||||||
|
// Don't check existing - We'll rely on the SHA256 hash only
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
ResourceHistoryTable currentHistoryVersion = theEntity.getCurrentVersionEntity();
|
ResourceHistoryTable currentHistoryVersion = theEntity.getCurrentVersionEntity();
|
||||||
if (currentHistoryVersion == null) {
|
if (currentHistoryVersion == null) {
|
||||||
@ -1719,6 +1726,11 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> extends BaseStora
|
|||||||
ourDisableIncrementOnUpdateForUnitTest = theDisableIncrementOnUpdateForUnitTest;
|
ourDisableIncrementOnUpdateForUnitTest = theDisableIncrementOnUpdateForUnitTest;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
public void setDaoConfigForUnitTest(DaoConfig theDaoConfig) {
|
||||||
|
myConfig = theDaoConfig;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Do not call this method outside of unit tests
|
* Do not call this method outside of unit tests
|
||||||
*/
|
*/
|
||||||
|
@ -151,8 +151,6 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
|
|||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
protected PlatformTransactionManager myPlatformTransactionManager;
|
protected PlatformTransactionManager myPlatformTransactionManager;
|
||||||
@Autowired
|
|
||||||
protected DaoConfig myDaoConfig;
|
|
||||||
@Autowired(required = false)
|
@Autowired(required = false)
|
||||||
protected IFulltextSearchSvc mySearchDao;
|
protected IFulltextSearchSvc mySearchDao;
|
||||||
@Autowired
|
@Autowired
|
||||||
@ -236,7 +234,7 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (myDaoConfig.getResourceServerIdStrategy() == DaoConfig.IdStrategyEnum.UUID) {
|
if (getConfig().getResourceServerIdStrategy() == DaoConfig.IdStrategyEnum.UUID) {
|
||||||
theResource.setId(UUID.randomUUID().toString());
|
theResource.setId(UUID.randomUUID().toString());
|
||||||
theResource.setUserData(JpaConstants.RESOURCE_ID_SERVER_ASSIGNED, Boolean.TRUE);
|
theResource.setUserData(JpaConstants.RESOURCE_ID_SERVER_ASSIGNED, Boolean.TRUE);
|
||||||
}
|
}
|
||||||
@ -304,7 +302,7 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
|
|||||||
createForcedIdIfNeeded(entity, theResource.getIdElement(), true);
|
createForcedIdIfNeeded(entity, theResource.getIdElement(), true);
|
||||||
serverAssignedId = true;
|
serverAssignedId = true;
|
||||||
} else {
|
} else {
|
||||||
switch (myDaoConfig.getResourceClientIdStrategy()) {
|
switch (getConfig().getResourceClientIdStrategy()) {
|
||||||
case NOT_ALLOWED:
|
case NOT_ALLOWED:
|
||||||
throw new ResourceNotFoundException(
|
throw new ResourceNotFoundException(
|
||||||
getContext().getLocalizer().getMessageSanitized(BaseHapiFhirResourceDao.class, "failedToCreateWithClientAssignedIdNotAllowed", theResource.getIdElement().getIdPart()));
|
getContext().getLocalizer().getMessageSanitized(BaseHapiFhirResourceDao.class, "failedToCreateWithClientAssignedIdNotAllowed", theResource.getIdElement().getIdPart()));
|
||||||
@ -344,7 +342,7 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
|
|||||||
|
|
||||||
theResource.setId(entity.getIdDt());
|
theResource.setId(entity.getIdDt());
|
||||||
if (serverAssignedId) {
|
if (serverAssignedId) {
|
||||||
switch (myDaoConfig.getResourceClientIdStrategy()) {
|
switch (getConfig().getResourceClientIdStrategy()) {
|
||||||
case NOT_ALLOWED:
|
case NOT_ALLOWED:
|
||||||
case ALPHANUMERIC:
|
case ALPHANUMERIC:
|
||||||
break;
|
break;
|
||||||
@ -550,7 +548,7 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
|
|||||||
Set<ResourcePersistentId> resourceIds = myMatchResourceUrlService.search(paramMap, myResourceType, theRequest);
|
Set<ResourcePersistentId> resourceIds = myMatchResourceUrlService.search(paramMap, myResourceType, theRequest);
|
||||||
|
|
||||||
if (resourceIds.size() > 1) {
|
if (resourceIds.size() > 1) {
|
||||||
if (!myDaoConfig.isAllowMultipleDelete()) {
|
if (!getConfig().isAllowMultipleDelete()) {
|
||||||
throw new PreconditionFailedException(getContext().getLocalizer().getMessageSanitized(BaseHapiFhirDao.class, "transactionOperationWithMultipleMatchFailure", "DELETE", theUrl, resourceIds.size()));
|
throw new PreconditionFailedException(getContext().getLocalizer().getMessageSanitized(BaseHapiFhirDao.class, "transactionOperationWithMultipleMatchFailure", "DELETE", theUrl, resourceIds.size()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -563,7 +561,7 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
|
|||||||
}
|
}
|
||||||
|
|
||||||
private DeleteMethodOutcome deleteExpunge(String theUrl, RequestDetails theTheRequest, Set<ResourcePersistentId> theResourceIds) {
|
private DeleteMethodOutcome deleteExpunge(String theUrl, RequestDetails theTheRequest, Set<ResourcePersistentId> theResourceIds) {
|
||||||
if (!myDaoConfig.isExpungeEnabled() || !myDaoConfig.isDeleteExpungeEnabled()) {
|
if (!getConfig().isExpungeEnabled() || !getConfig().isDeleteExpungeEnabled()) {
|
||||||
throw new MethodNotAllowedException("_expunge is not enabled on this server");
|
throw new MethodNotAllowedException("_expunge is not enabled on this server");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -643,7 +641,7 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void validateDeleteEnabled() {
|
private void validateDeleteEnabled() {
|
||||||
if (!myDaoConfig.isDeleteEnabled()) {
|
if (!getConfig().isDeleteEnabled()) {
|
||||||
String msg = getContext().getLocalizer().getMessage(BaseHapiFhirResourceDao.class, "deleteBlockedBecauseDisabled");
|
String msg = getContext().getLocalizer().getMessage(BaseHapiFhirResourceDao.class, "deleteBlockedBecauseDisabled");
|
||||||
throw new PreconditionFailedException(msg);
|
throw new PreconditionFailedException(msg);
|
||||||
}
|
}
|
||||||
@ -764,7 +762,7 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void validateExpungeEnabled() {
|
private void validateExpungeEnabled() {
|
||||||
if (!myDaoConfig.isExpungeEnabled()) {
|
if (!getConfig().isExpungeEnabled()) {
|
||||||
throw new MethodNotAllowedException("$expunge is not enabled on this server");
|
throw new MethodNotAllowedException("$expunge is not enabled on this server");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -870,7 +868,7 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (myDaoConfig.isMarkResourcesForReindexingUponSearchParameterChange()) {
|
if (getConfig().isMarkResourcesForReindexingUponSearchParameterChange()) {
|
||||||
|
|
||||||
String expression = defaultString(theExpression);
|
String expression = defaultString(theExpression);
|
||||||
|
|
||||||
@ -1065,6 +1063,8 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
|
|||||||
@PostConstruct
|
@PostConstruct
|
||||||
@Override
|
@Override
|
||||||
public void start() {
|
public void start() {
|
||||||
|
assert getConfig() != null;
|
||||||
|
|
||||||
ourLog.debug("Starting resource DAO for type: {}", getResourceName());
|
ourLog.debug("Starting resource DAO for type: {}", getResourceName());
|
||||||
myInstanceValidator = getApplicationContext().getBean(IInstanceValidatorModule.class);
|
myInstanceValidator = getApplicationContext().getBean(IInstanceValidatorModule.class);
|
||||||
myTxTemplate = new TransactionTemplate(myPlatformTransactionManager);
|
myTxTemplate = new TransactionTemplate(myPlatformTransactionManager);
|
||||||
@ -1349,7 +1349,7 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
|
|||||||
throw new MethodNotAllowedException("Searching with _contained mode enabled is not enabled on this server");
|
throw new MethodNotAllowedException("Searching with _contained mode enabled is not enabled on this server");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (myDaoConfig.getIndexMissingFields() == DaoConfig.IndexEnabledEnum.DISABLED) {
|
if (getConfig().getIndexMissingFields() == DaoConfig.IndexEnabledEnum.DISABLED) {
|
||||||
for (List<List<IQueryParameterType>> nextAnds : theParams.values()) {
|
for (List<List<IQueryParameterType>> nextAnds : theParams.values()) {
|
||||||
for (List<? extends IQueryParameterType> nextOrs : nextAnds) {
|
for (List<? extends IQueryParameterType> nextOrs : nextAnds) {
|
||||||
for (IQueryParameterType next : nextOrs) {
|
for (IQueryParameterType next : nextOrs) {
|
||||||
@ -1414,10 +1414,10 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
|
|||||||
notifyInterceptors(RestOperationTypeEnum.SEARCH_TYPE, requestDetails);
|
notifyInterceptors(RestOperationTypeEnum.SEARCH_TYPE, requestDetails);
|
||||||
|
|
||||||
if (theRequest.isSubRequest()) {
|
if (theRequest.isSubRequest()) {
|
||||||
Integer max = myDaoConfig.getMaximumSearchResultCountInTransaction();
|
Integer max = getConfig().getMaximumSearchResultCountInTransaction();
|
||||||
if (max != null) {
|
if (max != null) {
|
||||||
Validate.inclusiveBetween(1, Integer.MAX_VALUE, max, "Maximum search result count in transaction ust be a positive integer");
|
Validate.inclusiveBetween(1, Integer.MAX_VALUE, max, "Maximum search result count in transaction ust be a positive integer");
|
||||||
theParams.setLoadSynchronousUpTo(myDaoConfig.getMaximumSearchResultCountInTransaction());
|
theParams.setLoadSynchronousUpTo(getConfig().getMaximumSearchResultCountInTransaction());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1447,7 +1447,7 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
|
|||||||
@Override
|
@Override
|
||||||
public Set<ResourcePersistentId> searchForIds(SearchParameterMap theParams, RequestDetails theRequest) {
|
public Set<ResourcePersistentId> searchForIds(SearchParameterMap theParams, RequestDetails theRequest) {
|
||||||
return myTransactionService.execute(theRequest, tx -> {
|
return myTransactionService.execute(theRequest, tx -> {
|
||||||
theParams.setLoadSynchronousUpTo(myDaoConfig.getInternalSynchronousSearchSize());
|
theParams.setLoadSynchronousUpTo(getConfig().getInternalSynchronousSearchSize());
|
||||||
|
|
||||||
ISearchBuilder builder = mySearchBuilderFactory.newSearchBuilder(this, getResourceName(), getResourceType());
|
ISearchBuilder builder = mySearchBuilderFactory.newSearchBuilder(this, getResourceName(), getResourceType());
|
||||||
|
|
||||||
@ -1619,7 +1619,12 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
|
|||||||
"Invalid resource ID[" + entity.getIdDt().toUnqualifiedVersionless() + "] of type[" + entity.getResourceType() + "] - Does not match expected [" + getResourceName() + "]");
|
"Invalid resource ID[" + entity.getIdDt().toUnqualifiedVersionless() + "] of type[" + entity.getResourceType() + "] - Does not match expected [" + getResourceName() + "]");
|
||||||
}
|
}
|
||||||
|
|
||||||
IBaseResource oldResource = toResource(entity, false);
|
IBaseResource oldResource;
|
||||||
|
if (getConfig().isMassIngestionMode()) {
|
||||||
|
oldResource = null;
|
||||||
|
} else {
|
||||||
|
oldResource = toResource(entity, false);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Mark the entity as not deleted - This is also done in the actual updateInternal()
|
* Mark the entity as not deleted - This is also done in the actual updateInternal()
|
||||||
@ -1689,7 +1694,7 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
|
|||||||
// Validate that there are no resources pointing to the candidate that
|
// Validate that there are no resources pointing to the candidate that
|
||||||
// would prevent deletion
|
// would prevent deletion
|
||||||
DeleteConflictList deleteConflicts = new DeleteConflictList();
|
DeleteConflictList deleteConflicts = new DeleteConflictList();
|
||||||
if (myDaoConfig.isEnforceReferentialIntegrityOnDelete()) {
|
if (getConfig().isEnforceReferentialIntegrityOnDelete()) {
|
||||||
myDeleteConflictService.validateOkToDelete(deleteConflicts, entity, true, theRequest, new TransactionDetails());
|
myDeleteConflictService.validateOkToDelete(deleteConflicts, entity, true, theRequest, new TransactionDetails());
|
||||||
}
|
}
|
||||||
DeleteConflictService.validateDeleteConflictsEmptyOrThrowException(getContext(), deleteConflicts);
|
DeleteConflictService.validateDeleteConflictsEmptyOrThrowException(getContext(), deleteConflicts);
|
||||||
@ -1759,7 +1764,7 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
|
|||||||
|
|
||||||
private void validateGivenIdIsAppropriateToRetrieveResource(IIdType theId, BaseHasResource entity) {
|
private void validateGivenIdIsAppropriateToRetrieveResource(IIdType theId, BaseHasResource entity) {
|
||||||
if (entity.getForcedId() != null) {
|
if (entity.getForcedId() != null) {
|
||||||
if (myDaoConfig.getResourceClientIdStrategy() != DaoConfig.ClientIdStrategyEnum.ANY) {
|
if (getConfig().getResourceClientIdStrategy() != DaoConfig.ClientIdStrategyEnum.ANY) {
|
||||||
if (theId.isIdPartValidLong()) {
|
if (theId.isIdPartValidLong()) {
|
||||||
// This means that the resource with the given numeric ID exists, but it has a "forced ID", meaning that
|
// This means that the resource with the given numeric ID exists, but it has a "forced ID", meaning that
|
||||||
// as far as the outside world is concerned, the given ID doesn't exist (it's just an internal pointer
|
// as far as the outside world is concerned, the given ID doesn't exist (it's just an internal pointer
|
||||||
@ -1782,11 +1787,6 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@VisibleForTesting
|
|
||||||
public void setDaoConfig(DaoConfig theDaoConfig) {
|
|
||||||
myDaoConfig = theDaoConfig;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class IdChecker implements IValidatorModule {
|
private static class IdChecker implements IValidatorModule {
|
||||||
|
|
||||||
private final ValidationModeEnum myMode;
|
private final ValidationModeEnum myMode;
|
||||||
|
@ -54,7 +54,7 @@ public abstract class BaseHapiFhirResourceDaoObservation<T extends IBaseResource
|
|||||||
ResourceTable retVal = super.updateEntity(theRequest, theResource, theEntity, theDeletedTimestampOrNull, thePerformIndexing, theUpdateVersion,
|
ResourceTable retVal = super.updateEntity(theRequest, theResource, theEntity, theDeletedTimestampOrNull, thePerformIndexing, theUpdateVersion,
|
||||||
theTransactionDetails, theForceUpdate, theCreateNewHistoryEntry);
|
theTransactionDetails, theForceUpdate, theCreateNewHistoryEntry);
|
||||||
|
|
||||||
if (myDaoConfig.isLastNEnabled()) {
|
if (getConfig().isLastNEnabled()) {
|
||||||
if (!retVal.isUnchangedInCurrentOperation()) {
|
if (!retVal.isUnchangedInCurrentOperation()) {
|
||||||
if (retVal.getDeleted() == null) {
|
if (retVal.getDeleted() == null) {
|
||||||
// Update indexes here for LastN operation.
|
// Update indexes here for LastN operation.
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package ca.uhn.fhir.jpa.dao;
|
package ca.uhn.fhir.jpa.dao;
|
||||||
|
|
||||||
|
import ca.uhn.fhir.jpa.api.config.DaoConfig;
|
||||||
import ca.uhn.fhir.jpa.api.dao.IFhirSystemDao;
|
import ca.uhn.fhir.jpa.api.dao.IFhirSystemDao;
|
||||||
import ca.uhn.fhir.jpa.api.model.ExpungeOptions;
|
import ca.uhn.fhir.jpa.api.model.ExpungeOptions;
|
||||||
import ca.uhn.fhir.jpa.api.model.ExpungeOutcome;
|
import ca.uhn.fhir.jpa.api.model.ExpungeOutcome;
|
||||||
@ -123,4 +124,5 @@ public abstract class BaseHapiFhirSystemDao<T extends IBaseBundle, MT> extends B
|
|||||||
protected String getResourceName() {
|
protected String getResourceName() {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -82,7 +82,7 @@ public class FhirResourceDaoValueSetDstu3 extends BaseHapiFhirResourceDao<ValueS
|
|||||||
boolean theUpdateVersion, TransactionDetails theTransactionDetails, boolean theForceUpdate, boolean theCreateNewHistoryEntry) {
|
boolean theUpdateVersion, TransactionDetails theTransactionDetails, boolean theForceUpdate, boolean theCreateNewHistoryEntry) {
|
||||||
ResourceTable retVal = super.updateEntity(theRequestDetails, theResource, theEntity, theDeletedTimestampOrNull, thePerformIndexing, theUpdateVersion, theTransactionDetails, theForceUpdate, theCreateNewHistoryEntry);
|
ResourceTable retVal = super.updateEntity(theRequestDetails, theResource, theEntity, theDeletedTimestampOrNull, thePerformIndexing, theUpdateVersion, theTransactionDetails, theForceUpdate, theCreateNewHistoryEntry);
|
||||||
|
|
||||||
if (myDaoConfig.isPreExpandValueSets() && !retVal.isUnchangedInCurrentOperation()) {
|
if (getConfig().isPreExpandValueSets() && !retVal.isUnchangedInCurrentOperation()) {
|
||||||
if (retVal.getDeleted() == null) {
|
if (retVal.getDeleted() == null) {
|
||||||
try {
|
try {
|
||||||
ValueSet valueSet = (ValueSet) theResource;
|
ValueSet valueSet = (ValueSet) theResource;
|
||||||
|
@ -42,6 +42,7 @@ import org.apache.commons.lang3.Validate;
|
|||||||
import org.hl7.fhir.instance.model.api.IAnyResource;
|
import org.hl7.fhir.instance.model.api.IAnyResource;
|
||||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||||
import org.hl7.fhir.instance.model.api.IIdType;
|
import org.hl7.fhir.instance.model.api.IIdType;
|
||||||
|
import org.hl7.fhir.r4.model.IdType;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
@ -144,7 +145,14 @@ public class IdHelperService {
|
|||||||
retVal = new ResourcePersistentId(resolveResourceIdentity(theRequestPartitionId, theResourceType, theId).getResourceId());
|
retVal = new ResourcePersistentId(resolveResourceIdentity(theRequestPartitionId, theResourceType, theId).getResourceId());
|
||||||
} else {
|
} else {
|
||||||
String key = toForcedIdToPidKey(theRequestPartitionId, theResourceType, theId);
|
String key = toForcedIdToPidKey(theRequestPartitionId, theResourceType, theId);
|
||||||
retVal = myMemoryCacheService.getThenPutAfterCommit(MemoryCacheService.CacheEnum.FORCED_ID_TO_PID, key, t -> new ResourcePersistentId(resolveResourceIdentity(theRequestPartitionId, theResourceType, theId).getResourceId()));
|
retVal = myMemoryCacheService.getThenPutAfterCommit(MemoryCacheService.CacheEnum.FORCED_ID_TO_PID, key, t -> {
|
||||||
|
List<IIdType> ids = Collections.singletonList(new IdType(theResourceType, theId));
|
||||||
|
List<ResourcePersistentId> resolvedIds = resolveResourcePersistentIdsWithCache(theRequestPartitionId, ids);
|
||||||
|
if (resolvedIds.isEmpty()) {
|
||||||
|
throw new ResourceNotFoundException(ids.get(0));
|
||||||
|
}
|
||||||
|
return resolvedIds.get(0);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
@ -196,14 +204,14 @@ public class IdHelperService {
|
|||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
String partitionIdStringForKey = RequestPartitionId.stringifyForKey(theRequestPartitionId);
|
// String partitionIdStringForKey = RequestPartitionId.stringifyForKey(theRequestPartitionId);
|
||||||
for (Iterator<String> idIterator = nextIds.iterator(); idIterator.hasNext(); ) {
|
for (Iterator<String> idIterator = nextIds.iterator(); idIterator.hasNext(); ) {
|
||||||
String nextId = idIterator.next();
|
String nextId = idIterator.next();
|
||||||
String key = partitionIdStringForKey + "/" + nextResourceType + "/" + nextId;
|
String key = toForcedIdToPidKey(theRequestPartitionId, nextResourceType, nextId);
|
||||||
Long nextCachedPid = myMemoryCacheService.getIfPresent(MemoryCacheService.CacheEnum.PERSISTENT_ID, key);
|
ResourcePersistentId nextCachedPid = myMemoryCacheService.getIfPresent(MemoryCacheService.CacheEnum.FORCED_ID_TO_PID, key);
|
||||||
if (nextCachedPid != null) {
|
if (nextCachedPid != null) {
|
||||||
idIterator.remove();
|
idIterator.remove();
|
||||||
retVal.add(new ResourcePersistentId(nextCachedPid));
|
retVal.add(nextCachedPid);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -224,10 +232,11 @@ public class IdHelperService {
|
|||||||
for (Object[] nextView : views) {
|
for (Object[] nextView : views) {
|
||||||
String forcedId = (String) nextView[0];
|
String forcedId = (String) nextView[0];
|
||||||
Long pid = (Long) nextView[1];
|
Long pid = (Long) nextView[1];
|
||||||
retVal.add(new ResourcePersistentId(pid));
|
ResourcePersistentId persistentId = new ResourcePersistentId(pid);
|
||||||
|
retVal.add(persistentId);
|
||||||
|
|
||||||
String key = partitionIdStringForKey + "/" + nextResourceType + "/" + forcedId;
|
String key = toForcedIdToPidKey(theRequestPartitionId, nextResourceType, forcedId);
|
||||||
myMemoryCacheService.put(MemoryCacheService.CacheEnum.PERSISTENT_ID, key, pid);
|
myMemoryCacheService.put(MemoryCacheService.CacheEnum.FORCED_ID_TO_PID, key, persistentId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -78,7 +78,7 @@ public class FhirResourceDaoValueSetR4 extends BaseHapiFhirResourceDao<ValueSet>
|
|||||||
boolean theUpdateVersion, TransactionDetails theTransactionDetails, boolean theForceUpdate, boolean theCreateNewHistoryEntry) {
|
boolean theUpdateVersion, TransactionDetails theTransactionDetails, boolean theForceUpdate, boolean theCreateNewHistoryEntry) {
|
||||||
ResourceTable retVal = super.updateEntity(theRequestDetails, theResource, theEntity, theDeletedTimestampOrNull, thePerformIndexing, theUpdateVersion, theTransactionDetails, theForceUpdate, theCreateNewHistoryEntry);
|
ResourceTable retVal = super.updateEntity(theRequestDetails, theResource, theEntity, theDeletedTimestampOrNull, thePerformIndexing, theUpdateVersion, theTransactionDetails, theForceUpdate, theCreateNewHistoryEntry);
|
||||||
|
|
||||||
if (myDaoConfig.isPreExpandValueSets() && !retVal.isUnchangedInCurrentOperation()) {
|
if (getConfig().isPreExpandValueSets() && !retVal.isUnchangedInCurrentOperation()) {
|
||||||
if (retVal.getDeleted() == null) {
|
if (retVal.getDeleted() == null) {
|
||||||
ValueSet valueSet = (ValueSet) theResource;
|
ValueSet valueSet = (ValueSet) theResource;
|
||||||
myTerminologySvc.storeTermValueSet(retVal, valueSet);
|
myTerminologySvc.storeTermValueSet(retVal, valueSet);
|
||||||
|
@ -79,7 +79,7 @@ public class FhirResourceDaoValueSetR5 extends BaseHapiFhirResourceDao<ValueSet>
|
|||||||
boolean theUpdateVersion, TransactionDetails theTransactionDetails, boolean theForceUpdate, boolean theCreateNewHistoryEntry) {
|
boolean theUpdateVersion, TransactionDetails theTransactionDetails, boolean theForceUpdate, boolean theCreateNewHistoryEntry) {
|
||||||
ResourceTable retVal = super.updateEntity(theRequestDetails, theResource, theEntity, theDeletedTimestampOrNull, thePerformIndexing, theUpdateVersion, theTransactionDetails, theForceUpdate, theCreateNewHistoryEntry);
|
ResourceTable retVal = super.updateEntity(theRequestDetails, theResource, theEntity, theDeletedTimestampOrNull, thePerformIndexing, theUpdateVersion, theTransactionDetails, theForceUpdate, theCreateNewHistoryEntry);
|
||||||
|
|
||||||
if (myDaoConfig.isPreExpandValueSets() && !retVal.isUnchangedInCurrentOperation()) {
|
if (getConfig().isPreExpandValueSets() && !retVal.isUnchangedInCurrentOperation()) {
|
||||||
if (retVal.getDeleted() == null) {
|
if (retVal.getDeleted() == null) {
|
||||||
ValueSet valueSet = (ValueSet) theResource;
|
ValueSet valueSet = (ValueSet) theResource;
|
||||||
myTerminologySvc.storeTermValueSet(retVal, org.hl7.fhir.convertors.conv40_50.ValueSet40_50.convertValueSet(valueSet));
|
myTerminologySvc.storeTermValueSet(retVal, org.hl7.fhir.convertors.conv40_50.ValueSet40_50.convertValueSet(valueSet));
|
||||||
|
@ -64,25 +64,35 @@ public class MemoryCacheService {
|
|||||||
for (CacheEnum next : CacheEnum.values()) {
|
for (CacheEnum next : CacheEnum.values()) {
|
||||||
|
|
||||||
long timeoutSeconds;
|
long timeoutSeconds;
|
||||||
|
int maximumSize;
|
||||||
|
|
||||||
switch (next) {
|
switch (next) {
|
||||||
case CONCEPT_TRANSLATION:
|
case CONCEPT_TRANSLATION:
|
||||||
case CONCEPT_TRANSLATION_REVERSE:
|
case CONCEPT_TRANSLATION_REVERSE:
|
||||||
timeoutSeconds = myDaoConfig.getTranslationCachesExpireAfterWriteInMinutes() * 1000;
|
timeoutSeconds = myDaoConfig.getTranslationCachesExpireAfterWriteInMinutes() * 1000;
|
||||||
|
maximumSize = 10000;
|
||||||
break;
|
break;
|
||||||
case HISTORY_COUNT:
|
|
||||||
case TAG_DEFINITION:
|
|
||||||
case PERSISTENT_ID:
|
|
||||||
case RESOURCE_LOOKUP:
|
|
||||||
case PID_TO_FORCED_ID:
|
case PID_TO_FORCED_ID:
|
||||||
case FORCED_ID_TO_PID:
|
case FORCED_ID_TO_PID:
|
||||||
case MATCH_URL:
|
case MATCH_URL:
|
||||||
|
timeoutSeconds = 60;
|
||||||
|
maximumSize = 10000;
|
||||||
|
if (myDaoConfig.isMassIngestionMode()) {
|
||||||
|
timeoutSeconds = 3000;
|
||||||
|
maximumSize = 100000;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case HISTORY_COUNT:
|
||||||
|
case TAG_DEFINITION:
|
||||||
|
case RESOURCE_LOOKUP:
|
||||||
case RESOURCE_CONDITIONAL_CREATE_VERSION:
|
case RESOURCE_CONDITIONAL_CREATE_VERSION:
|
||||||
default:
|
default:
|
||||||
timeoutSeconds = 60;
|
timeoutSeconds = 60;
|
||||||
|
maximumSize = 10000;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
Cache<Object, Object> nextCache = Caffeine.newBuilder().expireAfterWrite(timeoutSeconds, TimeUnit.MINUTES).maximumSize(10000).build();
|
Cache<Object, Object> nextCache = Caffeine.newBuilder().expireAfterWrite(timeoutSeconds, TimeUnit.MINUTES).maximumSize(maximumSize).build();
|
||||||
myCaches.put(next, nextCache);
|
myCaches.put(next, nextCache);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -163,7 +173,6 @@ public class MemoryCacheService {
|
|||||||
public enum CacheEnum {
|
public enum CacheEnum {
|
||||||
|
|
||||||
TAG_DEFINITION(TagDefinitionCacheKey.class),
|
TAG_DEFINITION(TagDefinitionCacheKey.class),
|
||||||
PERSISTENT_ID(String.class),
|
|
||||||
RESOURCE_LOOKUP(String.class),
|
RESOURCE_LOOKUP(String.class),
|
||||||
FORCED_ID_TO_PID(String.class),
|
FORCED_ID_TO_PID(String.class),
|
||||||
PID_TO_FORCED_ID(Long.class),
|
PID_TO_FORCED_ID(Long.class),
|
||||||
|
@ -79,6 +79,7 @@ import ca.uhn.fhir.jpa.term.api.ITermDeferredStorageSvc;
|
|||||||
import ca.uhn.fhir.jpa.term.api.ITermLoaderSvc;
|
import ca.uhn.fhir.jpa.term.api.ITermLoaderSvc;
|
||||||
import ca.uhn.fhir.jpa.term.api.ITermReadSvc;
|
import ca.uhn.fhir.jpa.term.api.ITermReadSvc;
|
||||||
import ca.uhn.fhir.jpa.term.api.ITermReadSvcR4;
|
import ca.uhn.fhir.jpa.term.api.ITermReadSvcR4;
|
||||||
|
import ca.uhn.fhir.jpa.util.MemoryCacheService;
|
||||||
import ca.uhn.fhir.jpa.util.ResourceCountCache;
|
import ca.uhn.fhir.jpa.util.ResourceCountCache;
|
||||||
import ca.uhn.fhir.jpa.validation.ValidationSettings;
|
import ca.uhn.fhir.jpa.validation.ValidationSettings;
|
||||||
import ca.uhn.fhir.parser.IParser;
|
import ca.uhn.fhir.parser.IParser;
|
||||||
@ -472,6 +473,8 @@ public abstract class BaseJpaR4Test extends BaseJpaTest implements ITestDataBuil
|
|||||||
@Autowired
|
@Autowired
|
||||||
protected ITermConceptMapGroupElementTargetDao myTermConceptMapGroupElementTargetDao;
|
protected ITermConceptMapGroupElementTargetDao myTermConceptMapGroupElementTargetDao;
|
||||||
@Autowired
|
@Autowired
|
||||||
|
protected MemoryCacheService myMemoryCacheService;
|
||||||
|
@Autowired
|
||||||
protected ICacheWarmingSvc myCacheWarmingSvc;
|
protected ICacheWarmingSvc myCacheWarmingSvc;
|
||||||
protected IServerInterceptor myInterceptor;
|
protected IServerInterceptor myInterceptor;
|
||||||
@Autowired
|
@Autowired
|
||||||
|
@ -1,10 +1,14 @@
|
|||||||
package ca.uhn.fhir.jpa.dao.r4;
|
package ca.uhn.fhir.jpa.dao.r4;
|
||||||
|
|
||||||
|
import ca.uhn.fhir.context.RuntimeSearchParam;
|
||||||
import ca.uhn.fhir.jpa.api.config.DaoConfig;
|
import ca.uhn.fhir.jpa.api.config.DaoConfig;
|
||||||
import ca.uhn.fhir.jpa.api.model.HistoryCountModeEnum;
|
import ca.uhn.fhir.jpa.api.model.HistoryCountModeEnum;
|
||||||
|
import ca.uhn.fhir.jpa.model.entity.ModelConfig;
|
||||||
import ca.uhn.fhir.jpa.model.util.JpaConstants;
|
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.SearchParameterMap;
|
||||||
import ca.uhn.fhir.jpa.util.SqlQuery;
|
import ca.uhn.fhir.jpa.util.SqlQuery;
|
||||||
|
import ca.uhn.fhir.rest.api.RestSearchParameterTypeEnum;
|
||||||
import ca.uhn.fhir.rest.api.SortSpec;
|
import ca.uhn.fhir.rest.api.SortSpec;
|
||||||
import ca.uhn.fhir.rest.api.server.IBundleProvider;
|
import ca.uhn.fhir.rest.api.server.IBundleProvider;
|
||||||
import ca.uhn.fhir.rest.param.ReferenceParam;
|
import ca.uhn.fhir.rest.param.ReferenceParam;
|
||||||
@ -14,7 +18,11 @@ import org.hl7.fhir.instance.model.api.IIdType;
|
|||||||
import org.hl7.fhir.r4.model.Bundle;
|
import org.hl7.fhir.r4.model.Bundle;
|
||||||
import org.hl7.fhir.r4.model.CareTeam;
|
import org.hl7.fhir.r4.model.CareTeam;
|
||||||
import org.hl7.fhir.r4.model.CodeSystem;
|
import org.hl7.fhir.r4.model.CodeSystem;
|
||||||
|
import org.hl7.fhir.r4.model.CodeableConcept;
|
||||||
|
import org.hl7.fhir.r4.model.Coding;
|
||||||
|
import org.hl7.fhir.r4.model.Coverage;
|
||||||
import org.hl7.fhir.r4.model.DateTimeType;
|
import org.hl7.fhir.r4.model.DateTimeType;
|
||||||
|
import org.hl7.fhir.r4.model.ExplanationOfBenefit;
|
||||||
import org.hl7.fhir.r4.model.IdType;
|
import org.hl7.fhir.r4.model.IdType;
|
||||||
import org.hl7.fhir.r4.model.Narrative;
|
import org.hl7.fhir.r4.model.Narrative;
|
||||||
import org.hl7.fhir.r4.model.Observation;
|
import org.hl7.fhir.r4.model.Observation;
|
||||||
@ -27,7 +35,11 @@ import org.junit.jupiter.api.AfterEach;
|
|||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
@ -48,6 +60,10 @@ public class FhirResourceDaoR4QueryCountTest extends BaseJpaR4Test {
|
|||||||
myDaoConfig.setDeleteEnabled(new DaoConfig().isDeleteEnabled());
|
myDaoConfig.setDeleteEnabled(new DaoConfig().isDeleteEnabled());
|
||||||
myDaoConfig.setMatchUrlCache(new DaoConfig().getMatchUrlCache());
|
myDaoConfig.setMatchUrlCache(new DaoConfig().getMatchUrlCache());
|
||||||
myDaoConfig.setHistoryCountMode(DaoConfig.DEFAULT_HISTORY_COUNT_MODE);
|
myDaoConfig.setHistoryCountMode(DaoConfig.DEFAULT_HISTORY_COUNT_MODE);
|
||||||
|
myDaoConfig.setMassIngestionMode(new DaoConfig().isMassIngestionMode());
|
||||||
|
myModelConfig.setAutoVersionReferenceAtPaths(new ModelConfig().getAutoVersionReferenceAtPaths());
|
||||||
|
myModelConfig.setRespectVersionsForSearchIncludes(new ModelConfig().isRespectVersionsForSearchIncludes());
|
||||||
|
myFhirCtx.getParserOptions().setStripVersionsFromReferences(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@BeforeEach
|
@BeforeEach
|
||||||
@ -537,7 +553,7 @@ public class FhirResourceDaoR4QueryCountTest extends BaseJpaR4Test {
|
|||||||
myCaptureQueriesListener.clear();
|
myCaptureQueriesListener.clear();
|
||||||
assertEquals(1, myObservationDao.search(map).size().intValue());
|
assertEquals(1, myObservationDao.search(map).size().intValue());
|
||||||
// Resolve forced ID, Perform search, load result
|
// Resolve forced ID, Perform search, load result
|
||||||
assertEquals(3, myCaptureQueriesListener.countSelectQueriesForCurrentThread());
|
assertEquals(2, myCaptureQueriesListener.countSelectQueriesForCurrentThread());
|
||||||
assertNoPartitionSelectors();
|
assertNoPartitionSelectors();
|
||||||
assertEquals(0, myCaptureQueriesListener.countInsertQueriesForCurrentThread());
|
assertEquals(0, myCaptureQueriesListener.countInsertQueriesForCurrentThread());
|
||||||
assertEquals(0, myCaptureQueriesListener.countUpdateQueriesForCurrentThread());
|
assertEquals(0, myCaptureQueriesListener.countUpdateQueriesForCurrentThread());
|
||||||
@ -579,7 +595,7 @@ public class FhirResourceDaoR4QueryCountTest extends BaseJpaR4Test {
|
|||||||
assertEquals(1, myObservationDao.search(map).size().intValue());
|
assertEquals(1, myObservationDao.search(map).size().intValue());
|
||||||
myCaptureQueriesListener.logAllQueriesForCurrentThread();
|
myCaptureQueriesListener.logAllQueriesForCurrentThread();
|
||||||
// Resolve forced ID, Perform search, load result
|
// Resolve forced ID, Perform search, load result
|
||||||
assertEquals(3, myCaptureQueriesListener.countSelectQueriesForCurrentThread());
|
assertEquals(2, myCaptureQueriesListener.countSelectQueriesForCurrentThread());
|
||||||
assertEquals(0, myCaptureQueriesListener.countInsertQueriesForCurrentThread());
|
assertEquals(0, myCaptureQueriesListener.countInsertQueriesForCurrentThread());
|
||||||
assertEquals(0, myCaptureQueriesListener.countUpdateQueriesForCurrentThread());
|
assertEquals(0, myCaptureQueriesListener.countUpdateQueriesForCurrentThread());
|
||||||
assertEquals(0, myCaptureQueriesListener.countDeleteQueriesForCurrentThread());
|
assertEquals(0, myCaptureQueriesListener.countDeleteQueriesForCurrentThread());
|
||||||
@ -830,9 +846,9 @@ public class FhirResourceDaoR4QueryCountTest extends BaseJpaR4Test {
|
|||||||
myCaptureQueriesListener.logSelectQueriesForCurrentThread();
|
myCaptureQueriesListener.logSelectQueriesForCurrentThread();
|
||||||
assertEquals(1, myCaptureQueriesListener.countSelectQueriesForCurrentThread());
|
assertEquals(1, myCaptureQueriesListener.countSelectQueriesForCurrentThread());
|
||||||
myCaptureQueriesListener.logInsertQueriesForCurrentThread();
|
myCaptureQueriesListener.logInsertQueriesForCurrentThread();
|
||||||
assertEquals(5, myCaptureQueriesListener.countInsertQueriesForCurrentThread());
|
assertEquals(4, myCaptureQueriesListener.countInsertQueriesForCurrentThread());
|
||||||
myCaptureQueriesListener.logUpdateQueriesForCurrentThread();
|
myCaptureQueriesListener.logUpdateQueriesForCurrentThread();
|
||||||
assertEquals(2, myCaptureQueriesListener.countUpdateQueriesForCurrentThread());
|
assertEquals(1, myCaptureQueriesListener.countUpdateQueriesForCurrentThread());
|
||||||
assertEquals(0, myCaptureQueriesListener.countDeleteQueriesForCurrentThread());
|
assertEquals(0, myCaptureQueriesListener.countDeleteQueriesForCurrentThread());
|
||||||
|
|
||||||
// Pass 2
|
// Pass 2
|
||||||
@ -1484,4 +1500,73 @@ public class FhirResourceDaoR4QueryCountTest extends BaseJpaR4Test {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testMassIngestionMode_TransactionWithChanges() {
|
||||||
|
myDaoConfig.setDeleteEnabled(false);
|
||||||
|
myDaoConfig.setMatchUrlCache(true);
|
||||||
|
myDaoConfig.setMassIngestionMode(true);
|
||||||
|
myFhirCtx.getParserOptions().setStripVersionsFromReferences(false);
|
||||||
|
myModelConfig.setRespectVersionsForSearchIncludes(true);
|
||||||
|
myModelConfig.setAutoVersionReferenceAtPaths(
|
||||||
|
"ExplanationOfBenefit.patient",
|
||||||
|
"ExplanationOfBenefit.insurance.coverage"
|
||||||
|
);
|
||||||
|
|
||||||
|
Patient warmUpPt = new Patient();
|
||||||
|
warmUpPt.getMeta().addProfile("http://foo");
|
||||||
|
warmUpPt.setActive(true);
|
||||||
|
myPatientDao.create(warmUpPt);
|
||||||
|
|
||||||
|
AtomicInteger ai = new AtomicInteger(0);
|
||||||
|
Supplier<Bundle> supplier = () -> {
|
||||||
|
BundleBuilder bb = new BundleBuilder(myFhirCtx);
|
||||||
|
|
||||||
|
Coverage coverage = new Coverage();
|
||||||
|
coverage.getMeta().addProfile("http://foo");
|
||||||
|
coverage.setId(IdType.newRandomUuid());
|
||||||
|
coverage.addIdentifier().setSystem("http://coverage").setValue("12345");
|
||||||
|
coverage.setStatus(Coverage.CoverageStatus.ACTIVE);
|
||||||
|
coverage.setType(new CodeableConcept().addCoding(new Coding("http://coverage-type", "12345", null)));
|
||||||
|
bb.addTransactionUpdateEntry(coverage).conditional("Coverage?identifier=http://coverage|12345");
|
||||||
|
|
||||||
|
Patient patient = new Patient();
|
||||||
|
patient.getMeta().addProfile("http://foo");
|
||||||
|
patient.setId("Patient/PATIENT-A");
|
||||||
|
patient.setActive(true);
|
||||||
|
patient.addName().setFamily("SMITH").addGiven("JAMES" + ai.incrementAndGet());
|
||||||
|
bb.addTransactionUpdateEntry(patient);
|
||||||
|
|
||||||
|
ExplanationOfBenefit eob = new ExplanationOfBenefit();
|
||||||
|
eob.getMeta().addProfile("http://foo");
|
||||||
|
eob.addIdentifier().setSystem("http://eob").setValue("12345");
|
||||||
|
eob.addInsurance().setCoverage(new Reference(coverage.getId()));
|
||||||
|
eob.getPatient().setReference(patient.getId());
|
||||||
|
eob.setCreatedElement(new DateTimeType("2021-01-01T12:12:12Z"));
|
||||||
|
bb.addTransactionUpdateEntry(eob).conditional("ExplanationOfBenefit?identifier=http://eob|12345");
|
||||||
|
|
||||||
|
return (Bundle) bb.getBundle();
|
||||||
|
};
|
||||||
|
|
||||||
|
myCaptureQueriesListener.clear();
|
||||||
|
mySystemDao.transaction(new SystemRequestDetails(), supplier.get());
|
||||||
|
// myCaptureQueriesListener.logSelectQueriesForCurrentThread();
|
||||||
|
assertEquals(5, myCaptureQueriesListener.countSelectQueriesForCurrentThread());
|
||||||
|
assertEquals(13, myCaptureQueriesListener.countInsertQueriesForCurrentThread());
|
||||||
|
assertEquals(3, myCaptureQueriesListener.countUpdateQueriesForCurrentThread());
|
||||||
|
assertEquals(0, myCaptureQueriesListener.countDeleteQueriesForCurrentThread());
|
||||||
|
|
||||||
|
myCaptureQueriesListener.clear();
|
||||||
|
mySystemDao.transaction(new SystemRequestDetails(), supplier.get());
|
||||||
|
myCaptureQueriesListener.logSelectQueriesForCurrentThread();
|
||||||
|
assertEquals(11, myCaptureQueriesListener.countSelectQueriesForCurrentThread());
|
||||||
|
assertEquals(2, myCaptureQueriesListener.countInsertQueriesForCurrentThread());
|
||||||
|
assertEquals(3, myCaptureQueriesListener.countUpdateQueriesForCurrentThread());
|
||||||
|
assertEquals(0, myCaptureQueriesListener.countDeleteQueriesForCurrentThread());
|
||||||
|
|
||||||
|
// assertEquals(15, myCaptureQueriesListener.countSelectQueriesForCurrentThread());
|
||||||
|
// assertEquals(1, myCaptureQueriesListener.countInsertQueriesForCurrentThread());
|
||||||
|
// assertEquals(3, myCaptureQueriesListener.countUpdateQueriesForCurrentThread());
|
||||||
|
// assertEquals(0, myCaptureQueriesListener.countDeleteQueriesForCurrentThread());
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1142,7 +1142,6 @@ public class FhirResourceDaoR4SearchOptimizedTest extends BaseJpaR4Test {
|
|||||||
myPatientDao.create(pt).getId().getIdPartAsLong();
|
myPatientDao.create(pt).getId().getIdPartAsLong();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
myCaptureQueriesListener.clear();
|
myCaptureQueriesListener.clear();
|
||||||
SearchParameterMap map = new SearchParameterMap();
|
SearchParameterMap map = new SearchParameterMap();
|
||||||
map.add(Patient.SP_ORGANIZATION, new ReferenceOrListParam()
|
map.add(Patient.SP_ORGANIZATION, new ReferenceOrListParam()
|
||||||
@ -1162,8 +1161,40 @@ public class FhirResourceDaoR4SearchOptimizedTest extends BaseJpaR4Test {
|
|||||||
.map(t -> t.getSql(true, false))
|
.map(t -> t.getSql(true, false))
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
// Forced ID resolution
|
// No resolution of the forced IDs since they should already be in the
|
||||||
|
// cache from the original write operation. So:
|
||||||
|
// 1 - perform the search
|
||||||
|
// 2 - load the results
|
||||||
|
assertEquals(2, queries.size());
|
||||||
|
|
||||||
|
// The search itself
|
||||||
String resultingQueryNotFormatted = queries.get(0);
|
String resultingQueryNotFormatted = queries.get(0);
|
||||||
|
assertEquals(1, StringUtils.countMatches(resultingQueryNotFormatted, "Patient.managingOrganization"), resultingQueryNotFormatted);
|
||||||
|
assertThat(resultingQueryNotFormatted, matchesPattern(".*TARGET_RESOURCE_ID IN \\('[0-9]+','[0-9]+','[0-9]+','[0-9]+','[0-9]+'\\).*"));
|
||||||
|
|
||||||
|
// Ensure that the search actually worked
|
||||||
|
assertEquals(5, search.size().intValue());
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Now clear the caches and make sure the lookup works as expected
|
||||||
|
*/
|
||||||
|
|
||||||
|
myMemoryCacheService.invalidateAllCaches();
|
||||||
|
myCaptureQueriesListener.clear();
|
||||||
|
search = myPatientDao.search(map);
|
||||||
|
|
||||||
|
myCaptureQueriesListener.logSelectQueriesForCurrentThread();
|
||||||
|
queries = myCaptureQueriesListener
|
||||||
|
.getSelectQueriesForCurrentThread()
|
||||||
|
.stream()
|
||||||
|
.map(t -> t.getSql(true, false))
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
|
// The first query is the forced ID resolution this time
|
||||||
|
assertEquals(3, queries.size());
|
||||||
|
|
||||||
|
// Forced ID resolution
|
||||||
|
resultingQueryNotFormatted = queries.get(0);
|
||||||
assertThat(resultingQueryNotFormatted, containsString("RESOURCE_TYPE='Organization'"));
|
assertThat(resultingQueryNotFormatted, containsString("RESOURCE_TYPE='Organization'"));
|
||||||
assertThat(resultingQueryNotFormatted, containsString("FORCED_ID in ('ORG0' , 'ORG1' , 'ORG2' , 'ORG3' , 'ORG4')"));
|
assertThat(resultingQueryNotFormatted, containsString("FORCED_ID in ('ORG0' , 'ORG1' , 'ORG2' , 'ORG3' , 'ORG4')"));
|
||||||
|
|
||||||
|
@ -36,7 +36,7 @@ public class FhirResourceDaoSearchParameterR4Test {
|
|||||||
|
|
||||||
myDao = new FhirResourceDaoSearchParameterR4();
|
myDao = new FhirResourceDaoSearchParameterR4();
|
||||||
myDao.setContext(myCtx);
|
myDao.setContext(myCtx);
|
||||||
myDao.setConfig(new DaoConfig());
|
myDao.setDaoConfigForUnitTest(new DaoConfig());
|
||||||
myDao.setApplicationContext(myApplicationContext);
|
myDao.setApplicationContext(myApplicationContext);
|
||||||
myDao.start();
|
myDao.start();
|
||||||
}
|
}
|
||||||
|
@ -2548,8 +2548,7 @@ public class PartitioningSqlR4Test extends BasePartitioningR4Test {
|
|||||||
|
|
||||||
ourLog.info("Search SQL:\n{}", myCaptureQueriesListener.getSelectQueriesForCurrentThread().get(0).getSql(true, true));
|
ourLog.info("Search SQL:\n{}", myCaptureQueriesListener.getSelectQueriesForCurrentThread().get(0).getSql(true, true));
|
||||||
String searchSql = myCaptureQueriesListener.getSelectQueriesForCurrentThread().get(0).getSql(true, false);
|
String searchSql = myCaptureQueriesListener.getSelectQueriesForCurrentThread().get(0).getSql(true, false);
|
||||||
assertEquals(1, StringUtils.countMatches(searchSql, "forcedid0_.PARTITION_ID in ('1')"), searchSql);
|
assertEquals(1, StringUtils.countMatches(searchSql, "PARTITION_ID IN ('1')"), searchSql);
|
||||||
assertEquals(1, StringUtils.countMatches(searchSql, "and forcedid0_.RESOURCE_TYPE='Patient'"), searchSql);
|
|
||||||
assertEquals(1, StringUtils.countMatches(searchSql, "PARTITION_ID"), searchSql);
|
assertEquals(1, StringUtils.countMatches(searchSql, "PARTITION_ID"), searchSql);
|
||||||
|
|
||||||
// Same query, different partition
|
// Same query, different partition
|
||||||
@ -2584,8 +2583,7 @@ public class PartitioningSqlR4Test extends BasePartitioningR4Test {
|
|||||||
|
|
||||||
String searchSql = myCaptureQueriesListener.getSelectQueriesForCurrentThread().get(0).getSql(true, true);
|
String searchSql = myCaptureQueriesListener.getSelectQueriesForCurrentThread().get(0).getSql(true, true);
|
||||||
ourLog.info("Search SQL:\n{}", searchSql);
|
ourLog.info("Search SQL:\n{}", searchSql);
|
||||||
assertEquals(1, StringUtils.countMatches(searchSql, "forcedid0_.PARTITION_ID is null"), searchSql);
|
assertEquals(1, StringUtils.countMatches(searchSql, "PARTITION_ID IS NULL"), searchSql);
|
||||||
assertEquals(1, StringUtils.countMatches(searchSql, "forcedid0_.RESOURCE_TYPE='Patient'"), searchSql);
|
|
||||||
assertEquals(1, StringUtils.countMatches(searchSql, "PARTITION_ID"), searchSql);
|
assertEquals(1, StringUtils.countMatches(searchSql, "PARTITION_ID"), searchSql);
|
||||||
|
|
||||||
// Same query, different partition
|
// Same query, different partition
|
||||||
|
@ -176,6 +176,7 @@ public class GiantTransactionPerfTest {
|
|||||||
|
|
||||||
mySystemDao = new FhirSystemDaoR4();
|
mySystemDao = new FhirSystemDaoR4();
|
||||||
mySystemDao.setTransactionProcessorForUnitTest(myTransactionProcessor);
|
mySystemDao.setTransactionProcessorForUnitTest(myTransactionProcessor);
|
||||||
|
mySystemDao.setDaoConfigForUnitTest(myDaoConfig);
|
||||||
mySystemDao.start();
|
mySystemDao.start();
|
||||||
|
|
||||||
when(myAppCtx.getBean(eq(IInstanceValidatorModule.class))).thenReturn(myInstanceValidatorSvc);
|
when(myAppCtx.getBean(eq(IInstanceValidatorModule.class))).thenReturn(myInstanceValidatorSvc);
|
||||||
@ -235,11 +236,10 @@ public class GiantTransactionPerfTest {
|
|||||||
|
|
||||||
myEobDao = new JpaResourceDao<>();
|
myEobDao = new JpaResourceDao<>();
|
||||||
myEobDao.setContext(myCtx);
|
myEobDao.setContext(myCtx);
|
||||||
myEobDao.setConfig(myDaoConfig);
|
myEobDao.setDaoConfigForUnitTest(myDaoConfig);
|
||||||
myEobDao.setResourceType(ExplanationOfBenefit.class);
|
myEobDao.setResourceType(ExplanationOfBenefit.class);
|
||||||
myEobDao.setApplicationContext(myAppCtx);
|
myEobDao.setApplicationContext(myAppCtx);
|
||||||
myEobDao.setTransactionService(myHapiTransactionService);
|
myEobDao.setTransactionService(myHapiTransactionService);
|
||||||
myEobDao.setDaoConfig(myDaoConfig);
|
|
||||||
myEobDao.setRequestPartitionHelperService(new MockRequestPartitionHelperSvc());
|
myEobDao.setRequestPartitionHelperService(new MockRequestPartitionHelperSvc());
|
||||||
myEobDao.setEntityManager(myEntityManager);
|
myEobDao.setEntityManager(myEntityManager);
|
||||||
myEobDao.setSearchParamWithInlineReferencesExtractor(mySearchParamWithInlineReferencesExtractor);
|
myEobDao.setSearchParamWithInlineReferencesExtractor(mySearchParamWithInlineReferencesExtractor);
|
||||||
@ -247,6 +247,7 @@ public class GiantTransactionPerfTest {
|
|||||||
myEobDao.setSearchParamRegistry(mySearchParamRegistry);
|
myEobDao.setSearchParamRegistry(mySearchParamRegistry);
|
||||||
myEobDao.setSearchParamPresenceSvc(mySearchParamPresenceSvc);
|
myEobDao.setSearchParamPresenceSvc(mySearchParamPresenceSvc);
|
||||||
myEobDao.setDaoSearchParamSynchronizer(myDaoSearchParamSynchronizer);
|
myEobDao.setDaoSearchParamSynchronizer(myDaoSearchParamSynchronizer);
|
||||||
|
myEobDao.setDaoConfigForUnitTest(myDaoConfig);
|
||||||
myEobDao.start();
|
myEobDao.start();
|
||||||
|
|
||||||
myDaoRegistry.setResourceDaos(Lists.newArrayList(myEobDao));
|
myDaoRegistry.setResourceDaos(Lists.newArrayList(myEobDao));
|
||||||
|
659
hapi-fhir-jpaserver-base/src/test/resources/r4/eob-bundle.json
Normal file
659
hapi-fhir-jpaserver-base/src/test/resources/r4/eob-bundle.json
Normal file
@ -0,0 +1,659 @@
|
|||||||
|
{
|
||||||
|
"resourceType": "Bundle",
|
||||||
|
"type": "transaction",
|
||||||
|
"entry": [{
|
||||||
|
"resource": {
|
||||||
|
"resourceType": "ExplanationOfBenefit",
|
||||||
|
"identifier": [{
|
||||||
|
"type": {
|
||||||
|
"coding": [{
|
||||||
|
"system": "http://hl7.org/fhir/us/carin-bb/CodeSystem/C4BBIdentifierType",
|
||||||
|
"code": "payerid"
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
"system": "https://hl7.org/fhir/sid/payerid",
|
||||||
|
"value": "37470269207"
|
||||||
|
}, {
|
||||||
|
"type": {
|
||||||
|
"coding": [{
|
||||||
|
"system": "http://hl7.org/fhir/us/carin-bb/CodeSystem/C4BBIdentifierType",
|
||||||
|
"code": "uc"
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
"system": "https://hl7.org/fhir/sid/claimid",
|
||||||
|
"value": "208676340"
|
||||||
|
}],
|
||||||
|
"status": "active",
|
||||||
|
"type": {
|
||||||
|
"coding": [{
|
||||||
|
"system": "http://terminology.hl7.org/CodeSystem/claim-type",
|
||||||
|
"code": "professional"
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
"use": "claim",
|
||||||
|
"patient": {
|
||||||
|
"reference": "Patient/7ba514fa-6ec2-3203-ef80-2d142a88bb1d"
|
||||||
|
},
|
||||||
|
"billablePeriod": {
|
||||||
|
"start": "2021-01-06",
|
||||||
|
"end": "2021-01-06"
|
||||||
|
},
|
||||||
|
"created": "2021-01-06T00:00:00-08:00",
|
||||||
|
"insurer": {
|
||||||
|
"reference": "Organization/4772bdd0-7f10-d3d1-458c-db66eb2b0d17"
|
||||||
|
},
|
||||||
|
"provider": {
|
||||||
|
"reference": "Organization/330cfdc3-22d4-6946-bd37-4ac82e5b48c5"
|
||||||
|
},
|
||||||
|
"related": [{
|
||||||
|
"relationship": {
|
||||||
|
"coding": [{
|
||||||
|
"system": "http://terminology.hl7.org/CodeSystem/ex-relatedclaimrelationship",
|
||||||
|
"code": "prior"
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
"reference": {
|
||||||
|
"type": {
|
||||||
|
"coding": [{
|
||||||
|
"system": "http://hl7.org/fhir/us/carin-bb/CodeSystem/C4BBIdentifierType",
|
||||||
|
"code": "uc"
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
"value": "208676157"
|
||||||
|
}
|
||||||
|
}],
|
||||||
|
"payee": {
|
||||||
|
"type": {
|
||||||
|
"coding": [{
|
||||||
|
"system": "http://terminology.hl7.org/CodeSystem/payeetype",
|
||||||
|
"code": "provider"
|
||||||
|
}],
|
||||||
|
"text": "Claim paid to Provider"
|
||||||
|
},
|
||||||
|
"party": {
|
||||||
|
"reference": "Organization/330cfdc3-22d4-6946-bd37-4ac82e5b48c5"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"facility": {
|
||||||
|
"reference": "Location/48f91ece-c048-6b55-0e37-782630e9c4d0"
|
||||||
|
},
|
||||||
|
"outcome": "complete",
|
||||||
|
"disposition": "PAID",
|
||||||
|
"careTeam": [{
|
||||||
|
"sequence": 1,
|
||||||
|
"provider": {
|
||||||
|
"reference": "Practitioner/dbb4fe06-98c4-e8de-3eef-f1b42e07509b"
|
||||||
|
},
|
||||||
|
"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": "2021-01-06"
|
||||||
|
}, {
|
||||||
|
"sequence": 2,
|
||||||
|
"category": {
|
||||||
|
"coding": [{
|
||||||
|
"system": "http://hl7.org/fhir/us/carin-bb/CodeSystem/C4BBSupportingInfoType",
|
||||||
|
"code": "noncontracted"
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
}],
|
||||||
|
"diagnosis": [{
|
||||||
|
"sequence": 1,
|
||||||
|
"diagnosisCodeableConcept": {
|
||||||
|
"coding": [{
|
||||||
|
"system": "http://hl7.org/fhir/sid/icd-10-cm",
|
||||||
|
"code": "R50.9"
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
"type": [{
|
||||||
|
"coding": [{
|
||||||
|
"system": "http://terminology.hl7.org/CodeSystem/ex-diagnosistype",
|
||||||
|
"code": "principal"
|
||||||
|
}]
|
||||||
|
}]
|
||||||
|
}],
|
||||||
|
"procedure": [{
|
||||||
|
"sequence": 1,
|
||||||
|
"date": "2021-01-06T00:00:00-08:00",
|
||||||
|
"procedureCodeableConcept": {
|
||||||
|
"coding": [{
|
||||||
|
"system": "http://www.ama-assn.org/go/cpt",
|
||||||
|
"code": "99283",
|
||||||
|
"display": "Emergency department visit for moderate problem"
|
||||||
|
}],
|
||||||
|
"text": "EMERGENCY DEPARTMENT VISIT MODERATE SEVERITY"
|
||||||
|
}
|
||||||
|
}],
|
||||||
|
"insurance": [{
|
||||||
|
"focal": true,
|
||||||
|
"coverage": {
|
||||||
|
"reference": "urn:uuid:f556ad3d-e1a3-46f2-91d5-fd3ff57c1cef"
|
||||||
|
}
|
||||||
|
}],
|
||||||
|
"item": [{
|
||||||
|
"sequence": 1,
|
||||||
|
"diagnosisSequence": [1],
|
||||||
|
"procedureSequence": [1],
|
||||||
|
"productOrService": {
|
||||||
|
"coding": [{
|
||||||
|
"system": "http://www.ama-assn.org/go/cpt",
|
||||||
|
"code": "99283",
|
||||||
|
"display": "Emergency department visit for moderate problem"
|
||||||
|
}],
|
||||||
|
"text": "EMERGENCY DEPARTMENT VISIT MODERATE SEVERITY"
|
||||||
|
},
|
||||||
|
"servicedPeriod": {
|
||||||
|
"start": "2021-01-06",
|
||||||
|
"end": "2021-01-06"
|
||||||
|
},
|
||||||
|
"locationCodeableConcept": {
|
||||||
|
"coding": [{
|
||||||
|
"system": "https://www.cms.gov/Medicare/Coding/place-of-service-codes/Place_of_Service_Code_Set",
|
||||||
|
"code": "23"
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
"quantity": {
|
||||||
|
"value": -1,
|
||||||
|
"unit": "Units",
|
||||||
|
"system": "http://unitsofmeasure.org",
|
||||||
|
"code": "[arb'U]"
|
||||||
|
},
|
||||||
|
"net": {
|
||||||
|
"value": -2000000.0
|
||||||
|
},
|
||||||
|
"adjudication": [{
|
||||||
|
"category": {
|
||||||
|
"coding": [{
|
||||||
|
"system": "http://terminology.hl7.org/CodeSystem/adjudication",
|
||||||
|
"code": "submitted"
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
"amount": {
|
||||||
|
"value": -2000000.00,
|
||||||
|
"currency": "USD"
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
"category": {
|
||||||
|
"coding": [{
|
||||||
|
"system": "http://terminology.hl7.org/CodeSystem/adjudication",
|
||||||
|
"code": "benefit"
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
"amount": {
|
||||||
|
"value": -2000000.00,
|
||||||
|
"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": 0.00,
|
||||||
|
"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": 0.00,
|
||||||
|
"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": -2000000.00,
|
||||||
|
"currency": "USD"
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
"category": {
|
||||||
|
"coding": [{
|
||||||
|
"system": "http://hl7.org/fhir/us/carin-bb/CodeSystem/C4BBPayerAdjudicationStatus",
|
||||||
|
"code": "outofnetwork"
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
"amount": {
|
||||||
|
"value": -2000000.00,
|
||||||
|
"currency": "USD"
|
||||||
|
}
|
||||||
|
}]
|
||||||
|
}],
|
||||||
|
"total": [{
|
||||||
|
"category": {
|
||||||
|
"coding": [{
|
||||||
|
"system": "http://terminology.hl7.org/CodeSystem/adjudication",
|
||||||
|
"code": "submitted"
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
"amount": {
|
||||||
|
"value": -2000000.00,
|
||||||
|
"currency": "USD"
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
"category": {
|
||||||
|
"coding": [{
|
||||||
|
"system": "http://terminology.hl7.org/CodeSystem/adjudication",
|
||||||
|
"code": "benefit"
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
"amount": {
|
||||||
|
"value": -2000000.00,
|
||||||
|
"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": 0.00,
|
||||||
|
"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": 0.00,
|
||||||
|
"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": -2000000.00,
|
||||||
|
"currency": "USD"
|
||||||
|
}
|
||||||
|
}],
|
||||||
|
"payment": {
|
||||||
|
"date": "2021-01-11",
|
||||||
|
"amount": {
|
||||||
|
"value": -2000000.00,
|
||||||
|
"currency": "USD"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"request": {
|
||||||
|
"method": "PUT",
|
||||||
|
"url": "ExplanationOfBenefit?identifier=37470269207"
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
"resource": {
|
||||||
|
"resourceType": "Patient",
|
||||||
|
"id": "7ba514fa-6ec2-3203-ef80-2d142a88bb1d",
|
||||||
|
"meta": {
|
||||||
|
"lastUpdated": "2021-05-22",
|
||||||
|
"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://foo.org/front-door",
|
||||||
|
"value": "A0A0A0A0"
|
||||||
|
}],
|
||||||
|
"name": [{
|
||||||
|
"use": "usual",
|
||||||
|
"text": "Rhrg Tapymgr",
|
||||||
|
"family": "Tapymgr",
|
||||||
|
"given": ["Rhrg"]
|
||||||
|
}],
|
||||||
|
"gender": "male",
|
||||||
|
"birthDate": "1982-05-05",
|
||||||
|
"address": [{
|
||||||
|
"use": "home",
|
||||||
|
"type": "postal",
|
||||||
|
"line": ["300 GAVEN ST"],
|
||||||
|
"city": "SAN FRANCISCO",
|
||||||
|
"state": "CA",
|
||||||
|
"postalCode": "94134-1113"
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
"request": {
|
||||||
|
"method": "PUT",
|
||||||
|
"url": "Patient/7ba514fa-6ec2-3203-ef80-2d142a88bb1d"
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
"fullUrl": "urn:uuid:f556ad3d-e1a3-46f2-91d5-fd3ff57c1cef",
|
||||||
|
"resource": {
|
||||||
|
"resourceType": "Coverage",
|
||||||
|
"meta": {
|
||||||
|
"lastUpdated": "2021-05-22",
|
||||||
|
"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": "A0A0A0A0-000088006"
|
||||||
|
}],
|
||||||
|
"status": "active",
|
||||||
|
"type": {
|
||||||
|
"coding": [{
|
||||||
|
"system": "http://terminology.hl7.org/CodeSystem/v3-ActCode",
|
||||||
|
"code": "HMO",
|
||||||
|
"display": "health maintenance organization policy"
|
||||||
|
}],
|
||||||
|
"text": "HMO - HMO COMMERCIAL-HMO"
|
||||||
|
},
|
||||||
|
"subscriberId": "110066672294",
|
||||||
|
"beneficiary": {
|
||||||
|
"reference": "Patient/7ba514fa-6ec2-3203-ef80-2d142a88bb1d"
|
||||||
|
},
|
||||||
|
"relationship": {
|
||||||
|
"coding": [{
|
||||||
|
"system": "http://terminology.hl7.org/CodeSystem/subscriber-relationship",
|
||||||
|
"code": "self",
|
||||||
|
"display": "Self"
|
||||||
|
}],
|
||||||
|
"text": "The Beneficiary is the Subscriber"
|
||||||
|
},
|
||||||
|
"period": {
|
||||||
|
"start": "2018-07-01"
|
||||||
|
},
|
||||||
|
"class": [{
|
||||||
|
"type": {
|
||||||
|
"coding": [{
|
||||||
|
"system": "http://terminology.hl7.org/CodeSystem/coverage-class",
|
||||||
|
"code": "group",
|
||||||
|
"display": "Group"
|
||||||
|
}],
|
||||||
|
"text": "An employee group"
|
||||||
|
},
|
||||||
|
"value": "88006",
|
||||||
|
"name": "JEFFCO PAINTING & COATING JEFFCO PAINTING & COATING-HMO"
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
"request": {
|
||||||
|
"method": "PUT",
|
||||||
|
"url": "Coverage?identifier=A0A0A0A0-000088006"
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
"resource": {
|
||||||
|
"resourceType": "Organization",
|
||||||
|
"id": "330cfdc3-22d4-6946-bd37-4ac82e5b48c5",
|
||||||
|
"meta": {
|
||||||
|
"lastUpdated": "2021-05-22",
|
||||||
|
"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": "1649794157"
|
||||||
|
}, {
|
||||||
|
"type": {
|
||||||
|
"coding": [{
|
||||||
|
"system": "http://terminology.hl7.org/CodeSystem/v2-0203",
|
||||||
|
"code": "TAX"
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
"system": "urn:oid:2.16.840.1.113883.4.4",
|
||||||
|
"value": "821883948"
|
||||||
|
}],
|
||||||
|
"active": true,
|
||||||
|
"type": [{
|
||||||
|
"coding": [{
|
||||||
|
"system": "http://terminology.hl7.org/CodeSystem/organization-type",
|
||||||
|
"code": "prov"
|
||||||
|
}]
|
||||||
|
}],
|
||||||
|
"name": "OU MEDICAL CENTER",
|
||||||
|
"address": [{
|
||||||
|
"use": "work",
|
||||||
|
"type": "physical",
|
||||||
|
"line": ["PO BOX 277362"],
|
||||||
|
"city": "ATLANTA",
|
||||||
|
"state": "GA",
|
||||||
|
"postalCode": "30384-9998",
|
||||||
|
"country": "USA"
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
"request": {
|
||||||
|
"method": "PUT",
|
||||||
|
"url": "Organization/330cfdc3-22d4-6946-bd37-4ac82e5b48c5"
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
"resource": {
|
||||||
|
"resourceType": "Organization",
|
||||||
|
"id": "4772bdd0-7f10-d3d1-458c-db66eb2b0d17",
|
||||||
|
"meta": {
|
||||||
|
"lastUpdated": "2021-05-22",
|
||||||
|
"profile": ["http://hl7.org/fhir/us/carin-bb/StructureDefinition/C4BB-Organization"]
|
||||||
|
},
|
||||||
|
"active": true,
|
||||||
|
"type": [{
|
||||||
|
"coding": [{
|
||||||
|
"system": "http://terminology.hl7.org/CodeSystem/organization-type",
|
||||||
|
"code": "pay",
|
||||||
|
"display": "Payer"
|
||||||
|
}]
|
||||||
|
}],
|
||||||
|
"name": "FOO",
|
||||||
|
"telecom": [{
|
||||||
|
"system": "phone",
|
||||||
|
"value": "1-800-000-0000",
|
||||||
|
"use": "work"
|
||||||
|
}],
|
||||||
|
"address": [{
|
||||||
|
"use": "work",
|
||||||
|
"type": "postal",
|
||||||
|
"line": ["NATIONAL CLAIMS ADMINISTRATION NORTHERN CALIFORNIA", "PO Box 629028"],
|
||||||
|
"city": "El Dorado Hills",
|
||||||
|
"state": "CA",
|
||||||
|
"postalCode": "95762-9028"
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
"request": {
|
||||||
|
"method": "PUT",
|
||||||
|
"url": "Organization/4772bdd0-7f10-d3d1-458c-db66eb2b0d17"
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
"resource": {
|
||||||
|
"resourceType": "Practitioner",
|
||||||
|
"id": "dbb4fe06-98c4-e8de-3eef-f1b42e07509b",
|
||||||
|
"meta": {
|
||||||
|
"lastUpdated": "2021-05-22",
|
||||||
|
"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": "1649794157"
|
||||||
|
}],
|
||||||
|
"name": [{
|
||||||
|
"use": "usual",
|
||||||
|
"text": "OU MEDICAL CENTER",
|
||||||
|
"family": "OU MEDICAL CENTER"
|
||||||
|
}],
|
||||||
|
"address": [{
|
||||||
|
"use": "work",
|
||||||
|
"line": ["1200 EVERETT DRIVE"],
|
||||||
|
"city": "OKLAHOMA CITY",
|
||||||
|
"state": "OK",
|
||||||
|
"postalCode": "73104-5047"
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
"request": {
|
||||||
|
"method": "PUT",
|
||||||
|
"url": "Practitioner/dbb4fe06-98c4-e8de-3eef-f1b42e07509b"
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
"resource": {
|
||||||
|
"resourceType": "Location",
|
||||||
|
"id": "48f91ece-c048-6b55-0e37-782630e9c4d0",
|
||||||
|
"meta": {
|
||||||
|
"lastUpdated": "2021-05-22"
|
||||||
|
},
|
||||||
|
"identifier": [{
|
||||||
|
"use": "usual",
|
||||||
|
"type": {
|
||||||
|
"coding": [{
|
||||||
|
"system": "http://terminology.hl7.org/CodeSystem/v2-0203",
|
||||||
|
"code": "NPI"
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
"value": "PIN12181422"
|
||||||
|
}],
|
||||||
|
"status": "active",
|
||||||
|
"name": "OU MED CTR - CHILDRENS HOSPITAL",
|
||||||
|
"mode": "kind",
|
||||||
|
"type": [{
|
||||||
|
"coding": [{
|
||||||
|
"system": "https://www.cms.gov/Medicare/Coding/place-of-service-codes/Place_of_Service_Code_Set",
|
||||||
|
"code": "99"
|
||||||
|
}]
|
||||||
|
}],
|
||||||
|
"address": {
|
||||||
|
"use": "work",
|
||||||
|
"type": "physical",
|
||||||
|
"line": ["1200 EVERETT DRIVE"],
|
||||||
|
"city": "OKLAHOMA CITY",
|
||||||
|
"state": "OK",
|
||||||
|
"postalCode": "73104-5047"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"request": {
|
||||||
|
"method": "PUT",
|
||||||
|
"url": "Location/48f91ece-c048-6b55-0e37-782630e9c4d0"
|
||||||
|
}
|
||||||
|
}]
|
||||||
|
}
|
@ -59,6 +59,7 @@ import static org.apache.commons.lang3.StringUtils.defaultString;
|
|||||||
@Index(name = "IDX_RES_TYPE", columnList = "RES_TYPE"),
|
@Index(name = "IDX_RES_TYPE", columnList = "RES_TYPE"),
|
||||||
@Index(name = "IDX_INDEXSTATUS", columnList = "SP_INDEX_STATUS")
|
@Index(name = "IDX_INDEXSTATUS", columnList = "SP_INDEX_STATUS")
|
||||||
})
|
})
|
||||||
|
@NamedEntityGraph(name = "Resource.noJoins")
|
||||||
public class ResourceTable extends BaseHasResource implements Serializable, IBasePersistedResource, IResourceLookup {
|
public class ResourceTable extends BaseHasResource implements Serializable, IBasePersistedResource, IResourceLookup {
|
||||||
public static final int RESTYPE_LEN = 40;
|
public static final int RESTYPE_LEN = 40;
|
||||||
private static final int MAX_LANGUAGE_LENGTH = 20;
|
private static final int MAX_LANGUAGE_LENGTH = 20;
|
||||||
@ -691,12 +692,14 @@ public class ResourceTable extends BaseHasResource implements Serializable, IBas
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public IdDt getIdDt() {
|
public IdDt getIdDt() {
|
||||||
if (getForcedId() == null) {
|
if (getTransientForcedId() != null) {
|
||||||
|
// Avoid a join query if possible
|
||||||
|
return new IdDt(getResourceType() + '/' + getTransientForcedId() + '/' + Constants.PARAM_HISTORY + '/' + getVersion());
|
||||||
|
} else if (getForcedId() == null) {
|
||||||
Long id = this.getResourceId();
|
Long id = this.getResourceId();
|
||||||
return new IdDt(getResourceType() + '/' + id + '/' + Constants.PARAM_HISTORY + '/' + getVersion());
|
return new IdDt(getResourceType() + '/' + id + '/' + Constants.PARAM_HISTORY + '/' + getVersion());
|
||||||
} else {
|
} else {
|
||||||
// Avoid a join query if possible
|
String forcedId = getForcedId().getForcedId();
|
||||||
String forcedId = getTransientForcedId() != null ? getTransientForcedId() : getForcedId().getForcedId();
|
|
||||||
return new IdDt(getResourceType() + '/' + forcedId + '/' + Constants.PARAM_HISTORY + '/' + getVersion());
|
return new IdDt(getResourceType() + '/' + forcedId + '/' + Constants.PARAM_HISTORY + '/' + getVersion());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -23,6 +23,7 @@ package ca.uhn.fhir.jpa.searchparam.registry;
|
|||||||
import ca.uhn.fhir.context.FhirContext;
|
import ca.uhn.fhir.context.FhirContext;
|
||||||
import ca.uhn.fhir.context.RuntimeResourceDefinition;
|
import ca.uhn.fhir.context.RuntimeResourceDefinition;
|
||||||
import ca.uhn.fhir.context.RuntimeSearchParam;
|
import ca.uhn.fhir.context.RuntimeSearchParam;
|
||||||
|
import com.google.common.annotations.VisibleForTesting;
|
||||||
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
@ -45,8 +45,8 @@ import org.slf4j.Logger;
|
|||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
|
import javax.annotation.Nullable;
|
||||||
import javax.annotation.PostConstruct;
|
import javax.annotation.PostConstruct;
|
||||||
import javax.annotation.PreDestroy;
|
import javax.annotation.PreDestroy;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@ -313,4 +313,5 @@ public class SearchParamRegistryImpl implements ISearchParamRegistry, IResourceC
|
|||||||
public void resetForUnitTest() {
|
public void resetForUnitTest() {
|
||||||
handleInit(Collections.emptyList());
|
handleInit(Collections.emptyList());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user