Accept conditional updates with _id as parameter
This commit is contained in:
parent
309b67c010
commit
7942d69d5d
|
@ -83,16 +83,6 @@ class ConditionalParamBinder implements IParameter {
|
|||
if (theRequest.getId() != null && theRequest.getId().hasIdPart()) {
|
||||
return null;
|
||||
}
|
||||
boolean haveParam = false;
|
||||
for (String next : theRequest.getParameters().keySet()) {
|
||||
if (!next.startsWith("_")) {
|
||||
haveParam=true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!haveParam) {
|
||||
return null;
|
||||
}
|
||||
|
||||
int questionMarkIndex = theRequest.getCompleteUrl().indexOf('?');
|
||||
return theRequest.getResourceName() + theRequest.getCompleteUrl().substring(questionMarkIndex);
|
||||
|
|
|
@ -528,6 +528,40 @@ public class FhirSystemDaoDstu3Test extends BaseJpaDstu3SystemTest {
|
|||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTransactionCreateInlineMatchUrlWithOneMatchLastUpdated() {
|
||||
Bundle request = new Bundle();
|
||||
Observation o = new Observation();
|
||||
o.getCode().setText("Some Observation");
|
||||
request.addEntry().setResource(o).getRequest().setMethod(HTTPVerb.POST).setIfNoneExist("Observation?_lastUpdated=gt2011-01-01");
|
||||
Bundle resp = mySystemDao.transaction(mySrd, request);
|
||||
assertEquals(1, resp.getEntry().size());
|
||||
|
||||
BundleEntryComponent respEntry = resp.getEntry().get(0);
|
||||
assertEquals(Constants.STATUS_HTTP_201_CREATED + " Created", respEntry.getResponse().getStatus());
|
||||
assertThat(respEntry.getResponse().getLocation(), containsString("Observation/"));
|
||||
assertThat(respEntry.getResponse().getLocation(), endsWith("/_history/1"));
|
||||
assertEquals("1", respEntry.getResponse().getEtag());
|
||||
|
||||
/*
|
||||
* Second time should not update
|
||||
*/
|
||||
|
||||
request = new Bundle();
|
||||
o = new Observation();
|
||||
o.getCode().setText("Some Observation");
|
||||
request.addEntry().setResource(o).getRequest().setMethod(HTTPVerb.POST).setIfNoneExist("Observation?_lastUpdated=gt2011-01-01");
|
||||
resp = mySystemDao.transaction(mySrd, request);
|
||||
assertEquals(1, resp.getEntry().size());
|
||||
|
||||
respEntry = resp.getEntry().get(0);
|
||||
assertEquals(Constants.STATUS_HTTP_200_OK + " OK", respEntry.getResponse().getStatus());
|
||||
assertThat(respEntry.getResponse().getLocation(), containsString("Observation/"));
|
||||
assertThat(respEntry.getResponse().getLocation(), endsWith("/_history/1"));
|
||||
assertEquals("1", respEntry.getResponse().getEtag());
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTransactionCreateInlineMatchUrlWithNoMatches() {
|
||||
String methodName = "testTransactionCreateInlineMatchUrlWithNoMatches";
|
||||
|
|
|
@ -0,0 +1,57 @@
|
|||
<Bundle xmlns="http://hl7.org/fhir">
|
||||
<type value="transaction"/>
|
||||
<id value="f9935843-19a2-4a1a-4016-7bea52de77f8"/>
|
||||
<entry>
|
||||
<fullUrl value="urn:uuid:47709cc7-b3ec-4abc-9d26-3df3d3d57907"/>
|
||||
<resource>
|
||||
<Practitioner xmlns="http://hl7.org/fhir">
|
||||
<identifier>
|
||||
<use value="official"/>
|
||||
<!--Reuse value from CDA -->
|
||||
<system value="urn:oid:2.16.840.1.113883.2.4.6.3"/>
|
||||
<!--Reuse OIDs from CDA -->
|
||||
<!-- BSN identification system -->
|
||||
<value value="567IUI51C157"/>
|
||||
</identifier>
|
||||
<name>
|
||||
<use value="official"/>
|
||||
<family value="Heps"/>
|
||||
<given value="Simone"/>
|
||||
<suffix value="MD"/>
|
||||
</name>
|
||||
<telecom>
|
||||
<system value="phone"/>
|
||||
<value value="020556936"/>
|
||||
<use value="work"/>
|
||||
</telecom>
|
||||
<telecom>
|
||||
<system value="email"/>
|
||||
<value value="S.M.Heps@bmc.nl"/>
|
||||
<use value="work"/>
|
||||
</telecom>
|
||||
<telecom>
|
||||
<system value="fax"/>
|
||||
<value value="0205669283"/>
|
||||
<use value="work"/>
|
||||
</telecom>
|
||||
<address>
|
||||
<use value="work"/>
|
||||
<line value="Galapagosweg 91"/>
|
||||
<city value="Den Burg"/>
|
||||
<postalCode value="9105 PZ"/>
|
||||
<country value="NLD"/>
|
||||
<!-- ISO 3166 Codes (Countries) -->
|
||||
</address>
|
||||
<gender value="female"/>
|
||||
<birthDate value="1971-11-07"/>
|
||||
</Practitioner>
|
||||
</resource>
|
||||
<request>
|
||||
<!--For this entry we only want to create the practitioner based on the entry data if we dont find one -->
|
||||
<method value="POST"/>
|
||||
<url value="Practitioner"/>
|
||||
<!--Use DrProviderNumber Paul to add more syntax below -->
|
||||
<ifNoneExist value="Practitioner?identifier=567IUI51C157"/>
|
||||
</request>
|
||||
</entry>
|
||||
</Bundle>
|
|
@ -31,6 +31,7 @@ import org.junit.BeforeClass;
|
|||
import org.junit.Test;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.rest.annotation.ConditionalUrlParam;
|
||||
import ca.uhn.fhir.rest.annotation.Create;
|
||||
import ca.uhn.fhir.rest.annotation.IdParam;
|
||||
import ca.uhn.fhir.rest.annotation.Read;
|
||||
|
@ -49,33 +50,6 @@ public class CreateDstu3Test {
|
|||
private static int ourPort;
|
||||
private static Server ourServer;
|
||||
|
||||
@Test
|
||||
public void testRead() throws Exception {
|
||||
|
||||
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/2?_format=xml&_pretty=true");
|
||||
HttpResponse status = ourClient.execute(httpGet);
|
||||
|
||||
String responseContent = IOUtils.toString(status.getEntity().getContent());
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
|
||||
ourLog.info("Response was:\n{}", responseContent);
|
||||
|
||||
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||
|
||||
//@formatter:off
|
||||
assertThat(responseContent, stringContainsInOrder(
|
||||
"<Patient xmlns=\"http://hl7.org/fhir\">",
|
||||
"<id value=\"2\"/>",
|
||||
"<meta>",
|
||||
"<profile value=\"http://example.com/StructureDefinition/patient_with_extensions\"/>",
|
||||
"</meta>",
|
||||
"<modifierExtension url=\"http://example.com/ext/date\">",
|
||||
"<valueDate value=\"2011-01-01\"/>",
|
||||
"</modifierExtension>",
|
||||
"</Patient>"));
|
||||
//@formatter:on
|
||||
}
|
||||
|
||||
/**
|
||||
* #342
|
||||
*/
|
||||
|
@ -93,7 +67,34 @@ public class CreateDstu3Test {
|
|||
assertEquals(400, status.getStatusLine().getStatusCode());
|
||||
String expected = "<OperationOutcome xmlns=\"http://hl7.org/fhir\"><issue><severity value=\"error\"/><code value=\"processing\"/><diagnostics value=\"Failed to parse request body as XML resource. Error was: com.ctc.wstx.exc.WstxUnexpectedCharException: Unexpected character 'F' (code 70) in prolog; expected '<'
 at [row,col {unknown-source}]: [1,1]\"/></issue></OperationOutcome>";
|
||||
assertEquals(expected, responseContent);
|
||||
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRead() throws Exception {
|
||||
|
||||
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/2?_format=xml&_pretty=true");
|
||||
HttpResponse status = ourClient.execute(httpGet);
|
||||
|
||||
String responseContent = IOUtils.toString(status.getEntity().getContent());
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
|
||||
ourLog.info("Response was:\n{}", responseContent);
|
||||
|
||||
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||
|
||||
//@formatter:off
|
||||
assertThat(responseContent, stringContainsInOrder(
|
||||
"<Patient xmlns=\"http://hl7.org/fhir\">",
|
||||
"<id value=\"2\"/>",
|
||||
"<meta>",
|
||||
"<profile value=\"http://example.com/StructureDefinition/patient_with_extensions\"/>",
|
||||
"</meta>",
|
||||
"<modifierExtension url=\"http://example.com/ext/date\">",
|
||||
"<valueDate value=\"2011-01-01\"/>",
|
||||
"</modifierExtension>",
|
||||
"</Patient>"));
|
||||
//@formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -108,7 +109,7 @@ public class CreateDstu3Test {
|
|||
ourLog.info("Response was:\n{}", responseContent);
|
||||
|
||||
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||
|
||||
|
||||
//@formatter:off
|
||||
assertThat(responseContent, stringContainsInOrder(
|
||||
"<Patient xmlns=\"http://hl7.org/fhir\">",
|
||||
|
@ -121,7 +122,7 @@ public class CreateDstu3Test {
|
|||
"</modifierExtension>",
|
||||
"</Patient>"));
|
||||
//@formatter:on
|
||||
|
||||
|
||||
assertThat(responseContent, not(containsString("http://hl7.org/fhir/")));
|
||||
}
|
||||
|
||||
|
@ -156,6 +157,11 @@ public class CreateDstu3Test {
|
|||
|
||||
public static class PatientProvider implements IResourceProvider {
|
||||
|
||||
@Create()
|
||||
public MethodOutcome create(@ResourceParam Patient theIdParam) {
|
||||
return new MethodOutcome(new IdType("Patient", "1"), true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<Patient> getResourceType() {
|
||||
return Patient.class;
|
||||
|
@ -169,11 +175,6 @@ public class CreateDstu3Test {
|
|||
return p0;
|
||||
}
|
||||
|
||||
@Create()
|
||||
public MethodOutcome read(@ResourceParam Patient theIdParam) {
|
||||
return new MethodOutcome(new IdType("Patient", "1"), true);
|
||||
}
|
||||
|
||||
@Search
|
||||
public List<IBaseResource> search() {
|
||||
ArrayList<IBaseResource> retVal = new ArrayList<IBaseResource>();
|
||||
|
|
|
@ -6,6 +6,7 @@ import java.util.concurrent.TimeUnit;
|
|||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.client.methods.CloseableHttpResponse;
|
||||
import org.apache.http.client.methods.HttpPut;
|
||||
import org.apache.http.entity.ContentType;
|
||||
import org.apache.http.entity.StringEntity;
|
||||
|
@ -19,11 +20,13 @@ import org.hl7.fhir.dstu3.model.IdType;
|
|||
import org.hl7.fhir.dstu3.model.OperationOutcome;
|
||||
import org.hl7.fhir.dstu3.model.Patient;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Before;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.model.primitive.IdDt;
|
||||
import ca.uhn.fhir.rest.annotation.ConditionalUrlParam;
|
||||
import ca.uhn.fhir.rest.annotation.IdParam;
|
||||
import ca.uhn.fhir.rest.annotation.ResourceParam;
|
||||
import ca.uhn.fhir.rest.annotation.Update;
|
||||
|
@ -63,6 +66,53 @@ public class UpdateDstu3Test {
|
|||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateConditional() throws Exception {
|
||||
|
||||
Patient patient = new Patient();
|
||||
patient.setId("001");
|
||||
patient.addIdentifier().setValue("002");
|
||||
|
||||
HttpPut httpPost = new HttpPut("http://localhost:" + ourPort + "/Patient?_id=001");
|
||||
httpPost.setEntity(new StringEntity(ourCtx.newXmlParser().encodeResourceToString(patient), ContentType.create(Constants.CT_FHIR_XML, "UTF-8")));
|
||||
|
||||
CloseableHttpResponse status = ourClient.execute(httpPost);
|
||||
try {
|
||||
String responseContent = IOUtils.toString(status.getEntity().getContent());
|
||||
ourLog.info("Response was:\n{}", responseContent);
|
||||
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||
|
||||
assertEquals("Patient?_id=001",ourConditionalUrl);
|
||||
assertEquals(null, ourId);
|
||||
} finally {
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateNormal() throws Exception {
|
||||
|
||||
Patient patient = new Patient();
|
||||
patient.addIdentifier().setValue("002");
|
||||
|
||||
HttpPut httpPost = new HttpPut("http://localhost:" + ourPort + "/Patient/001");
|
||||
httpPost.setEntity(new StringEntity(ourCtx.newXmlParser().encodeResourceToString(patient), ContentType.create(Constants.CT_FHIR_XML, "UTF-8")));
|
||||
|
||||
CloseableHttpResponse status = ourClient.execute(httpPost);
|
||||
try {
|
||||
String responseContent = IOUtils.toString(status.getEntity().getContent());
|
||||
ourLog.info("Response was:\n{}", responseContent);
|
||||
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||
|
||||
assertNull(ourConditionalUrl);
|
||||
assertEquals("Patient/001", ourId.getValue());
|
||||
} finally {
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateWrongUrlInBody() throws Exception {
|
||||
|
||||
|
@ -81,7 +131,9 @@ public class UpdateDstu3Test {
|
|||
ourLog.info("Response was:\n{}", responseContent);
|
||||
|
||||
OperationOutcome oo = ourCtx.newXmlParser().parseResource(OperationOutcome.class, responseContent);
|
||||
assertEquals("Can not update resource, resource body must contain an ID element which matches the request URL for update (PUT) operation - Resource body ID of \"3\" does not match URL ID of \"001\"", oo.getIssueFirstRep().getDiagnostics());
|
||||
assertEquals(
|
||||
"Can not update resource, resource body must contain an ID element which matches the request URL for update (PUT) operation - Resource body ID of \"3\" does not match URL ID of \"001\"",
|
||||
oo.getIssueFirstRep().getDiagnostics());
|
||||
|
||||
assertEquals(400, status.getStatusLine().getStatusCode());
|
||||
assertNull(status.getFirstHeader("location"));
|
||||
|
@ -115,7 +167,15 @@ public class UpdateDstu3Test {
|
|||
|
||||
}
|
||||
|
||||
private static String ourConditionalUrl;
|
||||
|
||||
@Before
|
||||
public void before() {
|
||||
ourConditionalUrl = null;
|
||||
ourId = null;
|
||||
}
|
||||
|
||||
private static IdType ourId;
|
||||
|
||||
public static class PatientProvider implements IResourceProvider {
|
||||
|
||||
|
@ -125,11 +185,13 @@ public class UpdateDstu3Test {
|
|||
}
|
||||
|
||||
@Update()
|
||||
public MethodOutcome updatePatient(@IdParam IdType theId, @ResourceParam Patient thePatient) {
|
||||
IdType id = theId.withVersion(thePatient.getIdentifierFirstRep().getValue());
|
||||
public MethodOutcome updatePatient(@IdParam IdType theId, @ResourceParam Patient thePatient, @ConditionalUrlParam String theConditionalUrl) {
|
||||
ourId = theId;
|
||||
ourConditionalUrl = theConditionalUrl;
|
||||
IdType id = theId != null ? theId.withVersion(thePatient.getIdentifierFirstRep().getValue()) : new IdType("Patient/1");
|
||||
OperationOutcome oo = new OperationOutcome();
|
||||
oo.addIssue().setDiagnostics("OODETAILS");
|
||||
if (theId.getValueAsString().contains("CREATE")) {
|
||||
if (id.getValueAsString().contains("CREATE")) {
|
||||
return new MethodOutcome(id, oo, true);
|
||||
}
|
||||
|
||||
|
|
|
@ -181,6 +181,11 @@
|
|||
count would not appear in the self/prev/next links and would not actually be applied
|
||||
to the search results by the server. Thanks to Jim Steele for letting us know!
|
||||
</action>
|
||||
<action type="fix">
|
||||
Conditional update on server failed to process if the conditional URL did not have any
|
||||
search parameters that did not start with an underscore. E.g. "Patient?_id=1" failed
|
||||
even though this is a valid conditional reference.
|
||||
</action>
|
||||
</release>
|
||||
<release version="1.5" date="2016-04-20">
|
||||
<action type="fix" issue="339">
|
||||
|
|
Loading…
Reference in New Issue