Add some tests for unique search params
This commit is contained in:
parent
377bae8c16
commit
abf76a778f
|
@ -181,12 +181,6 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
|
|||
}
|
||||
}
|
||||
|
||||
InstantDt createHistoryToTimestamp() {
|
||||
// final InstantDt end = new InstantDt(DateUtils.addSeconds(DateUtils.truncate(new Date(), Calendar.SECOND),
|
||||
// -1));
|
||||
return InstantDt.withCurrentTime();
|
||||
}
|
||||
|
||||
private Set<ResourceIndexedCompositeStringUnique> extractCompositeStringUniques(ResourceTable theEntity, Set<ResourceIndexedSearchParamString> theStringParams, Set<ResourceIndexedSearchParamToken> theTokenParams, Set<ResourceIndexedSearchParamNumber> theNumberParams, Set<ResourceIndexedSearchParamQuantity> theQuantityParams, Set<ResourceIndexedSearchParamDate> theDateParams, Set<ResourceIndexedSearchParamUri> theUriParams, Set<ResourceLink> theLinks) {
|
||||
Set<ResourceIndexedCompositeStringUnique> compositeStringUniques;
|
||||
compositeStringUniques = new HashSet<>();
|
||||
|
@ -198,6 +192,7 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
|
|||
for (RuntimeSearchParam nextCompositeOf : next.getCompositeOf()) {
|
||||
Set<? extends BaseResourceIndexedSearchParam> paramsListForCompositePart = null;
|
||||
Set<ResourceLink> linksForCompositePart = null;
|
||||
Set<String> linksForCompositePartWantPaths = null;
|
||||
switch (nextCompositeOf.getParamType()) {
|
||||
case NUMBER:
|
||||
paramsListForCompositePart = theNumberParams;
|
||||
|
@ -213,6 +208,8 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
|
|||
break;
|
||||
case REFERENCE:
|
||||
linksForCompositePart = theLinks;
|
||||
linksForCompositePartWantPaths = new HashSet<>();
|
||||
linksForCompositePartWantPaths.addAll(nextCompositeOf.getPathsSplit());
|
||||
break;
|
||||
case QUANTITY:
|
||||
paramsListForCompositePart = theQuantityParams;
|
||||
|
@ -243,10 +240,12 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
|
|||
}
|
||||
if (linksForCompositePart != null) {
|
||||
for (ResourceLink nextLink : linksForCompositePart) {
|
||||
String value = nextLink.getTargetResource().getIdDt().toUnqualifiedVersionless().getValue();
|
||||
if (isNotBlank(value)) {
|
||||
value = UrlUtil.escapeUrlParam(value);
|
||||
nextChoicesList.add(key + "=" + value);
|
||||
if (linksForCompositePartWantPaths.contains(nextLink.getSourcePath())) {
|
||||
String value = nextLink.getTargetResource().getIdDt().toUnqualifiedVersionless().getValue();
|
||||
if (isNotBlank(value)) {
|
||||
value = UrlUtil.escapeUrlParam(value);
|
||||
nextChoicesList.add(key + "=" + value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -942,7 +941,7 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
|
|||
break;
|
||||
}
|
||||
|
||||
ourLog.info("Encoded {} chars of resource body as {} bytes", encoded.length(), bytes.length);
|
||||
ourLog.debug("Encoded {} chars of resource body as {} bytes", encoded.length(), bytes.length);
|
||||
|
||||
boolean changed = false;
|
||||
|
||||
|
@ -1615,7 +1614,13 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
|
|||
* Create history entry
|
||||
*/
|
||||
if (theCreateNewHistoryEntry) {
|
||||
final ResourceHistoryTable historyEntry = theEntity.toHistory(null);
|
||||
|
||||
ResourceHistoryTable existing = null;
|
||||
// if (theEntity.getVersion() > 1) {
|
||||
// existing = myResourceHistoryTableDao.findForIdAndVersion(theEntity.getId(), theEntity.getVersion());
|
||||
// ourLog.warn("Reusing existing history entry entity {}", theEntity.getIdDt().getValue());
|
||||
// }
|
||||
final ResourceHistoryTable historyEntry = theEntity.toHistory(existing);
|
||||
|
||||
ourLog.info("Saving history entry {}", historyEntry.getIdDt());
|
||||
myResourceHistoryTableDao.save(historyEntry);
|
||||
|
@ -1692,6 +1697,7 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
|
|||
if (getConfig().isUniqueIndexesEnabled()) {
|
||||
for (ResourceIndexedCompositeStringUnique next : existingCompositeStringUniques) {
|
||||
if (!compositeStringUniques.contains(next)) {
|
||||
ourLog.info("Removing unique index: {}", next);
|
||||
myEntityManager.remove(next);
|
||||
}
|
||||
}
|
||||
|
@ -1703,7 +1709,7 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
|
|||
throw new PreconditionFailedException("Can not create resource of type " + theEntity.getResourceType() + " as it would create a duplicate index matching query: " + next.getIndexString() + " (existing index belongs to " + existing.getResource().getIdDt().toUnqualifiedVersionless().getValue() + ")");
|
||||
}
|
||||
}
|
||||
ourLog.debug("Persisting unique index: {}", next);
|
||||
ourLog.info("Persisting unique index: {}", next);
|
||||
myEntityManager.persist(next);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -593,22 +593,23 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
|
|||
}
|
||||
|
||||
protected void markResourcesMatchingExpressionAsNeedingReindexing(String theExpression) {
|
||||
if (isNotBlank(theExpression)) {
|
||||
final String resourceType = theExpression.substring(0, theExpression.indexOf('.'));
|
||||
ourLog.info("Marking all resources of type {} for reindexing due to updated search parameter with path: {}", resourceType, theExpression);
|
||||
if (myDaoConfig.isMarkResourcesForReindexingUponSearchParameterChange()) {
|
||||
if (isNotBlank(theExpression)) {
|
||||
final String resourceType = theExpression.substring(0, theExpression.indexOf('.'));
|
||||
ourLog.info("Marking all resources of type {} for reindexing due to updated search parameter with path: {}", resourceType, theExpression);
|
||||
|
||||
TransactionTemplate txTemplate = new TransactionTemplate(myPlatformTransactionManager);
|
||||
txTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
|
||||
int updatedCount = txTemplate.execute(new TransactionCallback<Integer>() {
|
||||
@Override
|
||||
public Integer doInTransaction(TransactionStatus theStatus) {
|
||||
return myResourceTableDao.markResourcesOfTypeAsRequiringReindexing(resourceType);
|
||||
}
|
||||
});
|
||||
TransactionTemplate txTemplate = new TransactionTemplate(myPlatformTransactionManager);
|
||||
txTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
|
||||
int updatedCount = txTemplate.execute(new TransactionCallback<Integer>() {
|
||||
@Override
|
||||
public Integer doInTransaction(TransactionStatus theStatus) {
|
||||
return myResourceTableDao.markResourcesOfTypeAsRequiringReindexing(resourceType);
|
||||
}
|
||||
});
|
||||
|
||||
ourLog.info("Marked {} resources for reindexing", updatedCount);
|
||||
ourLog.info("Marked {} resources for reindexing", updatedCount);
|
||||
}
|
||||
}
|
||||
|
||||
mySearchParamRegistry.forceRefresh();
|
||||
}
|
||||
|
||||
|
|
|
@ -17,9 +17,9 @@ import java.util.*;
|
|||
* 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.
|
||||
|
@ -109,6 +109,7 @@ public class DaoConfig {
|
|||
private Integer myCacheControlNoStoreMaxResultsUpperLimit = 1000;
|
||||
private Integer myCountSearchResultsUpTo = null;
|
||||
private IdStrategyEnum myResourceServerIdStrategy = IdStrategyEnum.SEQUENTIAL_NUMERIC;
|
||||
private boolean myMarkResourcesForReindexingUponSearchParameterChange;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
|
@ -117,6 +118,7 @@ public class DaoConfig {
|
|||
setSubscriptionEnabled(true);
|
||||
setSubscriptionPollDelay(0);
|
||||
setSubscriptionPurgeInactiveAfterMillis(Long.MAX_VALUE);
|
||||
setMarkResourcesForReindexingUponSearchParameterChange(true);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -340,18 +342,6 @@ public class DaoConfig {
|
|||
myHardTagListLimit = theHardTagListLimit;
|
||||
}
|
||||
|
||||
/**
|
||||
* This is the maximum number of resources that will be added to a single page of returned resources. Because of
|
||||
* includes with wildcards and other possibilities it is possible for a client to make requests that include very
|
||||
* large amounts of data, so this hard limit can be imposed to prevent runaway requests.
|
||||
*
|
||||
* @deprecated Deprecated in HAPI FHIR 3.2.0 as this method doesn't actually do anything
|
||||
*/
|
||||
@Deprecated
|
||||
public void setIncludeLimit(@SuppressWarnings("unused") int theIncludeLimit) {
|
||||
// nothing
|
||||
}
|
||||
|
||||
/**
|
||||
* If set to {@link IndexEnabledEnum#DISABLED} (default is {@link IndexEnabledEnum#DISABLED})
|
||||
* the server will not create search indexes for search parameters with no values in resources.
|
||||
|
@ -404,11 +394,8 @@ public class DaoConfig {
|
|||
/**
|
||||
* This may be used to optionally register server interceptors directly against the DAOs.
|
||||
*/
|
||||
public void setInterceptors(IServerInterceptor... theInterceptor) {
|
||||
setInterceptors(new ArrayList<IServerInterceptor>());
|
||||
if (theInterceptor != null && theInterceptor.length != 0) {
|
||||
getInterceptors().addAll(Arrays.asList(theInterceptor));
|
||||
}
|
||||
public void setInterceptors(List<IServerInterceptor> theInterceptors) {
|
||||
myInterceptors = theInterceptors;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -465,25 +452,6 @@ public class DaoConfig {
|
|||
myResourceEncoding = theResourceEncoding;
|
||||
}
|
||||
|
||||
/**
|
||||
* This setting configures the strategy to use in generating IDs for newly
|
||||
* created resources on the server. The default is {@link IdStrategyEnum#SEQUENTIAL_NUMERIC}.
|
||||
*/
|
||||
public IdStrategyEnum getResourceServerIdStrategy() {
|
||||
return myResourceServerIdStrategy;
|
||||
}
|
||||
|
||||
/**
|
||||
* This setting configures the strategy to use in generating IDs for newly
|
||||
* created resources on the server. The default is {@link IdStrategyEnum#SEQUENTIAL_NUMERIC}.
|
||||
*
|
||||
* @param theResourceIdStrategy The strategy. Must not be null.
|
||||
*/
|
||||
public void setResourceServerIdStrategy(IdStrategyEnum theResourceIdStrategy) {
|
||||
Validate.notNull(theResourceIdStrategy, "theResourceIdStrategy must not be null");
|
||||
myResourceServerIdStrategy = theResourceIdStrategy;
|
||||
}
|
||||
|
||||
/**
|
||||
* If set, an individual resource will not be allowed to have more than the
|
||||
* given number of tags, profiles, and security labels (the limit is for the combined
|
||||
|
@ -514,6 +482,25 @@ public class DaoConfig {
|
|||
myResourceMetaCountHardLimit = theResourceMetaCountHardLimit;
|
||||
}
|
||||
|
||||
/**
|
||||
* This setting configures the strategy to use in generating IDs for newly
|
||||
* created resources on the server. The default is {@link IdStrategyEnum#SEQUENTIAL_NUMERIC}.
|
||||
*/
|
||||
public IdStrategyEnum getResourceServerIdStrategy() {
|
||||
return myResourceServerIdStrategy;
|
||||
}
|
||||
|
||||
/**
|
||||
* This setting configures the strategy to use in generating IDs for newly
|
||||
* created resources on the server. The default is {@link IdStrategyEnum#SEQUENTIAL_NUMERIC}.
|
||||
*
|
||||
* @param theResourceIdStrategy The strategy. Must not be null.
|
||||
*/
|
||||
public void setResourceServerIdStrategy(IdStrategyEnum theResourceIdStrategy) {
|
||||
Validate.notNull(theResourceIdStrategy, "theResourceIdStrategy must not be null");
|
||||
myResourceServerIdStrategy = theResourceIdStrategy;
|
||||
}
|
||||
|
||||
/**
|
||||
* If set to a non {@literal null} value (default is {@link #DEFAULT_REUSE_CACHED_SEARCH_RESULTS_FOR_MILLIS non null})
|
||||
* if an identical search is requested multiple times within this window, the same results will be returned
|
||||
|
@ -922,6 +909,24 @@ public class DaoConfig {
|
|||
myIndexContainedResources = theIndexContainedResources;
|
||||
}
|
||||
|
||||
/**
|
||||
* Should resources be marked as needing reindexing when a
|
||||
* SearchParameter resource is added or changed. This should generally
|
||||
* be true (which is the default)
|
||||
*/
|
||||
public boolean isMarkResourcesForReindexingUponSearchParameterChange() {
|
||||
return myMarkResourcesForReindexingUponSearchParameterChange;
|
||||
}
|
||||
|
||||
/**
|
||||
* Should resources be marked as needing reindexing when a
|
||||
* SearchParameter resource is added or changed. This should generally
|
||||
* be true (which is the default)
|
||||
*/
|
||||
public void setMarkResourcesForReindexingUponSearchParameterChange(boolean theMarkResourcesForReindexingUponSearchParameterChange) {
|
||||
myMarkResourcesForReindexingUponSearchParameterChange = theMarkResourcesForReindexingUponSearchParameterChange;
|
||||
}
|
||||
|
||||
public boolean isSchedulingDisabled() {
|
||||
return mySchedulingDisabled;
|
||||
}
|
||||
|
@ -979,7 +984,7 @@ public class DaoConfig {
|
|||
* a new one.
|
||||
* <p>
|
||||
* This causes friendlier error messages to be generated, but adds an
|
||||
* extra round-trip to the database for eavh save so it can cause
|
||||
* extra round-trip to the database for each save so it can cause
|
||||
* a small performance hit.
|
||||
* </p>
|
||||
*/
|
||||
|
@ -1022,11 +1027,26 @@ public class DaoConfig {
|
|||
// this method does nothing
|
||||
}
|
||||
|
||||
/**
|
||||
* This is the maximum number of resources that will be added to a single page of returned resources. Because of
|
||||
* includes with wildcards and other possibilities it is possible for a client to make requests that include very
|
||||
* large amounts of data, so this hard limit can be imposed to prevent runaway requests.
|
||||
*
|
||||
* @deprecated Deprecated in HAPI FHIR 3.2.0 as this method doesn't actually do anything
|
||||
*/
|
||||
@Deprecated
|
||||
public void setIncludeLimit(@SuppressWarnings("unused") int theIncludeLimit) {
|
||||
// nothing
|
||||
}
|
||||
|
||||
/**
|
||||
* This may be used to optionally register server interceptors directly against the DAOs.
|
||||
*/
|
||||
public void setInterceptors(List<IServerInterceptor> theInterceptors) {
|
||||
myInterceptors = theInterceptors;
|
||||
public void setInterceptors(IServerInterceptor... theInterceptor) {
|
||||
setInterceptors(new ArrayList<IServerInterceptor>());
|
||||
if (theInterceptor != null && theInterceptor.length != 0) {
|
||||
getInterceptors().addAll(Arrays.asList(theInterceptor));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -9,9 +9,9 @@ package ca.uhn.fhir.jpa.entity;
|
|||
* 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.
|
||||
|
@ -22,7 +22,6 @@ package ca.uhn.fhir.jpa.entity;
|
|||
|
||||
import org.apache.commons.lang3.Validate;
|
||||
import org.apache.commons.lang3.builder.*;
|
||||
import org.hl7.fhir.r4.model.Resource;
|
||||
|
||||
import javax.persistence.*;
|
||||
|
||||
|
@ -44,20 +43,10 @@ public class ResourceIndexedCompositeStringUnique implements Comparable<Resource
|
|||
private Long myId;
|
||||
|
||||
@ManyToOne
|
||||
@JoinColumn(name = "RES_ID", referencedColumnName = "RES_ID", foreignKey = @ForeignKey(name="FK_IDXCMPSTRUNIQ_RES_ID"))
|
||||
@JoinColumn(name = "RES_ID", referencedColumnName = "RES_ID", foreignKey = @ForeignKey(name = "FK_IDXCMPSTRUNIQ_RES_ID"))
|
||||
private ResourceTable myResource;
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE)
|
||||
.append("resourceId", myResourceId)
|
||||
.append("indexString", myIndexString)
|
||||
.toString();
|
||||
}
|
||||
|
||||
@Column(name="RES_ID", insertable = false, updatable = false)
|
||||
@Column(name = "RES_ID", insertable = false, updatable = false)
|
||||
private Long myResourceId;
|
||||
|
||||
@Column(name = "IDX_STRING", nullable = false, length = MAX_STRING_LENGTH)
|
||||
private String myIndexString;
|
||||
|
||||
|
@ -88,12 +77,13 @@ public class ResourceIndexedCompositeStringUnique implements Comparable<Resource
|
|||
public boolean equals(Object theO) {
|
||||
if (this == theO) return true;
|
||||
|
||||
if (theO == null || getClass() != theO.getClass()) return false;
|
||||
if (!(theO instanceof ResourceIndexedCompositeStringUnique)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ResourceIndexedCompositeStringUnique that = (ResourceIndexedCompositeStringUnique) theO;
|
||||
|
||||
return new EqualsBuilder()
|
||||
.append(getResource(), that.getResource())
|
||||
.append(myIndexString, that.myIndexString)
|
||||
.isEquals();
|
||||
}
|
||||
|
@ -118,8 +108,16 @@ public class ResourceIndexedCompositeStringUnique implements Comparable<Resource
|
|||
@Override
|
||||
public int hashCode() {
|
||||
return new HashCodeBuilder(17, 37)
|
||||
.append(getResource())
|
||||
.append(myIndexString)
|
||||
.toHashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE)
|
||||
.append("id", myId)
|
||||
.append("resourceId", myResourceId)
|
||||
.append("indexString", myIndexString)
|
||||
.toString();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package ca.uhn.fhir.jpa.dao.r4;
|
||||
|
||||
import ca.uhn.fhir.jpa.dao.DaoConfig;
|
||||
import ca.uhn.fhir.jpa.dao.DaoMethodOutcome;
|
||||
import ca.uhn.fhir.jpa.dao.SearchBuilder;
|
||||
import ca.uhn.fhir.jpa.dao.SearchParameterMap;
|
||||
import ca.uhn.fhir.jpa.entity.ResourceIndexedCompositeStringUnique;
|
||||
|
@ -19,6 +20,9 @@ import org.junit.AfterClass;
|
|||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.orm.jpa.JpaSystemException;
|
||||
import org.springframework.transaction.TransactionStatus;
|
||||
import org.springframework.transaction.support.TransactionCallbackWithoutResult;
|
||||
import org.springframework.transaction.support.TransactionTemplate;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
@ -44,6 +48,32 @@ public class FhirResourceDaoR4UniqueSearchParamTest extends BaseJpaR4Test {
|
|||
myDaoConfig.setDefaultSearchParamsCanBeOverridden(true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNonTransaction() {
|
||||
createUniqueBirthdateAndGenderSps();
|
||||
|
||||
Patient p = new Patient();
|
||||
p.setGender(Enumerations.AdministrativeGender.MALE);
|
||||
p.setBirthDateElement(new DateType("2001-01-01"));
|
||||
|
||||
Bundle input = new Bundle();
|
||||
input.setType(Bundle.BundleType.TRANSACTION);
|
||||
input.addEntry()
|
||||
.setResource(p)
|
||||
.setFullUrl("Patient")
|
||||
.getRequest()
|
||||
.setMethod(Bundle.HTTPVerb.POST)
|
||||
.setUrl("/Patient")
|
||||
.setIfNoneExist("Patient?gender=http%3A%2F%2Fhl7.org%2Ffhir%2Fadministrative-gender%7Cmale&birthdate=2001-01-01");
|
||||
|
||||
Bundle output0 = mySystemDao.transaction(mySrd, input);
|
||||
Bundle output1 = mySystemDao.transaction(mySrd, input);
|
||||
assertEquals(output1.getEntry().get(0).getFullUrl(), output0.getEntry().get(0).getFullUrl());
|
||||
Bundle output2 = mySystemDao.transaction(mySrd, input);
|
||||
assertEquals(output2.getEntry().get(0).getFullUrl(), output0.getEntry().get(0).getFullUrl());
|
||||
|
||||
}
|
||||
|
||||
private void createUniqueBirthdateAndGenderSps() {
|
||||
SearchParameter sp = new SearchParameter();
|
||||
sp.setId("SearchParameter/patient-gender");
|
||||
|
@ -387,6 +417,90 @@ public class FhirResourceDaoR4UniqueSearchParamTest extends BaseJpaR4Test {
|
|||
mySearchParamRegsitry.forceRefresh();
|
||||
}
|
||||
|
||||
private void createUniqueIndexPatientIdentifier() {
|
||||
|
||||
SearchParameter sp = new SearchParameter();
|
||||
sp.setId("SearchParameter/patient-identifier");
|
||||
sp.setCode("identifier");
|
||||
sp.setExpression("Patient.identifier");
|
||||
sp.setType(Enumerations.SearchParamType.TOKEN);
|
||||
sp.setStatus(PublicationStatus.ACTIVE);
|
||||
sp.addBase("Patient");
|
||||
mySearchParameterDao.update(sp);
|
||||
|
||||
sp = new SearchParameter();
|
||||
sp.setId("SearchParameter/patient-uniq-identifier");
|
||||
sp.setCode("patient-uniq-identifier");
|
||||
sp.setExpression("Patient.identifier");
|
||||
sp.setType(Enumerations.SearchParamType.COMPOSITE);
|
||||
sp.setStatus(PublicationStatus.ACTIVE);
|
||||
sp.addBase("Patient");
|
||||
sp.addComponent()
|
||||
.setExpression("Patient")
|
||||
.setDefinition(new Reference("/SearchParameter/patient-identifier"));
|
||||
sp.addExtension()
|
||||
.setUrl(JpaConstants.EXT_SP_UNIQUE)
|
||||
.setValue(new BooleanType(true));
|
||||
mySearchParameterDao.update(sp);
|
||||
mySearchParamRegsitry.forceRefresh();
|
||||
}
|
||||
|
||||
private void createUniqueIndexPatientIdentifierCount1() {
|
||||
|
||||
SearchParameter sp = new SearchParameter();
|
||||
sp.setId("SearchParameter/patient-identifier");
|
||||
sp.setCode("first-identifier");
|
||||
sp.setExpression("Patient.identifier.first()");
|
||||
sp.setType(Enumerations.SearchParamType.TOKEN);
|
||||
sp.setStatus(PublicationStatus.ACTIVE);
|
||||
sp.addBase("Patient");
|
||||
mySearchParameterDao.update(sp);
|
||||
|
||||
sp = new SearchParameter();
|
||||
sp.setId("SearchParameter/patient-uniq-identifier");
|
||||
sp.setCode("patient-uniq-identifier");
|
||||
sp.setExpression("Patient.identifier");
|
||||
sp.setType(Enumerations.SearchParamType.COMPOSITE);
|
||||
sp.setStatus(PublicationStatus.ACTIVE);
|
||||
sp.addBase("Patient");
|
||||
sp.addComponent()
|
||||
.setExpression("Patient")
|
||||
.setDefinition(new Reference("/SearchParameter/patient-identifier"));
|
||||
sp.addExtension()
|
||||
.setUrl(JpaConstants.EXT_SP_UNIQUE)
|
||||
.setValue(new BooleanType(true));
|
||||
mySearchParameterDao.update(sp);
|
||||
mySearchParamRegsitry.forceRefresh();
|
||||
}
|
||||
|
||||
private void createUniqueIndexObservationSubject() {
|
||||
|
||||
SearchParameter sp = new SearchParameter();
|
||||
sp.setId("SearchParameter/observation-subject");
|
||||
sp.setCode("observation-subject");
|
||||
sp.setExpression("Observation.subject");
|
||||
sp.setType(Enumerations.SearchParamType.REFERENCE);
|
||||
sp.setStatus(PublicationStatus.ACTIVE);
|
||||
sp.addBase("Observation");
|
||||
mySearchParameterDao.update(sp);
|
||||
|
||||
sp = new SearchParameter();
|
||||
sp.setId("SearchParameter/observation-uniq-subject");
|
||||
sp.setCode("observation-uniq-subject");
|
||||
sp.setExpression("Observation.subject");
|
||||
sp.setType(Enumerations.SearchParamType.COMPOSITE);
|
||||
sp.setStatus(PublicationStatus.ACTIVE);
|
||||
sp.addBase("Observation");
|
||||
sp.addComponent()
|
||||
.setExpression("Observation")
|
||||
.setDefinition(new Reference("/SearchParameter/observation-subject"));
|
||||
sp.addExtension()
|
||||
.setUrl(JpaConstants.EXT_SP_UNIQUE)
|
||||
.setValue(new BooleanType(true));
|
||||
mySearchParameterDao.update(sp);
|
||||
mySearchParamRegsitry.forceRefresh();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIndexTransactionWithMatchUrl() {
|
||||
Patient pt2 = new Patient();
|
||||
|
@ -412,6 +526,161 @@ public class FhirResourceDaoR4UniqueSearchParamTest extends BaseJpaR4Test {
|
|||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDoubleMatching() {
|
||||
createUniqueIndexPatientIdentifier();
|
||||
|
||||
Patient pt = new Patient();
|
||||
pt.addIdentifier().setSystem("urn").setValue("111");
|
||||
pt.addIdentifier().setSystem("urn").setValue("222");
|
||||
|
||||
Bundle input = new Bundle();
|
||||
input.setType(Bundle.BundleType.TRANSACTION);
|
||||
input.addEntry()
|
||||
.setResource(pt)
|
||||
.setFullUrl("Patient")
|
||||
.getRequest()
|
||||
.setMethod(Bundle.HTTPVerb.POST)
|
||||
.setUrl("/Patient")
|
||||
.setIfNoneExist("/Patient?identifier=urn|111,urn|222");
|
||||
mySystemDao.transaction(mySrd, input);
|
||||
|
||||
myEntityManager.clear();
|
||||
|
||||
pt = new Patient();
|
||||
pt.setActive(true);
|
||||
pt.addIdentifier().setSystem("urn").setValue("111");
|
||||
pt.addIdentifier().setSystem("urn").setValue("222");
|
||||
|
||||
input = new Bundle();
|
||||
input.setType(Bundle.BundleType.TRANSACTION);
|
||||
input.addEntry()
|
||||
.setResource(pt)
|
||||
.setFullUrl("Patient")
|
||||
.getRequest()
|
||||
.setMethod(Bundle.HTTPVerb.POST)
|
||||
.setUrl("/Patient")
|
||||
.setIfNoneExist("/Patient?identifier=urn|111,urn|222");
|
||||
mySystemDao.transaction(mySrd, input);
|
||||
|
||||
new TransactionTemplate(myTxManager).execute(new TransactionCallbackWithoutResult() {
|
||||
@Override
|
||||
protected void doInTransactionWithoutResult(TransactionStatus status) {
|
||||
List<ResourceIndexedCompositeStringUnique> all = myResourceIndexedCompositeStringUniqueDao.findAll();
|
||||
assertEquals(2, all.size());
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testObservationSubject() {
|
||||
createUniqueIndexObservationSubject();
|
||||
|
||||
Patient pt = new Patient();
|
||||
pt.addIdentifier().setSystem("urn").setValue("111");
|
||||
pt.addIdentifier().setSystem("urn").setValue("222");
|
||||
IIdType ptid = myPatientDao.create(pt).getId().toUnqualifiedVersionless();
|
||||
|
||||
Encounter enc = new Encounter();
|
||||
enc.setSubject(new Reference(ptid));
|
||||
IIdType encid = myEncounterDao.create(enc).getId().toUnqualifiedVersionless();
|
||||
|
||||
Observation obs = new Observation();
|
||||
obs.setSubject(new Reference(ptid));
|
||||
obs.setContext(new Reference(encid));
|
||||
myObservationDao.create(obs);
|
||||
|
||||
new TransactionTemplate(myTxManager).execute(new TransactionCallbackWithoutResult() {
|
||||
@Override
|
||||
protected void doInTransactionWithoutResult(TransactionStatus status) {
|
||||
List<ResourceIndexedCompositeStringUnique> all = myResourceIndexedCompositeStringUniqueDao.findAll();
|
||||
assertEquals(all.toString(), 1, all.size());
|
||||
}
|
||||
});
|
||||
|
||||
}er
|
||||
|
||||
@Test
|
||||
public void testIndexFirstMatchOnly() {
|
||||
createUniqueIndexPatientIdentifierCount1();
|
||||
|
||||
Patient pt = new Patient();
|
||||
pt.addIdentifier().setSystem("urn").setValue("111");
|
||||
pt.addIdentifier().setSystem("urn").setValue("222");
|
||||
myPatientDao.create(pt);
|
||||
|
||||
pt = new Patient();
|
||||
pt.addIdentifier().setSystem("urn").setValue("111");
|
||||
pt.addIdentifier().setSystem("urn").setValue("222");
|
||||
try {
|
||||
myPatientDao.create(pt);
|
||||
fail();
|
||||
} catch (PreconditionFailedException e) {
|
||||
// good
|
||||
}
|
||||
|
||||
pt = new Patient();
|
||||
pt.addIdentifier().setSystem("urn").setValue("333");
|
||||
pt.addIdentifier().setSystem("urn").setValue("222");
|
||||
myPatientDao.create(pt);
|
||||
|
||||
new TransactionTemplate(myTxManager).execute(new TransactionCallbackWithoutResult() {
|
||||
@Override
|
||||
protected void doInTransactionWithoutResult(TransactionStatus status) {
|
||||
List<ResourceIndexedCompositeStringUnique> all = myResourceIndexedCompositeStringUniqueDao.findAll();
|
||||
assertEquals(2, all.size());
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testDoubleMatchingPut() {
|
||||
createUniqueIndexPatientIdentifier();
|
||||
|
||||
Patient pt = new Patient();
|
||||
pt.addIdentifier().setSystem("urn").setValue("111");
|
||||
pt.addIdentifier().setSystem("urn").setValue("222");
|
||||
|
||||
Bundle input = new Bundle();
|
||||
input.setType(Bundle.BundleType.TRANSACTION);
|
||||
input.addEntry()
|
||||
.setResource(pt)
|
||||
.setFullUrl("Patient")
|
||||
.getRequest()
|
||||
.setMethod(Bundle.HTTPVerb.PUT)
|
||||
.setUrl("/Patient?identifier=urn|111,urn|222");
|
||||
mySystemDao.transaction(mySrd, input);
|
||||
|
||||
myEntityManager.clear();
|
||||
|
||||
pt = new Patient();
|
||||
pt.setActive(true);
|
||||
pt.addIdentifier().setSystem("urn").setValue("111");
|
||||
pt.addIdentifier().setSystem("urn").setValue("222");
|
||||
|
||||
input = new Bundle();
|
||||
input.setType(Bundle.BundleType.TRANSACTION);
|
||||
input.addEntry()
|
||||
.setResource(pt)
|
||||
.setFullUrl("Patient")
|
||||
.getRequest()
|
||||
.setMethod(Bundle.HTTPVerb.PUT)
|
||||
.setUrl("/Patient?identifier=urn|111,urn|222");
|
||||
mySystemDao.transaction(mySrd, input);
|
||||
|
||||
new TransactionTemplate(myTxManager).execute(new TransactionCallbackWithoutResult() {
|
||||
@Override
|
||||
protected void doInTransactionWithoutResult(TransactionStatus status) {
|
||||
List<ResourceIndexedCompositeStringUnique> all = myResourceIndexedCompositeStringUniqueDao.findAll();
|
||||
assertEquals(2, all.size());
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIndexTransactionWithMatchUrl2() {
|
||||
createUniqueIndexCoverageBeneficiary();
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
<configuration>
|
||||
|
||||
|
||||
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
|
||||
<level>INFO</level>
|
||||
|
|
Loading…
Reference in New Issue