Add transactionbuilder (#2041)
* Add transactionbuilder * Add changelog * Add creates
This commit is contained in:
parent
3a5e0ed872
commit
eab828f47a
|
@ -32,7 +32,7 @@ import org.thymeleaf.util.Validate;
|
|||
|
||||
/**
|
||||
* This class can be used to build a Bundle resource to be used as a FHIR transaction.
|
||||
*
|
||||
* <p>
|
||||
* This is not yet complete, and doesn't support all FHIR features. <b>USE WITH CAUTION</b> as the API
|
||||
* may change.
|
||||
*
|
||||
|
@ -52,6 +52,7 @@ public class TransactionBuilder {
|
|||
private final BaseRuntimeChildDefinition myEntryRequestUrlChild;
|
||||
private final BaseRuntimeChildDefinition myEntryRequestMethodChild;
|
||||
private final BaseRuntimeElementDefinition<?> myEntryRequestMethodDef;
|
||||
private final BaseRuntimeChildDefinition myEntryRequestIfNoneExistChild;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
|
@ -81,6 +82,7 @@ public class TransactionBuilder {
|
|||
myEntryRequestMethodChild = myEntryRequestDef.getChildByName("method");
|
||||
myEntryRequestMethodDef = myEntryRequestMethodChild.getChildByName("method");
|
||||
|
||||
myEntryRequestIfNoneExistChild = myEntryRequestDef.getChildByName("ifNoneExist");
|
||||
|
||||
}
|
||||
|
||||
|
@ -89,9 +91,47 @@ public class TransactionBuilder {
|
|||
*
|
||||
* @param theResource The resource to update
|
||||
*/
|
||||
public TransactionBuilder addUpdateEntry(IBaseResource theResource) {
|
||||
public UpdateBuilder addUpdateEntry(IBaseResource theResource) {
|
||||
IBase request = addEntryAndReturnRequest(theResource);
|
||||
|
||||
// Bundle.entry.request.url
|
||||
IPrimitiveType<?> url = (IPrimitiveType<?>) myContext.getElementDefinition("uri").newInstance();
|
||||
url.setValueAsString(theResource.getIdElement().toUnqualifiedVersionless().getValue());
|
||||
myEntryRequestUrlChild.getMutator().setValue(request, url);
|
||||
|
||||
// Bundle.entry.request.url
|
||||
IPrimitiveType<?> method = (IPrimitiveType<?>) myEntryRequestMethodDef.newInstance(myEntryRequestMethodChild.getInstanceConstructorArguments());
|
||||
method.setValueAsString("PUT");
|
||||
myEntryRequestMethodChild.getMutator().setValue(request, method);
|
||||
|
||||
return new UpdateBuilder(url);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an entry containing an create (POST) request
|
||||
*
|
||||
* @param theResource The resource to create
|
||||
*/
|
||||
public CreateBuilder addCreateEntry(IBaseResource theResource) {
|
||||
IBase request = addEntryAndReturnRequest(theResource);
|
||||
|
||||
String resourceType = myContext.getResourceType(theResource);
|
||||
|
||||
// Bundle.entry.request.url
|
||||
IPrimitiveType<?> url = (IPrimitiveType<?>) myContext.getElementDefinition("uri").newInstance();
|
||||
url.setValueAsString(resourceType);
|
||||
myEntryRequestUrlChild.getMutator().setValue(request, url);
|
||||
|
||||
// Bundle.entry.request.url
|
||||
IPrimitiveType<?> method = (IPrimitiveType<?>) myEntryRequestMethodDef.newInstance(myEntryRequestMethodChild.getInstanceConstructorArguments());
|
||||
method.setValueAsString("POST");
|
||||
myEntryRequestMethodChild.getMutator().setValue(request, method);
|
||||
|
||||
return new CreateBuilder(request);
|
||||
}
|
||||
|
||||
public IBase addEntryAndReturnRequest(IBaseResource theResource) {
|
||||
Validate.notNull(theResource, "theResource must not be null");
|
||||
Validate.notEmpty(theResource.getIdElement().getValue(), "theResource must have an ID");
|
||||
|
||||
IBase entry = myEntryDef.newInstance();
|
||||
myEntryChild.getMutator().addValue(myBundle, entry);
|
||||
|
@ -107,24 +147,47 @@ public class TransactionBuilder {
|
|||
// Bundle.entry.request
|
||||
IBase request = myEntryRequestDef.newInstance();
|
||||
myEntryRequestChild.getMutator().setValue(entry, request);
|
||||
|
||||
// Bundle.entry.request.url
|
||||
IPrimitiveType<?> url = (IPrimitiveType<?>) myContext.getElementDefinition("uri").newInstance();
|
||||
url.setValueAsString(theResource.getIdElement().toUnqualifiedVersionless().getValue());
|
||||
myEntryRequestUrlChild.getMutator().setValue(request, url);
|
||||
|
||||
// Bundle.entry.request.url
|
||||
IPrimitiveType<?> method = (IPrimitiveType<?>) myEntryRequestMethodDef.newInstance(myEntryRequestMethodChild.getInstanceConstructorArguments());
|
||||
method.setValueAsString("PUT");
|
||||
myEntryRequestMethodChild.getMutator().setValue(request, method);
|
||||
|
||||
return this;
|
||||
return request;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public IBaseBundle getBundle() {
|
||||
return myBundle;
|
||||
}
|
||||
|
||||
public class UpdateBuilder {
|
||||
|
||||
private final IPrimitiveType<?> myUrl;
|
||||
|
||||
public UpdateBuilder(IPrimitiveType<?> theUrl) {
|
||||
myUrl = theUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Make this update a Conditional Update
|
||||
*/
|
||||
public void conditional(String theConditionalUrl) {
|
||||
myUrl.setValueAsString(theConditionalUrl);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public class CreateBuilder {
|
||||
private final IBase myRequest;
|
||||
|
||||
public CreateBuilder(IBase theRequest) {
|
||||
myRequest = theRequest;
|
||||
}
|
||||
|
||||
/**
|
||||
* Make this create a Conditional Create
|
||||
*/
|
||||
public void conditional(String theConditionalUrl) {
|
||||
IPrimitiveType<?> ifNoneExist = (IPrimitiveType<?>) myContext.getElementDefinition("string").newInstance();
|
||||
ifNoneExist.setValueAsString(theConditionalUrl);
|
||||
|
||||
myEntryRequestIfNoneExistChild.getMutator().setValue(myRequest, ifNoneExist);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,107 @@
|
|||
package ca.uhn.hapi.fhir.docs;
|
||||
|
||||
/*-
|
||||
* #%L
|
||||
* HAPI FHIR - Docs
|
||||
* %%
|
||||
* 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.rest.client.api.IGenericClient;
|
||||
import ca.uhn.fhir.util.TransactionBuilder;
|
||||
import org.hl7.fhir.exceptions.FHIRException;
|
||||
import org.hl7.fhir.instance.model.api.IBaseBundle;
|
||||
import org.hl7.fhir.r4.model.Patient;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public class TransactionBuilderExamples {
|
||||
|
||||
private FhirContext myFhirContext;
|
||||
private IGenericClient myFhirClient;
|
||||
|
||||
public void update() throws FHIRException {
|
||||
//START SNIPPET: update
|
||||
// Create a TransactionBuilder
|
||||
TransactionBuilder builder = new TransactionBuilder(myFhirContext);
|
||||
|
||||
// Create a Patient to update
|
||||
Patient patient = new Patient();
|
||||
patient.setId("http://foo/Patient/123");
|
||||
patient.setActive(true);
|
||||
|
||||
// Add the patient as an update (aka PUT) to the Bundle
|
||||
builder.addUpdateEntry(patient);
|
||||
|
||||
// Execute the transaction
|
||||
IBaseBundle outcome = myFhirClient.transaction().withBundle(builder.getBundle()).execute();
|
||||
//END SNIPPET: update
|
||||
}
|
||||
|
||||
public void updateConditional() throws FHIRException {
|
||||
//START SNIPPET: updateConditional
|
||||
// Create a TransactionBuilder
|
||||
TransactionBuilder builder = new TransactionBuilder(myFhirContext);
|
||||
|
||||
// Create a Patient to update
|
||||
Patient patient = new Patient();
|
||||
patient.setActive(true);
|
||||
patient.addIdentifier().setSystem("http://foo").setValue("bar");
|
||||
|
||||
// Add the patient as an update (aka PUT) to the Bundle
|
||||
builder.addUpdateEntry(patient).conditional("Patient?identifier=http://foo|bar");
|
||||
|
||||
// Execute the transaction
|
||||
IBaseBundle outcome = myFhirClient.transaction().withBundle(builder.getBundle()).execute();
|
||||
//END SNIPPET: updateConditional
|
||||
}
|
||||
|
||||
public void create() throws FHIRException {
|
||||
//START SNIPPET: create
|
||||
// Create a TransactionBuilder
|
||||
TransactionBuilder builder = new TransactionBuilder(myFhirContext);
|
||||
|
||||
// Create a Patient to create
|
||||
Patient patient = new Patient();
|
||||
patient.setActive(true);
|
||||
|
||||
// Add the patient as a create (aka POST) to the Bundle
|
||||
builder.addCreateEntry(patient);
|
||||
|
||||
// Execute the transaction
|
||||
IBaseBundle outcome = myFhirClient.transaction().withBundle(builder.getBundle()).execute();
|
||||
//END SNIPPET: create
|
||||
}
|
||||
|
||||
public void createConditional() throws FHIRException {
|
||||
//START SNIPPET: createConditional
|
||||
// Create a TransactionBuilder
|
||||
TransactionBuilder builder = new TransactionBuilder(myFhirContext);
|
||||
|
||||
// Create a Patient to create
|
||||
Patient patient = new Patient();
|
||||
patient.setActive(true);
|
||||
patient.addIdentifier().setSystem("http://foo").setValue("bar");
|
||||
|
||||
// Add the patient as a create (aka POST) to the Bundle
|
||||
builder.addCreateEntry(patient).conditional("Patient?identifier=http://foo|bar");
|
||||
|
||||
// Execute the transaction
|
||||
IBaseBundle outcome = myFhirClient.transaction().withBundle(builder.getBundle()).execute();
|
||||
//END SNIPPET: createConditional
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
---
|
||||
type: add
|
||||
issue: 2041
|
||||
title: "A new class called TransactionBuilder has been added. This class can be used to build FHIR Transaction Bundles easily."
|
|
@ -15,6 +15,7 @@ page.model.profiles_and_extensions=Profiles and Extensions
|
|||
page.model.converter=Version Converters
|
||||
page.model.custom_structures=Custom Structures
|
||||
page.model.narrative_generation=Narrative Generation
|
||||
page.model.transaction_builder=Transaction Builder
|
||||
|
||||
section.client.title=Client
|
||||
page.client.introduction=Introduction
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
# Transaction Builder
|
||||
|
||||
The TransactionBuilder ([JavaDoc](/hapi-fhir/apidocs/hapi-fhir-base/ca/uhn/fhir/util/TransactionBuilder.html)) can be used to construct FHIR Transaction Bundles.
|
||||
|
||||
Note that this class is a work in progress! It does not yet support all transaction features. We will add more features over time, and document them here. Pull requests are welcomed.
|
||||
|
||||
# Resource Create
|
||||
|
||||
To add an update (aka PUT) operation to a transaction bundle
|
||||
|
||||
```java
|
||||
{{snippet:classpath:/ca/uhn/hapi/fhir/docs/TransactionBuilderExamples.java|create}}
|
||||
```
|
||||
|
||||
## Conditional Create
|
||||
|
||||
If you want to perform a conditional create:
|
||||
|
||||
```java
|
||||
{{snippet:classpath:/ca/uhn/hapi/fhir/docs/TransactionBuilderExamples.java|createConditional}}
|
||||
```
|
||||
|
||||
# Resource Updates
|
||||
|
||||
To add an update (aka PUT) operation to a transaction bundle
|
||||
|
||||
```java
|
||||
{{snippet:classpath:/ca/uhn/hapi/fhir/docs/TransactionBuilderExamples.java|update}}
|
||||
```
|
||||
|
||||
## Conditional Update
|
||||
|
||||
If you want to perform a conditional update:
|
||||
|
||||
```java
|
||||
{{snippet:classpath:/ca/uhn/hapi/fhir/docs/TransactionBuilderExamples.java|updateConditional}}
|
||||
```
|
||||
|
||||
|
|
@ -37,4 +37,73 @@ public class TransactionBuilderTest {
|
|||
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testAddEntryUpdateConditional() {
|
||||
TransactionBuilder builder = new TransactionBuilder(myFhirContext);
|
||||
|
||||
Patient patient = new Patient();
|
||||
patient.setId("http://foo/Patient/123");
|
||||
patient.setActive(true);
|
||||
builder.addUpdateEntry(patient).conditional("Patient?active=true");
|
||||
|
||||
Bundle bundle = (Bundle) builder.getBundle();
|
||||
ourLog.info("Bundle:\n{}", myFhirContext.newJsonParser().setPrettyPrint(true).encodeResourceToString(bundle));
|
||||
|
||||
assertEquals(Bundle.BundleType.TRANSACTION, bundle.getType());
|
||||
assertEquals(1, bundle.getEntry().size());
|
||||
assertSame(patient, bundle.getEntry().get(0).getResource());
|
||||
assertEquals("http://foo/Patient/123", bundle.getEntry().get(0).getFullUrl());
|
||||
assertEquals("Patient?active=true", bundle.getEntry().get(0).getRequest().getUrl());
|
||||
assertEquals(Bundle.HTTPVerb.PUT, bundle.getEntry().get(0).getRequest().getMethod());
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testAddEntryCreate() {
|
||||
TransactionBuilder builder = new TransactionBuilder(myFhirContext);
|
||||
|
||||
Patient patient = new Patient();
|
||||
patient.setActive(true);
|
||||
builder.addCreateEntry(patient);
|
||||
|
||||
Bundle bundle = (Bundle) builder.getBundle();
|
||||
ourLog.info("Bundle:\n{}", myFhirContext.newJsonParser().setPrettyPrint(true).encodeResourceToString(bundle));
|
||||
|
||||
assertEquals(Bundle.BundleType.TRANSACTION, bundle.getType());
|
||||
assertEquals(1, bundle.getEntry().size());
|
||||
assertSame(patient, bundle.getEntry().get(0).getResource());
|
||||
assertEquals(null, bundle.getEntry().get(0).getFullUrl());
|
||||
assertEquals("Patient", bundle.getEntry().get(0).getRequest().getUrl());
|
||||
assertEquals(Bundle.HTTPVerb.POST, bundle.getEntry().get(0).getRequest().getMethod());
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testAddEntryCreateConditional() {
|
||||
TransactionBuilder builder = new TransactionBuilder(myFhirContext);
|
||||
|
||||
Patient patient = new Patient();
|
||||
patient.setActive(true);
|
||||
builder.addCreateEntry(patient).conditional("Patient?active=true");
|
||||
|
||||
Bundle bundle = (Bundle) builder.getBundle();
|
||||
ourLog.info("Bundle:\n{}", myFhirContext.newJsonParser().setPrettyPrint(true).encodeResourceToString(bundle));
|
||||
|
||||
assertEquals(Bundle.BundleType.TRANSACTION, bundle.getType());
|
||||
assertEquals(1, bundle.getEntry().size());
|
||||
assertSame(patient, bundle.getEntry().get(0).getResource());
|
||||
assertEquals(null, bundle.getEntry().get(0).getFullUrl());
|
||||
assertEquals("Patient", bundle.getEntry().get(0).getRequest().getUrl());
|
||||
assertEquals("Patient?active=true", bundle.getEntry().get(0).getRequest().getIfNoneExist());
|
||||
assertEquals(Bundle.HTTPVerb.POST, bundle.getEntry().get(0).getRequest().getMethod());
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue