Merge branch 'master' into bugfix/1752-support-chained-parameters-inside-reverse-chained-parameter
This commit is contained in:
commit
4777d75e6b
|
@ -0,0 +1,9 @@
|
||||||
|
package ca.uhn.fhir.model.api;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonAutoDetect;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||||
|
|
||||||
|
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||||
|
@JsonAutoDetect(creatorVisibility = JsonAutoDetect.Visibility.NONE, fieldVisibility = JsonAutoDetect.Visibility.NONE, getterVisibility = JsonAutoDetect.Visibility.NONE, isGetterVisibility = JsonAutoDetect.Visibility.NONE, setterVisibility = JsonAutoDetect.Visibility.NONE)
|
||||||
|
public interface IModelJson {
|
||||||
|
}
|
|
@ -83,6 +83,7 @@ ca.uhn.fhir.jpa.dao.BaseHapiFhirSystemDao.transactionMissingUrl=Unable to perfor
|
||||||
ca.uhn.fhir.jpa.dao.BaseHapiFhirSystemDao.transactionInvalidUrl=Unable to perform {0}, URL provided is invalid: {1}
|
ca.uhn.fhir.jpa.dao.BaseHapiFhirSystemDao.transactionInvalidUrl=Unable to perform {0}, URL provided is invalid: {1}
|
||||||
|
|
||||||
ca.uhn.fhir.jpa.dao.BaseHapiFhirResourceDao.cantValidateWithNoResource=No resource supplied for $validate operation (resource is required unless mode is \"delete\")
|
ca.uhn.fhir.jpa.dao.BaseHapiFhirResourceDao.cantValidateWithNoResource=No resource supplied for $validate operation (resource is required unless mode is \"delete\")
|
||||||
|
ca.uhn.fhir.jpa.dao.BaseHapiFhirResourceDao.deleteBlockedBecauseDisabled=Resource deletion is not permitted on this server
|
||||||
ca.uhn.fhir.jpa.dao.BaseHapiFhirResourceDao.duplicateCreateForcedId=Can not create entity with ID[{0}], a resource with this ID already exists
|
ca.uhn.fhir.jpa.dao.BaseHapiFhirResourceDao.duplicateCreateForcedId=Can not create entity with ID[{0}], a resource with this ID already exists
|
||||||
ca.uhn.fhir.jpa.dao.BaseHapiFhirResourceDao.failedToCreateWithInvalidId=Can not process entity with ID[{0}], this is not a valid FHIR ID
|
ca.uhn.fhir.jpa.dao.BaseHapiFhirResourceDao.failedToCreateWithInvalidId=Can not process entity with ID[{0}], this is not a valid FHIR ID
|
||||||
ca.uhn.fhir.jpa.dao.BaseHapiFhirResourceDao.incorrectResourceType=Incorrect resource type detected for endpoint, found {0} but expected {1}
|
ca.uhn.fhir.jpa.dao.BaseHapiFhirResourceDao.incorrectResourceType=Incorrect resource type detected for endpoint, found {0} but expected {1}
|
||||||
|
|
|
@ -324,6 +324,17 @@
|
||||||
"city": "Germany",
|
"city": "Germany",
|
||||||
"lat": 51.165691,
|
"lat": 51.165691,
|
||||||
"lon": 10.451526
|
"lon": 10.451526
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "VEIG",
|
||||||
|
"description": "Vietnam Ehealth Innovation Group",
|
||||||
|
"link": "http://emr.com.vn",
|
||||||
|
"contactName": "Nguyen Hai Phong",
|
||||||
|
"contactEmail": "haiphong.nguyen@gmail.com",
|
||||||
|
"city": "Hanoi,Vietnam",
|
||||||
|
"lat": 21.026058,
|
||||||
|
"lon": 105.822715,
|
||||||
|
"added": "2020-03-06"
|
||||||
}
|
}
|
||||||
|
|
||||||
]
|
]
|
||||||
|
|
|
@ -43,6 +43,7 @@ page.server_jpa.get_started=Get Started ⚡
|
||||||
page.server_jpa.architecture=Architecture
|
page.server_jpa.architecture=Architecture
|
||||||
page.server_jpa.configuration=Configuration
|
page.server_jpa.configuration=Configuration
|
||||||
page.server_jpa.search=Search
|
page.server_jpa.search=Search
|
||||||
|
page.server_jpa.performance=Performance
|
||||||
page.server_jpa.upgrading=Upgrade Guide
|
page.server_jpa.upgrading=Upgrade Guide
|
||||||
|
|
||||||
section.interceptors.title=Interceptors
|
section.interceptors.title=Interceptors
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
# Performance
|
||||||
|
|
||||||
|
This page contains information for performance optimization.
|
||||||
|
|
||||||
|
# Bulk Loading
|
||||||
|
|
||||||
|
On servers where a large amount of data will be ingested, the following considerations may be helpful:
|
||||||
|
|
||||||
|
* Optimize your database thread pool count and HTTP client thread count: Every environment will have a different optimal setting for the number of concurrent writes that are permitted, and the maximum number of database connections allowed.
|
||||||
|
|
||||||
|
* Disable deletes: If the JPA server is configured to have the FHIR delete operation disabled, it is able to skip some resource reference deletion checks during resource creation, which can have a measurable improvement to performance over large datasets.
|
|
@ -22,8 +22,7 @@ package ca.uhn.fhir.jpa.binstore;
|
||||||
|
|
||||||
import ca.uhn.fhir.jpa.util.JsonDateDeserializer;
|
import ca.uhn.fhir.jpa.util.JsonDateDeserializer;
|
||||||
import ca.uhn.fhir.jpa.util.JsonDateSerializer;
|
import ca.uhn.fhir.jpa.util.JsonDateSerializer;
|
||||||
import com.fasterxml.jackson.annotation.JsonAutoDetect;
|
import ca.uhn.fhir.model.api.IModelJson;
|
||||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
|
||||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
|
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
|
||||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||||
|
@ -33,9 +32,7 @@ import org.apache.commons.lang3.builder.ToStringBuilder;
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
|
||||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
public class StoredDetails implements IModelJson {
|
||||||
@JsonAutoDetect(creatorVisibility = JsonAutoDetect.Visibility.NONE, fieldVisibility = JsonAutoDetect.Visibility.NONE, getterVisibility = JsonAutoDetect.Visibility.NONE, isGetterVisibility = JsonAutoDetect.Visibility.NONE, setterVisibility = JsonAutoDetect.Visibility.NONE)
|
|
||||||
public class StoredDetails {
|
|
||||||
|
|
||||||
@JsonProperty("blobId")
|
@JsonProperty("blobId")
|
||||||
private String myBlobId;
|
private String myBlobId;
|
||||||
|
|
|
@ -23,6 +23,7 @@ package ca.uhn.fhir.jpa.bulk;
|
||||||
|
|
||||||
import ca.uhn.fhir.jpa.util.JsonDateDeserializer;
|
import ca.uhn.fhir.jpa.util.JsonDateDeserializer;
|
||||||
import ca.uhn.fhir.jpa.util.JsonDateSerializer;
|
import ca.uhn.fhir.jpa.util.JsonDateSerializer;
|
||||||
|
import ca.uhn.fhir.model.api.IModelJson;
|
||||||
import com.fasterxml.jackson.annotation.JsonAutoDetect;
|
import com.fasterxml.jackson.annotation.JsonAutoDetect;
|
||||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
|
@ -98,9 +99,7 @@ public class BulkExportResponseJson {
|
||||||
return retVal;
|
return retVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
public static class Output implements IModelJson {
|
||||||
@JsonAutoDetect(creatorVisibility = JsonAutoDetect.Visibility.NONE, fieldVisibility = JsonAutoDetect.Visibility.NONE, getterVisibility = JsonAutoDetect.Visibility.NONE, isGetterVisibility = JsonAutoDetect.Visibility.NONE, setterVisibility = JsonAutoDetect.Visibility.NONE)
|
|
||||||
public static class Output {
|
|
||||||
|
|
||||||
@JsonProperty("type")
|
@JsonProperty("type")
|
||||||
private String myType;
|
private String myType;
|
||||||
|
|
|
@ -1146,7 +1146,7 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> extends BaseStora
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Syncrhonize composite params
|
// Synchronize composite params
|
||||||
mySearchParamWithInlineReferencesExtractor.storeCompositeStringUniques(newParams, entity, existingParams);
|
mySearchParamWithInlineReferencesExtractor.storeCompositeStringUniques(newParams, entity, existingParams);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -181,8 +181,9 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
|
||||||
@Override
|
@Override
|
||||||
public DaoMethodOutcome delete(IIdType theId, DeleteConflictList theDeleteConflicts, RequestDetails theRequest) {
|
public DaoMethodOutcome delete(IIdType theId, DeleteConflictList theDeleteConflicts, RequestDetails theRequest) {
|
||||||
validateIdPresentForDelete(theId);
|
validateIdPresentForDelete(theId);
|
||||||
|
validateDeleteEnabled();
|
||||||
|
|
||||||
final ResourceTable entity = readEntityLatestVersion(theId, theRequest);
|
final ResourceTable entity = readEntityLatestVersion(theId);
|
||||||
if (theId.hasVersionIdPart() && Long.parseLong(theId.getVersionIdPart()) != entity.getVersion()) {
|
if (theId.hasVersionIdPart() && Long.parseLong(theId.getVersionIdPart()) != entity.getVersion()) {
|
||||||
throw new ResourceVersionConflictException("Trying to delete " + theId + " but this is not the current version");
|
throw new ResourceVersionConflictException("Trying to delete " + theId + " but this is not the current version");
|
||||||
}
|
}
|
||||||
|
@ -258,6 +259,7 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
|
||||||
@Override
|
@Override
|
||||||
public DaoMethodOutcome delete(IIdType theId, RequestDetails theRequestDetails) {
|
public DaoMethodOutcome delete(IIdType theId, RequestDetails theRequestDetails) {
|
||||||
validateIdPresentForDelete(theId);
|
validateIdPresentForDelete(theId);
|
||||||
|
validateDeleteEnabled();
|
||||||
|
|
||||||
DeleteConflictList deleteConflicts = new DeleteConflictList();
|
DeleteConflictList deleteConflicts = new DeleteConflictList();
|
||||||
if (isNotBlank(theId.getValue())) {
|
if (isNotBlank(theId.getValue())) {
|
||||||
|
@ -280,6 +282,8 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public DeleteMethodOutcome deleteByUrl(String theUrl, DeleteConflictList deleteConflicts, RequestDetails theRequest) {
|
public DeleteMethodOutcome deleteByUrl(String theUrl, DeleteConflictList deleteConflicts, RequestDetails theRequest) {
|
||||||
|
validateDeleteEnabled();
|
||||||
|
|
||||||
StopWatch w = new StopWatch();
|
StopWatch w = new StopWatch();
|
||||||
|
|
||||||
Set<ResourcePersistentId> resourceIds = myMatchResourceUrlService.processMatchUrl(theUrl, myResourceType, theRequest);
|
Set<ResourcePersistentId> resourceIds = myMatchResourceUrlService.processMatchUrl(theUrl, myResourceType, theRequest);
|
||||||
|
@ -355,6 +359,8 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public DeleteMethodOutcome deleteByUrl(String theUrl, RequestDetails theRequestDetails) {
|
public DeleteMethodOutcome deleteByUrl(String theUrl, RequestDetails theRequestDetails) {
|
||||||
|
validateDeleteEnabled();
|
||||||
|
|
||||||
DeleteConflictList deleteConflicts = new DeleteConflictList();
|
DeleteConflictList deleteConflicts = new DeleteConflictList();
|
||||||
|
|
||||||
DeleteMethodOutcome outcome = deleteByUrl(theUrl, deleteConflicts, theRequestDetails);
|
DeleteMethodOutcome outcome = deleteByUrl(theUrl, deleteConflicts, theRequestDetails);
|
||||||
|
@ -364,6 +370,13 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
|
||||||
return outcome;
|
return outcome;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void validateDeleteEnabled() {
|
||||||
|
if (!myDaoConfig.isDeleteEnabled()) {
|
||||||
|
String msg = getContext().getLocalizer().getMessage(BaseHapiFhirResourceDao.class, "deleteBlockedBecauseDisabled");
|
||||||
|
throw new PreconditionFailedException(msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void validateIdPresentForDelete(IIdType theId) {
|
private void validateIdPresentForDelete(IIdType theId) {
|
||||||
if (theId == null || !theId.hasIdPart()) {
|
if (theId == null || !theId.hasIdPart()) {
|
||||||
throw new InvalidRequestException("Can not perform delete, no ID provided");
|
throw new InvalidRequestException("Can not perform delete, no ID provided");
|
||||||
|
@ -683,7 +696,7 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
|
||||||
throw new ResourceNotFoundException(theResourceId);
|
throw new ResourceNotFoundException(theResourceId);
|
||||||
}
|
}
|
||||||
|
|
||||||
ResourceTable latestVersion = readEntityLatestVersion(theResourceId, theRequest);
|
ResourceTable latestVersion = readEntityLatestVersion(theResourceId);
|
||||||
if (latestVersion.getVersion() != entity.getVersion()) {
|
if (latestVersion.getVersion() != entity.getVersion()) {
|
||||||
doMetaAdd(theMetaAdd, entity);
|
doMetaAdd(theMetaAdd, entity);
|
||||||
} else {
|
} else {
|
||||||
|
@ -715,7 +728,7 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
|
||||||
throw new ResourceNotFoundException(theResourceId);
|
throw new ResourceNotFoundException(theResourceId);
|
||||||
}
|
}
|
||||||
|
|
||||||
ResourceTable latestVersion = readEntityLatestVersion(theResourceId, theRequest);
|
ResourceTable latestVersion = readEntityLatestVersion(theResourceId);
|
||||||
if (latestVersion.getVersion() != entity.getVersion()) {
|
if (latestVersion.getVersion() != entity.getVersion()) {
|
||||||
doMetaDelete(theMetaDel, entity);
|
doMetaDelete(theMetaDel, entity);
|
||||||
} else {
|
} else {
|
||||||
|
@ -791,7 +804,7 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
entityToUpdate = readEntityLatestVersion(theId, theRequest);
|
entityToUpdate = readEntityLatestVersion(theId);
|
||||||
if (theId.hasVersionIdPart()) {
|
if (theId.hasVersionIdPart()) {
|
||||||
if (theId.getVersionIdPartAsLong() != entityToUpdate.getVersion()) {
|
if (theId.getVersionIdPartAsLong() != entityToUpdate.getVersion()) {
|
||||||
throw new ResourceVersionConflictException("Version " + theId.getVersionIdPart() + " is not the most recent version of this resource, unable to apply patch");
|
throw new ResourceVersionConflictException("Version " + theId.getVersionIdPart() + " is not the most recent version of this resource, unable to apply patch");
|
||||||
|
@ -926,7 +939,7 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
|
||||||
public BaseHasResource readEntity(IIdType theId, boolean theCheckForForcedId, RequestDetails theRequest) {
|
public BaseHasResource readEntity(IIdType theId, boolean theCheckForForcedId, RequestDetails theRequest) {
|
||||||
validateResourceTypeAndThrowInvalidRequestException(theId);
|
validateResourceTypeAndThrowInvalidRequestException(theId);
|
||||||
|
|
||||||
ResourcePersistentId pid = myIdHelperService.translateForcedIdToPid(getResourceName(), theId.getIdPart(), theRequest);
|
ResourcePersistentId pid = myIdHelperService.resolveResourcePersistentIds(getResourceName(), theId.getIdPart());
|
||||||
BaseHasResource entity = myEntityManager.find(ResourceTable.class, pid.getIdAsLong());
|
BaseHasResource entity = myEntityManager.find(ResourceTable.class, pid.getIdAsLong());
|
||||||
|
|
||||||
if (entity == null) {
|
if (entity == null) {
|
||||||
|
@ -964,8 +977,8 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
|
||||||
return entity;
|
return entity;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected ResourceTable readEntityLatestVersion(IIdType theId, RequestDetails theRequest) {
|
protected ResourceTable readEntityLatestVersion(IIdType theId) {
|
||||||
ResourcePersistentId persistentId = myIdHelperService.translateForcedIdToPid(getResourceName(), theId.getIdPart(), theRequest);
|
ResourcePersistentId persistentId = myIdHelperService.resolveResourcePersistentIds(getResourceName(), theId.getIdPart());
|
||||||
ResourceTable entity = myEntityManager.find(ResourceTable.class, persistentId.getId());
|
ResourceTable entity = myEntityManager.find(ResourceTable.class, persistentId.getId());
|
||||||
if (entity == null) {
|
if (entity == null) {
|
||||||
throw new ResourceNotFoundException(theId);
|
throw new ResourceNotFoundException(theId);
|
||||||
|
@ -1206,7 +1219,7 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
|
||||||
resourceId = theResource.getIdElement();
|
resourceId = theResource.getIdElement();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
entity = readEntityLatestVersion(resourceId, theRequest);
|
entity = readEntityLatestVersion(resourceId);
|
||||||
} catch (ResourceNotFoundException e) {
|
} catch (ResourceNotFoundException e) {
|
||||||
return doCreate(theResource, null, thePerformIndexing, new Date(), theRequest);
|
return doCreate(theResource, null, thePerformIndexing, new Date(), theRequest);
|
||||||
}
|
}
|
||||||
|
@ -1278,7 +1291,7 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
|
||||||
if (theId == null || theId.hasIdPart() == false) {
|
if (theId == null || theId.hasIdPart() == false) {
|
||||||
throw new InvalidRequestException("No ID supplied. ID is required when validating with mode=DELETE");
|
throw new InvalidRequestException("No ID supplied. ID is required when validating with mode=DELETE");
|
||||||
}
|
}
|
||||||
final ResourceTable entity = readEntityLatestVersion(theId, theRequest);
|
final ResourceTable entity = readEntityLatestVersion(theId);
|
||||||
|
|
||||||
// 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
|
||||||
|
|
|
@ -183,6 +183,11 @@ public class DaoConfig {
|
||||||
*/
|
*/
|
||||||
private boolean myPopulateIdentifierInAutoCreatedPlaceholderReferenceTargets;
|
private boolean myPopulateIdentifierInAutoCreatedPlaceholderReferenceTargets;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @since 5.0.0
|
||||||
|
*/
|
||||||
|
private boolean myDeleteEnabled = true;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
*/
|
*/
|
||||||
|
@ -1907,7 +1912,33 @@ public class DaoConfig {
|
||||||
setPreExpandValueSetsDefaultCount(Math.min(getPreExpandValueSetsDefaultCount(), getPreExpandValueSetsMaxCount()));
|
setPreExpandValueSetsDefaultCount(Math.min(getPreExpandValueSetsDefaultCount(), getPreExpandValueSetsMaxCount()));
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum StoreMetaSourceInformationEnum {
|
/**
|
||||||
|
* This setting should be disabled (set to <code>false</code>) on servers that are not allowing
|
||||||
|
* deletes. Default is <code>true</code>. If deletes are disabled, some checks for resource
|
||||||
|
* deletion can be skipped, which improves performance. This is particularly helpful when large
|
||||||
|
* amounts of data containing client-assigned IDs are being loaded, but it can also improve
|
||||||
|
* search performance.
|
||||||
|
*
|
||||||
|
* @since 5.0.0
|
||||||
|
*/
|
||||||
|
public void setDeleteEnabled(boolean theDeleteEnabled) {
|
||||||
|
myDeleteEnabled = theDeleteEnabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This setting should be disabled (set to <code>false</code>) on servers that are not allowing
|
||||||
|
* deletes. Default is <code>true</code>. If deletes are disabled, some checks for resource
|
||||||
|
* deletion can be skipped, which improves performance. This is particularly helpful when large
|
||||||
|
* amounts of data containing client-assigned IDs are being loaded, but it can also improve
|
||||||
|
* search performance.
|
||||||
|
*
|
||||||
|
* @since 5.0.0
|
||||||
|
*/
|
||||||
|
public boolean isDeleteEnabled() {
|
||||||
|
return myDeleteEnabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum StoreMetaSourceInformationEnum {
|
||||||
NONE(false, false),
|
NONE(false, false),
|
||||||
SOURCE_URI(true, false),
|
SOURCE_URI(true, false),
|
||||||
REQUEST_ID(false, true),
|
REQUEST_ID(false, true),
|
||||||
|
|
|
@ -20,16 +20,12 @@ package ca.uhn.fhir.jpa.dao;
|
||||||
* #L%
|
* #L%
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import ca.uhn.fhir.context.RuntimeResourceDefinition;
|
|
||||||
import ca.uhn.fhir.jpa.dao.data.ISubscriptionTableDao;
|
import ca.uhn.fhir.jpa.dao.data.ISubscriptionTableDao;
|
||||||
import ca.uhn.fhir.jpa.model.cross.IBasePersistedResource;
|
import ca.uhn.fhir.jpa.model.cross.IBasePersistedResource;
|
||||||
import ca.uhn.fhir.jpa.model.entity.ResourceTable;
|
import ca.uhn.fhir.jpa.model.entity.ResourceTable;
|
||||||
import ca.uhn.fhir.jpa.entity.SubscriptionTable;
|
import ca.uhn.fhir.jpa.entity.SubscriptionTable;
|
||||||
import ca.uhn.fhir.model.dstu2.resource.Subscription;
|
import ca.uhn.fhir.model.dstu2.resource.Subscription;
|
||||||
import ca.uhn.fhir.model.dstu2.valueset.SubscriptionStatusEnum;
|
|
||||||
import ca.uhn.fhir.parser.DataFormatException;
|
|
||||||
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
||||||
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
|
|
||||||
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.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
@ -37,8 +33,6 @@ import org.springframework.transaction.PlatformTransactionManager;
|
||||||
|
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
|
||||||
import static org.apache.commons.lang3.StringUtils.isBlank;
|
|
||||||
|
|
||||||
public class FhirResourceDaoSubscriptionDstu2 extends BaseHapiFhirResourceDao<Subscription> implements IFhirResourceDaoSubscription<Subscription> {
|
public class FhirResourceDaoSubscriptionDstu2 extends BaseHapiFhirResourceDao<Subscription> implements IFhirResourceDaoSubscription<Subscription> {
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
|
@ -56,7 +50,7 @@ public class FhirResourceDaoSubscriptionDstu2 extends BaseHapiFhirResourceDao<Su
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Long getSubscriptionTablePidForSubscriptionResource(IIdType theId, RequestDetails theRequest) {
|
public Long getSubscriptionTablePidForSubscriptionResource(IIdType theId, RequestDetails theRequest) {
|
||||||
ResourceTable entity = readEntityLatestVersion(theId, theRequest);
|
ResourceTable entity = readEntityLatestVersion(theId);
|
||||||
SubscriptionTable table = mySubscriptionTableDao.findOneByResourcePid(entity.getId());
|
SubscriptionTable table = mySubscriptionTableDao.findOneByResourcePid(entity.getId());
|
||||||
if (table == null) {
|
if (table == null) {
|
||||||
return null;
|
return null;
|
||||||
|
|
|
@ -229,7 +229,7 @@ public class FulltextSearchSvcImpl implements IFulltextSearchSvc {
|
||||||
StringParam idParm = (StringParam) idParam;
|
StringParam idParm = (StringParam) idParam;
|
||||||
idParamValue = idParm.getValue();
|
idParamValue = idParm.getValue();
|
||||||
}
|
}
|
||||||
pid = myIdHelperService.translateForcedIdToPid(theResourceName, idParamValue, theRequest);
|
// pid = myIdHelperService.translateForcedIdToPid_(theResourceName, idParamValue, theRequest);
|
||||||
}
|
}
|
||||||
|
|
||||||
ResourcePersistentId referencingPid = pid;
|
ResourcePersistentId referencingPid = pid;
|
||||||
|
@ -282,7 +282,7 @@ public class FulltextSearchSvcImpl implements IFulltextSearchSvc {
|
||||||
if (contextParts.length != 3 || "Patient".equals(contextParts[0]) == false || "$everything".equals(contextParts[2]) == false) {
|
if (contextParts.length != 3 || "Patient".equals(contextParts[0]) == false || "$everything".equals(contextParts[2]) == false) {
|
||||||
throw new InvalidRequestException("Invalid context: " + theContext);
|
throw new InvalidRequestException("Invalid context: " + theContext);
|
||||||
}
|
}
|
||||||
ResourcePersistentId pid = myIdHelperService.translateForcedIdToPid(contextParts[0], contextParts[1], theRequest);
|
ResourcePersistentId pid = myIdHelperService.resolveResourcePersistentIds(contextParts[0], contextParts[1]);
|
||||||
|
|
||||||
FullTextEntityManager em = org.hibernate.search.jpa.Search.getFullTextEntityManager(myEntityManager);
|
FullTextEntityManager em = org.hibernate.search.jpa.Search.getFullTextEntityManager(myEntityManager);
|
||||||
|
|
||||||
|
|
|
@ -267,7 +267,7 @@ public class SearchBuilder implements ISearchBuilder {
|
||||||
|
|
||||||
if (myParams.get(IAnyResource.SP_RES_ID) != null) {
|
if (myParams.get(IAnyResource.SP_RES_ID) != null) {
|
||||||
StringParam idParam = (StringParam) myParams.get(IAnyResource.SP_RES_ID).get(0).get(0);
|
StringParam idParam = (StringParam) myParams.get(IAnyResource.SP_RES_ID).get(0).get(0);
|
||||||
ResourcePersistentId pid = myIdHelperService.translateForcedIdToPid(myResourceName, idParam.getValue(), theRequest);
|
ResourcePersistentId pid = myIdHelperService.resolveResourcePersistentIds(myResourceName, idParam.getValue());
|
||||||
if (myAlsoIncludePids == null) {
|
if (myAlsoIncludePids == null) {
|
||||||
myAlsoIncludePids = new ArrayList<>(1);
|
myAlsoIncludePids = new ArrayList<>(1);
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@ package ca.uhn.fhir.jpa.dao.data;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* #%L
|
* #%L
|
||||||
|
@ -35,8 +36,8 @@ public interface IForcedIdDao extends JpaRepository<ForcedId, Long> {
|
||||||
@Query("SELECT f.myResourcePid FROM ForcedId f WHERE myForcedId IN (:forced_id)")
|
@Query("SELECT f.myResourcePid FROM ForcedId f WHERE myForcedId IN (:forced_id)")
|
||||||
List<Long> findByForcedId(@Param("forced_id") Collection<String> theForcedId);
|
List<Long> findByForcedId(@Param("forced_id") Collection<String> theForcedId);
|
||||||
|
|
||||||
@Query("SELECT f.myResourcePid FROM ForcedId f WHERE myResourceType = :resource_type AND myForcedId IN (:forced_id)")
|
@Query("SELECT f.myResourcePid FROM ForcedId f WHERE myResourceType = :resource_type AND myForcedId = :forced_id")
|
||||||
List<Long> findByTypeAndForcedId(@Param("resource_type") String theResourceType, @Param("forced_id") Collection<String> theForcedId);
|
Optional<Long> findByTypeAndForcedId(@Param("resource_type") String theResourceType, @Param("forced_id") String theForcedId);
|
||||||
|
|
||||||
@Query("SELECT f FROM ForcedId f WHERE f.myResourcePid = :resource_pid")
|
@Query("SELECT f FROM ForcedId f WHERE f.myResourcePid = :resource_pid")
|
||||||
ForcedId findByResourcePid(@Param("resource_pid") Long theResourcePid);
|
ForcedId findByResourcePid(@Param("resource_pid") Long theResourcePid);
|
||||||
|
@ -44,4 +45,37 @@ public interface IForcedIdDao extends JpaRepository<ForcedId, Long> {
|
||||||
@Modifying
|
@Modifying
|
||||||
@Query("DELETE FROM ForcedId t WHERE t.myId = :pid")
|
@Query("DELETE FROM ForcedId t WHERE t.myId = :pid")
|
||||||
void deleteByPid(@Param("pid") Long theId);
|
void deleteByPid(@Param("pid") Long theId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method returns a Collection where each row is an element in the collection. Each element in the collection
|
||||||
|
* is an object array, where the order matters (the array represents columns returned by the query). Be careful if you change this query in any way.
|
||||||
|
*/
|
||||||
|
@Query("SELECT f.myForcedId, f.myResourcePid FROM ForcedId f WHERE myResourceType = :resource_type AND myForcedId IN ( :forced_id )")
|
||||||
|
Collection<Object[]> findByTypeAndForcedId(@Param("resource_type") String theResourceType, @Param("forced_id") Collection<String> theForcedId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Warning: No DB index exists for this particular query, so it may not perform well
|
||||||
|
*
|
||||||
|
* This method returns a Collection where each row is an element in the collection. Each element in the collection
|
||||||
|
* is an object array, where the order matters (the array represents columns returned by the query). Be careful if you change this query in any way.
|
||||||
|
*/
|
||||||
|
@Query("" +
|
||||||
|
"SELECT " +
|
||||||
|
" f.myResourceType, f.myResourcePid, f.myForcedId, t.myDeleted " +
|
||||||
|
"FROM ForcedId f " +
|
||||||
|
"JOIN ResourceTable t ON t.myId = f.myResourcePid " +
|
||||||
|
"WHERE f.myForcedId IN ( :forced_id )")
|
||||||
|
Collection<Object[]> findAndResolveByForcedIdWithNoType(@Param("forced_id") Collection<String> theForcedIds);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method returns a Collection where each row is an element in the collection. Each element in the collection
|
||||||
|
* is an object array, where the order matters (the array represents columns returned by the query). Be careful if you change this query in any way.
|
||||||
|
*/
|
||||||
|
@Query("" +
|
||||||
|
"SELECT " +
|
||||||
|
" f.myResourceType, f.myResourcePid, f.myForcedId, t.myDeleted " +
|
||||||
|
"FROM ForcedId f " +
|
||||||
|
"JOIN ResourceTable t ON t.myId = f.myResourcePid " +
|
||||||
|
"WHERE f.myResourceType = :resource_type AND f.myForcedId IN ( :forced_id )")
|
||||||
|
Collection<Object[]> findAndResolveByForcedIdWithNoType(@Param("resource_type") String theResourceType, @Param("forced_id") Collection<String> theForcedIds);
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,9 +8,11 @@ import org.springframework.data.jpa.repository.Modifying;
|
||||||
import org.springframework.data.jpa.repository.Query;
|
import org.springframework.data.jpa.repository.Query;
|
||||||
import org.springframework.data.repository.query.Param;
|
import org.springframework.data.repository.query.Param;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* #%L
|
* #%L
|
||||||
|
@ -63,4 +65,6 @@ public interface IResourceTableDao extends JpaRepository<ResourceTable, Long> {
|
||||||
@Query("DELETE FROM ResourceTable t WHERE t.myId = :pid")
|
@Query("DELETE FROM ResourceTable t WHERE t.myId = :pid")
|
||||||
void deleteByPid(@Param("pid") Long theId);
|
void deleteByPid(@Param("pid") Long theId);
|
||||||
|
|
||||||
|
@Query("SELECT t.myResourceType, t.myId, t.myDeleted FROM ResourceTable t WHERE t.myId IN (:pid)")
|
||||||
|
Collection<Object[]> findLookupFieldsByResourcePid(@Param("pid") List<Long> thePids);
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,7 +48,7 @@ public class FhirResourceDaoSubscriptionDstu3 extends BaseHapiFhirResourceDao<Su
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Long getSubscriptionTablePidForSubscriptionResource(IIdType theId, RequestDetails theRequest) {
|
public Long getSubscriptionTablePidForSubscriptionResource(IIdType theId, RequestDetails theRequest) {
|
||||||
ResourceTable entity = readEntityLatestVersion(theId, theRequest);
|
ResourceTable entity = readEntityLatestVersion(theId);
|
||||||
SubscriptionTable table = mySubscriptionTableDao.findOneByResourcePid(entity.getId());
|
SubscriptionTable table = mySubscriptionTableDao.findOneByResourcePid(entity.getId());
|
||||||
if (table == null) {
|
if (table == null) {
|
||||||
return null;
|
return null;
|
||||||
|
|
|
@ -29,7 +29,7 @@ import ca.uhn.fhir.context.RuntimeSearchParam;
|
||||||
import ca.uhn.fhir.jpa.dao.DaoConfig;
|
import ca.uhn.fhir.jpa.dao.DaoConfig;
|
||||||
import ca.uhn.fhir.jpa.dao.DaoRegistry;
|
import ca.uhn.fhir.jpa.dao.DaoRegistry;
|
||||||
import ca.uhn.fhir.jpa.dao.IFhirResourceDao;
|
import ca.uhn.fhir.jpa.dao.IFhirResourceDao;
|
||||||
import ca.uhn.fhir.jpa.model.cross.ResourcePersistentId;
|
import ca.uhn.fhir.jpa.model.cross.IResourceLookup;
|
||||||
import ca.uhn.fhir.jpa.model.entity.ResourceTable;
|
import ca.uhn.fhir.jpa.model.entity.ResourceTable;
|
||||||
import ca.uhn.fhir.jpa.searchparam.extractor.IResourceLinkResolver;
|
import ca.uhn.fhir.jpa.searchparam.extractor.IResourceLinkResolver;
|
||||||
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
||||||
|
@ -64,17 +64,16 @@ public class DaoResourceLinkResolver implements IResourceLinkResolver {
|
||||||
private DaoRegistry myDaoRegistry;
|
private DaoRegistry myDaoRegistry;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ResourceTable findTargetResource(RuntimeSearchParam theNextSpDef, String theNextPathsUnsplit, IIdType theNextId, String theTypeString, Class<? extends IBaseResource> theType, IBaseReference theReference, RequestDetails theRequest) {
|
public IResourceLookup findTargetResource(RuntimeSearchParam theSearchParam, String theSourcePath, IIdType theSourceResourceId, String theTypeString, Class<? extends IBaseResource> theType, IBaseReference theReference, RequestDetails theRequest) {
|
||||||
ResourceTable target;
|
IResourceLookup resolvedResource;
|
||||||
ResourcePersistentId valueOf;
|
String idPart = theSourceResourceId.getIdPart();
|
||||||
String idPart = theNextId.getIdPart();
|
|
||||||
try {
|
try {
|
||||||
valueOf = myIdHelperService.translateForcedIdToPid(theTypeString, idPart, theRequest);
|
resolvedResource = myIdHelperService.resolveResourceIdentity(theTypeString, idPart, theRequest);
|
||||||
ourLog.trace("Translated {}/{} to resource PID {}", theType, idPart, valueOf);
|
ourLog.trace("Translated {}/{} to resource PID {}", theType, idPart, resolvedResource);
|
||||||
} catch (ResourceNotFoundException e) {
|
} catch (ResourceNotFoundException e) {
|
||||||
|
|
||||||
Optional<ResourcePersistentId> pidOpt = createPlaceholderTargetIfConfiguredToDoSo(theType, theReference, idPart);
|
Optional<ResourceTable> createdTableOpt = createPlaceholderTargetIfConfiguredToDoSo(theType, theReference, idPart);
|
||||||
if (!pidOpt.isPresent()) {
|
if (!createdTableOpt.isPresent()) {
|
||||||
|
|
||||||
if (myDaoConfig.isEnforceReferentialIntegrityOnWrite() == false) {
|
if (myDaoConfig.isEnforceReferentialIntegrityOnWrite() == false) {
|
||||||
return null;
|
return null;
|
||||||
|
@ -82,43 +81,36 @@ public class DaoResourceLinkResolver implements IResourceLinkResolver {
|
||||||
|
|
||||||
RuntimeResourceDefinition missingResourceDef = myContext.getResourceDefinition(theType);
|
RuntimeResourceDefinition missingResourceDef = myContext.getResourceDefinition(theType);
|
||||||
String resName = missingResourceDef.getName();
|
String resName = missingResourceDef.getName();
|
||||||
throw new InvalidRequestException("Resource " + resName + "/" + idPart + " not found, specified in path: " + theNextPathsUnsplit);
|
throw new InvalidRequestException("Resource " + resName + "/" + idPart + " not found, specified in path: " + theSourcePath);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
valueOf = pidOpt.get();
|
resolvedResource = createdTableOpt.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
target = myEntityManager.find(ResourceTable.class, valueOf.getIdAsLong());
|
ourLog.trace("Resolved resource of type {} as PID: {}", resolvedResource.getResourceType(), resolvedResource.getResourceId());
|
||||||
RuntimeResourceDefinition targetResourceDef = myContext.getResourceDefinition(theType);
|
if (!theTypeString.equals(resolvedResource.getResourceType())) {
|
||||||
if (target == null) {
|
ourLog.error("Resource with PID {} was of type {} and wanted {}", resolvedResource.getResourceId(), theTypeString, resolvedResource.getResourceType());
|
||||||
String resName = targetResourceDef.getName();
|
throw new UnprocessableEntityException("Resource contains reference to unknown resource ID " + theSourceResourceId.getValue());
|
||||||
throw new InvalidRequestException("Resource " + resName + "/" + idPart + " not found, specified in path: " + theNextPathsUnsplit);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ourLog.trace("Resource PID {} is of type {}", valueOf, target.getResourceType());
|
if (resolvedResource.getDeleted() != null) {
|
||||||
if (!theTypeString.equals(target.getResourceType())) {
|
String resName = resolvedResource.getResourceType();
|
||||||
ourLog.error("Resource {} with PID {} was not of type {}", target.getIdDt().getValue(), target.getId(), theTypeString);
|
throw new InvalidRequestException("Resource " + resName + "/" + idPart + " is deleted, specified in path: " + theSourcePath);
|
||||||
throw new UnprocessableEntityException(
|
|
||||||
"Resource contains reference to " + theNextId.getValue() + " but resource with ID " + theNextId.getIdPart() + " is actually of type " + target.getResourceType());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (target.getDeleted() != null) {
|
if (!theSearchParam.hasTargets() && theSearchParam.getTargets().contains(theTypeString)) {
|
||||||
String resName = targetResourceDef.getName();
|
|
||||||
throw new InvalidRequestException("Resource " + resName + "/" + idPart + " is deleted, specified in path: " + theNextPathsUnsplit);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!theNextSpDef.hasTargets() && theNextSpDef.getTargets().contains(theTypeString)) {
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return target;
|
|
||||||
|
return resolvedResource;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param theIdToAssignToPlaceholder If specified, the placeholder resource created will be given a specific ID
|
* @param theIdToAssignToPlaceholder If specified, the placeholder resource created will be given a specific ID
|
||||||
*/
|
*/
|
||||||
public <T extends IBaseResource> Optional<ResourcePersistentId> createPlaceholderTargetIfConfiguredToDoSo(Class<T> theType, IBaseReference theReference, @Nullable String theIdToAssignToPlaceholder) {
|
public <T extends IBaseResource> Optional<ResourceTable> createPlaceholderTargetIfConfiguredToDoSo(Class<T> theType, IBaseReference theReference, @Nullable String theIdToAssignToPlaceholder) {
|
||||||
ResourcePersistentId valueOf = null;
|
ResourceTable valueOf = null;
|
||||||
|
|
||||||
if (myDaoConfig.isAutoCreatePlaceholderReferenceTargets()) {
|
if (myDaoConfig.isAutoCreatePlaceholderReferenceTargets()) {
|
||||||
RuntimeResourceDefinition missingResourceDef = myContext.getResourceDefinition(theType);
|
RuntimeResourceDefinition missingResourceDef = myContext.getResourceDefinition(theType);
|
||||||
|
@ -136,9 +128,9 @@ public class DaoResourceLinkResolver implements IResourceLinkResolver {
|
||||||
|
|
||||||
if (theIdToAssignToPlaceholder != null) {
|
if (theIdToAssignToPlaceholder != null) {
|
||||||
newResource.setId(resName + "/" + theIdToAssignToPlaceholder);
|
newResource.setId(resName + "/" + theIdToAssignToPlaceholder);
|
||||||
valueOf = placeholderResourceDao.update(newResource).getEntity().getPersistentId();
|
valueOf = ((ResourceTable) placeholderResourceDao.update(newResource).getEntity());
|
||||||
} else {
|
} else {
|
||||||
valueOf = placeholderResourceDao.create(newResource).getEntity().getPersistentId();
|
valueOf = ((ResourceTable) placeholderResourceDao.create(newResource).getEntity());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,7 +21,8 @@ package ca.uhn.fhir.jpa.dao.index;
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import ca.uhn.fhir.jpa.dao.DaoConfig;
|
import ca.uhn.fhir.jpa.dao.DaoConfig;
|
||||||
import ca.uhn.fhir.jpa.model.entity.*;
|
import ca.uhn.fhir.jpa.model.entity.BaseResourceIndex;
|
||||||
|
import ca.uhn.fhir.jpa.model.entity.ResourceTable;
|
||||||
import ca.uhn.fhir.jpa.searchparam.extractor.ResourceIndexedSearchParams;
|
import ca.uhn.fhir.jpa.searchparam.extractor.ResourceIndexedSearchParams;
|
||||||
import ca.uhn.fhir.jpa.util.AddRemoveCount;
|
import ca.uhn.fhir.jpa.util.AddRemoveCount;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
@ -36,23 +37,22 @@ import java.util.List;
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
public class DaoSearchParamSynchronizer {
|
public class DaoSearchParamSynchronizer {
|
||||||
@Autowired
|
|
||||||
private DaoConfig myDaoConfig;
|
|
||||||
|
|
||||||
@PersistenceContext(type = PersistenceContextType.TRANSACTION)
|
@PersistenceContext(type = PersistenceContextType.TRANSACTION)
|
||||||
protected EntityManager myEntityManager;
|
protected EntityManager myEntityManager;
|
||||||
|
@Autowired
|
||||||
|
private DaoConfig myDaoConfig;
|
||||||
|
|
||||||
public AddRemoveCount synchronizeSearchParamsToDatabase(ResourceIndexedSearchParams theParams, ResourceTable theEntity, ResourceIndexedSearchParams existingParams) {
|
public AddRemoveCount synchronizeSearchParamsToDatabase(ResourceIndexedSearchParams theParams, ResourceTable theEntity, ResourceIndexedSearchParams existingParams) {
|
||||||
AddRemoveCount retVal = new AddRemoveCount();
|
AddRemoveCount retVal = new AddRemoveCount();
|
||||||
|
|
||||||
synchronize(theParams, theEntity, retVal, theParams.myStringParams, existingParams.myStringParams);
|
synchronize(theParams, theEntity, retVal, theParams.myStringParams, existingParams.myStringParams);
|
||||||
synchronize(theParams, theEntity, retVal, theParams.myTokenParams, existingParams.myTokenParams);
|
synchronize(theParams, theEntity, retVal, theParams.myTokenParams, existingParams.myTokenParams);
|
||||||
synchronize(theParams, theEntity,retVal, theParams.myNumberParams, existingParams.myNumberParams);
|
synchronize(theParams, theEntity, retVal, theParams.myNumberParams, existingParams.myNumberParams);
|
||||||
synchronize(theParams, theEntity,retVal, theParams.myQuantityParams, existingParams.myQuantityParams);
|
synchronize(theParams, theEntity, retVal, theParams.myQuantityParams, existingParams.myQuantityParams);
|
||||||
synchronize(theParams, theEntity,retVal, theParams.myDateParams, existingParams.myDateParams);
|
synchronize(theParams, theEntity, retVal, theParams.myDateParams, existingParams.myDateParams);
|
||||||
synchronize(theParams, theEntity,retVal, theParams.myUriParams, existingParams.myUriParams);
|
synchronize(theParams, theEntity, retVal, theParams.myUriParams, existingParams.myUriParams);
|
||||||
synchronize(theParams, theEntity, retVal, theParams.myCoordsParams, existingParams.myCoordsParams);
|
synchronize(theParams, theEntity, retVal, theParams.myCoordsParams, existingParams.myCoordsParams);
|
||||||
synchronize(theParams, theEntity,retVal, theParams.myLinks, existingParams.myLinks);
|
synchronize(theParams, theEntity, retVal, theParams.myLinks, existingParams.myLinks);
|
||||||
|
|
||||||
// make sure links are indexed
|
// make sure links are indexed
|
||||||
theEntity.setResourceLinks(theParams.myLinks);
|
theEntity.setResourceLinks(theParams.myLinks);
|
||||||
|
@ -85,7 +85,7 @@ public class DaoSearchParamSynchronizer {
|
||||||
* "one delete + one insert" with "one update"
|
* "one delete + one insert" with "one update"
|
||||||
*
|
*
|
||||||
* @param theIndexesToRemove The rows that would be removed
|
* @param theIndexesToRemove The rows that would be removed
|
||||||
* @param theIndexesToAdd The rows that would be added
|
* @param theIndexesToAdd The rows that would be added
|
||||||
*/
|
*/
|
||||||
private <T extends BaseResourceIndex> void tryToReuseIndexEntities(List<T> theIndexesToRemove, List<T> theIndexesToAdd) {
|
private <T extends BaseResourceIndex> void tryToReuseIndexEntities(List<T> theIndexesToRemove, List<T> theIndexesToAdd) {
|
||||||
for (int addIndex = 0; addIndex < theIndexesToAdd.size(); addIndex++) {
|
for (int addIndex = 0; addIndex < theIndexesToAdd.size(); addIndex++) {
|
||||||
|
@ -107,8 +107,6 @@ public class DaoSearchParamSynchronizer {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<T> List<T> subtract(Collection<T> theSubtractFrom, Collection<T> theToSubtract) {
|
<T> List<T> subtract(Collection<T> theSubtractFrom, Collection<T> theToSubtract) {
|
||||||
assert theSubtractFrom != theToSubtract;
|
assert theSubtractFrom != theToSubtract;
|
||||||
|
|
||||||
|
|
|
@ -22,45 +22,98 @@ package ca.uhn.fhir.jpa.dao.index;
|
||||||
|
|
||||||
import ca.uhn.fhir.context.FhirContext;
|
import ca.uhn.fhir.context.FhirContext;
|
||||||
import ca.uhn.fhir.interceptor.api.HookParams;
|
import ca.uhn.fhir.interceptor.api.HookParams;
|
||||||
import ca.uhn.fhir.jpa.dao.DaoConfig;
|
|
||||||
import ca.uhn.fhir.jpa.model.cross.ResourcePersistentId;
|
|
||||||
import ca.uhn.fhir.jpa.dao.data.IForcedIdDao;
|
|
||||||
import ca.uhn.fhir.jpa.model.entity.ForcedId;
|
|
||||||
import ca.uhn.fhir.interceptor.api.IInterceptorBroadcaster;
|
import ca.uhn.fhir.interceptor.api.IInterceptorBroadcaster;
|
||||||
import ca.uhn.fhir.interceptor.api.Pointcut;
|
import ca.uhn.fhir.interceptor.api.Pointcut;
|
||||||
|
import ca.uhn.fhir.jpa.dao.DaoConfig;
|
||||||
|
import ca.uhn.fhir.jpa.dao.data.IForcedIdDao;
|
||||||
|
import ca.uhn.fhir.jpa.dao.data.IResourceTableDao;
|
||||||
|
import ca.uhn.fhir.jpa.model.cross.IResourceLookup;
|
||||||
|
import ca.uhn.fhir.jpa.model.cross.ResourceLookup;
|
||||||
|
import ca.uhn.fhir.jpa.model.cross.ResourcePersistentId;
|
||||||
|
import ca.uhn.fhir.jpa.model.entity.ForcedId;
|
||||||
import ca.uhn.fhir.jpa.model.search.StorageProcessingMessage;
|
import ca.uhn.fhir.jpa.model.search.StorageProcessingMessage;
|
||||||
import ca.uhn.fhir.jpa.util.JpaInterceptorBroadcaster;
|
import ca.uhn.fhir.jpa.util.JpaInterceptorBroadcaster;
|
||||||
import ca.uhn.fhir.model.primitive.IdDt;
|
import ca.uhn.fhir.model.primitive.IdDt;
|
||||||
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
||||||
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
|
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
|
||||||
import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails;
|
import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails;
|
||||||
|
import com.github.benmanes.caffeine.cache.Cache;
|
||||||
|
import com.github.benmanes.caffeine.cache.Caffeine;
|
||||||
import com.google.common.collect.ListMultimap;
|
import com.google.common.collect.ListMultimap;
|
||||||
import com.google.common.collect.MultimapBuilder;
|
import com.google.common.collect.MultimapBuilder;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.apache.commons.lang3.Validate;
|
import org.apache.commons.lang3.Validate;
|
||||||
|
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||||
import org.hl7.fhir.instance.model.api.IIdType;
|
import org.hl7.fhir.instance.model.api.IIdType;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
import java.util.*;
|
import javax.annotation.PostConstruct;
|
||||||
import java.util.stream.Stream;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import static org.apache.commons.lang3.StringUtils.isBlank;
|
import static org.apache.commons.lang3.StringUtils.isBlank;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class is used to convert between PIDs (the internal primary key for a particular resource as
|
||||||
|
* stored in the {@link ca.uhn.fhir.jpa.model.entity.ResourceTable HFJ_RESOURCE} table), and the
|
||||||
|
* public ID that a resource has.
|
||||||
|
* <p>
|
||||||
|
* These IDs are sometimes one and the same (by default, a resource that the server assigns the ID of
|
||||||
|
* <code>Patient/1</code> will simply use a PID of 1 and and ID of 1. However, they may also be different
|
||||||
|
* in cases where a forced ID is used (an arbitrary client-assigned ID).
|
||||||
|
* </p>
|
||||||
|
* <p>
|
||||||
|
* This service is highly optimized in order to minimize the number of DB calls as much as possible,
|
||||||
|
* since ID resolution is fundamental to many basic operations. This service returns either
|
||||||
|
* {@link IResourceLookup} or {@link ResourcePersistentId} depending on the method being called.
|
||||||
|
* The former involves an extra database join that the latter does not require, so selecting the
|
||||||
|
* right method here is important.
|
||||||
|
* </p>
|
||||||
|
*/
|
||||||
@Service
|
@Service
|
||||||
public class IdHelperService {
|
public class IdHelperService {
|
||||||
|
private static final Logger ourLog = LoggerFactory.getLogger(IdHelperService.class);
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
protected IForcedIdDao myForcedIdDao;
|
protected IForcedIdDao myForcedIdDao;
|
||||||
|
@Autowired
|
||||||
|
protected IResourceTableDao myResourceTableDao;
|
||||||
@Autowired(required = true)
|
@Autowired(required = true)
|
||||||
private DaoConfig myDaoConfig;
|
private DaoConfig myDaoConfig;
|
||||||
@Autowired
|
@Autowired
|
||||||
private IInterceptorBroadcaster myInterceptorBroadcaster;
|
private IInterceptorBroadcaster myInterceptorBroadcaster;
|
||||||
|
|
||||||
|
private Cache<String, Long> myPersistentIdCache;
|
||||||
|
private Cache<String, IResourceLookup> myResourceLookupCache;
|
||||||
|
|
||||||
|
@PostConstruct
|
||||||
|
public void start() {
|
||||||
|
myPersistentIdCache = newCache();
|
||||||
|
myResourceLookupCache = newCache();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public void delete(ForcedId forcedId) {
|
public void delete(ForcedId forcedId) {
|
||||||
myForcedIdDao.deleteByPid(forcedId.getId());
|
myForcedIdDao.deleteByPid(forcedId.getId());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Given a resource type and ID, looks up the resource and returns a {@link IResourceLookup}. This
|
||||||
|
* object contains the internal PID for the resource and the resource deletion status, making it sufficient
|
||||||
|
* for persisting resource links between resources without adding any further database calls after the
|
||||||
|
* single one performed by this call.
|
||||||
|
*
|
||||||
* @throws ResourceNotFoundException If the ID can not be found
|
* @throws ResourceNotFoundException If the ID can not be found
|
||||||
*/
|
*/
|
||||||
@Nonnull
|
@Nonnull
|
||||||
|
@ -75,79 +128,117 @@ public class IdHelperService {
|
||||||
* @throws ResourceNotFoundException If the ID can not be found
|
* @throws ResourceNotFoundException If the ID can not be found
|
||||||
*/
|
*/
|
||||||
@Nonnull
|
@Nonnull
|
||||||
public ResourcePersistentId translateForcedIdToPid(String theResourceName, String theResourceId, RequestDetails theRequestDetails) throws ResourceNotFoundException {
|
public IResourceLookup resolveResourceIdentity(String theResourceName, String theResourceId, RequestDetails theRequestDetails) throws ResourceNotFoundException {
|
||||||
// We only pass 1 input in so only 0..1 will come back
|
// We only pass 1 input in so only 0..1 will come back
|
||||||
IdDt id = new IdDt(theResourceName, theResourceId);
|
IdDt id = new IdDt(theResourceName, theResourceId);
|
||||||
List<ResourcePersistentId> matches = translateForcedIdToPids(myDaoConfig, myInterceptorBroadcaster, theRequestDetails, myForcedIdDao, Collections.singletonList(id));
|
Collection<IResourceLookup> matches = translateForcedIdToPids(theRequestDetails, Collections.singletonList(id));
|
||||||
assert matches.size() <= 1;
|
assert matches.size() <= 1;
|
||||||
if (matches.isEmpty()) {
|
if (matches.isEmpty()) {
|
||||||
throw new ResourceNotFoundException(id);
|
throw new ResourceNotFoundException(id);
|
||||||
}
|
}
|
||||||
return matches.get(0);
|
return matches.iterator().next();
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<ResourcePersistentId> translateForcedIdToPids(Collection<IIdType> theId, RequestDetails theRequestDetails) {
|
/**
|
||||||
return IdHelperService.translateForcedIdToPids(myDaoConfig, myInterceptorBroadcaster, theRequestDetails, myForcedIdDao, theId);
|
* Given a resource type and ID, determines the internal persistent ID for the resource.
|
||||||
|
*
|
||||||
|
* @throws ResourceNotFoundException If the ID can not be found
|
||||||
|
*/
|
||||||
|
@Nonnull
|
||||||
|
public ResourcePersistentId resolveResourcePersistentIds(String theResourceType, String theId) {
|
||||||
|
Long retVal;
|
||||||
|
if (myDaoConfig.getResourceClientIdStrategy() == DaoConfig.ClientIdStrategyEnum.ANY || !isValidPid(theId)) {
|
||||||
|
if (myDaoConfig.isDeleteEnabled()) {
|
||||||
|
retVal = resolveResourceIdentity(theResourceType, theId);
|
||||||
|
} else {
|
||||||
|
String key = theResourceType + "/" + theId;
|
||||||
|
retVal = myPersistentIdCache.get(key, t -> resolveResourceIdentity(theResourceType, theId));
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
retVal = Long.parseLong(theId);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new ResourcePersistentId(retVal);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static List<ResourcePersistentId> translateForcedIdToPids(DaoConfig theDaoConfig, IInterceptorBroadcaster theInterceptorBroadcaster, RequestDetails theRequest, IForcedIdDao theForcedIdDao, Collection<IIdType> theId) {
|
/**
|
||||||
theId.forEach(id -> Validate.isTrue(id.hasIdPart()));
|
* Given a collection of resource IDs (resource type + id), resolves the internal persistent IDs
|
||||||
|
*/
|
||||||
|
@Nonnull
|
||||||
|
public List<ResourcePersistentId> resolveResourcePersistentIds(List<IIdType> theIds, RequestDetails theRequest) {
|
||||||
|
theIds.forEach(id -> Validate.isTrue(id.hasIdPart()));
|
||||||
|
|
||||||
if (theId.isEmpty()) {
|
if (theIds.isEmpty()) {
|
||||||
return Collections.emptyList();
|
return Collections.emptyList();
|
||||||
}
|
}
|
||||||
|
|
||||||
List<ResourcePersistentId> retVal = new ArrayList<>();
|
List<ResourcePersistentId> retVal = new ArrayList<>();
|
||||||
|
|
||||||
ListMultimap<String, String> typeToIds = MultimapBuilder.hashKeys().arrayListValues().build();
|
if (myDaoConfig.getResourceClientIdStrategy() != DaoConfig.ClientIdStrategyEnum.ANY) {
|
||||||
//If the PID is fully numeric and we aren't in ClientIdStrategyEnum.ANY, add it to return value.
|
theIds
|
||||||
//Otherwise, add it to a map of resource type -> ID.
|
.stream()
|
||||||
for (IIdType nextId : theId) {
|
.filter(t -> isValidPid(t))
|
||||||
if (theDaoConfig.getResourceClientIdStrategy() != DaoConfig.ClientIdStrategyEnum.ANY && isValidPid(nextId)) {
|
.map(t -> t.getIdPartAsLong())
|
||||||
retVal.add(new ResourcePersistentId(nextId.getIdPartAsLong()));
|
.map(t -> new ResourcePersistentId(t))
|
||||||
} else {
|
.forEach(t -> retVal.add(t));
|
||||||
if (nextId.hasResourceType()) {
|
|
||||||
typeToIds.put(nextId.getResourceType(), nextId.getIdPart());
|
|
||||||
} else {
|
|
||||||
typeToIds.put("", nextId.getIdPart());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// For every resource type, fetch all of the requested ids against the forcedPidDao, and add them to the return value.
|
ListMultimap<String, String> typeToIds = organizeIdsByResourceType(theIds);
|
||||||
|
|
||||||
for (Map.Entry<String, Collection<String>> nextEntry : typeToIds.asMap().entrySet()) {
|
for (Map.Entry<String, Collection<String>> nextEntry : typeToIds.asMap().entrySet()) {
|
||||||
String nextResourceType = nextEntry.getKey();
|
String nextResourceType = nextEntry.getKey();
|
||||||
Collection<String> nextIds = nextEntry.getValue();
|
Collection<String> nextIds = nextEntry.getValue();
|
||||||
List<Long> convertedPidStream;
|
|
||||||
if (isBlank(nextResourceType)) {
|
if (isBlank(nextResourceType)) {
|
||||||
|
|
||||||
StorageProcessingMessage msg = new StorageProcessingMessage()
|
List<Long> views = myForcedIdDao.findByForcedId(nextIds);
|
||||||
.setMessage("This search uses unqualified resource IDs (an ID without a resource type). This is less efficient than using a qualified type.");
|
views.forEach(t -> retVal.add(new ResourcePersistentId(t)));
|
||||||
HookParams params = new HookParams()
|
|
||||||
.add(RequestDetails.class, theRequest)
|
|
||||||
.addIfMatchesType(ServletRequestDetails.class, theRequest)
|
|
||||||
.add(StorageProcessingMessage.class, msg);
|
|
||||||
JpaInterceptorBroadcaster.doCallHooks(theInterceptorBroadcaster, theRequest, Pointcut.JPA_PERFTRACE_WARNING, params);
|
|
||||||
|
|
||||||
convertedPidStream = theForcedIdDao.findByForcedId(nextIds);
|
|
||||||
} else {
|
} else {
|
||||||
convertedPidStream = theForcedIdDao.findByTypeAndForcedId(nextResourceType, nextIds);
|
|
||||||
|
if (!myDaoConfig.isDeleteEnabled()) {
|
||||||
|
for (Iterator<String> idIterator = nextIds.iterator(); idIterator.hasNext(); ) {
|
||||||
|
String nextId = idIterator.next();
|
||||||
|
String key = nextResourceType + "/" + nextId;
|
||||||
|
Long nextCachedPid = myPersistentIdCache.getIfPresent(key);
|
||||||
|
if (nextCachedPid != null) {
|
||||||
|
idIterator.remove();
|
||||||
|
retVal.add(new ResourcePersistentId(nextCachedPid));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nextIds.size() > 0) {
|
||||||
|
Collection<Object[]> views = myForcedIdDao.findByTypeAndForcedId(nextResourceType, nextIds);
|
||||||
|
for (Object[] nextView : views) {
|
||||||
|
String forcedId = (String) nextView[0];
|
||||||
|
Long pid = (Long) nextView[1];
|
||||||
|
retVal.add(new ResourcePersistentId(pid));
|
||||||
|
|
||||||
|
if (!myDaoConfig.isDeleteEnabled()) {
|
||||||
|
String key = nextResourceType + "/" + forcedId;
|
||||||
|
myPersistentIdCache.put(key, pid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
convertedPidStream
|
|
||||||
.stream()
|
|
||||||
.map(ResourcePersistentId::new)
|
|
||||||
.forEach(retVal::add);
|
|
||||||
}
|
}
|
||||||
return retVal;
|
|
||||||
|
return retVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Given a persistent ID, returns the associated resource ID
|
||||||
|
*/
|
||||||
|
@Nonnull
|
||||||
public IIdType translatePidIdToForcedId(FhirContext theCtx, String theResourceType, ResourcePersistentId theId) {
|
public IIdType translatePidIdToForcedId(FhirContext theCtx, String theResourceType, ResourcePersistentId theId) {
|
||||||
IIdType retVal = theCtx.getVersion().newIdType();
|
IIdType retVal = theCtx.getVersion().newIdType();
|
||||||
retVal.setValue(translatePidIdToForcedId(theResourceType, theId));
|
retVal.setValue(translatePidIdToForcedId(theResourceType, theId));
|
||||||
return retVal;
|
return retVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String translatePidIdToForcedId(String theResourceType, ResourcePersistentId theId) {
|
private String translatePidIdToForcedId(String theResourceType, ResourcePersistentId theId) {
|
||||||
ForcedId forcedId = myForcedIdDao.findByResourcePid(theId.getIdAsLong());
|
ForcedId forcedId = myForcedIdDao.findByResourcePid(theId.getIdAsLong());
|
||||||
if (forcedId != null) {
|
if (forcedId != null) {
|
||||||
return forcedId.getResourceType() + '/' + forcedId.getForcedId();
|
return forcedId.getResourceType() + '/' + forcedId.getForcedId();
|
||||||
|
@ -156,17 +247,139 @@ public class IdHelperService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isValidPid(IIdType theId) {
|
private ListMultimap<String, String> organizeIdsByResourceType(Collection<IIdType> theIds) {
|
||||||
if (theId == null || theId.getIdPart() == null) {
|
ListMultimap<String, String> typeToIds = MultimapBuilder.hashKeys().arrayListValues().build();
|
||||||
return false;
|
for (IIdType nextId : theIds) {
|
||||||
}
|
if (myDaoConfig.getResourceClientIdStrategy() == DaoConfig.ClientIdStrategyEnum.ANY || !isValidPid(nextId)) {
|
||||||
String idPart = theId.getIdPart();
|
if (nextId.hasResourceType()) {
|
||||||
for (int i = 0; i < idPart.length(); i++) {
|
typeToIds.put(nextId.getResourceType(), nextId.getIdPart());
|
||||||
char nextChar = idPart.charAt(i);
|
} else {
|
||||||
if (nextChar < '0' || nextChar > '9') {
|
typeToIds.put("", nextId.getIdPart());
|
||||||
return false;
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return typeToIds;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Long resolveResourceIdentity(String theResourceType, String theId) {
|
||||||
|
Long retVal;
|
||||||
|
retVal = myForcedIdDao
|
||||||
|
.findByTypeAndForcedId(theResourceType, theId)
|
||||||
|
.orElseThrow(() -> new ResourceNotFoundException(new IdDt(theResourceType, theId)));
|
||||||
|
return retVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Collection<IResourceLookup> translateForcedIdToPids(RequestDetails theRequest, Collection<IIdType> theId) {
|
||||||
|
theId.forEach(id -> Validate.isTrue(id.hasIdPart()));
|
||||||
|
|
||||||
|
if (theId.isEmpty()) {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
List<IResourceLookup> retVal = new ArrayList<>();
|
||||||
|
|
||||||
|
if (myDaoConfig.getResourceClientIdStrategy() != DaoConfig.ClientIdStrategyEnum.ANY) {
|
||||||
|
List<Long> pids = theId
|
||||||
|
.stream()
|
||||||
|
.filter(t -> isValidPid(t))
|
||||||
|
.map(t -> t.getIdPartAsLong())
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
if (!pids.isEmpty()) {
|
||||||
|
|
||||||
|
Collection<Object[]> lookups = myResourceTableDao.findLookupFieldsByResourcePid(pids);
|
||||||
|
for (Object[] next : lookups) {
|
||||||
|
String resourceType = (String) next[0];
|
||||||
|
Long resourcePid = (Long) next[1];
|
||||||
|
Date deletedAt = (Date) next[2];
|
||||||
|
retVal.add(new ResourceLookup(resourceType, resourcePid, deletedAt));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ListMultimap<String, String> typeToIds = organizeIdsByResourceType(theId);
|
||||||
|
for (Map.Entry<String, Collection<String>> nextEntry : typeToIds.asMap().entrySet()) {
|
||||||
|
String nextResourceType = nextEntry.getKey();
|
||||||
|
Collection<String> nextIds = nextEntry.getValue();
|
||||||
|
|
||||||
|
if (!myDaoConfig.isDeleteEnabled()) {
|
||||||
|
for (Iterator<String> forcedIdIterator = nextIds.iterator(); forcedIdIterator.hasNext(); ) {
|
||||||
|
String nextForcedId = forcedIdIterator.next();
|
||||||
|
String nextKey = nextResourceType + "/" + nextForcedId;
|
||||||
|
IResourceLookup cachedLookup = myResourceLookupCache.getIfPresent(nextKey);
|
||||||
|
if (cachedLookup != null) {
|
||||||
|
forcedIdIterator.remove();
|
||||||
|
retVal.add(cachedLookup);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nextIds.size() > 0) {
|
||||||
|
Collection<Object[]> views;
|
||||||
|
if (isBlank(nextResourceType)) {
|
||||||
|
warnAboutUnqualifiedForcedIdResolution(theRequest);
|
||||||
|
views = myForcedIdDao.findAndResolveByForcedIdWithNoType(nextIds);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
views = myForcedIdDao.findAndResolveByForcedIdWithNoType(nextResourceType, nextIds);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Object[] next : views) {
|
||||||
|
String resourceType = (String) next[0];
|
||||||
|
Long resourcePid = (Long) next[1];
|
||||||
|
String forcedId = (String) next[2];
|
||||||
|
Date deletedAt = (Date) next[3];
|
||||||
|
ResourceLookup lookup = new ResourceLookup(resourceType, resourcePid, deletedAt);
|
||||||
|
retVal.add(lookup);
|
||||||
|
|
||||||
|
if (!myDaoConfig.isDeleteEnabled()) {
|
||||||
|
String key = resourceType + "/" + forcedId;
|
||||||
|
myResourceLookupCache.put(key, lookup);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return retVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void warnAboutUnqualifiedForcedIdResolution(RequestDetails theRequest) {
|
||||||
|
StorageProcessingMessage msg = new StorageProcessingMessage()
|
||||||
|
.setMessage("This search uses unqualified resource IDs (an ID without a resource type). This is less efficient than using a qualified type.");
|
||||||
|
ourLog.debug(msg.getMessage());
|
||||||
|
HookParams params = new HookParams()
|
||||||
|
.add(RequestDetails.class, theRequest)
|
||||||
|
.addIfMatchesType(ServletRequestDetails.class, theRequest)
|
||||||
|
.add(StorageProcessingMessage.class, msg);
|
||||||
|
JpaInterceptorBroadcaster.doCallHooks(myInterceptorBroadcaster, theRequest, Pointcut.JPA_PERFTRACE_WARNING, params);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void clearCache() {
|
||||||
|
myPersistentIdCache.invalidateAll();
|
||||||
|
myResourceLookupCache.invalidateAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
private <T, V> @NonNull Cache<T, V> newCache() {
|
||||||
|
return Caffeine
|
||||||
|
.newBuilder()
|
||||||
|
.maximumSize(10000)
|
||||||
|
.expireAfterWrite(10, TimeUnit.MINUTES)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isValidPid(IIdType theId) {
|
||||||
|
if (theId == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
String idPart = theId.getIdPart();
|
||||||
|
return isValidPid(idPart);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isValidPid(String theIdPart) {
|
||||||
|
return StringUtils.isNumeric(theIdPart);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,6 +27,7 @@ import ca.uhn.fhir.jpa.dao.BaseHapiFhirDao;
|
||||||
import ca.uhn.fhir.jpa.dao.DaoConfig;
|
import ca.uhn.fhir.jpa.dao.DaoConfig;
|
||||||
import ca.uhn.fhir.jpa.dao.MatchResourceUrlService;
|
import ca.uhn.fhir.jpa.dao.MatchResourceUrlService;
|
||||||
import ca.uhn.fhir.jpa.dao.data.IResourceIndexedCompositeStringUniqueDao;
|
import ca.uhn.fhir.jpa.dao.data.IResourceIndexedCompositeStringUniqueDao;
|
||||||
|
import ca.uhn.fhir.jpa.model.cross.IResourceLookup;
|
||||||
import ca.uhn.fhir.jpa.model.cross.ResourcePersistentId;
|
import ca.uhn.fhir.jpa.model.cross.ResourcePersistentId;
|
||||||
import ca.uhn.fhir.jpa.model.entity.BaseResourceIndexedSearchParam;
|
import ca.uhn.fhir.jpa.model.entity.BaseResourceIndexedSearchParam;
|
||||||
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedCompositeStringUnique;
|
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedCompositeStringUnique;
|
||||||
|
@ -187,7 +188,9 @@ public class SearchParamWithInlineReferencesExtractor {
|
||||||
if (linksForCompositePart != null) {
|
if (linksForCompositePart != null) {
|
||||||
for (ResourceLink nextLink : linksForCompositePart) {
|
for (ResourceLink nextLink : linksForCompositePart) {
|
||||||
if (linksForCompositePartWantPaths.contains(nextLink.getSourcePath())) {
|
if (linksForCompositePartWantPaths.contains(nextLink.getSourcePath())) {
|
||||||
String value = nextLink.getTargetResource().getIdDt().toUnqualifiedVersionless().getValue();
|
assert isNotBlank(nextLink.getTargetResourceType());
|
||||||
|
assert isNotBlank(nextLink.getTargetResourceId());
|
||||||
|
String value = nextLink.getTargetResourceType() + "/" + nextLink.getTargetResourceId();
|
||||||
if (isNotBlank(value)) {
|
if (isNotBlank(value)) {
|
||||||
value = UrlUtil.escapeUrlParam(value);
|
value = UrlUtil.escapeUrlParam(value);
|
||||||
nextChoicesList.add(key + "=" + value);
|
nextChoicesList.add(key + "=" + value);
|
||||||
|
@ -250,13 +253,14 @@ public class SearchParamWithInlineReferencesExtractor {
|
||||||
ResourcePersistentId match;
|
ResourcePersistentId match;
|
||||||
if (matches.isEmpty()) {
|
if (matches.isEmpty()) {
|
||||||
|
|
||||||
Optional<ResourcePersistentId> placeholderOpt = myDaoResourceLinkResolver.createPlaceholderTargetIfConfiguredToDoSo(matchResourceType, nextRef, null);
|
Optional<ResourceTable> placeholderOpt = myDaoResourceLinkResolver.createPlaceholderTargetIfConfiguredToDoSo(matchResourceType, nextRef, null);
|
||||||
if (placeholderOpt.isPresent()) {
|
if (placeholderOpt.isPresent()) {
|
||||||
match = placeholderOpt.get();
|
match = new ResourcePersistentId(placeholderOpt.get().getResourceId());
|
||||||
} else {
|
} else {
|
||||||
String msg = myContext.getLocalizer().getMessage(BaseHapiFhirDao.class, "invalidMatchUrlNoMatches", nextId.getValue());
|
String msg = myContext.getLocalizer().getMessage(BaseHapiFhirDao.class, "invalidMatchUrlNoMatches", nextId.getValue());
|
||||||
throw new ResourceNotFoundException(msg);
|
throw new ResourceNotFoundException(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if (matches.size() > 1) {
|
} else if (matches.size() > 1) {
|
||||||
String msg = myContext.getLocalizer().getMessage(BaseHapiFhirDao.class, "invalidMatchUrlMultipleMatches", nextId.getValue());
|
String msg = myContext.getLocalizer().getMessage(BaseHapiFhirDao.class, "invalidMatchUrlMultipleMatches", nextId.getValue());
|
||||||
throw new PreconditionFailedException(msg);
|
throw new PreconditionFailedException(msg);
|
||||||
|
@ -264,9 +268,9 @@ public class SearchParamWithInlineReferencesExtractor {
|
||||||
match = matches.iterator().next();
|
match = matches.iterator().next();
|
||||||
}
|
}
|
||||||
|
|
||||||
String newId = myIdHelperService.translatePidIdToForcedId(resourceTypeString, match);
|
IIdType newId = myIdHelperService.translatePidIdToForcedId(myContext, resourceTypeString, match);
|
||||||
ourLog.debug("Replacing inline match URL[{}] with ID[{}}", nextId.getValue(), newId);
|
ourLog.debug("Replacing inline match URL[{}] with ID[{}}", nextId.getValue(), newId);
|
||||||
nextRef.setReference(newId);
|
nextRef.setReference(newId.getValue());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -160,7 +160,7 @@ class PredicateBuilderReference extends BasePredicateBuilder {
|
||||||
List<Predicate> codePredicates = new ArrayList<>();
|
List<Predicate> codePredicates = new ArrayList<>();
|
||||||
|
|
||||||
// Resources by ID
|
// Resources by ID
|
||||||
List<ResourcePersistentId> targetPids = myIdHelperService.translateForcedIdToPids(targetIds, theRequest);
|
List<ResourcePersistentId> targetPids = myIdHelperService.resolveResourcePersistentIds(targetIds, theRequest);
|
||||||
if (!targetPids.isEmpty()) {
|
if (!targetPids.isEmpty()) {
|
||||||
ourLog.debug("Searching for resource link with target PIDs: {}", targetPids);
|
ourLog.debug("Searching for resource link with target PIDs: {}", targetPids);
|
||||||
Predicate pathPredicate;
|
Predicate pathPredicate;
|
||||||
|
|
|
@ -60,7 +60,7 @@ class PredicateBuilderResourceId extends BasePredicateBuilder {
|
||||||
@Nullable
|
@Nullable
|
||||||
Predicate addPredicateResourceId(List<List<IQueryParameterType>> theValues, String theResourceName, SearchFilterParser.CompareOperation theOperation, RequestDetails theRequest) {
|
Predicate addPredicateResourceId(List<List<IQueryParameterType>> theValues, String theResourceName, SearchFilterParser.CompareOperation theOperation, RequestDetails theRequest) {
|
||||||
|
|
||||||
Predicate nextPredicate = createPredicate(myQueryRoot.getRoot(), theResourceName, theValues, theOperation, theRequest);
|
Predicate nextPredicate = createPredicate(myQueryRoot.getRoot(), theResourceName, theValues, theOperation);
|
||||||
|
|
||||||
if (nextPredicate != null) {
|
if (nextPredicate != null) {
|
||||||
myQueryRoot.addPredicate(nextPredicate);
|
myQueryRoot.addPredicate(nextPredicate);
|
||||||
|
@ -71,7 +71,7 @@ class PredicateBuilderResourceId extends BasePredicateBuilder {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
private Predicate createPredicate(Root<ResourceTable> theRoot, String theResourceName, List<List<IQueryParameterType>> theValues, SearchFilterParser.CompareOperation theOperation, RequestDetails theRequest) {
|
private Predicate createPredicate(Root<ResourceTable> theRoot, String theResourceName, List<List<IQueryParameterType>> theValues, SearchFilterParser.CompareOperation theOperation) {
|
||||||
Predicate nextPredicate = null;
|
Predicate nextPredicate = null;
|
||||||
|
|
||||||
Set<ResourcePersistentId> allOrPids = null;
|
Set<ResourcePersistentId> allOrPids = null;
|
||||||
|
@ -89,7 +89,7 @@ class PredicateBuilderResourceId extends BasePredicateBuilder {
|
||||||
if (isNotBlank(value)) {
|
if (isNotBlank(value)) {
|
||||||
haveValue = true;
|
haveValue = true;
|
||||||
try {
|
try {
|
||||||
ResourcePersistentId pid = myIdHelperService.translateForcedIdToPid(theResourceName, valueAsId.getIdPart(), theRequest);
|
ResourcePersistentId pid = myIdHelperService.resolveResourcePersistentIds(theResourceName, valueAsId.getIdPart());
|
||||||
orPids.add(pid);
|
orPids.add(pid);
|
||||||
} catch (ResourceNotFoundException e) {
|
} catch (ResourceNotFoundException e) {
|
||||||
// This is not an error in a search, it just results in no matchesFhirResourceDaoR4InterceptorTest
|
// This is not an error in a search, it just results in no matchesFhirResourceDaoR4InterceptorTest
|
||||||
|
|
|
@ -48,7 +48,7 @@ public class FhirResourceDaoSubscriptionR4 extends BaseHapiFhirResourceDao<Subsc
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Long getSubscriptionTablePidForSubscriptionResource(IIdType theId, RequestDetails theRequest) {
|
public Long getSubscriptionTablePidForSubscriptionResource(IIdType theId, RequestDetails theRequest) {
|
||||||
ResourceTable entity = readEntityLatestVersion(theId, theRequest);
|
ResourceTable entity = readEntityLatestVersion(theId);
|
||||||
SubscriptionTable table = mySubscriptionTableDao.findOneByResourcePid(entity.getId());
|
SubscriptionTable table = mySubscriptionTableDao.findOneByResourcePid(entity.getId());
|
||||||
if (table == null) {
|
if (table == null) {
|
||||||
return null;
|
return null;
|
||||||
|
|
|
@ -48,7 +48,7 @@ public class FhirResourceDaoSubscriptionR5 extends BaseHapiFhirResourceDao<Subsc
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Long getSubscriptionTablePidForSubscriptionResource(IIdType theId, RequestDetails theRequest) {
|
public Long getSubscriptionTablePidForSubscriptionResource(IIdType theId, RequestDetails theRequest) {
|
||||||
ResourceTable entity = readEntityLatestVersion(theId, theRequest);
|
ResourceTable entity = readEntityLatestVersion(theId);
|
||||||
SubscriptionTable table = mySubscriptionTableDao.findOneByResourcePid(entity.getId());
|
SubscriptionTable table = mySubscriptionTableDao.findOneByResourcePid(entity.getId());
|
||||||
if (table == null) {
|
if (table == null) {
|
||||||
return null;
|
return null;
|
||||||
|
|
|
@ -117,11 +117,7 @@ public class TermCodeSystemStorageSvcImpl implements ITermCodeSystemStorageSvc {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ResourcePersistentId getValueSetResourcePid(IIdType theIdType) {
|
public ResourcePersistentId getValueSetResourcePid(IIdType theIdType) {
|
||||||
return getValueSetResourcePid(theIdType, null);
|
return myIdHelperService.resolveResourcePersistentIds(theIdType.getResourceType(), theIdType.getIdPart());
|
||||||
}
|
|
||||||
|
|
||||||
private ResourcePersistentId getValueSetResourcePid(IIdType theIdType, RequestDetails theRequestDetails) {
|
|
||||||
return myIdHelperService.translateForcedIdToPid(theIdType, theRequestDetails);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Transactional
|
@Transactional
|
||||||
|
@ -295,7 +291,7 @@ public class TermCodeSystemStorageSvcImpl implements ITermCodeSystemStorageSvc {
|
||||||
Validate.notBlank(theCodeSystemResource.getUrl(), "theCodeSystemResource must have a URL");
|
Validate.notBlank(theCodeSystemResource.getUrl(), "theCodeSystemResource must have a URL");
|
||||||
|
|
||||||
IIdType csId = myTerminologyVersionAdapterSvc.createOrUpdateCodeSystem(theCodeSystemResource);
|
IIdType csId = myTerminologyVersionAdapterSvc.createOrUpdateCodeSystem(theCodeSystemResource);
|
||||||
ResourcePersistentId codeSystemResourcePid = myIdHelperService.translateForcedIdToPid(csId, theRequest);
|
ResourcePersistentId codeSystemResourcePid = myIdHelperService.resolveResourcePersistentIds(csId.getResourceType(), csId.getIdPart());
|
||||||
ResourceTable resource = myResourceTableDao.getOne(codeSystemResourcePid.getIdAsLong());
|
ResourceTable resource = myResourceTableDao.getOne(codeSystemResourcePid.getIdAsLong());
|
||||||
|
|
||||||
ourLog.info("CodeSystem resource has ID: {}", csId.getValue());
|
ourLog.info("CodeSystem resource has ID: {}", csId.getValue());
|
||||||
|
@ -555,11 +551,7 @@ public class TermCodeSystemStorageSvcImpl implements ITermCodeSystemStorageSvc {
|
||||||
}
|
}
|
||||||
|
|
||||||
private ResourcePersistentId getCodeSystemResourcePid(IIdType theIdType) {
|
private ResourcePersistentId getCodeSystemResourcePid(IIdType theIdType) {
|
||||||
return getCodeSystemResourcePid(theIdType, null);
|
return myIdHelperService.resolveResourcePersistentIds(theIdType.getResourceType(), theIdType.getIdPart());
|
||||||
}
|
|
||||||
|
|
||||||
private ResourcePersistentId getCodeSystemResourcePid(IIdType theIdType, RequestDetails theRequestDetails) {
|
|
||||||
return myIdHelperService.translateForcedIdToPid(theIdType, theRequestDetails);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void persistChildren(TermConcept theConcept, TermCodeSystemVersion theCodeSystem, IdentityHashMap<TermConcept, Object> theConceptsStack, int theTotalConcepts) {
|
private void persistChildren(TermConcept theConcept, TermCodeSystemVersion theCodeSystem, IdentityHashMap<TermConcept, Object> theConceptsStack, int theTotalConcepts) {
|
||||||
|
|
|
@ -28,6 +28,7 @@ import com.google.common.reflect.ClassPath;
|
||||||
import com.google.common.reflect.ClassPath.ClassInfo;
|
import com.google.common.reflect.ClassPath.ClassInfo;
|
||||||
import org.apache.commons.io.IOUtils;
|
import org.apache.commons.io.IOUtils;
|
||||||
import org.apache.commons.lang3.Validate;
|
import org.apache.commons.lang3.Validate;
|
||||||
|
import org.hibernate.annotations.Subselect;
|
||||||
import org.hibernate.validator.constraints.Length;
|
import org.hibernate.validator.constraints.Length;
|
||||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||||
import org.hl7.fhir.r4.model.InstantType;
|
import org.hl7.fhir.r4.model.InstantType;
|
||||||
|
@ -39,7 +40,11 @@ import java.io.InputStream;
|
||||||
import java.lang.reflect.AnnotatedElement;
|
import java.lang.reflect.AnnotatedElement;
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
import java.lang.reflect.Modifier;
|
import java.lang.reflect.Modifier;
|
||||||
import java.util.*;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import static com.google.common.base.Ascii.toUpperCase;
|
import static com.google.common.base.Ascii.toUpperCase;
|
||||||
|
@ -96,7 +101,10 @@ public class TestUtil {
|
||||||
private static void scanClass(Set<String> theNames, Class<?> theClazz, boolean theIsSuperClass) {
|
private static void scanClass(Set<String> theNames, Class<?> theClazz, boolean theIsSuperClass) {
|
||||||
ourLog.info("Scanning: {}", theClazz.getSimpleName());
|
ourLog.info("Scanning: {}", theClazz.getSimpleName());
|
||||||
|
|
||||||
scan(theClazz, theNames, theIsSuperClass);
|
Subselect subselect = theClazz.getAnnotation(Subselect.class);
|
||||||
|
boolean isView = (subselect != null);
|
||||||
|
|
||||||
|
scan(theClazz, theNames, theIsSuperClass, isView);
|
||||||
|
|
||||||
for (Field nextField : theClazz.getDeclaredFields()) {
|
for (Field nextField : theClazz.getDeclaredFields()) {
|
||||||
if (Modifier.isStatic(nextField.getModifiers())) {
|
if (Modifier.isStatic(nextField.getModifiers())) {
|
||||||
|
@ -104,7 +112,7 @@ public class TestUtil {
|
||||||
}
|
}
|
||||||
|
|
||||||
ourLog.info(" * Scanning field: {}", nextField.getName());
|
ourLog.info(" * Scanning field: {}", nextField.getName());
|
||||||
scan(nextField, theNames, theIsSuperClass);
|
scan(nextField, theNames, theIsSuperClass, isView);
|
||||||
|
|
||||||
Lob lobClass = nextField.getAnnotation(Lob.class);
|
Lob lobClass = nextField.getAnnotation(Lob.class);
|
||||||
if (lobClass != null) {
|
if (lobClass != null) {
|
||||||
|
@ -140,7 +148,7 @@ public class TestUtil {
|
||||||
scanClass(theNames, theClazz.getSuperclass(), true);
|
scanClass(theNames, theClazz.getSuperclass(), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void scan(AnnotatedElement theAnnotatedElement, Set<String> theNames, boolean theIsSuperClass) {
|
private static void scan(AnnotatedElement theAnnotatedElement, Set<String> theNames, boolean theIsSuperClass, boolean theIsView) {
|
||||||
Table table = theAnnotatedElement.getAnnotation(Table.class);
|
Table table = theAnnotatedElement.getAnnotation(Table.class);
|
||||||
if (table != null) {
|
if (table != null) {
|
||||||
|
|
||||||
|
@ -198,7 +206,7 @@ public class TestUtil {
|
||||||
*/
|
*/
|
||||||
if (field.getType().equals(String.class)) {
|
if (field.getType().equals(String.class)) {
|
||||||
if (!hasLob) {
|
if (!hasLob) {
|
||||||
if (column.length() == 255) {
|
if (!theIsView && column.length() == 255) {
|
||||||
throw new IllegalStateException("Field does not have an explicit maximum length specified: " + field);
|
throw new IllegalStateException("Field does not have an explicit maximum length specified: " + field);
|
||||||
}
|
}
|
||||||
if (column.length() > MAX_COL_LENGTH) {
|
if (column.length() > MAX_COL_LENGTH) {
|
||||||
|
|
|
@ -426,7 +426,7 @@ public class FhirResourceDaoDstu2Test extends BaseJpaDstu2Test {
|
||||||
myPatientDao.create(p, mySrd);
|
myPatientDao.create(p, mySrd);
|
||||||
fail();
|
fail();
|
||||||
} catch (UnprocessableEntityException e) {
|
} catch (UnprocessableEntityException e) {
|
||||||
assertEquals("Resource contains reference to Organization/" + id1.getIdPart() + " but resource with ID " + id1.getIdPart() + " is actually of type Observation", e.getMessage());
|
assertEquals("Resource contains reference to unknown resource ID Organization/" + id1.getIdPart(), e.getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now with a forced ID
|
// Now with a forced ID
|
||||||
|
|
|
@ -36,6 +36,7 @@ import org.junit.AfterClass;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Ignore;
|
import org.junit.Ignore;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
import org.springframework.transaction.TransactionDefinition;
|
||||||
import org.springframework.transaction.TransactionStatus;
|
import org.springframework.transaction.TransactionStatus;
|
||||||
import org.springframework.transaction.support.TransactionCallback;
|
import org.springframework.transaction.support.TransactionCallback;
|
||||||
import org.springframework.transaction.support.TransactionTemplate;
|
import org.springframework.transaction.support.TransactionTemplate;
|
||||||
|
@ -491,7 +492,7 @@ public class FhirResourceDaoDstu3SearchNoFtTest extends BaseJpaDstu3Test {
|
||||||
assertEquals(2, results.size());
|
assertEquals(2, results.size());
|
||||||
|
|
||||||
List<IIdType> actual = toUnqualifiedVersionlessIds(
|
List<IIdType> actual = toUnqualifiedVersionlessIds(
|
||||||
mySubstanceDao.search(new SearchParameterMap().setLoadSynchronous(true).add(Substance.SP_QUANTITY, new QuantityParam((ParamPrefixEnum) null, 123, "http://foo", "UNIT"))));
|
mySubstanceDao.search(new SearchParameterMap().setLoadSynchronous(true).add(Substance.SP_QUANTITY, new QuantityParam(null, 123, "http://foo", "UNIT"))));
|
||||||
assertThat(actual, contains(id));
|
assertThat(actual, contains(id));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1588,7 +1589,7 @@ public class FhirResourceDaoDstu3SearchNoFtTest extends BaseJpaDstu3Test {
|
||||||
dr01.setSubject(new Reference(patientId01));
|
dr01.setSubject(new Reference(patientId01));
|
||||||
IIdType drId01 = myDiagnosticReportDao.create(dr01, mySrd).getId();
|
IIdType drId01 = myDiagnosticReportDao.create(dr01, mySrd).getId();
|
||||||
|
|
||||||
ourLog.info("P1[{}] P2[{}] O1[{}] O2[{}] D1[{}]", new Object[]{patientId01, patientId02, obsId01, obsId02, drId01});
|
ourLog.info("P1[{}] P2[{}] O1[{}] O2[{}] D1[{}]", patientId01, patientId02, obsId01, obsId02, drId01);
|
||||||
|
|
||||||
List<Observation> result = toList(myObservationDao
|
List<Observation> result = toList(myObservationDao
|
||||||
.search(new SearchParameterMap().setLoadSynchronous(true).add(Observation.SP_SUBJECT, new ReferenceParam(Patient.SP_IDENTIFIER, "urn:system|testSearchResourceLinkWithChain01"))));
|
.search(new SearchParameterMap().setLoadSynchronous(true).add(Observation.SP_SUBJECT, new ReferenceParam(Patient.SP_IDENTIFIER, "urn:system|testSearchResourceLinkWithChain01"))));
|
||||||
|
@ -1693,7 +1694,7 @@ public class FhirResourceDaoDstu3SearchNoFtTest extends BaseJpaDstu3Test {
|
||||||
Date after = new Date();
|
Date after = new Date();
|
||||||
ca.uhn.fhir.jpa.util.TestUtil.sleepOneClick();
|
ca.uhn.fhir.jpa.util.TestUtil.sleepOneClick();
|
||||||
|
|
||||||
ourLog.info("P1[{}] L1[{}] Obs1[{}] Obs2[{}]", new Object[]{patientId01, locId01, obsId01, obsId02});
|
ourLog.info("P1[{}] L1[{}] Obs1[{}] Obs2[{}]", patientId01, locId01, obsId01, obsId02);
|
||||||
|
|
||||||
List<IIdType> result;
|
List<IIdType> result;
|
||||||
SearchParameterMap params;
|
SearchParameterMap params;
|
||||||
|
@ -1756,7 +1757,7 @@ public class FhirResourceDaoDstu3SearchNoFtTest extends BaseJpaDstu3Test {
|
||||||
dr01.setSubject(new Reference(patientId01));
|
dr01.setSubject(new Reference(patientId01));
|
||||||
IIdType drId01 = myDiagnosticReportDao.create(dr01, mySrd).getId();
|
IIdType drId01 = myDiagnosticReportDao.create(dr01, mySrd).getId();
|
||||||
|
|
||||||
ourLog.info("P1[{}] P2[{}] O1[{}] O2[{}] D1[{}]", new Object[]{patientId01, patientId02, obsId01, obsId02, drId01});
|
ourLog.info("P1[{}] P2[{}] O1[{}] O2[{}] D1[{}]", patientId01, patientId02, obsId01, obsId02, drId01);
|
||||||
|
|
||||||
List<Observation> result = toList(
|
List<Observation> result = toList(
|
||||||
myObservationDao.search(new SearchParameterMap().setLoadSynchronous(true).add(Observation.SP_SUBJECT, new ReferenceParam("testSearchResourceLinkWithTextLogicalId01"))));
|
myObservationDao.search(new SearchParameterMap().setLoadSynchronous(true).add(Observation.SP_SUBJECT, new ReferenceParam("testSearchResourceLinkWithTextLogicalId01"))));
|
||||||
|
@ -2847,7 +2848,7 @@ public class FhirResourceDaoDstu3SearchNoFtTest extends BaseJpaDstu3Test {
|
||||||
ourLog.info("Initial size: " + value.size());
|
ourLog.info("Initial size: " + value.size());
|
||||||
for (IBaseResource next : value.getResources(0, value.size())) {
|
for (IBaseResource next : value.getResources(0, value.size())) {
|
||||||
ourLog.info("Deleting: {}", next.getIdElement());
|
ourLog.info("Deleting: {}", next.getIdElement());
|
||||||
myDeviceDao.delete((IIdType) next.getIdElement(), mySrd);
|
myDeviceDao.delete(next.getIdElement(), mySrd);
|
||||||
}
|
}
|
||||||
|
|
||||||
value = myDeviceDao.search(new SearchParameterMap());
|
value = myDeviceDao.search(new SearchParameterMap());
|
||||||
|
@ -2866,7 +2867,7 @@ public class FhirResourceDaoDstu3SearchNoFtTest extends BaseJpaDstu3Test {
|
||||||
public void testSearchWithRevIncludes() {
|
public void testSearchWithRevIncludes() {
|
||||||
final String methodName = "testSearchWithRevIncludes";
|
final String methodName = "testSearchWithRevIncludes";
|
||||||
TransactionTemplate txTemplate = new TransactionTemplate(myTransactionMgr);
|
TransactionTemplate txTemplate = new TransactionTemplate(myTransactionMgr);
|
||||||
txTemplate.setPropagationBehavior(TransactionTemplate.PROPAGATION_REQUIRES_NEW);
|
txTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
|
||||||
IIdType pid = txTemplate.execute(new TransactionCallback<IIdType>() {
|
IIdType pid = txTemplate.execute(new TransactionCallback<IIdType>() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -2884,7 +2885,7 @@ public class FhirResourceDaoDstu3SearchNoFtTest extends BaseJpaDstu3Test {
|
||||||
});
|
});
|
||||||
|
|
||||||
SearchParameterMap map = new SearchParameterMap();
|
SearchParameterMap map = new SearchParameterMap();
|
||||||
map.add(Patient.SP_RES_ID, new StringParam(pid.getIdPart()));
|
map.add(IAnyResource.SP_RES_ID, new StringParam(pid.getIdPart()));
|
||||||
map.addRevInclude(Condition.INCLUDE_PATIENT);
|
map.addRevInclude(Condition.INCLUDE_PATIENT);
|
||||||
IBundleProvider results = myPatientDao.search(map);
|
IBundleProvider results = myPatientDao.search(map);
|
||||||
List<IBaseResource> foundResources = results.getResources(0, results.size());
|
List<IBaseResource> foundResources = results.getResources(0, results.size());
|
||||||
|
|
|
@ -700,7 +700,7 @@ public class FhirResourceDaoDstu3Test extends BaseJpaDstu3Test {
|
||||||
myPatientDao.create(p, mySrd);
|
myPatientDao.create(p, mySrd);
|
||||||
fail();
|
fail();
|
||||||
} catch (UnprocessableEntityException e) {
|
} catch (UnprocessableEntityException e) {
|
||||||
assertEquals("Resource contains reference to Organization/" + id1.getIdPart() + " but resource with ID " + id1.getIdPart() + " is actually of type Observation", e.getMessage());
|
assertEquals("Resource contains reference to unknown resource ID Organization/" + id1.getIdPart(), e.getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now with a forced ID
|
// Now with a forced ID
|
||||||
|
|
|
@ -9,6 +9,7 @@ import ca.uhn.fhir.jpa.config.TestR4Config;
|
||||||
import ca.uhn.fhir.jpa.dao.*;
|
import ca.uhn.fhir.jpa.dao.*;
|
||||||
import ca.uhn.fhir.jpa.dao.data.*;
|
import ca.uhn.fhir.jpa.dao.data.*;
|
||||||
import ca.uhn.fhir.jpa.dao.dstu2.FhirResourceDaoDstu2SearchNoFtTest;
|
import ca.uhn.fhir.jpa.dao.dstu2.FhirResourceDaoDstu2SearchNoFtTest;
|
||||||
|
import ca.uhn.fhir.jpa.dao.index.IdHelperService;
|
||||||
import ca.uhn.fhir.jpa.entity.TermCodeSystem;
|
import ca.uhn.fhir.jpa.entity.TermCodeSystem;
|
||||||
import ca.uhn.fhir.jpa.entity.TermCodeSystemVersion;
|
import ca.uhn.fhir.jpa.entity.TermCodeSystemVersion;
|
||||||
import ca.uhn.fhir.jpa.entity.TermConcept;
|
import ca.uhn.fhir.jpa.entity.TermConcept;
|
||||||
|
@ -352,6 +353,8 @@ public abstract class BaseJpaR4Test extends BaseJpaTest {
|
||||||
private DaoRegistry myDaoRegistry;
|
private DaoRegistry myDaoRegistry;
|
||||||
@Autowired
|
@Autowired
|
||||||
private IBulkDataExportSvc myBulkDataExportSvc;
|
private IBulkDataExportSvc myBulkDataExportSvc;
|
||||||
|
@Autowired
|
||||||
|
private IdHelperService myIdHelperService;
|
||||||
|
|
||||||
@After()
|
@After()
|
||||||
public void afterCleanupDao() {
|
public void afterCleanupDao() {
|
||||||
|
@ -380,6 +383,8 @@ public abstract class BaseJpaR4Test extends BaseJpaTest {
|
||||||
BaseTermReadSvcImpl.clearOurLastResultsFromTranslationWithReverseCache();
|
BaseTermReadSvcImpl.clearOurLastResultsFromTranslationWithReverseCache();
|
||||||
TermDeferredStorageSvcImpl termDeferredStorageSvc = AopTestUtils.getTargetObject(myTerminologyDeferredStorageSvc);
|
TermDeferredStorageSvcImpl termDeferredStorageSvc = AopTestUtils.getTargetObject(myTerminologyDeferredStorageSvc);
|
||||||
termDeferredStorageSvc.clearDeferred();
|
termDeferredStorageSvc.clearDeferred();
|
||||||
|
|
||||||
|
myIdHelperService.clearCache();
|
||||||
}
|
}
|
||||||
|
|
||||||
@After()
|
@After()
|
||||||
|
|
|
@ -1,12 +1,18 @@
|
||||||
package ca.uhn.fhir.jpa.dao.r4;
|
package ca.uhn.fhir.jpa.dao.r4;
|
||||||
|
|
||||||
|
import ca.uhn.fhir.jpa.dao.DaoConfig;
|
||||||
import ca.uhn.fhir.jpa.model.entity.ResourceHistoryTable;
|
import ca.uhn.fhir.jpa.model.entity.ResourceHistoryTable;
|
||||||
import ca.uhn.fhir.jpa.model.entity.ResourceTable;
|
import ca.uhn.fhir.jpa.model.entity.ResourceTable;
|
||||||
|
import ca.uhn.fhir.rest.server.exceptions.PreconditionFailedException;
|
||||||
import ca.uhn.fhir.rest.server.exceptions.ResourceGoneException;
|
import ca.uhn.fhir.rest.server.exceptions.ResourceGoneException;
|
||||||
import ca.uhn.fhir.rest.server.exceptions.ResourceVersionConflictException;
|
import ca.uhn.fhir.rest.server.exceptions.ResourceVersionConflictException;
|
||||||
import ca.uhn.fhir.util.TestUtil;
|
import ca.uhn.fhir.util.TestUtil;
|
||||||
import org.hl7.fhir.instance.model.api.IIdType;
|
import org.hl7.fhir.instance.model.api.IIdType;
|
||||||
import org.hl7.fhir.r4.model.*;
|
import org.hl7.fhir.r4.model.Bundle;
|
||||||
|
import org.hl7.fhir.r4.model.IdType;
|
||||||
|
import org.hl7.fhir.r4.model.Organization;
|
||||||
|
import org.hl7.fhir.r4.model.Patient;
|
||||||
|
import org.junit.After;
|
||||||
import org.junit.AfterClass;
|
import org.junit.AfterClass;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
|
@ -14,11 +20,20 @@ import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
import static org.junit.Assert.*;
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertNotNull;
|
||||||
|
import static org.junit.Assert.assertNull;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
import static org.junit.Assert.fail;
|
||||||
|
|
||||||
public class FhirResourceDaoR4DeleteTest extends BaseJpaR4Test {
|
public class FhirResourceDaoR4DeleteTest extends BaseJpaR4Test {
|
||||||
private static final Logger ourLog = LoggerFactory.getLogger(FhirResourceDaoR4DeleteTest.class);
|
private static final Logger ourLog = LoggerFactory.getLogger(FhirResourceDaoR4DeleteTest.class);
|
||||||
|
|
||||||
|
@After
|
||||||
|
public void after() {
|
||||||
|
myDaoConfig.setDeleteEnabled(new DaoConfig().isDeleteEnabled());
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testDeleteMarksResourceAndVersionAsDeleted() {
|
public void testDeleteMarksResourceAndVersionAsDeleted() {
|
||||||
|
|
||||||
|
@ -29,19 +44,19 @@ public class FhirResourceDaoR4DeleteTest extends BaseJpaR4Test {
|
||||||
myPatientDao.delete(id);
|
myPatientDao.delete(id);
|
||||||
|
|
||||||
// Table should be marked as deleted
|
// Table should be marked as deleted
|
||||||
runInTransaction(()->{
|
runInTransaction(() -> {
|
||||||
ResourceTable resourceTable = myResourceTableDao.findById(id.getIdPartAsLong()).get();
|
ResourceTable resourceTable = myResourceTableDao.findById(id.getIdPartAsLong()).get();
|
||||||
assertNotNull(resourceTable.getDeleted());
|
assertNotNull(resourceTable.getDeleted());
|
||||||
assertTrue(resourceTable.isDeleted());
|
assertTrue(resourceTable.isDeleted());
|
||||||
});
|
});
|
||||||
|
|
||||||
// Current version should be marked as deleted
|
// Current version should be marked as deleted
|
||||||
runInTransaction(()->{
|
runInTransaction(() -> {
|
||||||
ResourceHistoryTable resourceTable = myResourceHistoryTableDao.findForIdAndVersionAndFetchProvenance(id.getIdPartAsLong(), 1);
|
ResourceHistoryTable resourceTable = myResourceHistoryTableDao.findForIdAndVersionAndFetchProvenance(id.getIdPartAsLong(), 1);
|
||||||
assertNull(resourceTable.getDeleted());
|
assertNull(resourceTable.getDeleted());
|
||||||
assertNotNull(resourceTable.getPersistentId());
|
assertNotNull(resourceTable.getPersistentId());
|
||||||
});
|
});
|
||||||
runInTransaction(()->{
|
runInTransaction(() -> {
|
||||||
ResourceHistoryTable resourceTable = myResourceHistoryTableDao.findForIdAndVersionAndFetchProvenance(id.getIdPartAsLong(), 2);
|
ResourceHistoryTable resourceTable = myResourceHistoryTableDao.findForIdAndVersionAndFetchProvenance(id.getIdPartAsLong(), 2);
|
||||||
assertNotNull(resourceTable.getDeleted());
|
assertNotNull(resourceTable.getDeleted());
|
||||||
});
|
});
|
||||||
|
@ -66,6 +81,23 @@ public class FhirResourceDaoR4DeleteTest extends BaseJpaR4Test {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDeleteDisabled() {
|
||||||
|
myDaoConfig.setDeleteEnabled(false);
|
||||||
|
|
||||||
|
Patient p = new Patient();
|
||||||
|
p.setActive(true);
|
||||||
|
IIdType pId = myPatientDao.create(p).getId().toUnqualifiedVersionless();
|
||||||
|
|
||||||
|
try {
|
||||||
|
myPatientDao.delete(pId);
|
||||||
|
fail();
|
||||||
|
} catch (PreconditionFailedException e) {
|
||||||
|
assertEquals("Resource deletion is not permitted on this server", e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testDeleteCircularReferenceInTransaction() throws IOException {
|
public void testDeleteCircularReferenceInTransaction() throws IOException {
|
||||||
|
|
||||||
|
@ -157,14 +189,14 @@ public class FhirResourceDaoR4DeleteTest extends BaseJpaR4Test {
|
||||||
myPatientDao.delete(id);
|
myPatientDao.delete(id);
|
||||||
|
|
||||||
// Table should be marked as deleted
|
// Table should be marked as deleted
|
||||||
runInTransaction(()->{
|
runInTransaction(() -> {
|
||||||
ResourceTable resourceTable = myResourceTableDao.findById(id.getIdPartAsLong()).get();
|
ResourceTable resourceTable = myResourceTableDao.findById(id.getIdPartAsLong()).get();
|
||||||
assertNotNull(resourceTable.getDeleted());
|
assertNotNull(resourceTable.getDeleted());
|
||||||
});
|
});
|
||||||
|
|
||||||
// Mark the current history version as not-deleted even though the actual resource
|
// Mark the current history version as not-deleted even though the actual resource
|
||||||
// table entry is marked deleted
|
// table entry is marked deleted
|
||||||
runInTransaction(()->{
|
runInTransaction(() -> {
|
||||||
ResourceHistoryTable resourceTable = myResourceHistoryTableDao.findForIdAndVersionAndFetchProvenance(id.getIdPartAsLong(), 2);
|
ResourceHistoryTable resourceTable = myResourceHistoryTableDao.findForIdAndVersionAndFetchProvenance(id.getIdPartAsLong(), 2);
|
||||||
resourceTable.setDeleted(null);
|
resourceTable.setDeleted(null);
|
||||||
myResourceHistoryTableDao.save(resourceTable);
|
myResourceHistoryTableDao.save(resourceTable);
|
||||||
|
|
|
@ -1,29 +1,20 @@
|
||||||
package ca.uhn.fhir.jpa.dao.r4;
|
package ca.uhn.fhir.jpa.dao.r4;
|
||||||
|
|
||||||
import ca.uhn.fhir.jpa.dao.DaoConfig;
|
import ca.uhn.fhir.jpa.dao.DaoConfig;
|
||||||
import ca.uhn.fhir.jpa.model.entity.ResourceHistoryTable;
|
|
||||||
import ca.uhn.fhir.jpa.model.entity.ResourceTable;
|
|
||||||
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
||||||
import ca.uhn.fhir.jpa.util.TestUtil;
|
import ca.uhn.fhir.jpa.util.TestUtil;
|
||||||
import ca.uhn.fhir.model.primitive.InstantDt;
|
import ca.uhn.fhir.rest.param.ReferenceParam;
|
||||||
import ca.uhn.fhir.rest.api.MethodOutcome;
|
|
||||||
import ca.uhn.fhir.rest.api.server.IBundleProvider;
|
|
||||||
import ca.uhn.fhir.rest.param.StringParam;
|
|
||||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
|
||||||
import ca.uhn.fhir.rest.server.exceptions.ResourceGoneException;
|
|
||||||
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
|
|
||||||
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
|
|
||||||
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.*;
|
import org.hl7.fhir.r4.model.Observation;
|
||||||
import org.junit.*;
|
import org.hl7.fhir.r4.model.Patient;
|
||||||
import org.springframework.test.context.TestPropertySource;
|
import org.junit.After;
|
||||||
|
import org.junit.AfterClass;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
import java.util.*;
|
import static org.hamcrest.Matchers.empty;
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
import static org.hamcrest.Matchers.*;
|
import static org.junit.Assert.assertThat;
|
||||||
import static org.junit.Assert.*;
|
|
||||||
import static org.mockito.Mockito.reset;
|
|
||||||
|
|
||||||
public class FhirResourceDaoR4QueryCountTest extends BaseJpaR4Test {
|
public class FhirResourceDaoR4QueryCountTest extends BaseJpaR4Test {
|
||||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(FhirResourceDaoR4QueryCountTest.class);
|
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(FhirResourceDaoR4QueryCountTest.class);
|
||||||
|
@ -32,6 +23,7 @@ public class FhirResourceDaoR4QueryCountTest extends BaseJpaR4Test {
|
||||||
public void afterResetDao() {
|
public void afterResetDao() {
|
||||||
myDaoConfig.setResourceMetaCountHardLimit(new DaoConfig().getResourceMetaCountHardLimit());
|
myDaoConfig.setResourceMetaCountHardLimit(new DaoConfig().getResourceMetaCountHardLimit());
|
||||||
myDaoConfig.setIndexMissingFields(new DaoConfig().getIndexMissingFields());
|
myDaoConfig.setIndexMissingFields(new DaoConfig().getIndexMissingFields());
|
||||||
|
myDaoConfig.setDeleteEnabled(new DaoConfig().isDeleteEnabled());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
|
@ -53,7 +45,7 @@ public class FhirResourceDaoR4QueryCountTest extends BaseJpaR4Test {
|
||||||
Patient p = new Patient();
|
Patient p = new Patient();
|
||||||
p.setId(id.getIdPart());
|
p.setId(id.getIdPart());
|
||||||
p.addIdentifier().setSystem("urn:system").setValue("2");
|
p.addIdentifier().setSystem("urn:system").setValue("2");
|
||||||
myPatientDao.update(p).getResource();
|
myPatientDao.update(p);
|
||||||
});
|
});
|
||||||
myCaptureQueriesListener.logSelectQueriesForCurrentThread();
|
myCaptureQueriesListener.logSelectQueriesForCurrentThread();
|
||||||
assertEquals(5, myCaptureQueriesListener.getSelectQueriesForCurrentThread().size());
|
assertEquals(5, myCaptureQueriesListener.getSelectQueriesForCurrentThread().size());
|
||||||
|
@ -164,6 +156,177 @@ public class FhirResourceDaoR4QueryCountTest extends BaseJpaR4Test {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testReferenceToForcedId() {
|
||||||
|
myDaoConfig.setIndexMissingFields(DaoConfig.IndexEnabledEnum.DISABLED);
|
||||||
|
|
||||||
|
Patient patient = new Patient();
|
||||||
|
patient.setId("P");
|
||||||
|
patient.setActive(true);
|
||||||
|
|
||||||
|
myCaptureQueriesListener.clear();
|
||||||
|
myPatientDao.update(patient);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Add a resource with a forced ID target link
|
||||||
|
*/
|
||||||
|
|
||||||
|
myCaptureQueriesListener.clear();
|
||||||
|
Observation observation = new Observation();
|
||||||
|
observation.getSubject().setReference("Patient/P");
|
||||||
|
myObservationDao.create(observation);
|
||||||
|
myCaptureQueriesListener.logAllQueriesForCurrentThread();
|
||||||
|
// select: lookup forced ID
|
||||||
|
assertEquals(1, myCaptureQueriesListener.countSelectQueriesForCurrentThread());
|
||||||
|
assertEquals(0, myCaptureQueriesListener.countDeleteQueriesForCurrentThread());
|
||||||
|
// insert to: HFJ_RESOURCE, HFJ_RES_VER, HFJ_RES_LINK
|
||||||
|
assertEquals(3, myCaptureQueriesListener.countInsertQueriesForCurrentThread());
|
||||||
|
assertEquals(0, myCaptureQueriesListener.countUpdateQueriesForCurrentThread());
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Add another
|
||||||
|
*/
|
||||||
|
|
||||||
|
myCaptureQueriesListener.clear();
|
||||||
|
observation = new Observation();
|
||||||
|
observation.getSubject().setReference("Patient/P");
|
||||||
|
myObservationDao.create(observation);
|
||||||
|
// select: lookup forced ID
|
||||||
|
assertEquals(1, myCaptureQueriesListener.countSelectQueriesForCurrentThread());
|
||||||
|
assertEquals(0, myCaptureQueriesListener.countDeleteQueriesForCurrentThread());
|
||||||
|
// insert to: HFJ_RESOURCE, HFJ_RES_VER, HFJ_RES_LINK
|
||||||
|
assertEquals(3, myCaptureQueriesListener.countInsertQueriesForCurrentThread());
|
||||||
|
assertEquals(0, myCaptureQueriesListener.countUpdateQueriesForCurrentThread());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testReferenceToForcedId_DeletesDisabled() {
|
||||||
|
myDaoConfig.setIndexMissingFields(DaoConfig.IndexEnabledEnum.DISABLED);
|
||||||
|
myDaoConfig.setDeleteEnabled(false);
|
||||||
|
|
||||||
|
Patient patient = new Patient();
|
||||||
|
patient.setId("P");
|
||||||
|
patient.setActive(true);
|
||||||
|
|
||||||
|
myCaptureQueriesListener.clear();
|
||||||
|
myPatientDao.update(patient);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Add a resource with a forced ID target link
|
||||||
|
*/
|
||||||
|
|
||||||
|
myCaptureQueriesListener.clear();
|
||||||
|
Observation observation = new Observation();
|
||||||
|
observation.getSubject().setReference("Patient/P");
|
||||||
|
myObservationDao.create(observation);
|
||||||
|
myCaptureQueriesListener.logAllQueriesForCurrentThread();
|
||||||
|
// select: lookup forced ID
|
||||||
|
assertEquals(1, myCaptureQueriesListener.countSelectQueriesForCurrentThread());
|
||||||
|
assertEquals(0, myCaptureQueriesListener.countDeleteQueriesForCurrentThread());
|
||||||
|
// insert to: HFJ_RESOURCE, HFJ_RES_VER, HFJ_RES_LINK
|
||||||
|
assertEquals(3, myCaptureQueriesListener.countInsertQueriesForCurrentThread());
|
||||||
|
assertEquals(0, myCaptureQueriesListener.countUpdateQueriesForCurrentThread());
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Add another
|
||||||
|
*/
|
||||||
|
|
||||||
|
myCaptureQueriesListener.clear();
|
||||||
|
observation = new Observation();
|
||||||
|
observation.getSubject().setReference("Patient/P");
|
||||||
|
myObservationDao.create(observation);
|
||||||
|
// select: no lookups needed because of cache
|
||||||
|
assertEquals(0, myCaptureQueriesListener.countSelectQueriesForCurrentThread());
|
||||||
|
assertEquals(0, myCaptureQueriesListener.countDeleteQueriesForCurrentThread());
|
||||||
|
// insert to: HFJ_RESOURCE, HFJ_RES_VER, HFJ_RES_LINK
|
||||||
|
assertEquals(3, myCaptureQueriesListener.countInsertQueriesForCurrentThread());
|
||||||
|
assertEquals(0, myCaptureQueriesListener.countUpdateQueriesForCurrentThread());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSearchUsingForcedIdReference() {
|
||||||
|
|
||||||
|
Patient patient = new Patient();
|
||||||
|
patient.setId("P");
|
||||||
|
patient.setActive(true);
|
||||||
|
myPatientDao.update(patient);
|
||||||
|
|
||||||
|
Observation obs = new Observation();
|
||||||
|
obs.getSubject().setReference("Patient/P");
|
||||||
|
myObservationDao.update(obs);
|
||||||
|
|
||||||
|
SearchParameterMap map = new SearchParameterMap();
|
||||||
|
map.setLoadSynchronous(true);
|
||||||
|
map.add("subject", new ReferenceParam("Patient/P"));
|
||||||
|
|
||||||
|
myCaptureQueriesListener.clear();
|
||||||
|
assertEquals(1, myObservationDao.search(map).size().intValue());
|
||||||
|
// myCaptureQueriesListener.logAllQueriesForCurrentThread();
|
||||||
|
// Resolve forced ID, Perform search, load result
|
||||||
|
assertEquals(3, myCaptureQueriesListener.countSelectQueriesForCurrentThread());
|
||||||
|
assertEquals(0, myCaptureQueriesListener.countInsertQueriesForCurrentThread());
|
||||||
|
assertEquals(0, myCaptureQueriesListener.countUpdateQueriesForCurrentThread());
|
||||||
|
assertEquals(0, myCaptureQueriesListener.countDeleteQueriesForCurrentThread());
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Again
|
||||||
|
*/
|
||||||
|
|
||||||
|
myCaptureQueriesListener.clear();
|
||||||
|
assertEquals(1, myObservationDao.search(map).size().intValue());
|
||||||
|
myCaptureQueriesListener.logAllQueriesForCurrentThread();
|
||||||
|
// Resolve forced ID, Perform search, load result
|
||||||
|
assertEquals(3, myCaptureQueriesListener.countSelectQueriesForCurrentThread());
|
||||||
|
assertEquals(0, myCaptureQueriesListener.countInsertQueriesForCurrentThread());
|
||||||
|
assertEquals(0, myCaptureQueriesListener.countUpdateQueriesForCurrentThread());
|
||||||
|
assertEquals(0, myCaptureQueriesListener.countDeleteQueriesForCurrentThread());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSearchUsingForcedIdReference_DeletedDisabled() {
|
||||||
|
myDaoConfig.setDeleteEnabled(false);
|
||||||
|
|
||||||
|
Patient patient = new Patient();
|
||||||
|
patient.setId("P");
|
||||||
|
patient.setActive(true);
|
||||||
|
myPatientDao.update(patient);
|
||||||
|
|
||||||
|
Observation obs = new Observation();
|
||||||
|
obs.getSubject().setReference("Patient/P");
|
||||||
|
myObservationDao.update(obs);
|
||||||
|
|
||||||
|
SearchParameterMap map = new SearchParameterMap();
|
||||||
|
map.setLoadSynchronous(true);
|
||||||
|
map.add("subject", new ReferenceParam("Patient/P"));
|
||||||
|
|
||||||
|
myCaptureQueriesListener.clear();
|
||||||
|
assertEquals(1, myObservationDao.search(map).size().intValue());
|
||||||
|
myCaptureQueriesListener.logAllQueriesForCurrentThread();
|
||||||
|
// Resolve forced ID, Perform search, load result
|
||||||
|
assertEquals(3, myCaptureQueriesListener.countSelectQueriesForCurrentThread());
|
||||||
|
assertEquals(0, myCaptureQueriesListener.countInsertQueriesForCurrentThread());
|
||||||
|
assertEquals(0, myCaptureQueriesListener.countUpdateQueriesForCurrentThread());
|
||||||
|
assertEquals(0, myCaptureQueriesListener.countDeleteQueriesForCurrentThread());
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Again
|
||||||
|
*/
|
||||||
|
|
||||||
|
myCaptureQueriesListener.clear();
|
||||||
|
assertEquals(1, myObservationDao.search(map).size().intValue());
|
||||||
|
myCaptureQueriesListener.logAllQueriesForCurrentThread();
|
||||||
|
// (NO resolve forced ID), Perform search, load result
|
||||||
|
assertEquals(2, myCaptureQueriesListener.countSelectQueriesForCurrentThread());
|
||||||
|
assertEquals(0, myCaptureQueriesListener.countInsertQueriesForCurrentThread());
|
||||||
|
assertEquals(0, myCaptureQueriesListener.countUpdateQueriesForCurrentThread());
|
||||||
|
assertEquals(0, myCaptureQueriesListener.countDeleteQueriesForCurrentThread());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@AfterClass
|
@AfterClass
|
||||||
public static void afterClassClearContext() {
|
public static void afterClassClearContext() {
|
||||||
|
|
|
@ -910,7 +910,7 @@ public class FhirResourceDaoR4Test extends BaseJpaR4Test {
|
||||||
myPatientDao.create(p, mySrd);
|
myPatientDao.create(p, mySrd);
|
||||||
fail();
|
fail();
|
||||||
} catch (UnprocessableEntityException e) {
|
} catch (UnprocessableEntityException e) {
|
||||||
assertEquals("Resource contains reference to Organization/" + id1.getIdPart() + " but resource with ID " + id1.getIdPart() + " is actually of type Observation", e.getMessage());
|
assertEquals("Resource contains reference to unknown resource ID Organization/" + id1.getIdPart(), e.getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now with a forced ID
|
// Now with a forced ID
|
||||||
|
|
|
@ -193,8 +193,8 @@ public abstract class BaseSubscriptionsR4Test extends BaseResourceProviderR4Test
|
||||||
@Update
|
@Update
|
||||||
public MethodOutcome update(@ResourceParam Observation theObservation, HttpServletRequest theRequest) {
|
public MethodOutcome update(@ResourceParam Observation theObservation, HttpServletRequest theRequest) {
|
||||||
ourLog.info("Received Listener Update");
|
ourLog.info("Received Listener Update");
|
||||||
ourUpdatedObservations.add(theObservation);
|
|
||||||
ourContentTypes.add(theRequest.getHeader(Constants.HEADER_CONTENT_TYPE).replaceAll(";.*", ""));
|
ourContentTypes.add(theRequest.getHeader(Constants.HEADER_CONTENT_TYPE).replaceAll(";.*", ""));
|
||||||
|
ourUpdatedObservations.add(theObservation);
|
||||||
extractHeaders(theRequest);
|
extractHeaders(theRequest);
|
||||||
return new MethodOutcome(new IdType("Observation/1"), false);
|
return new MethodOutcome(new IdType("Observation/1"), false);
|
||||||
}
|
}
|
||||||
|
|
|
@ -56,6 +56,7 @@ public class FhirClientSubscriptionProviderTest extends BaseSubscriptionsR4Test
|
||||||
|
|
||||||
waitForSize(0, ourCreatedObservations);
|
waitForSize(0, ourCreatedObservations);
|
||||||
waitForSize(1, ourUpdatedObservations);
|
waitForSize(1, ourUpdatedObservations);
|
||||||
|
waitForSize(1, ourContentTypes);
|
||||||
assertEquals(Constants.CT_FHIR_JSON_NEW, ourContentTypes.get(0));
|
assertEquals(Constants.CT_FHIR_JSON_NEW, ourContentTypes.get(0));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,110 +0,0 @@
|
||||||
package ca.uhn.fhir.jpa.model.any;
|
|
||||||
|
|
||||||
/*-
|
|
||||||
* #%L
|
|
||||||
* HAPI FHIR Model
|
|
||||||
* %%
|
|
||||||
* Copyright (C) 2014 - 2020 University Health Network
|
|
||||||
* %%
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
* #L%
|
|
||||||
*/
|
|
||||||
|
|
||||||
import ca.uhn.fhir.context.FhirContext;
|
|
||||||
import ca.uhn.fhir.context.FhirVersionEnum;
|
|
||||||
import org.apache.commons.lang3.Validate;
|
|
||||||
import org.hl7.fhir.instance.model.api.IBaseBundle;
|
|
||||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
|
||||||
|
|
||||||
public class AnyBundle {
|
|
||||||
private final FhirVersionEnum myFhirVersion;
|
|
||||||
private final IBaseBundle myBundle;
|
|
||||||
|
|
||||||
public static AnyBundle fromFhirContext(FhirContext theFhirContext) {
|
|
||||||
FhirVersionEnum version = theFhirContext.getVersion().getVersion();
|
|
||||||
switch (version) {
|
|
||||||
case DSTU2:
|
|
||||||
return new AnyBundle(new ca.uhn.fhir.model.dstu2.resource.Bundle());
|
|
||||||
case DSTU3:
|
|
||||||
return new AnyBundle(new org.hl7.fhir.dstu3.model.Bundle());
|
|
||||||
case R4:
|
|
||||||
return new AnyBundle(new org.hl7.fhir.r4.model.Bundle());
|
|
||||||
default:
|
|
||||||
throw new UnsupportedOperationException(version + " not supported");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public AnyBundle(ca.uhn.fhir.model.dstu2.resource.Bundle theBundleR2) {
|
|
||||||
myFhirVersion = FhirVersionEnum.DSTU2;
|
|
||||||
myBundle = theBundleR2;
|
|
||||||
}
|
|
||||||
|
|
||||||
public AnyBundle(org.hl7.fhir.dstu3.model.Bundle theBundleR3) {
|
|
||||||
myFhirVersion = FhirVersionEnum.DSTU3;
|
|
||||||
myBundle = theBundleR3;
|
|
||||||
}
|
|
||||||
|
|
||||||
public AnyBundle(org.hl7.fhir.r4.model.Bundle theBundleR4) {
|
|
||||||
myFhirVersion = FhirVersionEnum.R4;
|
|
||||||
myBundle = theBundleR4;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static AnyBundle fromResource(IBaseResource theBundle) {
|
|
||||||
if (theBundle instanceof ca.uhn.fhir.model.dstu2.resource.Bundle) {
|
|
||||||
return new AnyBundle((ca.uhn.fhir.model.dstu2.resource.Bundle) theBundle);
|
|
||||||
} else if (theBundle instanceof org.hl7.fhir.dstu3.model.Bundle) {
|
|
||||||
return new AnyBundle((org.hl7.fhir.dstu3.model.Bundle) theBundle);
|
|
||||||
} else if (theBundle instanceof org.hl7.fhir.r4.model.Bundle) {
|
|
||||||
return new AnyBundle((org.hl7.fhir.r4.model.Bundle) theBundle);
|
|
||||||
} else {
|
|
||||||
throw new UnsupportedOperationException("Cannot convert " + theBundle.getClass().getName() + " to AnyBundle");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public IBaseBundle get() {
|
|
||||||
return myBundle;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ca.uhn.fhir.model.dstu2.resource.Bundle getDstu2() {
|
|
||||||
Validate.isTrue(myFhirVersion == FhirVersionEnum.DSTU2);
|
|
||||||
return (ca.uhn.fhir.model.dstu2.resource.Bundle) get();
|
|
||||||
}
|
|
||||||
|
|
||||||
public org.hl7.fhir.dstu3.model.Bundle getDstu3() {
|
|
||||||
Validate.isTrue(myFhirVersion == FhirVersionEnum.DSTU3);
|
|
||||||
return (org.hl7.fhir.dstu3.model.Bundle) get();
|
|
||||||
}
|
|
||||||
|
|
||||||
public org.hl7.fhir.r4.model.Bundle getR4() {
|
|
||||||
Validate.isTrue(myFhirVersion == FhirVersionEnum.R4);
|
|
||||||
return (org.hl7.fhir.r4.model.Bundle) get();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void addResource(IBaseResource theResource) {
|
|
||||||
switch (myFhirVersion) {
|
|
||||||
case DSTU3:
|
|
||||||
org.hl7.fhir.dstu3.model.Bundle.BundleEntryComponent entry = new org.hl7.fhir.dstu3.model.Bundle.BundleEntryComponent();
|
|
||||||
entry.setResource((org.hl7.fhir.dstu3.model.Resource) theResource);
|
|
||||||
getDstu3().getEntry().add(entry);
|
|
||||||
break;
|
|
||||||
case R4:
|
|
||||||
org.hl7.fhir.r4.model.Bundle.BundleEntryComponent entryr4 = new org.hl7.fhir.r4.model.Bundle.BundleEntryComponent();
|
|
||||||
entryr4.setResource((org.hl7.fhir.r4.model.Resource) theResource);
|
|
||||||
getR4().getEntry().add(entryr4);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw new UnsupportedOperationException(myFhirVersion + " not supported");
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,235 +0,0 @@
|
||||||
package ca.uhn.fhir.jpa.model.any;
|
|
||||||
|
|
||||||
/*-
|
|
||||||
* #%L
|
|
||||||
* HAPI FHIR Model
|
|
||||||
* %%
|
|
||||||
* Copyright (C) 2014 - 2020 University Health Network
|
|
||||||
* %%
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
* #L%
|
|
||||||
*/
|
|
||||||
|
|
||||||
import ca.uhn.fhir.context.FhirContext;
|
|
||||||
import ca.uhn.fhir.context.FhirVersionEnum;
|
|
||||||
import org.apache.commons.lang3.Validate;
|
|
||||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public class AnyComposition {
|
|
||||||
private final FhirVersionEnum myFhirVersion;
|
|
||||||
private final IBaseResource myComposition;
|
|
||||||
|
|
||||||
public static AnyComposition fromFhirContext(FhirContext theFhirContext) {
|
|
||||||
FhirVersionEnum version = theFhirContext.getVersion().getVersion();
|
|
||||||
switch (version) {
|
|
||||||
case DSTU3:
|
|
||||||
return new AnyComposition(new org.hl7.fhir.dstu3.model.Composition());
|
|
||||||
case R4:
|
|
||||||
return new AnyComposition(new org.hl7.fhir.r4.model.Composition());
|
|
||||||
default:
|
|
||||||
throw new UnsupportedOperationException(version + " not supported");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public AnyComposition(org.hl7.fhir.dstu3.model.Composition theCompositionR3) {
|
|
||||||
myFhirVersion = FhirVersionEnum.DSTU3;
|
|
||||||
myComposition = theCompositionR3;
|
|
||||||
}
|
|
||||||
|
|
||||||
public AnyComposition(org.hl7.fhir.r4.model.Composition theCompositionR4) {
|
|
||||||
myFhirVersion = FhirVersionEnum.R4;
|
|
||||||
myComposition = theCompositionR4;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static AnyComposition fromResource(IBaseResource theComposition) {
|
|
||||||
if (theComposition instanceof org.hl7.fhir.dstu3.model.Composition) {
|
|
||||||
return new AnyComposition((org.hl7.fhir.dstu3.model.Composition) theComposition);
|
|
||||||
} else if (theComposition instanceof org.hl7.fhir.r4.model.Composition) {
|
|
||||||
return new AnyComposition((org.hl7.fhir.r4.model.Composition) theComposition);
|
|
||||||
} else {
|
|
||||||
throw new UnsupportedOperationException("Cannot convert " + theComposition.getClass().getName() + " to AnyList");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public IBaseResource get() {
|
|
||||||
return myComposition;
|
|
||||||
}
|
|
||||||
|
|
||||||
public org.hl7.fhir.dstu3.model.Composition getDstu3() {
|
|
||||||
Validate.isTrue(myFhirVersion == FhirVersionEnum.DSTU3);
|
|
||||||
return (org.hl7.fhir.dstu3.model.Composition) get();
|
|
||||||
}
|
|
||||||
|
|
||||||
public org.hl7.fhir.r4.model.Composition getR4() {
|
|
||||||
Validate.isTrue(myFhirVersion == FhirVersionEnum.R4);
|
|
||||||
return (org.hl7.fhir.r4.model.Composition) get();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setIdentifier(String theSystem, String theValue) {
|
|
||||||
switch (myFhirVersion) {
|
|
||||||
case DSTU3:
|
|
||||||
getDstu3().setIdentifier(new org.hl7.fhir.dstu3.model.Identifier().setSystem(theSystem).setValue(theValue));
|
|
||||||
break;
|
|
||||||
case R4:
|
|
||||||
getR4().setIdentifier(new org.hl7.fhir.r4.model.Identifier().setSystem(theSystem).setValue(theValue));
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw new UnsupportedOperationException(myFhirVersion + " not supported");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getIdentifier() {
|
|
||||||
switch (myFhirVersion) {
|
|
||||||
case DSTU3:
|
|
||||||
return getDstu3().getIdentifier().getValue();
|
|
||||||
case R4:
|
|
||||||
return getR4().getIdentifier().getValue();
|
|
||||||
default:
|
|
||||||
throw new UnsupportedOperationException(myFhirVersion + " not supported");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setClass(String theSystem, String theCode) {
|
|
||||||
switch (myFhirVersion) {
|
|
||||||
case DSTU3:
|
|
||||||
setClassDstu3(theSystem, theCode);
|
|
||||||
break;
|
|
||||||
case R4:
|
|
||||||
setClassR4(theSystem, theCode);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw new UnsupportedOperationException(myFhirVersion + " not supported");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setClassDstu3(String theSystem, String theCode) {
|
|
||||||
org.hl7.fhir.dstu3.model.CodeableConcept codeableConcept = new org.hl7.fhir.dstu3.model.CodeableConcept();
|
|
||||||
codeableConcept.addCoding().setSystem(theSystem).setCode(theCode);
|
|
||||||
getDstu3().setClass_(codeableConcept);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setClassR4(String theSystem, String theCode) {
|
|
||||||
org.hl7.fhir.r4.model.CodeableConcept codeableConcept = new org.hl7.fhir.r4.model.CodeableConcept();
|
|
||||||
codeableConcept.addCoding().setSystem(theSystem).setCode(theCode);
|
|
||||||
getR4().addCategory(codeableConcept);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void addStringExtension(String theUrl, String theValue) {
|
|
||||||
switch (myFhirVersion) {
|
|
||||||
case DSTU3:
|
|
||||||
getDstu3().addExtension().setUrl(theUrl).setValue(new org.hl7.fhir.dstu3.model.StringType(theValue));
|
|
||||||
break;
|
|
||||||
case R4:
|
|
||||||
getR4().addExtension().setUrl(theUrl).setValue(new org.hl7.fhir.r4.model.StringType(theValue));
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw new UnsupportedOperationException(myFhirVersion + " not supported");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO KHS Consolidate with other classes in this package
|
|
||||||
public String getStringExtensionValueOrNull(String theUrl) {
|
|
||||||
switch (myFhirVersion) {
|
|
||||||
case DSTU3:
|
|
||||||
return getStringExtensionValueOrNullDstu3(theUrl);
|
|
||||||
case R4:
|
|
||||||
return getStringExtensionValueOrNullR4(theUrl);
|
|
||||||
default:
|
|
||||||
throw new UnsupportedOperationException(myFhirVersion + " not supported");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private String getStringExtensionValueOrNullDstu3(String theUrl) {
|
|
||||||
List<org.hl7.fhir.dstu3.model.Extension> targetTypes = getDstu3().getExtensionsByUrl(theUrl);
|
|
||||||
if (targetTypes.size() < 1) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
org.hl7.fhir.dstu3.model.StringType targetType = (org.hl7.fhir.dstu3.model.StringType) targetTypes.get(0).getValue();
|
|
||||||
return targetType.getValue();
|
|
||||||
}
|
|
||||||
|
|
||||||
private String getStringExtensionValueOrNullR4(String theUrl) {
|
|
||||||
List<org.hl7.fhir.r4.model.Extension> targetTypes = getR4().getExtensionsByUrl(theUrl);
|
|
||||||
if (targetTypes.size() < 1) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
org.hl7.fhir.r4.model.StringType targetType = (org.hl7.fhir.r4.model.StringType) targetTypes.get(0).getValue();
|
|
||||||
return targetType.getValue();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setSubject(String theReferenceId) {
|
|
||||||
switch (myFhirVersion) {
|
|
||||||
case DSTU3:
|
|
||||||
getDstu3().setSubject(new org.hl7.fhir.dstu3.model.Reference(theReferenceId));
|
|
||||||
break;
|
|
||||||
case R4:
|
|
||||||
getR4().setSubject(new org.hl7.fhir.r4.model.Reference(theReferenceId));
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw new UnsupportedOperationException(myFhirVersion + " not supported");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setTitle(String theTitle) {
|
|
||||||
switch (myFhirVersion) {
|
|
||||||
case DSTU3:
|
|
||||||
getDstu3().setTitle(theTitle);
|
|
||||||
break;
|
|
||||||
case R4:
|
|
||||||
getR4().setTitle(theTitle);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw new UnsupportedOperationException(myFhirVersion + " not supported");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getTitle() {
|
|
||||||
switch (myFhirVersion) {
|
|
||||||
case DSTU3:
|
|
||||||
return getDstu3().getTitle();
|
|
||||||
case R4:
|
|
||||||
return getR4().getTitle();
|
|
||||||
default:
|
|
||||||
throw new UnsupportedOperationException(myFhirVersion + " not supported");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void addEntry(String theReferenceId) {
|
|
||||||
switch (myFhirVersion) {
|
|
||||||
case DSTU3:
|
|
||||||
getDstu3().getSectionFirstRep().addEntry(new org.hl7.fhir.dstu3.model.Reference(theReferenceId));
|
|
||||||
break;
|
|
||||||
case R4:
|
|
||||||
getR4().getSectionFirstRep().addEntry(new org.hl7.fhir.r4.model.Reference(theReferenceId));
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw new UnsupportedOperationException(myFhirVersion + " not supported");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setRandomUuid() {
|
|
||||||
switch (myFhirVersion) {
|
|
||||||
case DSTU3:
|
|
||||||
getDstu3().setId(org.hl7.fhir.dstu3.model.IdType.newRandomUuid());
|
|
||||||
break;
|
|
||||||
case R4:
|
|
||||||
getR4().setId(org.hl7.fhir.r4.model.IdType.newRandomUuid());
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw new UnsupportedOperationException(myFhirVersion + " not supported");
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,361 +0,0 @@
|
||||||
package ca.uhn.fhir.jpa.model.any;
|
|
||||||
|
|
||||||
/*-
|
|
||||||
* #%L
|
|
||||||
* HAPI FHIR Model
|
|
||||||
* %%
|
|
||||||
* Copyright (C) 2014 - 2020 University Health Network
|
|
||||||
* %%
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
* #L%
|
|
||||||
*/
|
|
||||||
|
|
||||||
import ca.uhn.fhir.context.FhirContext;
|
|
||||||
import ca.uhn.fhir.context.FhirVersionEnum;
|
|
||||||
import ca.uhn.fhir.rest.param.TokenParam;
|
|
||||||
import org.apache.commons.lang3.Validate;
|
|
||||||
import org.hl7.fhir.instance.model.api.IBaseReference;
|
|
||||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.stream.Stream;
|
|
||||||
|
|
||||||
public class AnyListResource {
|
|
||||||
private final FhirVersionEnum myFhirVersion;
|
|
||||||
private final IBaseResource myListResource;
|
|
||||||
|
|
||||||
public static AnyListResource fromFhirContext(FhirContext theFhirContext) {
|
|
||||||
FhirVersionEnum version = theFhirContext.getVersion().getVersion();
|
|
||||||
switch (version) {
|
|
||||||
case DSTU2:
|
|
||||||
return new AnyListResource(new ca.uhn.fhir.model.dstu2.resource.ListResource());
|
|
||||||
case DSTU3:
|
|
||||||
return new AnyListResource(new org.hl7.fhir.dstu3.model.ListResource());
|
|
||||||
case R4:
|
|
||||||
return new AnyListResource(new org.hl7.fhir.r4.model.ListResource());
|
|
||||||
case R5:
|
|
||||||
return new AnyListResource(new org.hl7.fhir.r5.model.ListResource());
|
|
||||||
default:
|
|
||||||
throw new UnsupportedOperationException(version + " not supported");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public AnyListResource(ca.uhn.fhir.model.dstu2.resource.ListResource theListResourceR2) {
|
|
||||||
myFhirVersion = FhirVersionEnum.DSTU2;
|
|
||||||
myListResource = theListResourceR2;
|
|
||||||
}
|
|
||||||
|
|
||||||
public AnyListResource(org.hl7.fhir.dstu3.model.ListResource theListResourceR3) {
|
|
||||||
myFhirVersion = FhirVersionEnum.DSTU3;
|
|
||||||
myListResource = theListResourceR3;
|
|
||||||
}
|
|
||||||
|
|
||||||
public AnyListResource(org.hl7.fhir.r4.model.ListResource theListResourceR4) {
|
|
||||||
myFhirVersion = FhirVersionEnum.R4;
|
|
||||||
myListResource = theListResourceR4;
|
|
||||||
}
|
|
||||||
|
|
||||||
public AnyListResource(org.hl7.fhir.r5.model.ListResource theListResourceR5) {
|
|
||||||
myFhirVersion = FhirVersionEnum.R5;
|
|
||||||
myListResource = theListResourceR5;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static AnyListResource fromResource(IBaseResource theListResource) {
|
|
||||||
if (theListResource instanceof ca.uhn.fhir.model.dstu2.resource.ListResource) {
|
|
||||||
return new AnyListResource((ca.uhn.fhir.model.dstu2.resource.ListResource) theListResource);
|
|
||||||
} else if (theListResource instanceof org.hl7.fhir.dstu3.model.ListResource) {
|
|
||||||
return new AnyListResource((org.hl7.fhir.dstu3.model.ListResource) theListResource);
|
|
||||||
} else if (theListResource instanceof org.hl7.fhir.r4.model.ListResource) {
|
|
||||||
return new AnyListResource((org.hl7.fhir.r4.model.ListResource) theListResource);
|
|
||||||
} else if (theListResource instanceof org.hl7.fhir.r5.model.ListResource) {
|
|
||||||
return new AnyListResource((org.hl7.fhir.r5.model.ListResource) theListResource);
|
|
||||||
} else {
|
|
||||||
throw new UnsupportedOperationException("Cannot convert " + theListResource.getClass().getName() + " to AnyList");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public IBaseResource get() {
|
|
||||||
return myListResource;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ca.uhn.fhir.model.dstu2.resource.ListResource getDstu2() {
|
|
||||||
Validate.isTrue(myFhirVersion == FhirVersionEnum.DSTU2);
|
|
||||||
return (ca.uhn.fhir.model.dstu2.resource.ListResource) get();
|
|
||||||
}
|
|
||||||
|
|
||||||
public org.hl7.fhir.dstu3.model.ListResource getDstu3() {
|
|
||||||
Validate.isTrue(myFhirVersion == FhirVersionEnum.DSTU3);
|
|
||||||
return (org.hl7.fhir.dstu3.model.ListResource) get();
|
|
||||||
}
|
|
||||||
|
|
||||||
public org.hl7.fhir.r4.model.ListResource getR4() {
|
|
||||||
Validate.isTrue(myFhirVersion == FhirVersionEnum.R4);
|
|
||||||
return (org.hl7.fhir.r4.model.ListResource) get();
|
|
||||||
}
|
|
||||||
|
|
||||||
public org.hl7.fhir.r5.model.ListResource getR5() {
|
|
||||||
Validate.isTrue(myFhirVersion == FhirVersionEnum.R5);
|
|
||||||
return (org.hl7.fhir.r5.model.ListResource) get();
|
|
||||||
}
|
|
||||||
|
|
||||||
public FhirVersionEnum getFhirVersion() {
|
|
||||||
return myFhirVersion;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void addCode(String theSystem, String theCode) {
|
|
||||||
switch (myFhirVersion) {
|
|
||||||
case DSTU3:
|
|
||||||
getDstu3().getCode().addCoding().setSystem(theSystem).setCode(theCode);
|
|
||||||
break;
|
|
||||||
case R4:
|
|
||||||
getR4().getCode().addCoding().setSystem(theSystem).setCode(theCode);
|
|
||||||
break;
|
|
||||||
case R5:
|
|
||||||
getR5().getCode().addCoding().setSystem(theSystem).setCode(theCode);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw new UnsupportedOperationException(myFhirVersion + " not supported");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void addIdentifier(String theSystem, String theValue) {
|
|
||||||
switch (myFhirVersion) {
|
|
||||||
case DSTU3:
|
|
||||||
getDstu3().getIdentifier().add(new org.hl7.fhir.dstu3.model.Identifier().setSystem(theSystem).setValue(theValue));
|
|
||||||
break;
|
|
||||||
case R4:
|
|
||||||
getR4().getIdentifier().add(new org.hl7.fhir.r4.model.Identifier().setSystem(theSystem).setValue(theValue));
|
|
||||||
break;
|
|
||||||
case R5:
|
|
||||||
getR5().getIdentifier().add(new org.hl7.fhir.r5.model.Identifier().setSystem(theSystem).setValue(theValue));
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw new UnsupportedOperationException(myFhirVersion + " not supported");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void addStringExtension(String theUrl, String theValue) {
|
|
||||||
switch (myFhirVersion) {
|
|
||||||
case DSTU3:
|
|
||||||
getDstu3().addExtension().setUrl(theUrl).setValue(new org.hl7.fhir.dstu3.model.StringType(theValue));
|
|
||||||
break;
|
|
||||||
case R4:
|
|
||||||
getR4().addExtension().setUrl(theUrl).setValue(new org.hl7.fhir.r4.model.StringType(theValue));
|
|
||||||
break;
|
|
||||||
case R5:
|
|
||||||
getR5().addExtension().setUrl(theUrl).setValue(new org.hl7.fhir.r5.model.StringType(theValue));
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw new UnsupportedOperationException(myFhirVersion + " not supported");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getStringExtensionValueOrNull(String theUrl) {
|
|
||||||
switch (myFhirVersion) {
|
|
||||||
case DSTU3:
|
|
||||||
return getStringExtensionValueOrNullDstu3(theUrl);
|
|
||||||
case R4:
|
|
||||||
return getStringExtensionValueOrNullR4(theUrl);
|
|
||||||
case R5:
|
|
||||||
return getStringExtensionValueOrNullR5(theUrl);
|
|
||||||
default:
|
|
||||||
throw new UnsupportedOperationException(myFhirVersion + " not supported");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private String getStringExtensionValueOrNullDstu3(String theUrl) {
|
|
||||||
List<org.hl7.fhir.dstu3.model.Extension> targetTypes = getDstu3().getExtensionsByUrl(theUrl);
|
|
||||||
if (targetTypes.size() < 1) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
org.hl7.fhir.dstu3.model.StringType targetType = (org.hl7.fhir.dstu3.model.StringType) targetTypes.get(0).getValue();
|
|
||||||
return targetType.getValue();
|
|
||||||
}
|
|
||||||
|
|
||||||
private String getStringExtensionValueOrNullR4(String theUrl) {
|
|
||||||
List<org.hl7.fhir.r4.model.Extension> targetTypes = getR4().getExtensionsByUrl(theUrl);
|
|
||||||
if (targetTypes.size() < 1) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
org.hl7.fhir.r4.model.StringType targetType = (org.hl7.fhir.r4.model.StringType) targetTypes.get(0).getValue();
|
|
||||||
return targetType.getValue();
|
|
||||||
}
|
|
||||||
|
|
||||||
private String getStringExtensionValueOrNullR5(String theUrl) {
|
|
||||||
List<org.hl7.fhir.r5.model.Extension> targetTypes = getR5().getExtensionsByUrl(theUrl);
|
|
||||||
if (targetTypes.size() < 1) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
org.hl7.fhir.r5.model.StringType targetType = (org.hl7.fhir.r5.model.StringType) targetTypes.get(0).getValue();
|
|
||||||
return targetType.getValue();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void addReference(IBaseReference theReference) {
|
|
||||||
switch (myFhirVersion) {
|
|
||||||
case DSTU3:
|
|
||||||
getDstu3().addEntry().setItem((org.hl7.fhir.dstu3.model.Reference) theReference);
|
|
||||||
break;
|
|
||||||
case R4:
|
|
||||||
getR4().addEntry().setItem((org.hl7.fhir.r4.model.Reference) theReference);
|
|
||||||
break;
|
|
||||||
case R5:
|
|
||||||
getR5().addEntry().setItem((org.hl7.fhir.r5.model.Reference) theReference);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw new UnsupportedOperationException(myFhirVersion + " not supported");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void addReference(String theReferenceId) {
|
|
||||||
switch (myFhirVersion) {
|
|
||||||
case DSTU3:
|
|
||||||
getDstu3().addEntry().setItem(new org.hl7.fhir.dstu3.model.Reference(theReferenceId));
|
|
||||||
break;
|
|
||||||
case R4:
|
|
||||||
getR4().addEntry().setItem(new org.hl7.fhir.r4.model.Reference(theReferenceId));
|
|
||||||
break;
|
|
||||||
case R5:
|
|
||||||
getR5().addEntry().setItem(new org.hl7.fhir.r5.model.Reference(theReferenceId));
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw new UnsupportedOperationException(myFhirVersion + " not supported");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public Stream<String> getReferenceStream() {
|
|
||||||
switch (myFhirVersion) {
|
|
||||||
case DSTU3:
|
|
||||||
return getDstu3().getEntry().stream()
|
|
||||||
.map(entry -> entry.getItem().getReference())
|
|
||||||
.map(reference -> new org.hl7.fhir.dstu3.model.IdType(reference).toUnqualifiedVersionless().getValue());
|
|
||||||
case R4:
|
|
||||||
return getR4().getEntry().stream()
|
|
||||||
.map(entry -> entry.getItem().getReference())
|
|
||||||
.map(reference -> new org.hl7.fhir.r4.model.IdType(reference).toUnqualifiedVersionless().getValue());
|
|
||||||
case R5:
|
|
||||||
return getR5().getEntry().stream()
|
|
||||||
.map(entry -> entry.getItem().getReference())
|
|
||||||
.map(reference -> new org.hl7.fhir.r5.model.IdType(reference).toUnqualifiedVersionless().getValue());
|
|
||||||
default:
|
|
||||||
throw new UnsupportedOperationException(myFhirVersion + " not supported");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean removeItem(String theReferenceId) {
|
|
||||||
switch (myFhirVersion) {
|
|
||||||
case DSTU3:
|
|
||||||
return removeItemDstu3(theReferenceId);
|
|
||||||
case R4:
|
|
||||||
return removeItemR4(theReferenceId);
|
|
||||||
case R5:
|
|
||||||
return removeItemR5(theReferenceId);
|
|
||||||
default:
|
|
||||||
throw new UnsupportedOperationException(myFhirVersion + " not supported");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean removeItemDstu3(String theReferenceId) {
|
|
||||||
boolean removed = false;
|
|
||||||
for (org.hl7.fhir.dstu3.model.ListResource.ListEntryComponent entry : getDstu3().getEntry()) {
|
|
||||||
if (theReferenceId.equals(entry.getItem().getReference()) && !entry.getDeleted()) {
|
|
||||||
entry.setDeleted(true);
|
|
||||||
removed = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (removed) {
|
|
||||||
getDstu3().getEntry().removeIf(entry -> entry.getDeleted());
|
|
||||||
}
|
|
||||||
return removed;
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean removeItemR4(String theReferenceId) {
|
|
||||||
boolean removed = false;
|
|
||||||
for (org.hl7.fhir.r4.model.ListResource.ListEntryComponent entry : getR4().getEntry()) {
|
|
||||||
if (theReferenceId.equals(entry.getItem().getReference()) && !entry.getDeleted()) {
|
|
||||||
entry.setDeleted(true);
|
|
||||||
removed = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (removed) {
|
|
||||||
getR4().getEntry().removeIf(entry -> entry.getDeleted());
|
|
||||||
}
|
|
||||||
return removed;
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean removeItemR5(String theReferenceId) {
|
|
||||||
boolean removed = false;
|
|
||||||
for (org.hl7.fhir.r5.model.ListResource.ListResourceEntryComponent entry : getR5().getEntry()) {
|
|
||||||
if (theReferenceId.equals(entry.getItem().getReference()) && !entry.getDeleted()) {
|
|
||||||
entry.setDeleted(true);
|
|
||||||
removed = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (removed) {
|
|
||||||
getR5().getEntry().removeIf(entry -> entry.getDeleted());
|
|
||||||
}
|
|
||||||
return removed;
|
|
||||||
}
|
|
||||||
|
|
||||||
public TokenParam getCodeFirstRep() {
|
|
||||||
switch (myFhirVersion) {
|
|
||||||
case DSTU3:
|
|
||||||
org.hl7.fhir.dstu3.model.Coding codingDstu3 = getDstu3().getCode().getCodingFirstRep();
|
|
||||||
return new TokenParam(codingDstu3.getSystem(), codingDstu3.getCode());
|
|
||||||
case R4:
|
|
||||||
org.hl7.fhir.r4.model.Coding codingR4 = getR4().getCode().getCodingFirstRep();
|
|
||||||
return new TokenParam(codingR4.getSystem(), codingR4.getCode());
|
|
||||||
case R5:
|
|
||||||
org.hl7.fhir.r5.model.Coding codingR5 = getR5().getCode().getCodingFirstRep();
|
|
||||||
return new TokenParam(codingR5.getSystem(), codingR5.getCode());
|
|
||||||
default:
|
|
||||||
throw new UnsupportedOperationException(myFhirVersion + " not supported");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public TokenParam getIdentifierirstRep() {
|
|
||||||
switch (myFhirVersion) {
|
|
||||||
case DSTU3:
|
|
||||||
org.hl7.fhir.dstu3.model.Identifier identDstu3 = getDstu3().getIdentifierFirstRep();
|
|
||||||
return new TokenParam(identDstu3.getSystem(), identDstu3.getValue());
|
|
||||||
case R4:
|
|
||||||
org.hl7.fhir.r4.model.Identifier identR4 = getR4().getIdentifierFirstRep();
|
|
||||||
return new TokenParam(identR4.getSystem(), identR4.getValue());
|
|
||||||
case R5:
|
|
||||||
org.hl7.fhir.r5.model.Identifier identR5 = getR5().getIdentifierFirstRep();
|
|
||||||
return new TokenParam(identR5.getSystem(), identR5.getValue());
|
|
||||||
default:
|
|
||||||
throw new UnsupportedOperationException(myFhirVersion + " not supported");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public boolean isEmpty() {
|
|
||||||
switch (myFhirVersion) {
|
|
||||||
case DSTU3:
|
|
||||||
return getDstu3().getEntry().isEmpty();
|
|
||||||
case R4:
|
|
||||||
return getR4().getEntry().isEmpty();
|
|
||||||
case R5:
|
|
||||||
return getR5().getEntry().isEmpty();
|
|
||||||
default:
|
|
||||||
throw new UnsupportedOperationException(myFhirVersion + " not supported");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,451 +0,0 @@
|
||||||
package ca.uhn.fhir.jpa.model.any;
|
|
||||||
|
|
||||||
/*-
|
|
||||||
* #%L
|
|
||||||
* HAPI FHIR Model
|
|
||||||
* %%
|
|
||||||
* Copyright (C) 2014 - 2020 University Health Network
|
|
||||||
* %%
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
* #L%
|
|
||||||
*/
|
|
||||||
|
|
||||||
import ca.uhn.fhir.context.FhirContext;
|
|
||||||
import ca.uhn.fhir.context.FhirVersionEnum;
|
|
||||||
import ca.uhn.fhir.rest.param.TokenParam;
|
|
||||||
import org.apache.commons.lang3.Validate;
|
|
||||||
import org.hl7.fhir.instance.model.api.IBaseReference;
|
|
||||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Date;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public class AnyMeasure {
|
|
||||||
private final FhirVersionEnum myFhirVersion;
|
|
||||||
private final IBaseResource myMeasure;
|
|
||||||
|
|
||||||
public static AnyMeasure fromFhirContext(FhirContext theFhirContext) {
|
|
||||||
FhirVersionEnum version = theFhirContext.getVersion().getVersion();
|
|
||||||
switch (version) {
|
|
||||||
case DSTU3:
|
|
||||||
return new AnyMeasure(new org.hl7.fhir.dstu3.model.Measure());
|
|
||||||
case R4:
|
|
||||||
return new AnyMeasure(new org.hl7.fhir.r4.model.Measure());
|
|
||||||
default:
|
|
||||||
throw new UnsupportedOperationException(version + " not supported");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public AnyMeasure(org.hl7.fhir.dstu3.model.Measure theMeasureR3) {
|
|
||||||
myFhirVersion = FhirVersionEnum.DSTU3;
|
|
||||||
myMeasure = theMeasureR3;
|
|
||||||
}
|
|
||||||
|
|
||||||
public AnyMeasure(org.hl7.fhir.r4.model.Measure theMeasureR4) {
|
|
||||||
myFhirVersion = FhirVersionEnum.R4;
|
|
||||||
myMeasure = theMeasureR4;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static AnyMeasure fromResource(IBaseResource theMeasure) {
|
|
||||||
if (theMeasure instanceof org.hl7.fhir.dstu3.model.Measure) {
|
|
||||||
return new AnyMeasure((org.hl7.fhir.dstu3.model.Measure) theMeasure);
|
|
||||||
} else if (theMeasure instanceof org.hl7.fhir.r4.model.Measure) {
|
|
||||||
return new AnyMeasure((org.hl7.fhir.r4.model.Measure) theMeasure);
|
|
||||||
} else {
|
|
||||||
throw new UnsupportedOperationException("Cannot convert " + theMeasure.getClass().getName() + " to AnyList");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public IBaseResource get() {
|
|
||||||
return myMeasure;
|
|
||||||
}
|
|
||||||
|
|
||||||
public org.hl7.fhir.dstu3.model.Measure getDstu3() {
|
|
||||||
Validate.isTrue(myFhirVersion == FhirVersionEnum.DSTU3);
|
|
||||||
return (org.hl7.fhir.dstu3.model.Measure) get();
|
|
||||||
}
|
|
||||||
|
|
||||||
public org.hl7.fhir.r4.model.Measure getR4() {
|
|
||||||
Validate.isTrue(myFhirVersion == FhirVersionEnum.R4);
|
|
||||||
return (org.hl7.fhir.r4.model.Measure) get();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void addIdentifier(String theSystem, String theValue) {
|
|
||||||
switch (myFhirVersion) {
|
|
||||||
case DSTU3:
|
|
||||||
getDstu3().getIdentifier().add(new org.hl7.fhir.dstu3.model.Identifier().setSystem(theSystem).setValue(theValue));
|
|
||||||
break;
|
|
||||||
case R4:
|
|
||||||
getR4().getIdentifier().add(new org.hl7.fhir.r4.model.Identifier().setSystem(theSystem).setValue(theValue));
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw new UnsupportedOperationException(myFhirVersion + " not supported");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void addType(String theSystem, String theCode) {
|
|
||||||
switch (myFhirVersion) {
|
|
||||||
case DSTU3:
|
|
||||||
org.hl7.fhir.dstu3.model.CodeableConcept codeableConcept = new org.hl7.fhir.dstu3.model.CodeableConcept();
|
|
||||||
codeableConcept.addCoding().setSystem(theSystem).setCode(theCode);
|
|
||||||
getDstu3().getType().add(codeableConcept);
|
|
||||||
break;
|
|
||||||
case R4:
|
|
||||||
org.hl7.fhir.r4.model.CodeableConcept codeableConceptR4 = new org.hl7.fhir.r4.model.CodeableConcept();
|
|
||||||
codeableConceptR4.addCoding().setSystem(theSystem).setCode(theCode);
|
|
||||||
getR4().getType().add(codeableConceptR4);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw new UnsupportedOperationException(myFhirVersion + " not supported");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void addStringExtension(String theUrl, String theValue) {
|
|
||||||
switch (myFhirVersion) {
|
|
||||||
case DSTU3:
|
|
||||||
getDstu3().addExtension().setUrl(theUrl).setValue(new org.hl7.fhir.dstu3.model.StringType(theValue));
|
|
||||||
break;
|
|
||||||
case R4:
|
|
||||||
getR4().addExtension().setUrl(theUrl).setValue(new org.hl7.fhir.r4.model.StringType(theValue));
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw new UnsupportedOperationException(myFhirVersion + " not supported");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getStringExtensionValueOrNull(String theUrl) {
|
|
||||||
switch (myFhirVersion) {
|
|
||||||
case DSTU3:
|
|
||||||
return getStringExtensionValueOrNullDstu3(theUrl);
|
|
||||||
case R4:
|
|
||||||
return getStringExtensionValueOrNullR4(theUrl);
|
|
||||||
default:
|
|
||||||
throw new UnsupportedOperationException(myFhirVersion + " not supported");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private String getStringExtensionValueOrNullDstu3(String theUrl) {
|
|
||||||
List<org.hl7.fhir.dstu3.model.Extension> targetTypes = getDstu3().getExtensionsByUrl(theUrl);
|
|
||||||
if (targetTypes.size() < 1) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
org.hl7.fhir.dstu3.model.StringType targetType = (org.hl7.fhir.dstu3.model.StringType) targetTypes.get(0).getValue();
|
|
||||||
return targetType.getValue();
|
|
||||||
}
|
|
||||||
|
|
||||||
private String getStringExtensionValueOrNullR4(String theUrl) {
|
|
||||||
List<org.hl7.fhir.r4.model.Extension> targetTypes = getR4().getExtensionsByUrl(theUrl);
|
|
||||||
if (targetTypes.size() < 1) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
org.hl7.fhir.r4.model.StringType targetType = (org.hl7.fhir.r4.model.StringType) targetTypes.get(0).getValue();
|
|
||||||
return targetType.getValue();
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getIdentifierFirstRep() {
|
|
||||||
switch (myFhirVersion) {
|
|
||||||
case DSTU3:
|
|
||||||
return getDstu3().getIdentifierFirstRep().getValue();
|
|
||||||
case R4:
|
|
||||||
return getR4().getIdentifierFirstRep().getValue();
|
|
||||||
default:
|
|
||||||
throw new UnsupportedOperationException(myFhirVersion + " not supported");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setComposedOf(String theReferenceId) {
|
|
||||||
switch (myFhirVersion) {
|
|
||||||
case DSTU3:
|
|
||||||
getRelatedArtifactDstu3(theReferenceId, org.hl7.fhir.dstu3.model.RelatedArtifact.RelatedArtifactType.COMPOSEDOF);
|
|
||||||
break;
|
|
||||||
case R4:
|
|
||||||
getRelatedArtifactR4(theReferenceId, org.hl7.fhir.r4.model.RelatedArtifact.RelatedArtifactType.COMPOSEDOF);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw new UnsupportedOperationException(myFhirVersion + " not supported");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void getRelatedArtifactDstu3(String theReferenceId, org.hl7.fhir.dstu3.model.RelatedArtifact.RelatedArtifactType theArtifactType) {
|
|
||||||
org.hl7.fhir.dstu3.model.RelatedArtifact artifact = new org.hl7.fhir.dstu3.model.RelatedArtifact();
|
|
||||||
artifact.setType(theArtifactType);
|
|
||||||
artifact.setResource(new org.hl7.fhir.dstu3.model.Reference(theReferenceId));
|
|
||||||
getDstu3().getRelatedArtifact().add(artifact);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void getRelatedArtifactR4(String theReferenceId, org.hl7.fhir.r4.model.RelatedArtifact.RelatedArtifactType theArtifactType) {
|
|
||||||
org.hl7.fhir.r4.model.RelatedArtifact artifact = new org.hl7.fhir.r4.model.RelatedArtifact();
|
|
||||||
artifact.setType(theArtifactType);
|
|
||||||
artifact.setResource(theReferenceId);
|
|
||||||
getR4().getRelatedArtifact().add(artifact);
|
|
||||||
}
|
|
||||||
|
|
||||||
public IBaseReference getComposedOf() {
|
|
||||||
switch (myFhirVersion) {
|
|
||||||
case DSTU3:
|
|
||||||
return getArtifactOfTypeDstu3(getDstu3(), org.hl7.fhir.dstu3.model.RelatedArtifact.RelatedArtifactType.COMPOSEDOF);
|
|
||||||
case R4:
|
|
||||||
return getArtifactOfTypeR4(getR4(), org.hl7.fhir.r4.model.RelatedArtifact.RelatedArtifactType.COMPOSEDOF);
|
|
||||||
default:
|
|
||||||
throw new UnsupportedOperationException(myFhirVersion + " not supported");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setPredecessor(String theReferenceId) {
|
|
||||||
switch (myFhirVersion) {
|
|
||||||
case DSTU3:
|
|
||||||
getRelatedArtifactDstu3(theReferenceId, org.hl7.fhir.dstu3.model.RelatedArtifact.RelatedArtifactType.PREDECESSOR);
|
|
||||||
break;
|
|
||||||
case R4:
|
|
||||||
getRelatedArtifactR4(theReferenceId, org.hl7.fhir.r4.model.RelatedArtifact.RelatedArtifactType.PREDECESSOR);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw new UnsupportedOperationException(myFhirVersion + " not supported");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public IBaseReference getPredecessor() {
|
|
||||||
switch (myFhirVersion) {
|
|
||||||
case DSTU3:
|
|
||||||
return getArtifactOfTypeDstu3(getDstu3(), org.hl7.fhir.dstu3.model.RelatedArtifact.RelatedArtifactType.PREDECESSOR);
|
|
||||||
case R4:
|
|
||||||
return getArtifactOfTypeR4(getR4(), org.hl7.fhir.r4.model.RelatedArtifact.RelatedArtifactType.PREDECESSOR);
|
|
||||||
default:
|
|
||||||
throw new UnsupportedOperationException(myFhirVersion + " not supported");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public IBaseReference getDerivedFrom() {
|
|
||||||
switch (myFhirVersion) {
|
|
||||||
case DSTU3:
|
|
||||||
return getArtifactOfTypeDstu3(getDstu3(), org.hl7.fhir.dstu3.model.RelatedArtifact.RelatedArtifactType.DERIVEDFROM);
|
|
||||||
case R4:
|
|
||||||
return getArtifactOfTypeR4(getR4(), org.hl7.fhir.r4.model.RelatedArtifact.RelatedArtifactType.DERIVEDFROM);
|
|
||||||
default:
|
|
||||||
throw new UnsupportedOperationException(myFhirVersion + " not supported");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setDerivedFrom(String theReferenceId) {
|
|
||||||
switch (myFhirVersion) {
|
|
||||||
case DSTU3:
|
|
||||||
getRelatedArtifactDstu3(theReferenceId, org.hl7.fhir.dstu3.model.RelatedArtifact.RelatedArtifactType.DERIVEDFROM);
|
|
||||||
break;
|
|
||||||
case R4:
|
|
||||||
getRelatedArtifactR4(theReferenceId, org.hl7.fhir.r4.model.RelatedArtifact.RelatedArtifactType.DERIVEDFROM);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw new UnsupportedOperationException(myFhirVersion + " not supported");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public IBaseReference getSuccessor() {
|
|
||||||
switch (myFhirVersion) {
|
|
||||||
case DSTU3:
|
|
||||||
return getArtifactOfTypeDstu3(getDstu3(), org.hl7.fhir.dstu3.model.RelatedArtifact.RelatedArtifactType.SUCCESSOR);
|
|
||||||
case R4:
|
|
||||||
return getArtifactOfTypeR4(getR4(), org.hl7.fhir.r4.model.RelatedArtifact.RelatedArtifactType.SUCCESSOR);
|
|
||||||
default:
|
|
||||||
throw new UnsupportedOperationException(myFhirVersion + " not supported");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setSuccessor(String theReferenceId) {
|
|
||||||
switch (myFhirVersion) {
|
|
||||||
case DSTU3:
|
|
||||||
getRelatedArtifactDstu3(theReferenceId, org.hl7.fhir.dstu3.model.RelatedArtifact.RelatedArtifactType.SUCCESSOR);
|
|
||||||
break;
|
|
||||||
case R4:
|
|
||||||
getRelatedArtifactR4(theReferenceId, org.hl7.fhir.r4.model.RelatedArtifact.RelatedArtifactType.SUCCESSOR);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw new UnsupportedOperationException(myFhirVersion + " not supported");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private IBaseReference getArtifactOfTypeDstu3(org.hl7.fhir.dstu3.model.Measure theMeasure, org.hl7.fhir.dstu3.model.RelatedArtifact.RelatedArtifactType theType) {
|
|
||||||
return theMeasure.getRelatedArtifact()
|
|
||||||
.stream()
|
|
||||||
.filter(artifact -> theType == artifact.getType())
|
|
||||||
.map(org.hl7.fhir.dstu3.model.RelatedArtifact::getResource)
|
|
||||||
.findFirst()
|
|
||||||
.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
private IBaseReference getArtifactOfTypeR4(org.hl7.fhir.r4.model.Measure theMeasure, org.hl7.fhir.r4.model.RelatedArtifact.RelatedArtifactType theType) {
|
|
||||||
return new org.hl7.fhir.r4.model.Reference(theMeasure.getRelatedArtifact()
|
|
||||||
.stream()
|
|
||||||
.filter(artifact -> theType == artifact.getType())
|
|
||||||
.map(org.hl7.fhir.r4.model.RelatedArtifact::getResource)
|
|
||||||
.findFirst()
|
|
||||||
.get());
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setPublisher(String thePublisher) {
|
|
||||||
switch (myFhirVersion) {
|
|
||||||
case DSTU3:
|
|
||||||
getDstu3().setPublisher(thePublisher);
|
|
||||||
break;
|
|
||||||
case R4:
|
|
||||||
getR4().setPublisher(thePublisher);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw new UnsupportedOperationException(myFhirVersion + " not supported");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getPublisher() {
|
|
||||||
switch (myFhirVersion) {
|
|
||||||
case DSTU3:
|
|
||||||
return getDstu3().getPublisher();
|
|
||||||
case R4:
|
|
||||||
return getR4().getPublisher();
|
|
||||||
default:
|
|
||||||
throw new UnsupportedOperationException(myFhirVersion + " not supported");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setName(String theName) {
|
|
||||||
switch (myFhirVersion) {
|
|
||||||
case DSTU3:
|
|
||||||
getDstu3().setName(theName);
|
|
||||||
break;
|
|
||||||
case R4:
|
|
||||||
getR4().setName(theName);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw new UnsupportedOperationException(myFhirVersion + " not supported");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getName() {
|
|
||||||
switch (myFhirVersion) {
|
|
||||||
case DSTU3:
|
|
||||||
return getDstu3().getName();
|
|
||||||
case R4:
|
|
||||||
return getR4().getName();
|
|
||||||
default:
|
|
||||||
throw new UnsupportedOperationException(myFhirVersion + " not supported");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setEffectivePeriod(Date start, Date end) {
|
|
||||||
switch (myFhirVersion) {
|
|
||||||
case DSTU3:
|
|
||||||
org.hl7.fhir.dstu3.model.Period effectivePeriod = new org.hl7.fhir.dstu3.model.Period();
|
|
||||||
effectivePeriod.setStart(start);
|
|
||||||
effectivePeriod.setEnd(end);
|
|
||||||
getDstu3().setEffectivePeriod(effectivePeriod);
|
|
||||||
break;
|
|
||||||
case R4:
|
|
||||||
org.hl7.fhir.r4.model.Period effectivePeriodr4 = new org.hl7.fhir.r4.model.Period();
|
|
||||||
effectivePeriodr4.setStart(start);
|
|
||||||
effectivePeriodr4.setEnd(end);
|
|
||||||
getR4().setEffectivePeriod(effectivePeriodr4);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw new UnsupportedOperationException(myFhirVersion + " not supported");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public Date getEffectivePeriodStart() {
|
|
||||||
switch (myFhirVersion) {
|
|
||||||
case DSTU3:
|
|
||||||
return getDstu3().getEffectivePeriod().getStart();
|
|
||||||
case R4:
|
|
||||||
return getR4().getEffectivePeriod().getStart();
|
|
||||||
default:
|
|
||||||
throw new UnsupportedOperationException(myFhirVersion + " not supported");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public Date getEffectivePeriodEnd() {
|
|
||||||
switch (myFhirVersion) {
|
|
||||||
case DSTU3:
|
|
||||||
return getDstu3().getEffectivePeriod().getEnd();
|
|
||||||
case R4:
|
|
||||||
return getR4().getEffectivePeriod().getEnd();
|
|
||||||
default:
|
|
||||||
throw new UnsupportedOperationException(myFhirVersion + " not supported");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setTopics(List<TokenParam> theTokenParamList) {
|
|
||||||
switch (myFhirVersion) {
|
|
||||||
case DSTU3:
|
|
||||||
setTopicsDstu3(theTokenParamList);
|
|
||||||
break;
|
|
||||||
case R4:
|
|
||||||
setTopicsR4(theTokenParamList);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw new UnsupportedOperationException(myFhirVersion + " not supported");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setTopicsDstu3(List<TokenParam> theTokenParamList) {
|
|
||||||
List<org.hl7.fhir.dstu3.model.CodeableConcept> topicList = new ArrayList<>();
|
|
||||||
|
|
||||||
for (TokenParam tokenParam : theTokenParamList) {
|
|
||||||
org.hl7.fhir.dstu3.model.CodeableConcept codeableConcept = new org.hl7.fhir.dstu3.model.CodeableConcept();
|
|
||||||
codeableConcept.addCoding().setSystem(tokenParam.getSystem()).setCode(tokenParam.getValue());
|
|
||||||
topicList.add(codeableConcept);
|
|
||||||
}
|
|
||||||
getDstu3().setTopic(topicList);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setTopicsR4(List<TokenParam> theTokenParamList) {
|
|
||||||
List<org.hl7.fhir.r4.model.CodeableConcept> topicList = new ArrayList<>();
|
|
||||||
|
|
||||||
for (TokenParam tokenParam : theTokenParamList) {
|
|
||||||
org.hl7.fhir.r4.model.CodeableConcept codeableConcept = new org.hl7.fhir.r4.model.CodeableConcept();
|
|
||||||
codeableConcept.addCoding().setSystem(tokenParam.getSystem()).setCode(tokenParam.getValue());
|
|
||||||
topicList.add(codeableConcept);
|
|
||||||
}
|
|
||||||
getR4().setTopic(topicList);
|
|
||||||
}
|
|
||||||
|
|
||||||
public TokenParam getTopicFirstRep() {
|
|
||||||
switch (myFhirVersion) {
|
|
||||||
case DSTU3:
|
|
||||||
org.hl7.fhir.dstu3.model.Coding codingDstu3 = getDstu3().getTopicFirstRep().getCodingFirstRep();
|
|
||||||
return new TokenParam(codingDstu3.getSystem(), codingDstu3.getCode());
|
|
||||||
case R4:
|
|
||||||
org.hl7.fhir.r4.model.Coding codingR4 = getR4().getTopicFirstRep().getCodingFirstRep();
|
|
||||||
return new TokenParam(codingR4.getSystem(), codingR4.getCode());
|
|
||||||
default:
|
|
||||||
throw new UnsupportedOperationException(myFhirVersion + " not supported");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public TokenParam getTopicSecondRepOrNull() {
|
|
||||||
switch (myFhirVersion) {
|
|
||||||
case DSTU3:
|
|
||||||
if (getDstu3().getTopic().size() < 2) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
org.hl7.fhir.dstu3.model.Coding codingDstu3 = getDstu3().getTopic().get(1).getCodingFirstRep();
|
|
||||||
return new TokenParam(codingDstu3.getSystem(), codingDstu3.getCode());
|
|
||||||
case R4:
|
|
||||||
if (getR4().getTopic().size() < 2) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
org.hl7.fhir.r4.model.Coding codingR4 = getR4().getTopic().get(1).getCodingFirstRep();
|
|
||||||
return new TokenParam(codingR4.getSystem(), codingR4.getCode());
|
|
||||||
default:
|
|
||||||
throw new UnsupportedOperationException(myFhirVersion + " not supported");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,31 @@
|
||||||
|
package ca.uhn.fhir.jpa.model.cross;
|
||||||
|
|
||||||
|
/*-
|
||||||
|
* #%L
|
||||||
|
* HAPI FHIR Model
|
||||||
|
* %%
|
||||||
|
* Copyright (C) 2014 - 2020 University Health Network
|
||||||
|
* %%
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
* #L%
|
||||||
|
*/
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
public interface IResourceLookup {
|
||||||
|
String getResourceType();
|
||||||
|
|
||||||
|
Long getResourceId();
|
||||||
|
|
||||||
|
Date getDeleted();
|
||||||
|
}
|
|
@ -0,0 +1,50 @@
|
||||||
|
package ca.uhn.fhir.jpa.model.cross;
|
||||||
|
|
||||||
|
/*-
|
||||||
|
* #%L
|
||||||
|
* HAPI FHIR Model
|
||||||
|
* %%
|
||||||
|
* Copyright (C) 2014 - 2020 University Health Network
|
||||||
|
* %%
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
* #L%
|
||||||
|
*/
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
public class ResourceLookup implements IResourceLookup {
|
||||||
|
private final String myResourceType;
|
||||||
|
private final Long myResourcePid;
|
||||||
|
private final Date myDeletedAt;
|
||||||
|
|
||||||
|
public ResourceLookup(String theResourceType, Long theResourcePid, Date theDeletedAt) {
|
||||||
|
myResourceType = theResourceType;
|
||||||
|
myResourcePid = theResourcePid;
|
||||||
|
myDeletedAt = theDeletedAt;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getResourceType() {
|
||||||
|
return myResourceType;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Long getResourceId() {
|
||||||
|
return myResourcePid;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Date getDeleted() {
|
||||||
|
return myDeletedAt;
|
||||||
|
}
|
||||||
|
}
|
|
@ -25,6 +25,7 @@ import ca.uhn.fhir.util.ObjectUtil;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class is an abstraction for however primary keys are stored in the underlying storage engine. This might be
|
* This class is an abstraction for however primary keys are stored in the underlying storage engine. This might be
|
||||||
|
@ -35,6 +36,7 @@ public class ResourcePersistentId {
|
||||||
private Object myId;
|
private Object myId;
|
||||||
|
|
||||||
public ResourcePersistentId(Object theId) {
|
public ResourcePersistentId(Object theId) {
|
||||||
|
assert !(theId instanceof Optional);
|
||||||
myId = theId;
|
myId = theId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -60,30 +60,40 @@ public class ResourceLink extends BaseResourceIndex {
|
||||||
private String mySourceResourceType;
|
private String mySourceResourceType;
|
||||||
|
|
||||||
@ManyToOne(optional = true, fetch = FetchType.LAZY)
|
@ManyToOne(optional = true, fetch = FetchType.LAZY)
|
||||||
@JoinColumn(name = "TARGET_RESOURCE_ID", referencedColumnName = "RES_ID", nullable = true, foreignKey = @ForeignKey(name = "FK_RESLINK_TARGET"))
|
@JoinColumn(name = "TARGET_RESOURCE_ID", referencedColumnName = "RES_ID", nullable = true, insertable = false, updatable = false, foreignKey = @ForeignKey(name = "FK_RESLINK_TARGET"))
|
||||||
private ResourceTable myTargetResource;
|
private ResourceTable myTargetResource;
|
||||||
|
|
||||||
@Column(name = "TARGET_RESOURCE_ID", insertable = false, updatable = false, nullable = true)
|
@Column(name = "TARGET_RESOURCE_ID", insertable = true, updatable = true, nullable = true)
|
||||||
@Field()
|
@Field()
|
||||||
private Long myTargetResourcePid;
|
private Long myTargetResourcePid;
|
||||||
|
|
||||||
@Column(name = "TARGET_RESOURCE_TYPE", nullable = false, length = ResourceTable.RESTYPE_LEN)
|
@Column(name = "TARGET_RESOURCE_TYPE", nullable = false, length = ResourceTable.RESTYPE_LEN)
|
||||||
@Field()
|
@Field()
|
||||||
private String myTargetResourceType;
|
private String myTargetResourceType;
|
||||||
|
|
||||||
@Column(name = "TARGET_RESOURCE_URL", length = 200, nullable = true)
|
@Column(name = "TARGET_RESOURCE_URL", length = 200, nullable = true)
|
||||||
@Field()
|
@Field()
|
||||||
private String myTargetResourceUrl;
|
private String myTargetResourceUrl;
|
||||||
|
|
||||||
@Field()
|
@Field()
|
||||||
@Column(name = "SP_UPDATED", nullable = true) // TODO: make this false after HAPI 2.3
|
@Column(name = "SP_UPDATED", nullable = true) // TODO: make this false after HAPI 2.3
|
||||||
@Temporal(TemporalType.TIMESTAMP)
|
@Temporal(TemporalType.TIMESTAMP)
|
||||||
private Date myUpdated;
|
private Date myUpdated;
|
||||||
|
@Transient
|
||||||
|
private transient String myTargetResourceId;
|
||||||
|
|
||||||
public ResourceLink() {
|
public ResourceLink() {
|
||||||
super();
|
super();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getTargetResourceId() {
|
||||||
|
if (myTargetResourceId == null && myTargetResource != null) {
|
||||||
|
myTargetResourceId = getTargetResource().getIdDt().getIdPart();
|
||||||
|
}
|
||||||
|
return myTargetResourceId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getTargetResourceType() {
|
||||||
|
return myTargetResourceType;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object theObj) {
|
public boolean equals(Object theObj) {
|
||||||
if (this == theObj) {
|
if (this == theObj) {
|
||||||
|
@ -99,8 +109,9 @@ public class ResourceLink extends BaseResourceIndex {
|
||||||
EqualsBuilder b = new EqualsBuilder();
|
EqualsBuilder b = new EqualsBuilder();
|
||||||
b.append(mySourcePath, obj.mySourcePath);
|
b.append(mySourcePath, obj.mySourcePath);
|
||||||
b.append(mySourceResource, obj.mySourceResource);
|
b.append(mySourceResource, obj.mySourceResource);
|
||||||
b.append(myTargetResourcePid, obj.myTargetResourcePid);
|
|
||||||
b.append(myTargetResourceUrl, obj.myTargetResourceUrl);
|
b.append(myTargetResourceUrl, obj.myTargetResourceUrl);
|
||||||
|
b.append(myTargetResourceType, obj.myTargetResourceType);
|
||||||
|
b.append(getTargetResourceId(), obj.getTargetResourceId());
|
||||||
return b.isEquals();
|
return b.isEquals();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -122,15 +133,12 @@ public class ResourceLink extends BaseResourceIndex {
|
||||||
mySourceResourceType = theSourceResource.getResourceType();
|
mySourceResourceType = theSourceResource.getResourceType();
|
||||||
}
|
}
|
||||||
|
|
||||||
public ResourceTable getTargetResource() {
|
public void setTargetResource(String theResourceType, Long theResourcePid, String theTargetResourceId) {
|
||||||
return myTargetResource;
|
Validate.notBlank(theResourceType);
|
||||||
}
|
|
||||||
|
|
||||||
public void setTargetResource(ResourceTable theTargetResource) {
|
myTargetResourceType = theResourceType;
|
||||||
Validate.notNull(theTargetResource);
|
myTargetResourcePid = theResourcePid;
|
||||||
myTargetResource = theTargetResource;
|
myTargetResourceId = theTargetResourceId;
|
||||||
myTargetResourcePid = theTargetResource.getId();
|
|
||||||
myTargetResourceType = theTargetResource.getResourceType();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Long getTargetResourcePid() {
|
public Long getTargetResourcePid() {
|
||||||
|
@ -189,8 +197,9 @@ public class ResourceLink extends BaseResourceIndex {
|
||||||
HashCodeBuilder b = new HashCodeBuilder();
|
HashCodeBuilder b = new HashCodeBuilder();
|
||||||
b.append(mySourcePath);
|
b.append(mySourcePath);
|
||||||
b.append(mySourceResource);
|
b.append(mySourceResource);
|
||||||
b.append(myTargetResourcePid);
|
|
||||||
b.append(myTargetResourceUrl);
|
b.append(myTargetResourceUrl);
|
||||||
|
b.append(getTargetResourceType());
|
||||||
|
b.append(getTargetResourceId());
|
||||||
return b.toHashCode();
|
return b.toHashCode();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -207,6 +216,10 @@ public class ResourceLink extends BaseResourceIndex {
|
||||||
return b.toString();
|
return b.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ResourceTable getTargetResource() {
|
||||||
|
return myTargetResource;
|
||||||
|
}
|
||||||
|
|
||||||
public static ResourceLink forAbsoluteReference(String theSourcePath, ResourceTable theSourceResource, IIdType theTargetResourceUrl, Date theUpdated) {
|
public static ResourceLink forAbsoluteReference(String theSourcePath, ResourceTable theSourceResource, IIdType theTargetResourceUrl, Date theUpdated) {
|
||||||
ResourceLink retVal = new ResourceLink();
|
ResourceLink retVal = new ResourceLink();
|
||||||
retVal.setSourcePath(theSourcePath);
|
retVal.setSourcePath(theSourcePath);
|
||||||
|
@ -228,11 +241,11 @@ public class ResourceLink extends BaseResourceIndex {
|
||||||
return retVal;
|
return retVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ResourceLink forLocalReference(String theSourcePath, ResourceTable theSourceResource, ResourceTable theTargetResource, Date theUpdated) {
|
public static ResourceLink forLocalReference(String theSourcePath, ResourceTable theSourceResource, String theTargetResourceType, Long theTargetResourcePid, String theTargetResourceId, Date theUpdated) {
|
||||||
ResourceLink retVal = new ResourceLink();
|
ResourceLink retVal = new ResourceLink();
|
||||||
retVal.setSourcePath(theSourcePath);
|
retVal.setSourcePath(theSourcePath);
|
||||||
retVal.setSourceResource(theSourceResource);
|
retVal.setSourceResource(theSourceResource);
|
||||||
retVal.setTargetResource(theTargetResource);
|
retVal.setTargetResource(theTargetResourceType, theTargetResourcePid, theTargetResourceId);
|
||||||
retVal.setUpdated(theUpdated);
|
retVal.setUpdated(theUpdated);
|
||||||
return retVal;
|
return retVal;
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,6 +21,7 @@ package ca.uhn.fhir.jpa.model.entity;
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import ca.uhn.fhir.jpa.model.cross.IBasePersistedResource;
|
import ca.uhn.fhir.jpa.model.cross.IBasePersistedResource;
|
||||||
|
import ca.uhn.fhir.jpa.model.cross.IResourceLookup;
|
||||||
import ca.uhn.fhir.jpa.model.cross.ResourcePersistentId;
|
import ca.uhn.fhir.jpa.model.cross.ResourcePersistentId;
|
||||||
import ca.uhn.fhir.jpa.model.search.IndexNonDeletedInterceptor;
|
import ca.uhn.fhir.jpa.model.search.IndexNonDeletedInterceptor;
|
||||||
import ca.uhn.fhir.model.primitive.IdDt;
|
import ca.uhn.fhir.model.primitive.IdDt;
|
||||||
|
@ -29,12 +30,20 @@ import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
|
||||||
import org.apache.commons.lang3.builder.ToStringBuilder;
|
import org.apache.commons.lang3.builder.ToStringBuilder;
|
||||||
import org.apache.commons.lang3.builder.ToStringStyle;
|
import org.apache.commons.lang3.builder.ToStringStyle;
|
||||||
import org.hibernate.annotations.OptimisticLock;
|
import org.hibernate.annotations.OptimisticLock;
|
||||||
import org.hibernate.search.annotations.*;
|
import org.hibernate.search.annotations.Analyze;
|
||||||
|
import org.hibernate.search.annotations.Analyzer;
|
||||||
|
import org.hibernate.search.annotations.Field;
|
||||||
|
import org.hibernate.search.annotations.Fields;
|
||||||
|
import org.hibernate.search.annotations.Indexed;
|
||||||
|
import org.hibernate.search.annotations.Store;
|
||||||
|
|
||||||
import javax.persistence.Index;
|
|
||||||
import javax.persistence.*;
|
import javax.persistence.*;
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.util.*;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.Set;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import static org.apache.commons.lang3.StringUtils.defaultString;
|
import static org.apache.commons.lang3.StringUtils.defaultString;
|
||||||
|
@ -48,7 +57,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")
|
||||||
})
|
})
|
||||||
public class ResourceTable extends BaseHasResource implements Serializable, IBasePersistedResource {
|
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;
|
||||||
private static final int MAX_PROFILE_LENGTH = 200;
|
private static final int MAX_PROFILE_LENGTH = 200;
|
||||||
|
@ -626,7 +635,7 @@ public class ResourceTable extends BaseHasResource implements Serializable, IBas
|
||||||
@Override
|
@Override
|
||||||
public IdDt getIdDt() {
|
public IdDt getIdDt() {
|
||||||
if (getForcedId() == null) {
|
if (getForcedId() == null) {
|
||||||
Long id = 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
|
// Avoid a join query if possible
|
||||||
|
|
|
@ -1,24 +0,0 @@
|
||||||
package ca.uhn.fhir.jpa.model.any;
|
|
||||||
|
|
||||||
import org.hl7.fhir.r5.model.ListResource;
|
|
||||||
import org.junit.Test;
|
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
|
||||||
|
|
||||||
public class AnyListResourceTest {
|
|
||||||
@Test
|
|
||||||
public void getCodeFirstRep() {
|
|
||||||
AnyListResource listResource = AnyListResource.fromResource(new ListResource());
|
|
||||||
listResource.addCode("foo", "bar");
|
|
||||||
assertEquals("foo", listResource.getCodeFirstRep().getSystem());
|
|
||||||
assertEquals("bar", listResource.getCodeFirstRep().getValue());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void getIdentifierFirstRep() {
|
|
||||||
AnyListResource listResource = AnyListResource.fromResource(new ListResource());
|
|
||||||
listResource.addIdentifier("foo", "bar");
|
|
||||||
assertEquals("foo", listResource.getIdentifierirstRep().getSystem());
|
|
||||||
assertEquals("bar", listResource.getIdentifierirstRep().getValue());
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -21,14 +21,31 @@ package ca.uhn.fhir.jpa.searchparam.extractor;
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import ca.uhn.fhir.context.RuntimeSearchParam;
|
import ca.uhn.fhir.context.RuntimeSearchParam;
|
||||||
import ca.uhn.fhir.jpa.model.entity.ResourceTable;
|
import ca.uhn.fhir.jpa.model.cross.IResourceLookup;
|
||||||
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
||||||
import org.hl7.fhir.instance.model.api.IBaseReference;
|
import org.hl7.fhir.instance.model.api.IBaseReference;
|
||||||
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;
|
||||||
|
|
||||||
public interface IResourceLinkResolver {
|
public interface IResourceLinkResolver {
|
||||||
ResourceTable findTargetResource(RuntimeSearchParam theNextSpDef, String theNextPathsUnsplit, IIdType theNextId, String theTypeString, Class<? extends IBaseResource> theType, IBaseReference theReference, RequestDetails theRequest);
|
|
||||||
|
/**
|
||||||
|
* This method resolves the target of a reference found within a resource that is being created/updated. We do this
|
||||||
|
* so that we can create indexed links between resources, and so that we can validate that the target actually
|
||||||
|
* exists in cases where we need to check that.
|
||||||
|
* <p>
|
||||||
|
* This method returns an {@link IResourceLookup} so as to avoid needing to resolve the entire resource.
|
||||||
|
*
|
||||||
|
* @param theSearchParam The param that is being indexed
|
||||||
|
* @param theSourcePath The path within the resource where this reference was found
|
||||||
|
* @param theSourceResourceId The ID of the resource containing the reference to the target being resolved
|
||||||
|
* @param theTypeString The type of the resource being resolved
|
||||||
|
* @param theType The resource type of the target
|
||||||
|
* @param theReference The reference being resolved
|
||||||
|
* @param theRequest The incoming request, if any
|
||||||
|
*/
|
||||||
|
IResourceLookup findTargetResource(RuntimeSearchParam theSearchParam, String theSourcePath, IIdType theSourceResourceId, String theTypeString, Class<? extends IBaseResource> theType, IBaseReference theReference, RequestDetails theRequest);
|
||||||
|
|
||||||
void validateTypeOrThrowException(Class<? extends IBaseResource> theType);
|
void validateTypeOrThrowException(Class<? extends IBaseResource> theType);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,16 +23,17 @@ package ca.uhn.fhir.jpa.searchparam.extractor;
|
||||||
import ca.uhn.fhir.context.RuntimeSearchParam;
|
import ca.uhn.fhir.context.RuntimeSearchParam;
|
||||||
import ca.uhn.fhir.jpa.model.entity.*;
|
import ca.uhn.fhir.jpa.model.entity.*;
|
||||||
import ca.uhn.fhir.model.api.IQueryParameterType;
|
import ca.uhn.fhir.model.api.IQueryParameterType;
|
||||||
import ca.uhn.fhir.model.primitive.IdDt;
|
|
||||||
import ca.uhn.fhir.rest.api.RestSearchParameterTypeEnum;
|
import ca.uhn.fhir.rest.api.RestSearchParameterTypeEnum;
|
||||||
import ca.uhn.fhir.rest.param.ReferenceParam;
|
import ca.uhn.fhir.rest.param.ReferenceParam;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.springframework.context.annotation.DependsOn;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.Map.Entry;
|
import java.util.Map.Entry;
|
||||||
import java.util.function.Predicate;
|
import java.util.function.Predicate;
|
||||||
|
|
||||||
import static org.apache.commons.lang3.StringUtils.compare;
|
import static org.apache.commons.lang3.StringUtils.compare;
|
||||||
|
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||||
|
|
||||||
public final class ResourceIndexedSearchParams {
|
public final class ResourceIndexedSearchParams {
|
||||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ResourceIndexedSearchParams.class);
|
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ResourceIndexedSearchParams.class);
|
||||||
|
@ -217,7 +218,7 @@ public final class ResourceIndexedSearchParams {
|
||||||
return myPopulatedResourceLinkParameters;
|
return myPopulatedResourceLinkParameters;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean matchParam(String theResourceName, String theParamName, RuntimeSearchParam theParamDef, IQueryParameterType theParam) {
|
public boolean matchParam(ModelConfig theModelConfig, String theResourceName, String theParamName, RuntimeSearchParam theParamDef, IQueryParameterType theParam) {
|
||||||
if (theParamDef == null) {
|
if (theParamDef == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -242,7 +243,7 @@ public final class ResourceIndexedSearchParams {
|
||||||
resourceParams = myDateParams;
|
resourceParams = myDateParams;
|
||||||
break;
|
break;
|
||||||
case REFERENCE:
|
case REFERENCE:
|
||||||
return matchResourceLinks(theResourceName, theParamName, theParam, theParamDef.getPath());
|
return matchResourceLinks(theModelConfig, theResourceName, theParamName, theParam, theParamDef.getPath());
|
||||||
case COMPOSITE:
|
case COMPOSITE:
|
||||||
case HAS:
|
case HAS:
|
||||||
case SPECIAL:
|
case SPECIAL:
|
||||||
|
@ -259,39 +260,56 @@ public final class ResourceIndexedSearchParams {
|
||||||
return resourceParams.stream().anyMatch(namedParamPredicate);
|
return resourceParams.stream().anyMatch(namedParamPredicate);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated Replace with the method below
|
||||||
|
*/
|
||||||
// KHS This needs to be public as libraries outside of hapi call it directly
|
// KHS This needs to be public as libraries outside of hapi call it directly
|
||||||
|
@Deprecated
|
||||||
public boolean matchResourceLinks(String theResourceName, String theParamName, IQueryParameterType theParam, String theParamPath) {
|
public boolean matchResourceLinks(String theResourceName, String theParamName, IQueryParameterType theParam, String theParamPath) {
|
||||||
|
return matchResourceLinks(new ModelConfig(), theResourceName, theParamName, theParam, theParamPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
// KHS This needs to be public as libraries outside of hapi call it directly
|
||||||
|
public boolean matchResourceLinks(ModelConfig theModelConfig, String theResourceName, String theParamName, IQueryParameterType theParam, String theParamPath) {
|
||||||
ReferenceParam reference = (ReferenceParam)theParam;
|
ReferenceParam reference = (ReferenceParam)theParam;
|
||||||
|
|
||||||
Predicate<ResourceLink> namedParamPredicate = resourceLink ->
|
Predicate<ResourceLink> namedParamPredicate = resourceLink ->
|
||||||
resourceLinkMatches(theResourceName, resourceLink, theParamName, theParamPath)
|
searchParameterPathMatches(theResourceName, resourceLink, theParamName, theParamPath)
|
||||||
&& resourceIdMatches(resourceLink, reference);
|
&& resourceIdMatches(theModelConfig, resourceLink, reference);
|
||||||
|
|
||||||
return myLinks.stream().anyMatch(namedParamPredicate);
|
return myLinks.stream().anyMatch(namedParamPredicate);
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean resourceIdMatches(ResourceLink theResourceLink, ReferenceParam theReference) {
|
private boolean resourceIdMatches(ModelConfig theModelConfig, ResourceLink theResourceLink, ReferenceParam theReference) {
|
||||||
ResourceTable target = theResourceLink.getTargetResource();
|
String baseUrl = theReference.getBaseUrl();
|
||||||
IdDt idDt = target.getIdDt();
|
if (isNotBlank(baseUrl)) {
|
||||||
if (idDt.isIdPartValidLong()) {
|
if (!theModelConfig.getTreatBaseUrlsAsLocal().contains(baseUrl)) {
|
||||||
if (theReference.isIdPartValidLong()) {
|
|
||||||
return theReference.getIdPartAsLong().equals(idDt.getIdPartAsLong());
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
ForcedId forcedId = target.getForcedId();
|
|
||||||
if (forcedId != null) {
|
|
||||||
return forcedId.getForcedId().equals(theReference.getValue());
|
|
||||||
} else {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String targetType = theResourceLink.getTargetResourceType();
|
||||||
|
String targetId = theResourceLink.getTargetResourceId();
|
||||||
|
|
||||||
|
assert isNotBlank(targetType);
|
||||||
|
assert isNotBlank(targetId);
|
||||||
|
|
||||||
|
if (theReference.hasResourceType()) {
|
||||||
|
if (!theReference.getResourceType().equals(targetType)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!targetId.equals(theReference.getIdPart())) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean resourceLinkMatches(String theResourceName, ResourceLink theResourceLink, String theParamName, String theParamPath) {
|
private boolean searchParameterPathMatches(String theResourceName, ResourceLink theResourceLink, String theParamName, String theParamPath) {
|
||||||
return theResourceLink.getTargetResource().getResourceType().equalsIgnoreCase(theParamName) ||
|
String sourcePath = theResourceLink.getSourcePath();
|
||||||
theResourceLink.getSourcePath().equalsIgnoreCase(theParamPath);
|
return sourcePath.equalsIgnoreCase(theParamPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -24,6 +24,7 @@ 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 ca.uhn.fhir.interceptor.api.IInterceptorBroadcaster;
|
import ca.uhn.fhir.interceptor.api.IInterceptorBroadcaster;
|
||||||
|
import ca.uhn.fhir.jpa.model.cross.IResourceLookup;
|
||||||
import ca.uhn.fhir.jpa.model.entity.ModelConfig;
|
import ca.uhn.fhir.jpa.model.entity.ModelConfig;
|
||||||
import ca.uhn.fhir.jpa.model.entity.ResourceLink;
|
import ca.uhn.fhir.jpa.model.entity.ResourceLink;
|
||||||
import ca.uhn.fhir.jpa.model.entity.ResourceTable;
|
import ca.uhn.fhir.jpa.model.entity.ResourceTable;
|
||||||
|
@ -39,6 +40,8 @@ import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
import static org.apache.commons.lang3.StringUtils.isBlank;
|
import static org.apache.commons.lang3.StringUtils.isBlank;
|
||||||
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||||
|
@ -63,15 +66,17 @@ public class ResourceLinkExtractor {
|
||||||
|
|
||||||
ISearchParamExtractor.SearchParamSet<PathAndRef> refs = mySearchParamExtractor.extractResourceLinks(theResource);
|
ISearchParamExtractor.SearchParamSet<PathAndRef> refs = mySearchParamExtractor.extractResourceLinks(theResource);
|
||||||
SearchParamExtractorService.handleWarnings(theRequest, myInterceptorBroadcaster, refs);
|
SearchParamExtractorService.handleWarnings(theRequest, myInterceptorBroadcaster, refs);
|
||||||
|
|
||||||
|
Map<String, IResourceLookup> resourceIdToResolvedTarget = new HashMap<>();
|
||||||
for (PathAndRef nextPathAndRef : refs) {
|
for (PathAndRef nextPathAndRef : refs) {
|
||||||
RuntimeSearchParam searchParam = mySearchParamRegistry.getActiveSearchParam(resourceName, nextPathAndRef.getSearchParamName());
|
RuntimeSearchParam searchParam = mySearchParamRegistry.getActiveSearchParam(resourceName, nextPathAndRef.getSearchParamName());
|
||||||
extractResourceLinks(theParams, theEntity, theUpdateTime, theResourceLinkResolver, searchParam, nextPathAndRef, theFailOnInvalidReference, theRequest);
|
extractResourceLinks(theParams, theEntity, theUpdateTime, theResourceLinkResolver, searchParam, nextPathAndRef, theFailOnInvalidReference, theRequest, resourceIdToResolvedTarget);
|
||||||
}
|
}
|
||||||
|
|
||||||
theEntity.setHasLinks(theParams.myLinks.size() > 0);
|
theEntity.setHasLinks(theParams.myLinks.size() > 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void extractResourceLinks(ResourceIndexedSearchParams theParams, ResourceTable theEntity, Date theUpdateTime, IResourceLinkResolver theResourceLinkResolver, RuntimeSearchParam theRuntimeSearchParam, PathAndRef thePathAndRef, boolean theFailOnInvalidReference, RequestDetails theRequest) {
|
private void extractResourceLinks(ResourceIndexedSearchParams theParams, ResourceTable theEntity, Date theUpdateTime, IResourceLinkResolver theResourceLinkResolver, RuntimeSearchParam theRuntimeSearchParam, PathAndRef thePathAndRef, boolean theFailOnInvalidReference, RequestDetails theRequest, Map<String, IResourceLookup> theResourceIdToResolvedTarget) {
|
||||||
IBaseReference nextReference = thePathAndRef.getRef();
|
IBaseReference nextReference = thePathAndRef.getRef();
|
||||||
IIdType nextId = nextReference.getReferenceElement();
|
IIdType nextId = nextReference.getReferenceElement();
|
||||||
String path = thePathAndRef.getPath();
|
String path = thePathAndRef.getPath();
|
||||||
|
@ -153,21 +158,36 @@ public class ResourceLinkExtractor {
|
||||||
}
|
}
|
||||||
|
|
||||||
theResourceLinkResolver.validateTypeOrThrowException(type);
|
theResourceLinkResolver.validateTypeOrThrowException(type);
|
||||||
ResourceLink resourceLink = createResourceLink(theEntity, theUpdateTime, theResourceLinkResolver, theRuntimeSearchParam, path, thePathAndRef, nextId, typeString, type, nextReference, theRequest);
|
ResourceLink resourceLink = createResourceLink(theEntity, theUpdateTime, theResourceLinkResolver, theRuntimeSearchParam, path, thePathAndRef, nextId, typeString, type, nextReference, theRequest, theResourceIdToResolvedTarget);
|
||||||
if (resourceLink == null) {
|
if (resourceLink == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
theParams.myLinks.add(resourceLink);
|
theParams.myLinks.add(resourceLink);
|
||||||
}
|
}
|
||||||
|
|
||||||
private ResourceLink createResourceLink(ResourceTable theEntity, Date theUpdateTime, IResourceLinkResolver theResourceLinkResolver, RuntimeSearchParam nextSpDef, String theNextPathsUnsplit, PathAndRef nextPathAndRef, IIdType theNextId, String theTypeString, Class<? extends IBaseResource> theType, IBaseReference theReference, RequestDetails theRequest) {
|
private ResourceLink createResourceLink(ResourceTable theEntity, Date theUpdateTime, IResourceLinkResolver theResourceLinkResolver, RuntimeSearchParam nextSpDef, String theNextPathsUnsplit, PathAndRef nextPathAndRef, IIdType theNextId, String theTypeString, Class<? extends IBaseResource> theType, IBaseReference theReference, RequestDetails theRequest, Map<String, IResourceLookup> theResourceIdToResolvedTarget) {
|
||||||
ResourceTable targetResource = theResourceLinkResolver.findTargetResource(nextSpDef, theNextPathsUnsplit, theNextId, theTypeString, theType, theReference, theRequest);
|
/*
|
||||||
|
* We keep a cache of resolved target resources. This is good since for some resource types, there
|
||||||
|
* are multiple search parameters that map to the same element path within a resource (e.g.
|
||||||
|
* Observation:patient and Observation.subject and we don't want to force a resolution of the
|
||||||
|
* target any more times than we have to.
|
||||||
|
*/
|
||||||
|
|
||||||
|
IResourceLookup targetResource = theResourceIdToResolvedTarget.get(theNextId.getValue());
|
||||||
|
if (targetResource == null) {
|
||||||
|
targetResource = theResourceLinkResolver.findTargetResource(nextSpDef, theNextPathsUnsplit, theNextId, theTypeString, theType, theReference, theRequest);
|
||||||
|
}
|
||||||
|
|
||||||
if (targetResource == null) {
|
if (targetResource == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ResourceLink.forLocalReference(nextPathAndRef.getPath(), theEntity, targetResource, theUpdateTime);
|
theResourceIdToResolvedTarget.put(theNextId.getValue(), targetResource);
|
||||||
|
|
||||||
|
String targetResourceType = targetResource.getResourceType();
|
||||||
|
Long targetResourcePid = targetResource.getResourceId();
|
||||||
|
String targetResourceIdPart = theNextId.getIdPart();
|
||||||
|
return ResourceLink.forLocalReference(nextPathAndRef.getPath(), theEntity, targetResourceType, targetResourcePid, targetResourceIdPart, theUpdateTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,7 +30,6 @@ import ca.uhn.fhir.jpa.searchparam.extractor.ResourceIndexedSearchParams;
|
||||||
import ca.uhn.fhir.jpa.searchparam.registry.ISearchParamRegistry;
|
import ca.uhn.fhir.jpa.searchparam.registry.ISearchParamRegistry;
|
||||||
import ca.uhn.fhir.jpa.searchparam.util.SourceParam;
|
import ca.uhn.fhir.jpa.searchparam.util.SourceParam;
|
||||||
import ca.uhn.fhir.model.api.IQueryParameterType;
|
import ca.uhn.fhir.model.api.IQueryParameterType;
|
||||||
import ca.uhn.fhir.model.primitive.IdDt;
|
|
||||||
import ca.uhn.fhir.rest.api.Constants;
|
import ca.uhn.fhir.rest.api.Constants;
|
||||||
import ca.uhn.fhir.rest.api.RestSearchParameterTypeEnum;
|
import ca.uhn.fhir.rest.api.RestSearchParameterTypeEnum;
|
||||||
import ca.uhn.fhir.rest.param.BaseParamWithPrefix;
|
import ca.uhn.fhir.rest.param.BaseParamWithPrefix;
|
||||||
|
@ -146,7 +145,7 @@ public class InMemoryResourceMatcher {
|
||||||
case Constants.PARAM_SOURCE:
|
case Constants.PARAM_SOURCE:
|
||||||
return InMemoryMatchResult.fromBoolean(matchSourcesAndOr(theAndOrParams, theResource));
|
return InMemoryMatchResult.fromBoolean(matchSourcesAndOr(theAndOrParams, theResource));
|
||||||
default:
|
default:
|
||||||
return matchResourceParam(theParamName, theAndOrParams, theSearchParams, resourceName, paramDef);
|
return matchResourceParam(myModelConfig, theParamName, theAndOrParams, theSearchParams, resourceName, paramDef);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -189,7 +188,7 @@ public class InMemoryResourceMatcher {
|
||||||
return theValue.equals(theId.getValue()) || theValue.equals(theId.getIdPart());
|
return theValue.equals(theId.getValue()) || theValue.equals(theId.getIdPart());
|
||||||
}
|
}
|
||||||
|
|
||||||
private InMemoryMatchResult matchResourceParam(String theParamName, List<List<IQueryParameterType>> theAndOrParams, ResourceIndexedSearchParams theSearchParams, String theResourceName, RuntimeSearchParam theParamDef) {
|
private InMemoryMatchResult matchResourceParam(ModelConfig theModelConfig, String theParamName, List<List<IQueryParameterType>> theAndOrParams, ResourceIndexedSearchParams theSearchParams, String theResourceName, RuntimeSearchParam theParamDef) {
|
||||||
if (theParamDef != null) {
|
if (theParamDef != null) {
|
||||||
switch (theParamDef.getParamType()) {
|
switch (theParamDef.getParamType()) {
|
||||||
case QUANTITY:
|
case QUANTITY:
|
||||||
|
@ -202,7 +201,7 @@ public class InMemoryResourceMatcher {
|
||||||
if (theSearchParams == null) {
|
if (theSearchParams == null) {
|
||||||
return InMemoryMatchResult.successfulMatch();
|
return InMemoryMatchResult.successfulMatch();
|
||||||
} else {
|
} else {
|
||||||
return InMemoryMatchResult.fromBoolean(theAndOrParams.stream().anyMatch(nextAnd -> matchParams(theResourceName, theParamName, theParamDef, nextAnd, theSearchParams)));
|
return InMemoryMatchResult.fromBoolean(theAndOrParams.stream().anyMatch(nextAnd -> matchParams(theModelConfig, theResourceName, theParamName, theParamDef, nextAnd, theSearchParams)));
|
||||||
}
|
}
|
||||||
case COMPOSITE:
|
case COMPOSITE:
|
||||||
case HAS:
|
case HAS:
|
||||||
|
@ -219,28 +218,8 @@ public class InMemoryResourceMatcher {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean matchParams(String theResourceName, String theParamName, RuntimeSearchParam paramDef, List<? extends IQueryParameterType> theNextAnd, ResourceIndexedSearchParams theSearchParams) {
|
private boolean matchParams(ModelConfig theModelConfig, String theResourceName, String theParamName, RuntimeSearchParam paramDef, List<? extends IQueryParameterType> theNextAnd, ResourceIndexedSearchParams theSearchParams) {
|
||||||
if (paramDef.getParamType() == RestSearchParameterTypeEnum.REFERENCE) {
|
return theNextAnd.stream().anyMatch(token -> theSearchParams.matchParam(theModelConfig, theResourceName, theParamName, paramDef, token));
|
||||||
stripBaseUrlsFromReferenceParams(theNextAnd);
|
|
||||||
}
|
|
||||||
return theNextAnd.stream().anyMatch(token -> theSearchParams.matchParam(theResourceName, theParamName, paramDef, token));
|
|
||||||
}
|
|
||||||
|
|
||||||
private void stripBaseUrlsFromReferenceParams(List<? extends IQueryParameterType> theNextAnd) {
|
|
||||||
if (myModelConfig.getTreatBaseUrlsAsLocal().isEmpty()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (IQueryParameterType param : theNextAnd) {
|
|
||||||
ReferenceParam ref = (ReferenceParam) param;
|
|
||||||
IIdType dt = new IdDt(ref.getBaseUrl(), ref.getResourceType(), ref.getIdPart(), null);
|
|
||||||
|
|
||||||
if (dt.hasBaseUrl()) {
|
|
||||||
if (myModelConfig.getTreatBaseUrlsAsLocal().contains(dt.getBaseUrl())) {
|
|
||||||
ref.setValue(dt.toUnqualified().getValue());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean hasChain(List<List<IQueryParameterType>> theAndOrParams) {
|
private boolean hasChain(List<List<IQueryParameterType>> theAndOrParams) {
|
||||||
|
@ -256,7 +235,7 @@ public class InMemoryResourceMatcher {
|
||||||
for (List<IQueryParameterType> theAndOrParam : theAndOrParams) {
|
for (List<IQueryParameterType> theAndOrParam : theAndOrParams) {
|
||||||
for (IQueryParameterType param : theAndOrParam) {
|
for (IQueryParameterType param : theAndOrParam) {
|
||||||
if (param instanceof BaseParamWithPrefix) {
|
if (param instanceof BaseParamWithPrefix) {
|
||||||
ParamPrefixEnum prefix = ((BaseParamWithPrefix) param).getPrefix();
|
ParamPrefixEnum prefix = ((BaseParamWithPrefix<?>) param).getPrefix();
|
||||||
RestSearchParameterTypeEnum paramType = theParamDef.getParamType();
|
RestSearchParameterTypeEnum paramType = theParamDef.getParamType();
|
||||||
if (!supportedPrefix(prefix, paramType)) {
|
if (!supportedPrefix(prefix, paramType)) {
|
||||||
return InMemoryMatchResult.unsupportedFromParameterAndReason(theParamName, String.format("The prefix %s is not supported for param type %s", prefix, paramType));
|
return InMemoryMatchResult.unsupportedFromParameterAndReason(theParamName, String.format("The prefix %s is not supported for param type %s", prefix, paramType));
|
||||||
|
@ -268,6 +247,7 @@ public class InMemoryResourceMatcher {
|
||||||
return InMemoryMatchResult.successfulMatch();
|
return InMemoryMatchResult.successfulMatch();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("EnumSwitchStatementWhichMissesCases")
|
||||||
private boolean supportedPrefix(ParamPrefixEnum theParam, RestSearchParameterTypeEnum theParamType) {
|
private boolean supportedPrefix(ParamPrefixEnum theParam, RestSearchParameterTypeEnum theParamType) {
|
||||||
if (theParam == null || theParamType == null) {
|
if (theParam == null || theParamType == null) {
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -21,7 +21,8 @@ package ca.uhn.fhir.jpa.searchparam.matcher;
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import ca.uhn.fhir.context.RuntimeSearchParam;
|
import ca.uhn.fhir.context.RuntimeSearchParam;
|
||||||
import ca.uhn.fhir.jpa.model.entity.ForcedId;
|
import ca.uhn.fhir.jpa.model.cross.IResourceLookup;
|
||||||
|
import ca.uhn.fhir.jpa.model.cross.ResourceLookup;
|
||||||
import ca.uhn.fhir.jpa.model.entity.ResourceTable;
|
import ca.uhn.fhir.jpa.model.entity.ResourceTable;
|
||||||
import ca.uhn.fhir.jpa.searchparam.extractor.IResourceLinkResolver;
|
import ca.uhn.fhir.jpa.searchparam.extractor.IResourceLinkResolver;
|
||||||
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
||||||
|
@ -34,18 +35,17 @@ import org.springframework.stereotype.Service;
|
||||||
public class InlineResourceLinkResolver implements IResourceLinkResolver {
|
public class InlineResourceLinkResolver implements IResourceLinkResolver {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ResourceTable findTargetResource(RuntimeSearchParam theNextSpDef, String theNextPathsUnsplit, IIdType theNextId, String theTypeString, Class<? extends IBaseResource> theType, IBaseReference theReference, RequestDetails theRequest) {
|
public IResourceLookup findTargetResource(RuntimeSearchParam theSearchParam, String theSourcePath, IIdType theSourceResourceId, String theTypeString, Class<? extends IBaseResource> theType, IBaseReference theReference, RequestDetails theRequest) {
|
||||||
|
|
||||||
|
/*
|
||||||
|
* TODO: JA - This gets used during runtime in-memory matching for subscription. It's not
|
||||||
|
* really clear if it's useful or not.
|
||||||
|
*/
|
||||||
|
|
||||||
ResourceTable target;
|
ResourceTable target;
|
||||||
target = new ResourceTable();
|
target = new ResourceTable();
|
||||||
target.setResourceType(theTypeString);
|
target.setResourceType(theTypeString);
|
||||||
if (theNextId.isIdPartValidLong()) {
|
return new ResourceLookup(theTypeString, null, null);
|
||||||
target.setId(theNextId.getIdPartAsLong());
|
|
||||||
} else {
|
|
||||||
ForcedId forcedId = new ForcedId();
|
|
||||||
forcedId.setForcedId(theNextId.getIdPart());
|
|
||||||
target.setForcedId(forcedId);
|
|
||||||
}
|
|
||||||
return target;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -1,5 +1,25 @@
|
||||||
package ca.uhn.fhir.jpa.searchparam.util;
|
package ca.uhn.fhir.jpa.searchparam.util;
|
||||||
|
|
||||||
|
/*-
|
||||||
|
* #%L
|
||||||
|
* HAPI FHIR Search Parameters
|
||||||
|
* %%
|
||||||
|
* Copyright (C) 2014 - 2020 University Health Network
|
||||||
|
* %%
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
* #L%
|
||||||
|
*/
|
||||||
|
|
||||||
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
||||||
import ca.uhn.fhir.model.api.IQueryParameterType;
|
import ca.uhn.fhir.model.api.IQueryParameterType;
|
||||||
import ca.uhn.fhir.rest.param.QuantityParam;
|
import ca.uhn.fhir.rest.param.QuantityParam;
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
package ca.uhn.fhir.jpa.searchparam.extractor;
|
package ca.uhn.fhir.jpa.searchparam.extractor;
|
||||||
|
|
||||||
import ca.uhn.fhir.jpa.model.entity.ForcedId;
|
import ca.uhn.fhir.jpa.model.entity.ModelConfig;
|
||||||
import ca.uhn.fhir.jpa.model.entity.ResourceLink;
|
import ca.uhn.fhir.jpa.model.entity.ResourceLink;
|
||||||
import ca.uhn.fhir.jpa.model.entity.ResourceTable;
|
import ca.uhn.fhir.jpa.model.entity.ResourceTable;
|
||||||
import ca.uhn.fhir.rest.param.ReferenceParam;
|
import ca.uhn.fhir.rest.param.ReferenceParam;
|
||||||
|
@ -14,72 +14,70 @@ import java.util.Set;
|
||||||
|
|
||||||
import static org.hamcrest.Matchers.containsInAnyOrder;
|
import static org.hamcrest.Matchers.containsInAnyOrder;
|
||||||
import static org.hamcrest.Matchers.empty;
|
import static org.hamcrest.Matchers.empty;
|
||||||
import static org.junit.Assert.*;
|
import static org.junit.Assert.assertFalse;
|
||||||
|
import static org.junit.Assert.assertThat;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
public class ResourceIndexedSearchParamsTest {
|
public class ResourceIndexedSearchParamsTest {
|
||||||
|
|
||||||
public static final String STRING_ID = "StringId";
|
public static final String STRING_ID = "StringId";
|
||||||
public static final String LONG_ID = "123";
|
public static final String LONG_ID = "123";
|
||||||
private ResourceIndexedSearchParams myParams;
|
private ResourceIndexedSearchParams myParams;
|
||||||
private ResourceTable myTarget;
|
private ResourceTable mySource;
|
||||||
|
private ModelConfig myModelConfig = new ModelConfig();
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void before() {
|
public void before() {
|
||||||
ResourceTable source = new ResourceTable();
|
mySource = new ResourceTable();
|
||||||
source.setResourceType("Patient");
|
mySource.setResourceType("Patient");
|
||||||
|
|
||||||
myTarget = new ResourceTable();
|
myParams = new ResourceIndexedSearchParams(mySource);
|
||||||
myTarget.setResourceType("Organization");
|
|
||||||
|
|
||||||
myParams = new ResourceIndexedSearchParams(source);
|
|
||||||
ResourceLink link = ResourceLink.forLocalReference("organization", source, myTarget, new Date());
|
|
||||||
myParams.getResourceLinks().add(link);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void matchResourceLinksStringCompareToLong() {
|
public void matchResourceLinksStringCompareToLong() {
|
||||||
ReferenceParam referenceParam = getReferenceParam(STRING_ID);
|
ResourceLink link = ResourceLink.forLocalReference("organization", mySource, "Organization", 123L, LONG_ID, new Date());
|
||||||
myTarget.setId(123L);
|
myParams.getResourceLinks().add(link);
|
||||||
|
|
||||||
boolean result = myParams.matchResourceLinks("Patient", "organization", referenceParam, "organization");
|
ReferenceParam referenceParam = getReferenceParam(STRING_ID);
|
||||||
|
boolean result = myParams.matchResourceLinks(myModelConfig, "Patient", "organization", referenceParam, "organization");
|
||||||
assertFalse(result);
|
assertFalse(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void matchResourceLinksStringCompareToString() {
|
public void matchResourceLinksStringCompareToString() {
|
||||||
ReferenceParam referenceParam = getReferenceParam(STRING_ID);
|
ResourceLink link = ResourceLink.forLocalReference("organization", mySource, "Organization", 123L, STRING_ID, new Date());
|
||||||
ForcedId forcedid = new ForcedId();
|
myParams.getResourceLinks().add(link);
|
||||||
forcedid.setForcedId(STRING_ID);
|
|
||||||
myTarget.setForcedId(forcedid);
|
|
||||||
|
|
||||||
boolean result = myParams.matchResourceLinks("Patient", "organization", referenceParam, "organization");
|
ReferenceParam referenceParam = getReferenceParam(STRING_ID);
|
||||||
|
boolean result = myParams.matchResourceLinks(myModelConfig, "Patient", "organization", referenceParam, "organization");
|
||||||
assertTrue(result);
|
assertTrue(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void matchResourceLinksLongCompareToString() {
|
public void matchResourceLinksLongCompareToString() {
|
||||||
ReferenceParam referenceParam = getReferenceParam(LONG_ID);
|
ResourceLink link = ResourceLink.forLocalReference("organization", mySource, "Organization", 123L, STRING_ID, new Date());
|
||||||
ForcedId forcedid = new ForcedId();
|
myParams.getResourceLinks().add(link);
|
||||||
forcedid.setForcedId(STRING_ID);
|
|
||||||
myTarget.setForcedId(forcedid);
|
|
||||||
|
|
||||||
boolean result = myParams.matchResourceLinks("Patient", "organization", referenceParam, "organization");
|
ReferenceParam referenceParam = getReferenceParam(LONG_ID);
|
||||||
|
boolean result = myParams.matchResourceLinks(myModelConfig, "Patient", "organization", referenceParam, "organization");
|
||||||
assertFalse(result);
|
assertFalse(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void matchResourceLinksLongCompareToLong() {
|
public void matchResourceLinksLongCompareToLong() {
|
||||||
ReferenceParam referenceParam = getReferenceParam(LONG_ID);
|
ResourceLink link = ResourceLink.forLocalReference("organization", mySource, "Organization", 123L, LONG_ID, new Date());
|
||||||
myTarget.setId(123L);
|
myParams.getResourceLinks().add(link);
|
||||||
|
|
||||||
boolean result = myParams.matchResourceLinks("Patient", "organization", referenceParam, "organization");
|
ReferenceParam referenceParam = getReferenceParam(LONG_ID);
|
||||||
|
boolean result = myParams.matchResourceLinks(myModelConfig, "Patient", "organization", referenceParam, "organization");
|
||||||
assertTrue(result);
|
assertTrue(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
private ReferenceParam getReferenceParam(String theId) {
|
private ReferenceParam getReferenceParam(String theId) {
|
||||||
ReferenceParam retval = new ReferenceParam();
|
ReferenceParam retVal = new ReferenceParam();
|
||||||
retval.setValue(theId);
|
retVal.setValue(theId);
|
||||||
return retval;
|
return retVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -93,14 +91,14 @@ public class ResourceIndexedSearchParamsTest {
|
||||||
Lists.newArrayList("name=SMITH", "name=JOHN")
|
Lists.newArrayList("name=SMITH", "name=JOHN")
|
||||||
);
|
);
|
||||||
values = ResourceIndexedSearchParams.extractCompositeStringUniquesValueChains("Patient", partsChoices);
|
values = ResourceIndexedSearchParams.extractCompositeStringUniquesValueChains("Patient", partsChoices);
|
||||||
assertThat(values.toString(), values, containsInAnyOrder("Patient?gender=male&name=JOHN","Patient?gender=male&name=SMITH"));
|
assertThat(values.toString(), values, containsInAnyOrder("Patient?gender=male&name=JOHN", "Patient?gender=male&name=SMITH"));
|
||||||
|
|
||||||
partsChoices = Lists.newArrayList(
|
partsChoices = Lists.newArrayList(
|
||||||
Lists.newArrayList("gender=male", ""),
|
Lists.newArrayList("gender=male", ""),
|
||||||
Lists.newArrayList("name=SMITH", "name=JOHN", "")
|
Lists.newArrayList("name=SMITH", "name=JOHN", "")
|
||||||
);
|
);
|
||||||
values = ResourceIndexedSearchParams.extractCompositeStringUniquesValueChains("Patient", partsChoices);
|
values = ResourceIndexedSearchParams.extractCompositeStringUniquesValueChains("Patient", partsChoices);
|
||||||
assertThat(values.toString(), values, containsInAnyOrder("Patient?gender=male&name=JOHN","Patient?gender=male&name=SMITH"));
|
assertThat(values.toString(), values, containsInAnyOrder("Patient?gender=male&name=JOHN", "Patient?gender=male&name=SMITH"));
|
||||||
|
|
||||||
partsChoices = Lists.newArrayList(
|
partsChoices = Lists.newArrayList(
|
||||||
);
|
);
|
||||||
|
|
|
@ -21,8 +21,7 @@ package ca.uhn.fhir.jpa.subscription.module;
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import ca.uhn.fhir.context.FhirContext;
|
import ca.uhn.fhir.context.FhirContext;
|
||||||
import com.fasterxml.jackson.annotation.JsonAutoDetect;
|
import ca.uhn.fhir.model.api.IModelJson;
|
||||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
|
||||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
import org.apache.commons.lang3.builder.EqualsBuilder;
|
import org.apache.commons.lang3.builder.EqualsBuilder;
|
||||||
import org.apache.commons.lang3.builder.HashCodeBuilder;
|
import org.apache.commons.lang3.builder.HashCodeBuilder;
|
||||||
|
@ -39,9 +38,7 @@ import java.util.*;
|
||||||
|
|
||||||
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||||
|
|
||||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
public class CanonicalSubscription implements Serializable, Cloneable, IModelJson {
|
||||||
@JsonAutoDetect(creatorVisibility = JsonAutoDetect.Visibility.NONE, fieldVisibility = JsonAutoDetect.Visibility.NONE, getterVisibility = JsonAutoDetect.Visibility.NONE, isGetterVisibility = JsonAutoDetect.Visibility.NONE, setterVisibility = JsonAutoDetect.Visibility.NONE)
|
|
||||||
public class CanonicalSubscription implements Serializable, Cloneable {
|
|
||||||
|
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
@ -279,9 +276,7 @@ public class CanonicalSubscription implements Serializable, Cloneable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
public static class EmailDetails implements IModelJson {
|
||||||
@JsonAutoDetect(creatorVisibility = JsonAutoDetect.Visibility.NONE, fieldVisibility = JsonAutoDetect.Visibility.NONE, getterVisibility = JsonAutoDetect.Visibility.NONE, isGetterVisibility = JsonAutoDetect.Visibility.NONE, setterVisibility = JsonAutoDetect.Visibility.NONE)
|
|
||||||
public static class EmailDetails {
|
|
||||||
|
|
||||||
@JsonProperty("from")
|
@JsonProperty("from")
|
||||||
private String myFrom;
|
private String myFrom;
|
||||||
|
@ -334,9 +329,7 @@ public class CanonicalSubscription implements Serializable, Cloneable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
public static class RestHookDetails implements IModelJson {
|
||||||
@JsonAutoDetect(creatorVisibility = JsonAutoDetect.Visibility.NONE, fieldVisibility = JsonAutoDetect.Visibility.NONE, getterVisibility = JsonAutoDetect.Visibility.NONE, isGetterVisibility = JsonAutoDetect.Visibility.NONE, setterVisibility = JsonAutoDetect.Visibility.NONE)
|
|
||||||
public static class RestHookDetails {
|
|
||||||
|
|
||||||
@JsonProperty("stripVersionId")
|
@JsonProperty("stripVersionId")
|
||||||
private boolean myStripVersionId;
|
private boolean myStripVersionId;
|
||||||
|
@ -391,9 +384,7 @@ public class CanonicalSubscription implements Serializable, Cloneable {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
public static class CanonicalEventDefinition implements IModelJson {
|
||||||
@JsonAutoDetect(creatorVisibility = JsonAutoDetect.Visibility.NONE, fieldVisibility = JsonAutoDetect.Visibility.NONE, getterVisibility = JsonAutoDetect.Visibility.NONE, isGetterVisibility = JsonAutoDetect.Visibility.NONE, setterVisibility = JsonAutoDetect.Visibility.NONE)
|
|
||||||
public static class CanonicalEventDefinition {
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
|
|
|
@ -23,10 +23,9 @@ package ca.uhn.fhir.jpa.subscription.module;
|
||||||
import ca.uhn.fhir.context.FhirContext;
|
import ca.uhn.fhir.context.FhirContext;
|
||||||
import ca.uhn.fhir.jpa.subscription.module.subscriber.BaseResourceMessage;
|
import ca.uhn.fhir.jpa.subscription.module.subscriber.BaseResourceMessage;
|
||||||
import ca.uhn.fhir.jpa.subscription.module.subscriber.IResourceMessage;
|
import ca.uhn.fhir.jpa.subscription.module.subscriber.IResourceMessage;
|
||||||
|
import ca.uhn.fhir.model.api.IModelJson;
|
||||||
import ca.uhn.fhir.util.ResourceReferenceInfo;
|
import ca.uhn.fhir.util.ResourceReferenceInfo;
|
||||||
import com.fasterxml.jackson.annotation.JsonAutoDetect;
|
|
||||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
|
||||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
import org.apache.commons.lang3.builder.ToStringBuilder;
|
import org.apache.commons.lang3.builder.ToStringBuilder;
|
||||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||||
|
@ -37,9 +36,7 @@ import java.util.List;
|
||||||
import static org.apache.commons.lang3.StringUtils.isBlank;
|
import static org.apache.commons.lang3.StringUtils.isBlank;
|
||||||
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||||
|
|
||||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
public class ResourceModifiedMessage extends BaseResourceMessage implements IResourceMessage, IModelJson {
|
||||||
@JsonAutoDetect(creatorVisibility = JsonAutoDetect.Visibility.NONE, fieldVisibility = JsonAutoDetect.Visibility.NONE, getterVisibility = JsonAutoDetect.Visibility.NONE, isGetterVisibility = JsonAutoDetect.Visibility.NONE, setterVisibility = JsonAutoDetect.Visibility.NONE)
|
|
||||||
public class ResourceModifiedMessage extends BaseResourceMessage implements IResourceMessage {
|
|
||||||
|
|
||||||
@JsonProperty("resourceId")
|
@JsonProperty("resourceId")
|
||||||
private String myId;
|
private String myId;
|
||||||
|
|
|
@ -20,15 +20,12 @@ package ca.uhn.fhir.jpa.subscription.module.subscriber;
|
||||||
* #L%
|
* #L%
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonAutoDetect;
|
import ca.uhn.fhir.model.api.IModelJson;
|
||||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
|
||||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
import org.springframework.messaging.Message;
|
import org.springframework.messaging.Message;
|
||||||
import org.springframework.messaging.MessageHeaders;
|
import org.springframework.messaging.MessageHeaders;
|
||||||
|
|
||||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
public abstract class BaseJsonMessage<T> implements Message<T>, IModelJson {
|
||||||
@JsonAutoDetect(creatorVisibility = JsonAutoDetect.Visibility.NONE, fieldVisibility = JsonAutoDetect.Visibility.NONE, getterVisibility = JsonAutoDetect.Visibility.NONE, isGetterVisibility = JsonAutoDetect.Visibility.NONE, setterVisibility = JsonAutoDetect.Visibility.NONE)
|
|
||||||
public abstract class BaseJsonMessage<T> implements Message<T> {
|
|
||||||
|
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
@JsonProperty("headers")
|
@JsonProperty("headers")
|
||||||
|
|
|
@ -20,8 +20,7 @@ package ca.uhn.fhir.jpa.subscription.module.subscriber;
|
||||||
* #L%
|
* #L%
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonAutoDetect;
|
import ca.uhn.fhir.model.api.IModelJson;
|
||||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
|
||||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
import org.apache.commons.lang3.Validate;
|
import org.apache.commons.lang3.Validate;
|
||||||
|
|
||||||
|
@ -30,9 +29,7 @@ import java.util.Map;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
@SuppressWarnings("WeakerAccess")
|
@SuppressWarnings("WeakerAccess")
|
||||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
public abstract class BaseResourceMessage implements IResourceMessage, IModelJson {
|
||||||
@JsonAutoDetect(creatorVisibility = JsonAutoDetect.Visibility.NONE, fieldVisibility = JsonAutoDetect.Visibility.NONE, getterVisibility = JsonAutoDetect.Visibility.NONE, isGetterVisibility = JsonAutoDetect.Visibility.NONE, setterVisibility = JsonAutoDetect.Visibility.NONE)
|
|
||||||
public abstract class BaseResourceMessage implements IResourceMessage {
|
|
||||||
|
|
||||||
@JsonProperty("attributes")
|
@JsonProperty("attributes")
|
||||||
private Map<String, String> myAttributes;
|
private Map<String, String> myAttributes;
|
||||||
|
|
|
@ -20,13 +20,9 @@ package ca.uhn.fhir.jpa.subscription.module.subscriber;
|
||||||
* #L%
|
* #L%
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonAutoDetect;
|
|
||||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
|
||||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
import org.apache.commons.lang3.builder.ToStringBuilder;
|
import org.apache.commons.lang3.builder.ToStringBuilder;
|
||||||
|
|
||||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
|
||||||
@JsonAutoDetect(creatorVisibility = JsonAutoDetect.Visibility.NONE, fieldVisibility = JsonAutoDetect.Visibility.NONE, getterVisibility = JsonAutoDetect.Visibility.NONE, isGetterVisibility = JsonAutoDetect.Visibility.NONE, setterVisibility = JsonAutoDetect.Visibility.NONE)
|
|
||||||
public class ResourceDeliveryJsonMessage extends BaseJsonMessage<ResourceDeliveryMessage> {
|
public class ResourceDeliveryJsonMessage extends BaseJsonMessage<ResourceDeliveryMessage> {
|
||||||
|
|
||||||
@JsonProperty("payload")
|
@JsonProperty("payload")
|
||||||
|
|
|
@ -24,9 +24,7 @@ import ca.uhn.fhir.context.FhirContext;
|
||||||
import ca.uhn.fhir.jpa.subscription.module.CanonicalSubscription;
|
import ca.uhn.fhir.jpa.subscription.module.CanonicalSubscription;
|
||||||
import ca.uhn.fhir.jpa.subscription.module.ResourceModifiedMessage;
|
import ca.uhn.fhir.jpa.subscription.module.ResourceModifiedMessage;
|
||||||
import ca.uhn.fhir.rest.api.EncodingEnum;
|
import ca.uhn.fhir.rest.api.EncodingEnum;
|
||||||
import com.fasterxml.jackson.annotation.JsonAutoDetect;
|
|
||||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
|
||||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
import org.apache.commons.lang3.builder.ToStringBuilder;
|
import org.apache.commons.lang3.builder.ToStringBuilder;
|
||||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||||
|
@ -35,8 +33,6 @@ import org.hl7.fhir.instance.model.api.IIdType;
|
||||||
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||||
|
|
||||||
@SuppressWarnings("WeakerAccess")
|
@SuppressWarnings("WeakerAccess")
|
||||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
|
||||||
@JsonAutoDetect(creatorVisibility = JsonAutoDetect.Visibility.NONE, fieldVisibility = JsonAutoDetect.Visibility.NONE, getterVisibility = JsonAutoDetect.Visibility.NONE, isGetterVisibility = JsonAutoDetect.Visibility.NONE, setterVisibility = JsonAutoDetect.Visibility.NONE)
|
|
||||||
public class ResourceDeliveryMessage extends BaseResourceMessage implements IResourceMessage {
|
public class ResourceDeliveryMessage extends BaseResourceMessage implements IResourceMessage {
|
||||||
|
|
||||||
@JsonProperty("canonicalSubscription")
|
@JsonProperty("canonicalSubscription")
|
||||||
|
|
|
@ -21,13 +21,9 @@ package ca.uhn.fhir.jpa.subscription.module.subscriber;
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import ca.uhn.fhir.jpa.subscription.module.ResourceModifiedMessage;
|
import ca.uhn.fhir.jpa.subscription.module.ResourceModifiedMessage;
|
||||||
import com.fasterxml.jackson.annotation.JsonAutoDetect;
|
|
||||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
|
||||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
import org.apache.commons.lang3.builder.ToStringBuilder;
|
import org.apache.commons.lang3.builder.ToStringBuilder;
|
||||||
|
|
||||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
|
||||||
@JsonAutoDetect(creatorVisibility = JsonAutoDetect.Visibility.NONE, fieldVisibility = JsonAutoDetect.Visibility.NONE, getterVisibility = JsonAutoDetect.Visibility.NONE, isGetterVisibility = JsonAutoDetect.Visibility.NONE, setterVisibility = JsonAutoDetect.Visibility.NONE)
|
|
||||||
public class ResourceModifiedJsonMessage extends BaseJsonMessage<ResourceModifiedMessage> {
|
public class ResourceModifiedJsonMessage extends BaseJsonMessage<ResourceModifiedMessage> {
|
||||||
|
|
||||||
@JsonProperty("payload")
|
@JsonProperty("payload")
|
||||||
|
|
|
@ -11,6 +11,7 @@ import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
public class ReferenceParamTest {
|
public class ReferenceParamTest {
|
||||||
|
|
||||||
|
@ -202,6 +203,101 @@ public class ReferenceParamTest {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetIdPartAsBigDecimal() {
|
||||||
|
ReferenceParam rp = new ReferenceParam();
|
||||||
|
rp.setValueAsQueryToken(ourCtx, null, null, "123");
|
||||||
|
|
||||||
|
assertEquals("123", rp.getIdPartAsBigDecimal().toPlainString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetIdPart() {
|
||||||
|
ReferenceParam rp = new ReferenceParam();
|
||||||
|
rp.setValueAsQueryToken(ourCtx, null, null, "123");
|
||||||
|
|
||||||
|
assertTrue(rp.isIdPartValidLong());
|
||||||
|
assertEquals("123", rp.getIdPart());
|
||||||
|
assertEquals(null, rp.getResourceType(ourCtx));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetIdPartWithType() {
|
||||||
|
ReferenceParam rp = new ReferenceParam();
|
||||||
|
rp.setValueAsQueryToken(ourCtx, null, ":Patient", "123");
|
||||||
|
|
||||||
|
assertEquals("123", rp.getIdPart());
|
||||||
|
assertEquals("Patient", rp.getResourceType(ourCtx).getSimpleName());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSetValueWithType() {
|
||||||
|
ReferenceParam rp = new ReferenceParam();
|
||||||
|
rp.setValue("Patient/123");
|
||||||
|
|
||||||
|
assertEquals("123", rp.getIdPart());
|
||||||
|
assertEquals("Patient", rp.getResourceType(ourCtx).getSimpleName());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSetValueWithoutType() {
|
||||||
|
ReferenceParam rp = new ReferenceParam();
|
||||||
|
rp.setValue("123");
|
||||||
|
|
||||||
|
assertEquals("123", rp.getIdPart());
|
||||||
|
assertEquals(null, rp.getResourceType(ourCtx));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetIdPartAsLong() {
|
||||||
|
ReferenceParam rp = new ReferenceParam();
|
||||||
|
rp.setValueAsQueryToken(ourCtx, null, null, "123");
|
||||||
|
|
||||||
|
assertEquals(123L, rp.getIdPartAsLong().longValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testToStringParam() {
|
||||||
|
ReferenceParam rp = new ReferenceParam();
|
||||||
|
rp.setValueAsQueryToken(ourCtx, null, null, "123");
|
||||||
|
|
||||||
|
assertEquals("123", rp.toStringParam(ourCtx).getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testToTokenParam() {
|
||||||
|
ReferenceParam rp = new ReferenceParam();
|
||||||
|
rp.setValueAsQueryToken(ourCtx, null, null, "123");
|
||||||
|
|
||||||
|
assertEquals("123", rp.toTokenParam(ourCtx).getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testToDateParam() {
|
||||||
|
ReferenceParam rp = new ReferenceParam();
|
||||||
|
rp.setValueAsQueryToken(ourCtx, null, null, "2020-10-01");
|
||||||
|
|
||||||
|
assertEquals("2020-10-01", rp.toDateParam(ourCtx).getValueAsString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testToNumberParam() {
|
||||||
|
ReferenceParam rp = new ReferenceParam();
|
||||||
|
rp.setValueAsQueryToken(ourCtx, null, null, "1.23");
|
||||||
|
|
||||||
|
assertEquals("1.23", rp.toNumberParam(ourCtx).getValue().toPlainString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testToQuantityParam() {
|
||||||
|
ReferenceParam rp = new ReferenceParam();
|
||||||
|
rp.setValueAsQueryToken(ourCtx, null, null, "1.23|http://unitsofmeasure.org|cm");
|
||||||
|
|
||||||
|
assertEquals("1.23", rp.toQuantityParam(ourCtx).getValue().toPlainString());
|
||||||
|
assertEquals("http://unitsofmeasure.org", rp.toQuantityParam(ourCtx).getSystem());
|
||||||
|
assertEquals("cm", rp.toQuantityParam(ourCtx).getUnits());
|
||||||
|
}
|
||||||
|
|
||||||
@AfterClass
|
@AfterClass
|
||||||
public static void afterClassClearContext() {
|
public static void afterClassClearContext() {
|
||||||
TestUtil.clearAllStaticFieldsForUnitTest();
|
TestUtil.clearAllStaticFieldsForUnitTest();
|
||||||
|
|
Loading…
Reference in New Issue