Make sure we don't update unchanged resources in a transaction

This commit is contained in:
James 2017-05-20 17:55:09 -04:00
parent d550392047
commit 20c14fe8a6
7 changed files with 889 additions and 680 deletions

View File

@ -1508,6 +1508,7 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
if (theResource != null) { if (theResource != null) {
populateResourceIdFromEntity(theEntity, theResource); populateResourceIdFromEntity(theEntity, theResource);
} }
theEntity.setUnchangedInCurrentOperation(true);
return theEntity; return theEntity;
} }

View File

@ -1127,7 +1127,7 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
* we'll manually increase the version. This is important because we want the updated version number * we'll manually increase the version. This is important because we want the updated version number
* to be reflected in the resource shared with interceptors * to be reflected in the resource shared with interceptors
*/ */
if (!thePerformIndexing) { if (!thePerformIndexing && !savedEntity.isUnchangedInCurrentOperation()) {
if (resourceId.hasVersionIdPart() == false) { if (resourceId.hasVersionIdPart() == false) {
resourceId = resourceId.withVersion(Long.toString(savedEntity.getVersion())); resourceId = resourceId.withVersion(Long.toString(savedEntity.getVersion()));
} }

View File

@ -242,6 +242,9 @@ public class ResourceTable extends BaseHasResource implements Serializable {
@OneToMany(mappedBy = "myResource", cascade = CascadeType.ALL, fetch = FetchType.LAZY, orphanRemoval = true) @OneToMany(mappedBy = "myResource", cascade = CascadeType.ALL, fetch = FetchType.LAZY, orphanRemoval = true)
private Set<ResourceTag> myTags; private Set<ResourceTag> myTags;
@Transient
private transient boolean myUnchangedInCurrentOperation;
@Column(name = "RES_VER") @Column(name = "RES_VER")
private long myVersion; private long myVersion;
@ -398,6 +401,14 @@ public class ResourceTable extends BaseHasResource implements Serializable {
return myParamsUriPopulated; return myParamsUriPopulated;
} }
/**
* Transient (not saved in DB) flag indicating that this resource was found to be unchanged by the current operation
* and was not re-saved in the database
*/
public boolean isUnchangedInCurrentOperation() {
return myUnchangedInCurrentOperation;
}
public void setContentTextParsedIntoWords(String theContentText) { public void setContentTextParsedIntoWords(String theContentText) {
myContentText = theContentText; myContentText = theContentText;
} }
@ -532,6 +543,14 @@ public class ResourceTable extends BaseHasResource implements Serializable {
myResourceType = theResourceType; myResourceType = theResourceType;
} }
/**
* Transient (not saved in DB) flag indicating that this resource was found to be unchanged by the current operation
* and was not re-saved in the database
*/
public void setUnchangedInCurrentOperation(boolean theUnchangedInCurrentOperation) {
myUnchangedInCurrentOperation = theUnchangedInCurrentOperation;
}
public void setVersion(long theVersion) { public void setVersion(long theVersion) {
myVersion = theVersion; myVersion = theVersion;
} }

View File

@ -23,23 +23,59 @@ import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.verifyNoMoreInteractions;
import java.io.IOException; import java.util.ArrayList;
import java.util.*; import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
import java.util.Set;
import org.apache.commons.io.IOUtils; import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.RandomStringUtils; import org.apache.commons.lang3.RandomStringUtils;
import org.hamcrest.Matchers; import org.hamcrest.Matchers;
import org.hamcrest.core.StringContains; import org.hamcrest.core.StringContains;
import org.hl7.fhir.dstu3.model.*; import org.hl7.fhir.dstu3.model.Age;
import org.hl7.fhir.dstu3.model.Bundle;
import org.hl7.fhir.dstu3.model.Bundle.BundleEntryComponent; import org.hl7.fhir.dstu3.model.Bundle.BundleEntryComponent;
import org.hl7.fhir.dstu3.model.Bundle.BundleType; import org.hl7.fhir.dstu3.model.Bundle.BundleType;
import org.hl7.fhir.dstu3.model.Bundle.HTTPVerb; import org.hl7.fhir.dstu3.model.Bundle.HTTPVerb;
import org.hl7.fhir.dstu3.model.CarePlan;
import org.hl7.fhir.dstu3.model.CodeSystem;
import org.hl7.fhir.dstu3.model.CodeType;
import org.hl7.fhir.dstu3.model.CodeableConcept;
import org.hl7.fhir.dstu3.model.Coding;
import org.hl7.fhir.dstu3.model.CompartmentDefinition;
import org.hl7.fhir.dstu3.model.ConceptMap;
import org.hl7.fhir.dstu3.model.Condition;
import org.hl7.fhir.dstu3.model.DateTimeType;
import org.hl7.fhir.dstu3.model.DateType;
import org.hl7.fhir.dstu3.model.Device;
import org.hl7.fhir.dstu3.model.DiagnosticReport;
import org.hl7.fhir.dstu3.model.Encounter;
import org.hl7.fhir.dstu3.model.Enumerations.AdministrativeGender; import org.hl7.fhir.dstu3.model.Enumerations.AdministrativeGender;
import org.hl7.fhir.dstu3.model.Enumerations.PublicationStatus; import org.hl7.fhir.dstu3.model.Enumerations.PublicationStatus;
import org.hl7.fhir.dstu3.model.IdType;
import org.hl7.fhir.dstu3.model.Meta;
import org.hl7.fhir.dstu3.model.NamingSystem;
import org.hl7.fhir.dstu3.model.Observation;
import org.hl7.fhir.dstu3.model.Observation.ObservationStatus; import org.hl7.fhir.dstu3.model.Observation.ObservationStatus;
import org.hl7.fhir.dstu3.model.OperationDefinition;
import org.hl7.fhir.dstu3.model.OperationOutcome;
import org.hl7.fhir.dstu3.model.OperationOutcome.IssueSeverity; import org.hl7.fhir.dstu3.model.OperationOutcome.IssueSeverity;
import org.hl7.fhir.dstu3.model.OperationOutcome.IssueType; import org.hl7.fhir.dstu3.model.OperationOutcome.IssueType;
import org.hl7.fhir.dstu3.model.Organization;
import org.hl7.fhir.dstu3.model.Patient;
import org.hl7.fhir.dstu3.model.Period;
import org.hl7.fhir.dstu3.model.Quantity;
import org.hl7.fhir.dstu3.model.Quantity.QuantityComparator; import org.hl7.fhir.dstu3.model.Quantity.QuantityComparator;
import org.hl7.fhir.dstu3.model.Questionnaire;
import org.hl7.fhir.dstu3.model.Range;
import org.hl7.fhir.dstu3.model.Reference;
import org.hl7.fhir.dstu3.model.SimpleQuantity;
import org.hl7.fhir.dstu3.model.StringType;
import org.hl7.fhir.dstu3.model.StructureDefinition;
import org.hl7.fhir.dstu3.model.Timing;
import org.hl7.fhir.dstu3.model.UriType;
import org.hl7.fhir.instance.model.api.IAnyResource; import org.hl7.fhir.instance.model.api.IAnyResource;
import org.hl7.fhir.instance.model.api.IBaseResource; import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.instance.model.api.IIdType; import org.hl7.fhir.instance.model.api.IIdType;
@ -49,14 +85,22 @@ import org.junit.Before;
import org.junit.Ignore; import org.junit.Ignore;
import org.junit.Test; import org.junit.Test;
import org.mockito.ArgumentCaptor; import org.mockito.ArgumentCaptor;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus; import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.*; import org.springframework.transaction.support.TransactionCallbackWithoutResult;
import org.springframework.transaction.support.TransactionTemplate;
import com.google.common.base.Charsets; import com.google.common.base.Charsets;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import ca.uhn.fhir.jpa.dao.*; import ca.uhn.fhir.jpa.dao.BaseHapiFhirDao;
import ca.uhn.fhir.jpa.entity.*; import ca.uhn.fhir.jpa.dao.DaoConfig;
import ca.uhn.fhir.jpa.dao.IFhirResourceDao;
import ca.uhn.fhir.jpa.dao.SearchParameterMap;
import ca.uhn.fhir.jpa.entity.ResourceEncodingEnum;
import ca.uhn.fhir.jpa.entity.ResourceIndexedSearchParamString;
import ca.uhn.fhir.jpa.entity.ResourceTable;
import ca.uhn.fhir.jpa.entity.TagTypeEnum;
import ca.uhn.fhir.model.api.Include; import ca.uhn.fhir.model.api.Include;
import ca.uhn.fhir.model.api.ResourceMetadataKeyEnum; import ca.uhn.fhir.model.api.ResourceMetadataKeyEnum;
import ca.uhn.fhir.model.dstu.valueset.QuantityCompararatorEnum; import ca.uhn.fhir.model.dstu.valueset.QuantityCompararatorEnum;
@ -67,10 +111,21 @@ import ca.uhn.fhir.rest.api.MethodOutcome;
import ca.uhn.fhir.rest.api.RestOperationTypeEnum; import ca.uhn.fhir.rest.api.RestOperationTypeEnum;
import ca.uhn.fhir.rest.api.SortOrderEnum; import ca.uhn.fhir.rest.api.SortOrderEnum;
import ca.uhn.fhir.rest.api.SortSpec; import ca.uhn.fhir.rest.api.SortSpec;
import ca.uhn.fhir.rest.param.*; import ca.uhn.fhir.rest.param.DateParam;
import ca.uhn.fhir.rest.param.DateRangeParam;
import ca.uhn.fhir.rest.param.QuantityParam;
import ca.uhn.fhir.rest.param.ReferenceParam;
import ca.uhn.fhir.rest.param.StringParam;
import ca.uhn.fhir.rest.param.TokenOrListParam;
import ca.uhn.fhir.rest.param.TokenParam;
import ca.uhn.fhir.rest.server.Constants; import ca.uhn.fhir.rest.server.Constants;
import ca.uhn.fhir.rest.server.IBundleProvider; import ca.uhn.fhir.rest.server.IBundleProvider;
import ca.uhn.fhir.rest.server.exceptions.*; import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import ca.uhn.fhir.rest.server.exceptions.PreconditionFailedException;
import ca.uhn.fhir.rest.server.exceptions.ResourceGoneException;
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
import ca.uhn.fhir.rest.server.exceptions.ResourceVersionConflictException;
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor.ActionRequestDetails; import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor.ActionRequestDetails;
import ca.uhn.fhir.util.TestUtil; import ca.uhn.fhir.util.TestUtil;
@ -258,7 +313,7 @@ public class FhirResourceDaoDstu3Test extends BaseJpaDstu3Test {
final IIdType id = myPatientDao.create(p).getId().toUnqualifiedVersionless(); final IIdType id = myPatientDao.create(p).getId().toUnqualifiedVersionless();
TransactionTemplate tx = new TransactionTemplate(myTxManager); TransactionTemplate tx = new TransactionTemplate(myTxManager);
tx.setPropagationBehavior(TransactionTemplate.PROPAGATION_REQUIRES_NEW); tx.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
tx.execute(new TransactionCallbackWithoutResult() { tx.execute(new TransactionCallbackWithoutResult() {
@Override @Override
protected void doInTransactionWithoutResult(TransactionStatus theStatus) { protected void doInTransactionWithoutResult(TransactionStatus theStatus) {
@ -593,15 +648,15 @@ public class FhirResourceDaoDstu3Test extends BaseJpaDstu3Test {
* If any of this ever fails, it means that one of the OperationOutcome issue severity codes has changed code value across versions. We store the string as a constant, so something will need to * If any of this ever fails, it means that one of the OperationOutcome issue severity codes has changed code value across versions. We store the string as a constant, so something will need to
* be fixed. * be fixed.
*/ */
assertEquals(org.hl7.fhir.instance.model.OperationOutcome.IssueSeverity.ERROR.toCode(), BaseHapiFhirResourceDao.OO_SEVERITY_ERROR); assertEquals(org.hl7.fhir.instance.model.OperationOutcome.IssueSeverity.ERROR.toCode(), BaseHapiFhirDao.OO_SEVERITY_ERROR);
assertEquals(ca.uhn.fhir.model.dstu.valueset.IssueSeverityEnum.ERROR.getCode(), BaseHapiFhirResourceDao.OO_SEVERITY_ERROR); assertEquals(ca.uhn.fhir.model.dstu.valueset.IssueSeverityEnum.ERROR.getCode(), BaseHapiFhirDao.OO_SEVERITY_ERROR);
assertEquals(org.hl7.fhir.dstu3.model.OperationOutcome.IssueSeverity.ERROR.toCode(), BaseHapiFhirResourceDao.OO_SEVERITY_ERROR); assertEquals(org.hl7.fhir.dstu3.model.OperationOutcome.IssueSeverity.ERROR.toCode(), BaseHapiFhirDao.OO_SEVERITY_ERROR);
assertEquals(org.hl7.fhir.instance.model.OperationOutcome.IssueSeverity.INFORMATION.toCode(), BaseHapiFhirResourceDao.OO_SEVERITY_INFO); assertEquals(org.hl7.fhir.instance.model.OperationOutcome.IssueSeverity.INFORMATION.toCode(), BaseHapiFhirDao.OO_SEVERITY_INFO);
assertEquals(ca.uhn.fhir.model.dstu.valueset.IssueSeverityEnum.INFORMATION.getCode(), BaseHapiFhirResourceDao.OO_SEVERITY_INFO); assertEquals(ca.uhn.fhir.model.dstu.valueset.IssueSeverityEnum.INFORMATION.getCode(), BaseHapiFhirDao.OO_SEVERITY_INFO);
assertEquals(org.hl7.fhir.dstu3.model.OperationOutcome.IssueSeverity.INFORMATION.toCode(), BaseHapiFhirResourceDao.OO_SEVERITY_INFO); assertEquals(org.hl7.fhir.dstu3.model.OperationOutcome.IssueSeverity.INFORMATION.toCode(), BaseHapiFhirDao.OO_SEVERITY_INFO);
assertEquals(org.hl7.fhir.instance.model.OperationOutcome.IssueSeverity.WARNING.toCode(), BaseHapiFhirResourceDao.OO_SEVERITY_WARN); assertEquals(org.hl7.fhir.instance.model.OperationOutcome.IssueSeverity.WARNING.toCode(), BaseHapiFhirDao.OO_SEVERITY_WARN);
assertEquals(ca.uhn.fhir.model.dstu.valueset.IssueSeverityEnum.WARNING.getCode(), BaseHapiFhirResourceDao.OO_SEVERITY_WARN); assertEquals(ca.uhn.fhir.model.dstu.valueset.IssueSeverityEnum.WARNING.getCode(), BaseHapiFhirDao.OO_SEVERITY_WARN);
assertEquals(org.hl7.fhir.dstu3.model.OperationOutcome.IssueSeverity.WARNING.toCode(), BaseHapiFhirResourceDao.OO_SEVERITY_WARN); assertEquals(org.hl7.fhir.dstu3.model.OperationOutcome.IssueSeverity.WARNING.toCode(), BaseHapiFhirDao.OO_SEVERITY_WARN);
} }
@Test @Test
@ -2010,7 +2065,7 @@ public class FhirResourceDaoDstu3Test extends BaseJpaDstu3Test {
* See #534 * See #534
*/ */
@Test @Test
public void testLogicalReferencesAreSearchable() throws IOException { public void testLogicalReferencesAreSearchable() {
myDaoConfig.setTreatReferencesAsLogical(null); myDaoConfig.setTreatReferencesAsLogical(null);
myDaoConfig.addTreatReferencesAsLogical("http://foo.com/identifier*"); myDaoConfig.addTreatReferencesAsLogical("http://foo.com/identifier*");
@ -2288,7 +2343,7 @@ public class FhirResourceDaoDstu3Test extends BaseJpaDstu3Test {
} }
@Test @Test
public void testReadForcedIdVersionHistory() throws InterruptedException { public void testReadForcedIdVersionHistory() {
Patient p1 = new Patient(); Patient p1 = new Patient();
p1.addIdentifier().setSystem("urn:system").setValue("testReadVorcedIdVersionHistory01"); p1.addIdentifier().setSystem("urn:system").setValue("testReadVorcedIdVersionHistory01");
p1.setId("testReadVorcedIdVersionHistory"); p1.setId("testReadVorcedIdVersionHistory");
@ -2809,21 +2864,21 @@ public class FhirResourceDaoDstu3Test extends BaseJpaDstu3Test {
pm = new SearchParameterMap(); pm = new SearchParameterMap();
pm.add(Patient.SP_IDENTIFIER, new TokenParam("urn:system", methodName)); pm.add(Patient.SP_IDENTIFIER, new TokenParam("urn:system", methodName));
pm.setSort(new SortSpec(BaseResource.SP_RES_ID)); pm.setSort(new SortSpec(IAnyResource.SP_RES_ID));
actual = toUnqualifiedVersionlessIds(myPatientDao.search(pm)); actual = toUnqualifiedVersionlessIds(myPatientDao.search(pm));
assertEquals(5, actual.size()); assertEquals(5, actual.size());
assertThat(actual, contains(idMethodName, id1, id2, id3, id4)); assertThat(actual, contains(idMethodName, id1, id2, id3, id4));
pm = new SearchParameterMap(); pm = new SearchParameterMap();
pm.add(Patient.SP_IDENTIFIER, new TokenParam("urn:system", methodName)); pm.add(Patient.SP_IDENTIFIER, new TokenParam("urn:system", methodName));
pm.setSort(new SortSpec(BaseResource.SP_RES_ID).setOrder(SortOrderEnum.ASC)); pm.setSort(new SortSpec(IAnyResource.SP_RES_ID).setOrder(SortOrderEnum.ASC));
actual = toUnqualifiedVersionlessIds(myPatientDao.search(pm)); actual = toUnqualifiedVersionlessIds(myPatientDao.search(pm));
assertEquals(5, actual.size()); assertEquals(5, actual.size());
assertThat(actual, contains(idMethodName, id1, id2, id3, id4)); assertThat(actual, contains(idMethodName, id1, id2, id3, id4));
pm = new SearchParameterMap(); pm = new SearchParameterMap();
pm.add(Patient.SP_IDENTIFIER, new TokenParam("urn:system", methodName)); pm.add(Patient.SP_IDENTIFIER, new TokenParam("urn:system", methodName));
pm.setSort(new SortSpec(BaseResource.SP_RES_ID).setOrder(SortOrderEnum.DESC)); pm.setSort(new SortSpec(IAnyResource.SP_RES_ID).setOrder(SortOrderEnum.DESC));
actual = toUnqualifiedVersionlessIds(myPatientDao.search(pm)); actual = toUnqualifiedVersionlessIds(myPatientDao.search(pm));
assertEquals(5, actual.size()); assertEquals(5, actual.size());
assertThat(actual, contains(id4, id3, id2, id1, idMethodName)); assertThat(actual, contains(id4, id3, id2, id1, idMethodName));
@ -3218,13 +3273,13 @@ public class FhirResourceDaoDstu3Test extends BaseJpaDstu3Test {
SearchParameterMap map; SearchParameterMap map;
map = new SearchParameterMap(); map = new SearchParameterMap();
map.add(BaseResource.SP_RES_ID, new StringParam(id1.getIdPart())); map.add(IAnyResource.SP_RES_ID, new StringParam(id1.getIdPart()));
map.setLastUpdated(new DateRangeParam("2001", "2003")); map.setLastUpdated(new DateRangeParam("2001", "2003"));
map.setSort(new SortSpec(Constants.PARAM_LASTUPDATED)); map.setSort(new SortSpec(Constants.PARAM_LASTUPDATED));
assertThat(toUnqualifiedVersionlessIds(myPatientDao.search(map)), empty()); assertThat(toUnqualifiedVersionlessIds(myPatientDao.search(map)), empty());
map = new SearchParameterMap(); map = new SearchParameterMap();
map.add(BaseResource.SP_RES_ID, new StringParam(id1.getIdPart())); map.add(IAnyResource.SP_RES_ID, new StringParam(id1.getIdPart()));
map.setLastUpdated(new DateRangeParam("2001", "2003")); map.setLastUpdated(new DateRangeParam("2001", "2003"));
map.setSort(new SortSpec(Patient.SP_NAME)); map.setSort(new SortSpec(Patient.SP_NAME));
assertThat(toUnqualifiedVersionlessIds(myPatientDao.search(map)), empty()); assertThat(toUnqualifiedVersionlessIds(myPatientDao.search(map)), empty());
@ -3361,7 +3416,7 @@ public class FhirResourceDaoDstu3Test extends BaseJpaDstu3Test {
assertEquals("Kittens", published.get(1).getDisplay()); assertEquals("Kittens", published.get(1).getDisplay());
assertEquals("http://foo", published.get(1).getSystem()); assertEquals("http://foo", published.get(1).getSystem());
secLabels = (ArrayList<Coding>) retrieved.getMeta().getSecurity(); secLabels = retrieved.getMeta().getSecurity();
sortCodings(secLabels); sortCodings(secLabels);
assertEquals(2, secLabels.size()); assertEquals(2, secLabels.size());
assertEquals("seclabel:sys:1", secLabels.get(0).getSystemElement().getValue()); assertEquals("seclabel:sys:1", secLabels.get(0).getSystemElement().getValue());

View File

@ -46,19 +46,130 @@ import ca.uhn.fhir.rest.param.StringParam;
import ca.uhn.fhir.rest.server.IBundleProvider; import ca.uhn.fhir.rest.server.IBundleProvider;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException; import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import ca.uhn.fhir.rest.server.exceptions.ResourceGoneException; 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 ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor.ActionRequestDetails; import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor.ActionRequestDetails;
import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails;
import ca.uhn.fhir.util.TestUtil; import ca.uhn.fhir.util.TestUtil;
public class FhirResourceDaoDstu3UpdateTest extends BaseJpaDstu3Test { public class FhirResourceDaoDstu3UpdateTest extends BaseJpaDstu3Test {
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(FhirResourceDaoDstu3UpdateTest.class); private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(FhirResourceDaoDstu3UpdateTest.class);
@AfterClass @Test
public static void afterClassClearContext() { public void testCreateAndUpdateWithoutRequest() throws Exception {
TestUtil.clearAllStaticFieldsForUnitTest(); String methodName = "testUpdateByUrl";
Patient p = new Patient();
p.addIdentifier().setSystem("urn:system").setValue(methodName + "2");
IIdType id = myPatientDao.create(p).getId().toUnqualified();
p = new Patient();
p.addIdentifier().setSystem("urn:system").setValue(methodName + "2");
p.setActive(true);
IIdType id2 = myPatientDao.create(p, "Patient?identifier=urn:system|" + methodName + "2").getId().toUnqualified();
assertEquals(id.getValue(), id2.getValue());
p = new Patient();
p.setId(id);
p.addIdentifier().setSystem("urn:system").setValue(methodName + "2");
p.setActive(false);
myPatientDao.update(p).getId();
p.setActive(true);
id2 = myPatientDao.update(p, "Patient?identifier=urn:system|" + methodName + "2").getId().toUnqualified();
assertEquals(id.getIdPart(), id2.getIdPart());
assertEquals("3", id2.getVersionIdPart());
Patient newPatient = myPatientDao.read(id);
assertEquals("1", newPatient.getIdElement().getVersionIdPart());
newPatient = myPatientDao.read(id.toVersionless());
assertEquals("3", newPatient.getIdElement().getVersionIdPart());
myPatientDao.delete(id.toVersionless());
try {
myPatientDao.read(id.toVersionless());
fail();
} catch (ResourceGoneException e) {
// nothing
}
} }
@Test
public void testDuplicateProfilesIgnored() {
String name = "testDuplicateProfilesIgnored";
IIdType id;
{
Patient patient = new Patient();
patient.addName().setFamily(name);
List<IdType> tl = new ArrayList<IdType>();
tl.add(new IdType("http://foo/bar"));
tl.add(new IdType("http://foo/bar"));
tl.add(new IdType("http://foo/bar"));
patient.getMeta().getProfile().addAll(tl);
id = myPatientDao.create(patient, mySrd).getId().toUnqualifiedVersionless();
}
// Do a read
{
Patient patient = myPatientDao.read(id, mySrd);
List<UriType> tl = patient.getMeta().getProfile();
assertEquals(1, tl.size());
assertEquals("http://foo/bar", tl.get(0).getValue());
}
}
@Test
public void testMultipleUpdatesWithNoChangesDoesNotResultInAnUpdateForDiscreteUpdates() {
// First time
Patient p = new Patient();
p.setActive(true);
p.setId("Patient/A");
String id = myPatientDao.update(p).getId().getValue();
assertThat(id, endsWith("Patient/A/_history/1"));
// Second time should not result in an update
p = new Patient();
p.setActive(true);
p.setId("Patient/A");
id = myPatientDao.update(p).getId().getValue();
assertThat(id, endsWith("Patient/A/_history/1"));
// And third time should not result in an update
p = new Patient();
p.setActive(true);
p.setId("Patient/A");
id = myPatientDao.update(p).getId().getValue();
assertThat(id, endsWith("Patient/A/_history/1"));
myPatientDao.read(new IdType("Patient/A"));
myPatientDao.read(new IdType("Patient/A/_history/1"));
try {
myPatientDao.read(new IdType("Patient/A/_history/2"));
fail();
} catch (ResourceNotFoundException e) {
// good
}
try {
myPatientDao.read(new IdType("Patient/A/_history/3"));
fail();
} catch (ResourceNotFoundException e) {
// good
}
// Create one more
p = new Patient();
p.setActive(false);
p.setId("Patient/A");
id = myPatientDao.update(p).getId().getValue();
assertThat(id, endsWith("Patient/A/_history/2"));
}
@Test @Test
public void testUpdateAndGetHistoryResource() throws InterruptedException { public void testUpdateAndGetHistoryResource() throws InterruptedException {
@ -113,14 +224,14 @@ public class FhirResourceDaoDstu3UpdateTest extends BaseJpaDstu3Test {
IBundleProvider historyBundle = myPatientDao.history(outcome.getId(), null, null, mySrd); IBundleProvider historyBundle = myPatientDao.history(outcome.getId(), null, null, mySrd);
assertEquals(2, historyBundle.size().intValue()); assertEquals(2, historyBundle.size().intValue());
List<IBaseResource> history = historyBundle.getResources(0, 2); List<IBaseResource> history = historyBundle.getResources(0, 2);
ourLog.info("updated : {}", updated.getValueAsString()); ourLog.info("updated : {}", updated.getValueAsString());
ourLog.info(" * Exp : {}", ((Resource) history.get(1)).getMeta().getLastUpdatedElement().getValueAsString()); ourLog.info(" * Exp : {}", ((Resource) history.get(1)).getMeta().getLastUpdatedElement().getValueAsString());
ourLog.info("updated2: {}", updated2.getValueAsString()); ourLog.info("updated2: {}", updated2.getValueAsString());
ourLog.info(" * Exp : {}", ((Resource) history.get(0)).getMeta().getLastUpdatedElement().getValueAsString()); ourLog.info(" * Exp : {}", ((Resource) history.get(0)).getMeta().getLastUpdatedElement().getValueAsString());
assertEquals("1", history.get(1).getIdElement().getVersionIdPart()); assertEquals("1", history.get(1).getIdElement().getVersionIdPart());
assertEquals("2", history.get(0).getIdElement().getVersionIdPart()); assertEquals("2", history.get(0).getIdElement().getVersionIdPart());
assertEquals(updated.getValueAsString(), ((Resource) history.get(1)).getMeta().getLastUpdatedElement().getValueAsString()); assertEquals(updated.getValueAsString(), ((Resource) history.get(1)).getMeta().getLastUpdatedElement().getValueAsString());
@ -154,49 +265,6 @@ public class FhirResourceDaoDstu3UpdateTest extends BaseJpaDstu3Test {
} }
@Test
public void testCreateAndUpdateWithoutRequest() throws Exception {
String methodName = "testUpdateByUrl";
Patient p = new Patient();
p.addIdentifier().setSystem("urn:system").setValue(methodName + "2");
IIdType id = myPatientDao.create(p).getId().toUnqualified();
p = new Patient();
p.addIdentifier().setSystem("urn:system").setValue(methodName + "2");
p.setActive(true);
IIdType id2 = myPatientDao.create(p, "Patient?identifier=urn:system|" + methodName + "2").getId().toUnqualified();
assertEquals(id.getValue(), id2.getValue());
p = new Patient();
p.setId(id);
p.addIdentifier().setSystem("urn:system").setValue(methodName + "2");
p.setActive(false);
myPatientDao.update(p).getId();
p.setActive(true);
id2 = myPatientDao.update(p, "Patient?identifier=urn:system|" + methodName + "2").getId().toUnqualified();
assertEquals(id.getIdPart(), id2.getIdPart());
assertEquals("3", id2.getVersionIdPart());
Patient newPatient = myPatientDao.read(id);
assertEquals("1", newPatient.getIdElement().getVersionIdPart());
newPatient = myPatientDao.read(id.toVersionless());
assertEquals("3", newPatient.getIdElement().getVersionIdPart());
myPatientDao.delete(id.toVersionless());
try {
myPatientDao.read(id.toVersionless());
fail();
} catch (ResourceGoneException e) {
// nothing
}
}
@Test @Test
public void testUpdateConditionalByLastUpdated() throws Exception { public void testUpdateConditionalByLastUpdated() throws Exception {
String methodName = "testUpdateByUrl"; String methodName = "testUpdateByUrl";
@ -208,7 +276,7 @@ public class FhirResourceDaoDstu3UpdateTest extends BaseJpaDstu3Test {
InstantDt start = InstantDt.withCurrentTime(); InstantDt start = InstantDt.withCurrentTime();
ourLog.info("First time: {}", start.getValueAsString()); ourLog.info("First time: {}", start.getValueAsString());
Thread.sleep(100); Thread.sleep(100);
p = new Patient(); p = new Patient();
p.addIdentifier().setSystem("urn:system").setValue(methodName); p.addIdentifier().setSystem("urn:system").setValue(methodName);
IIdType id = myPatientDao.create(p, mySrd).getId(); IIdType id = myPatientDao.create(p, mySrd).getId();
@ -237,35 +305,35 @@ public class FhirResourceDaoDstu3UpdateTest extends BaseJpaDstu3Test {
public void testUpdateConditionalByLastUpdatedWithWrongTimezone() throws Exception { public void testUpdateConditionalByLastUpdatedWithWrongTimezone() throws Exception {
TimeZone def = TimeZone.getDefault(); TimeZone def = TimeZone.getDefault();
try { try {
TimeZone.setDefault(TimeZone.getTimeZone("GMT-0:00")); TimeZone.setDefault(TimeZone.getTimeZone("GMT-0:00"));
String methodName = "testUpdateByUrl"; String methodName = "testUpdateByUrl";
Patient p = new Patient(); Patient p = new Patient();
p.addIdentifier().setSystem("urn:system").setValue(methodName + "2"); p.addIdentifier().setSystem("urn:system").setValue(methodName + "2");
myPatientDao.create(p, mySrd).getId(); myPatientDao.create(p, mySrd).getId();
InstantDt start = InstantDt.withCurrentTime(); InstantDt start = InstantDt.withCurrentTime();
Thread.sleep(100); Thread.sleep(100);
p = new Patient();
p.addIdentifier().setSystem("urn:system").setValue(methodName);
IIdType id = myPatientDao.create(p, mySrd).getId();
ourLog.info("Created patient, got it: {}", id);
Thread.sleep(100); p = new Patient();
p.addIdentifier().setSystem("urn:system").setValue(methodName);
IIdType id = myPatientDao.create(p, mySrd).getId();
ourLog.info("Created patient, got it: {}", id);
p = new Patient(); Thread.sleep(100);
p.addIdentifier().setSystem("urn:system").setValue(methodName);
p.addName().setFamily("Hello");
p.setId("Patient/" + methodName);
myPatientDao.update(p, "Patient?_lastUpdated=gt" + start.getValueAsString(), mySrd); p = new Patient();
p.addIdentifier().setSystem("urn:system").setValue(methodName);
p.addName().setFamily("Hello");
p.setId("Patient/" + methodName);
p = myPatientDao.read(id.toVersionless(), mySrd); myPatientDao.update(p, "Patient?_lastUpdated=gt" + start.getValueAsString(), mySrd);
assertThat(p.getIdElement().toVersionless().toString(), not(containsString("test")));
assertEquals(id.toVersionless(), p.getIdElement().toVersionless()); p = myPatientDao.read(id.toVersionless(), mySrd);
assertNotEquals(id, p.getIdElement()); assertThat(p.getIdElement().toVersionless().toString(), not(containsString("test")));
assertThat(p.getIdElement().toString(), endsWith("/_history/2")); assertEquals(id.toVersionless(), p.getIdElement().toVersionless());
assertNotEquals(id, p.getIdElement());
assertThat(p.getIdElement().toString(), endsWith("/_history/2"));
} finally { } finally {
TimeZone.setDefault(def); TimeZone.setDefault(def);
} }
@ -296,57 +364,27 @@ public class FhirResourceDaoDstu3UpdateTest extends BaseJpaDstu3Test {
myPatientDao.update(p, mySrd); myPatientDao.update(p, mySrd);
} }
/**
* Per the spec, update should preserve tags and security labels but not profiles
*/
@Test @Test
public void testUpdateMaintainsTagsAndSecurityLabels() throws InterruptedException { @Ignore
String methodName = "testUpdateMaintainsTagsAndSecurityLabels"; public void testUpdateIgnoresIdenticalVersions() {
String methodName = "testUpdateIgnoresIdenticalVersions";
IIdType p1id; Patient p1 = new Patient();
{ p1.addIdentifier().setSystem("urn:system").setValue(methodName);
Patient p1 = new Patient(); p1.addName().setFamily("Tester").addGiven(methodName);
p1.addName().setFamily(methodName); IIdType p1id = myPatientDao.create(p1, mySrd).getId();
p1.getMeta().addTag("tag_scheme1", "tag_term1",null);
p1.getMeta().addSecurity("sec_scheme1", "sec_term1",null);
p1.getMeta().addProfile("http://foo1");
p1id = myPatientDao.create(p1, mySrd).getId().toUnqualifiedVersionless(); IIdType p1id2 = myPatientDao.update(p1, mySrd).getId();
} assertEquals(p1id.getValue(), p1id2.getValue());
{
Patient p1 = new Patient();
p1.setId(p1id);
p1.addName().setFamily(methodName);
p1.getMeta().addTag("tag_scheme2", "tag_term2", null); p1.addName().addGiven("NewGiven");
p1.getMeta().addSecurity("sec_scheme2", "sec_term2", null); IIdType p1id3 = myPatientDao.update(p1, mySrd).getId();
p1.getMeta().addProfile("http://foo2"); assertNotEquals(p1id.getValue(), p1id3.getValue());
myPatientDao.update(p1, mySrd);
}
{
Patient p1 = myPatientDao.read(p1id, mySrd);
List<Coding> tagList = p1.getMeta().getTag();
Set<String> secListValues = new HashSet<String>();
for (Coding next : tagList) {
secListValues.add(next.getSystemElement().getValue() + "|" + next.getCodeElement().getValue());
}
assertThat(secListValues, containsInAnyOrder("tag_scheme1|tag_term1", "tag_scheme2|tag_term2"));
List<Coding> secList = p1.getMeta().getSecurity();
secListValues = new HashSet<String>();
for (Coding next : secList) {
secListValues.add(next.getSystemElement().getValue() + "|" + next.getCodeElement().getValue());
}
assertThat(secListValues, containsInAnyOrder("sec_scheme1|sec_term1", "sec_scheme2|sec_term2"));
List<UriType> profileList = p1.getMeta().getProfile();
assertEquals(1, profileList.size());
assertEquals("http://foo2", profileList.get(0).getValueAsString()); // no foo1
}
} }
@Test @Test
public void testUpdateMaintainsSearchParams() throws InterruptedException { public void testUpdateMaintainsSearchParams() {
Patient p1 = new Patient(); Patient p1 = new Patient();
p1.addIdentifier().setSystem("urn:system").setValue("testUpdateMaintainsSearchParamsDstu2AAA"); p1.addIdentifier().setSystem("urn:system").setValue("testUpdateMaintainsSearchParamsDstu2AAA");
p1.addName().setFamily("Tester").addGiven("testUpdateMaintainsSearchParamsDstu2AAA"); p1.addName().setFamily("Tester").addGiven("testUpdateMaintainsSearchParamsDstu2AAA");
@ -381,77 +419,53 @@ public class FhirResourceDaoDstu3UpdateTest extends BaseJpaDstu3Test {
} }
/**
* Per the spec, update should preserve tags and security labels but not profiles
*/
@Test @Test
public void testUpdateRejectsInvalidTypes() throws InterruptedException { public void testUpdateMaintainsTagsAndSecurityLabels() {
Patient p1 = new Patient(); String methodName = "testUpdateMaintainsTagsAndSecurityLabels";
p1.addIdentifier().setSystem("urn:system").setValue("testUpdateRejectsInvalidTypes");
p1.addName().setFamily("Tester").addGiven("testUpdateRejectsInvalidTypes");
IIdType p1id = myPatientDao.create(p1, mySrd).getId();
Organization p2 = new Organization(); IIdType p1id;
p2.getNameElement().setValue("testUpdateRejectsInvalidTypes");
try {
p2.setId(new IdType("Organization/" + p1id.getIdPart()));
myOrganizationDao.update(p2, mySrd);
fail();
} catch (UnprocessableEntityException e) {
// good
}
try {
p2.setId(new IdType("Patient/" + p1id.getIdPart()));
myOrganizationDao.update(p2, mySrd);
fail();
} catch (UnprocessableEntityException e) {
ourLog.error("Good", e);
}
}
@Test
@Ignore
public void testUpdateIgnoresIdenticalVersions() throws InterruptedException {
String methodName = "testUpdateIgnoresIdenticalVersions";
Patient p1 = new Patient();
p1.addIdentifier().setSystem("urn:system").setValue(methodName);
p1.addName().setFamily("Tester").addGiven(methodName);
IIdType p1id = myPatientDao.create(p1, mySrd).getId();
IIdType p1id2 = myPatientDao.update(p1, mySrd).getId();
assertEquals(p1id.getValue(), p1id2.getValue());
p1.addName().addGiven("NewGiven");
IIdType p1id3 = myPatientDao.update(p1, mySrd).getId();
assertNotEquals(p1id.getValue(), p1id3.getValue());
}
@Test
public void testDuplicateProfilesIgnored() {
String name = "testDuplicateProfilesIgnored";
IIdType id;
{ {
Patient patient = new Patient(); Patient p1 = new Patient();
patient.addName().setFamily(name); p1.addName().setFamily(methodName);
List<IdType> tl = new ArrayList<IdType>(); p1.getMeta().addTag("tag_scheme1", "tag_term1", null);
tl.add(new IdType("http://foo/bar")); p1.getMeta().addSecurity("sec_scheme1", "sec_term1", null);
tl.add(new IdType("http://foo/bar")); p1.getMeta().addProfile("http://foo1");
tl.add(new IdType("http://foo/bar"));
patient.getMeta().getProfile().addAll(tl);
id = myPatientDao.create(patient, mySrd).getId().toUnqualifiedVersionless(); p1id = myPatientDao.create(p1, mySrd).getId().toUnqualifiedVersionless();
} }
// Do a read
{ {
Patient patient = myPatientDao.read(id, mySrd); Patient p1 = new Patient();
List<UriType> tl = patient.getMeta().getProfile(); p1.setId(p1id);
assertEquals(1, tl.size()); p1.addName().setFamily(methodName);
assertEquals("http://foo/bar", tl.get(0).getValue());
}
p1.getMeta().addTag("tag_scheme2", "tag_term2", null);
p1.getMeta().addSecurity("sec_scheme2", "sec_term2", null);
p1.getMeta().addProfile("http://foo2");
myPatientDao.update(p1, mySrd);
}
{
Patient p1 = myPatientDao.read(p1id, mySrd);
List<Coding> tagList = p1.getMeta().getTag();
Set<String> secListValues = new HashSet<String>();
for (Coding next : tagList) {
secListValues.add(next.getSystemElement().getValue() + "|" + next.getCodeElement().getValue());
}
assertThat(secListValues, containsInAnyOrder("tag_scheme1|tag_term1", "tag_scheme2|tag_term2"));
List<Coding> secList = p1.getMeta().getSecurity();
secListValues = new HashSet<String>();
for (Coding next : secList) {
secListValues.add(next.getSystemElement().getValue() + "|" + next.getCodeElement().getValue());
}
assertThat(secListValues, containsInAnyOrder("sec_scheme1|sec_term1", "sec_scheme2|sec_term2"));
List<UriType> profileList = p1.getMeta().getProfile();
assertEquals(1, profileList.size());
assertEquals("http://foo2", profileList.get(0).getValueAsString()); // no foo1
}
} }
@Test @Test
@ -501,6 +515,33 @@ public class FhirResourceDaoDstu3UpdateTest extends BaseJpaDstu3Test {
} }
@Test
public void testUpdateRejectsInvalidTypes() {
Patient p1 = new Patient();
p1.addIdentifier().setSystem("urn:system").setValue("testUpdateRejectsInvalidTypes");
p1.addName().setFamily("Tester").addGiven("testUpdateRejectsInvalidTypes");
IIdType p1id = myPatientDao.create(p1, mySrd).getId();
Organization p2 = new Organization();
p2.getNameElement().setValue("testUpdateRejectsInvalidTypes");
try {
p2.setId(new IdType("Organization/" + p1id.getIdPart()));
myOrganizationDao.update(p2, mySrd);
fail();
} catch (UnprocessableEntityException e) {
// good
}
try {
p2.setId(new IdType("Patient/" + p1id.getIdPart()));
myOrganizationDao.update(p2, mySrd);
fail();
} catch (UnprocessableEntityException e) {
ourLog.error("Good", e);
}
}
@Test @Test
public void testUpdateUnknownNumericIdFails() { public void testUpdateUnknownNumericIdFails() {
Patient p = new Patient(); Patient p = new Patient();
@ -529,63 +570,10 @@ public class FhirResourceDaoDstu3UpdateTest extends BaseJpaDstu3Test {
} }
} }
@Test
public void testUpdateWithNumericIdFails() {
Patient p = new Patient();
p.addIdentifier().setSystem("urn:system").setValue("testCreateNumericIdFails");
p.addName().setFamily("Hello");
p.setId("Patient/123");
try {
myPatientDao.update(p, mySrd);
fail();
} catch (InvalidRequestException e) {
assertThat(e.getMessage(), containsString("clients may only assign IDs which contain at least one non-numeric"));
}
}
@Test
public void testUpdateWithNumericThenTextIdSucceeds() {
Patient p = new Patient();
p.addIdentifier().setSystem("urn:system").setValue("testCreateNumericIdFails");
p.addName().setFamily("Hello");
p.setId("Patient/123abc");
IIdType id = myPatientDao.update(p, mySrd).getId();
assertEquals("123abc", id.getIdPart());
assertEquals("1", id.getVersionIdPart());
p = myPatientDao.read(id.toUnqualifiedVersionless(), mySrd);
assertEquals("Patient/123abc", p.getIdElement().toUnqualifiedVersionless().getValue());
assertEquals("Hello", p.getName().get(0).getFamily());
}
@Test
public void testUpdateWithNoChangeDetectionUpdateUnchanged() {
String name = "testUpdateUnchanged";
IIdType id1, id2;
{
Patient patient = new Patient();
patient.addName().setFamily(name);
id1 = myPatientDao.create(patient, mySrd).getId().toUnqualified();
}
// Update
{
Patient patient = new Patient();
patient.setId(id1);
patient.addName().setFamily(name);
id2 = myPatientDao.update(patient, mySrd).getId().toUnqualified();
}
assertEquals(id1.getValue(), id2.getValue());
}
@Test @Test
public void testUpdateWithNoChangeDetectionDisabledUpdateUnchanged() { public void testUpdateWithNoChangeDetectionDisabledUpdateUnchanged() {
myDaoConfig.setSuppressUpdatesWithNoChange(false); myDaoConfig.setSuppressUpdatesWithNoChange(false);
String name = "testUpdateUnchanged"; String name = "testUpdateUnchanged";
IIdType id1, id2; IIdType id1, id2;
{ {
@ -626,7 +614,39 @@ public class FhirResourceDaoDstu3UpdateTest extends BaseJpaDstu3Test {
assertNotEquals(id1.getValue(), id2.getValue()); assertNotEquals(id1.getValue(), id2.getValue());
} }
@Test
public void testUpdateWithNoChangeDetectionUpdateTagMetaRemoved() {
String name = "testUpdateUnchanged";
IIdType id1, id2;
{
Patient patient = new Patient();
patient.getMeta().addTag().setCode("CODE");
patient.addName().setFamily(name);
id1 = myPatientDao.create(patient, mySrd).getId().toUnqualified();
}
Meta meta = new Meta();
meta.addTag().setCode("CODE");
myPatientDao.metaDeleteOperation(id1, meta, null);
meta = myPatientDao.metaGetOperation(Meta.class, id1, null);
assertEquals(0, meta.getTag().size());
// Update
{
Patient patient = new Patient();
patient.setId(id1);
patient.addName().setFamily(name);
id2 = myPatientDao.update(patient, mySrd).getId().toUnqualified();
}
assertEquals(id1.getValue(), id2.getValue());
meta = myPatientDao.metaGetOperation(Meta.class, id2, null);
assertEquals(0, meta.getTag().size());
}
@Test @Test
public void testUpdateWithNoChangeDetectionUpdateTagNoChange() { public void testUpdateWithNoChangeDetectionUpdateTagNoChange() {
String name = "testUpdateUnchanged"; String name = "testUpdateUnchanged";
@ -641,7 +661,7 @@ public class FhirResourceDaoDstu3UpdateTest extends BaseJpaDstu3Test {
Meta meta = new Meta(); Meta meta = new Meta();
meta.addTag().setCode("CODE"); meta.addTag().setCode("CODE");
myPatientDao.metaAddOperation(id1, meta, null); myPatientDao.metaAddOperation(id1, meta, null);
// Update with tag // Update with tag
{ {
Patient patient = new Patient(); Patient patient = new Patient();
@ -652,7 +672,7 @@ public class FhirResourceDaoDstu3UpdateTest extends BaseJpaDstu3Test {
} }
assertEquals(id1.getValue(), id2.getValue()); assertEquals(id1.getValue(), id2.getValue());
meta = myPatientDao.metaGetOperation(Meta.class, id2, null); meta = myPatientDao.metaGetOperation(Meta.class, id2, null);
assertEquals(1, meta.getTag().size()); assertEquals(1, meta.getTag().size());
assertEquals("CODE", meta.getTag().get(0).getCode()); assertEquals("CODE", meta.getTag().get(0).getCode());
@ -678,31 +698,22 @@ public class FhirResourceDaoDstu3UpdateTest extends BaseJpaDstu3Test {
} }
assertEquals(id1.getValue(), id2.getValue()); assertEquals(id1.getValue(), id2.getValue());
Meta meta = myPatientDao.metaGetOperation(Meta.class, id2, null); Meta meta = myPatientDao.metaGetOperation(Meta.class, id2, null);
assertEquals(1, meta.getTag().size()); assertEquals(1, meta.getTag().size());
assertEquals("CODE", meta.getTag().get(0).getCode()); assertEquals("CODE", meta.getTag().get(0).getCode());
} }
@Test @Test
public void testUpdateWithNoChangeDetectionUpdateTagMetaRemoved() { public void testUpdateWithNoChangeDetectionUpdateUnchanged() {
String name = "testUpdateUnchanged"; String name = "testUpdateUnchanged";
IIdType id1, id2; IIdType id1, id2;
{ {
Patient patient = new Patient(); Patient patient = new Patient();
patient.getMeta().addTag().setCode("CODE");
patient.addName().setFamily(name); patient.addName().setFamily(name);
id1 = myPatientDao.create(patient, mySrd).getId().toUnqualified(); id1 = myPatientDao.create(patient, mySrd).getId().toUnqualified();
} }
Meta meta = new Meta();
meta.addTag().setCode("CODE");
myPatientDao.metaDeleteOperation(id1, meta, null);
meta = myPatientDao.metaGetOperation(Meta.class, id1, null);
assertEquals(0, meta.getTag().size());
// Update // Update
{ {
Patient patient = new Patient(); Patient patient = new Patient();
@ -712,9 +723,41 @@ public class FhirResourceDaoDstu3UpdateTest extends BaseJpaDstu3Test {
} }
assertEquals(id1.getValue(), id2.getValue()); assertEquals(id1.getValue(), id2.getValue());
}
meta = myPatientDao.metaGetOperation(Meta.class, id2, null);
assertEquals(0, meta.getTag().size()); @Test
public void testUpdateWithNumericIdFails() {
Patient p = new Patient();
p.addIdentifier().setSystem("urn:system").setValue("testCreateNumericIdFails");
p.addName().setFamily("Hello");
p.setId("Patient/123");
try {
myPatientDao.update(p, mySrd);
fail();
} catch (InvalidRequestException e) {
assertThat(e.getMessage(), containsString("clients may only assign IDs which contain at least one non-numeric"));
}
}
@Test
public void testUpdateWithNumericThenTextIdSucceeds() {
Patient p = new Patient();
p.addIdentifier().setSystem("urn:system").setValue("testCreateNumericIdFails");
p.addName().setFamily("Hello");
p.setId("Patient/123abc");
IIdType id = myPatientDao.update(p, mySrd).getId();
assertEquals("123abc", id.getIdPart());
assertEquals("1", id.getVersionIdPart());
p = myPatientDao.read(id.toUnqualifiedVersionless(), mySrd);
assertEquals("Patient/123abc", p.getIdElement().toUnqualifiedVersionless().getValue());
assertEquals("Hello", p.getName().get(0).getFamily());
}
@AfterClass
public static void afterClassClearContext() {
TestUtil.clearAllStaticFieldsForUnitTest();
} }
} }

View File

@ -36,7 +36,15 @@
Search results will be cached and reused (so that if a client Search results will be cached and reused (so that if a client
does two searches for "get me all patients matching FOO" does two searches for "get me all patients matching FOO"
with the same FOO in short succession, we won't query the DB with the same FOO in short succession, we won't query the DB
again but will instead reuse the cached results) again but will instead reuse the cached results). Note that
this can improve performance, but does mean that searches can
return slightly out of date results. Essentially what this means
is that the latest version of individual resources will always
be returned despite this cacheing, but newly created resources
that should match may not be returned until the cache
expires. By default this cache has been set to one minute,
which should be acceptable for most real-world usage, but
this can be changed or disabled entirely.
</li> </li>
<li> <li>
Updates which do not actually change the contents of the resource Updates which do not actually change the contents of the resource
@ -50,7 +58,8 @@
<code>HFJ_SEARCH_INCLUDE</code>, <code>HFJ_SEARCH_INCLUDE</code>,
and and
<code>HFJ_SEARCH_RESULT</code> <code>HFJ_SEARCH_RESULT</code>
tables from your database before upgrading. tables from your database before upgrading, as the structure of these tables
has changed and old search results can not be reused.
]]> ]]>
</action> </action>
<action type="fix" issue="590"> <action type="fix" issue="590">