Skip to content

Commit

Permalink
Include profile URL in generated IPS (#5938)
Browse files Browse the repository at this point in the history
* Include profile URL in generated IPS

* Add changelog

* Documentation tweak
  • Loading branch information
jamesagnew committed May 16, 2024
1 parent 446869b commit 14c364d
Show file tree
Hide file tree
Showing 6 changed files with 39 additions and 12 deletions.
10 changes: 10 additions & 0 deletions hapi-fhir-base/src/main/java/ca/uhn/fhir/util/BundleBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -626,6 +626,16 @@ public void setTimestamp(@Nonnull IPrimitiveType<Date> theTimestamp) {
terser.setElement(myBundle, "Bundle.timestamp", theTimestamp.getValueAsString());
}

/**
* Adds a profile URL to <code>Bundle.meta.profile</code>
*
* @since 7.4.0
*/
public void addProfile(String theProfile) {
FhirTerser terser = myContext.newTerser();
terser.addElement(myBundle, "Bundle.meta.profile", theProfile);
}

public class DeleteBuilder extends BaseOperationBuilder {

// nothing yet
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
---
type: add
issue: 5938
title: "Generated IPS documents will now include a bundle profile declaration."
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,10 @@ public interface IIpsGenerationStrategy {

/**
* This method returns the profile associated with the IPS document
* generated by this strategy.
* generated by this strategy. This URL will be added to generated
* IPS Bundles in <code>Bundle.meta.profile</code>, and can also
* be used to support the <code>profile</code> parameter on the
* <code>$summary</code> operation.
*/
String getBundleProfile();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,7 @@ private IBaseBundle createDocumentBundleForComposition(
bundleBuilder.setType(Bundle.BundleType.DOCUMENT.toCode());
bundleBuilder.setIdentifier("urn:ietf:rfc:4122", UUID.randomUUID().toString());
bundleBuilder.setTimestamp(InstantType.now());
bundleBuilder.addProfile(theStrategy.getBundleProfile());

// Add composition to document
bundleBuilder.addDocumentEntry(composition);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
import ca.uhn.fhir.context.support.IValidationSupport;
import ca.uhn.fhir.context.support.ValidationSupportContext;
import ca.uhn.fhir.jpa.api.config.JpaStorageSettings;
import ca.uhn.fhir.jpa.api.dao.DaoRegistry;
import ca.uhn.fhir.jpa.ips.api.IIpsGenerationStrategy;
import ca.uhn.fhir.jpa.ips.jpa.DefaultJpaIpsGenerationStrategy;
import ca.uhn.fhir.jpa.ips.provider.IpsOperationProvider;
Expand All @@ -18,6 +17,7 @@
import ca.uhn.fhir.validation.ValidationResult;
import jakarta.annotation.Nonnull;
import jakarta.annotation.Nullable;
import org.hl7.fhir.common.hapi.validation.support.NpmPackageValidationSupport;
import org.hl7.fhir.common.hapi.validation.support.ValidationSupportChain;
import org.hl7.fhir.common.hapi.validation.validator.FhirInstanceValidator;
import org.hl7.fhir.instance.model.api.IBaseResource;
Expand All @@ -31,6 +31,7 @@
import org.hl7.fhir.r4.model.MedicationStatement;
import org.hl7.fhir.r4.model.Parameters;
import org.hl7.fhir.r4.model.Patient;
import org.hl7.fhir.r4.model.PrimitiveType;
import org.hl7.fhir.r4.model.Reference;
import org.hl7.fhir.r4.model.Resource;
import org.junit.jupiter.api.AfterEach;
Expand All @@ -41,17 +42,18 @@
import org.springframework.context.annotation.Configuration;
import org.springframework.test.context.ContextConfiguration;

import java.io.IOException;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.stringContainsInOrder;
import static org.hibernate.validator.internal.util.Contracts.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertTrue;

/**
* This test uses a complete R4 JPA server as a backend and wires the
Expand All @@ -77,7 +79,7 @@ public void afterEach() {


@Test
public void testGenerateLargePatientSummary() {
public void testGenerateLargePatientSummary() throws IOException {
Bundle sourceData = ClasspathUtil.loadCompressedResource(myFhirContext, Bundle.class, "/large-patient-everything.json.gz");
sourceData.setType(Bundle.BundleType.TRANSACTION);
for (Bundle.BundleEntryComponent nextEntry : sourceData.getEntry()) {
Expand All @@ -97,6 +99,9 @@ public void testGenerateLargePatientSummary() {
ourLog.info("Output: {}", myFhirContext.newJsonParser().setPrettyPrint(true).encodeResourceToString(output));

// Verify
assertThat(output.getMeta().getProfile().stream().map(PrimitiveType::getValue).toList(), contains(
"http:https://hl7.org/fhir/uv/ips/StructureDefinition/Bundle-uv-ips"
));
validateDocument(output);
assertEquals(117, output.getEntry().size());
String patientId = findFirstEntryResource(output, Patient.class, 1).getIdElement().toUnqualifiedVersionless().getValue();
Expand Down Expand Up @@ -162,7 +167,7 @@ public void testGenerateLargePatientSummary3() {
}

@Test
public void testGenerateTinyPatientSummary() {
public void testGenerateTinyPatientSummary() throws IOException {
myStorageSettings.setResourceClientIdStrategy(JpaStorageSettings.ClientIdStrategyEnum.ANY);

Bundle sourceData = ClasspathUtil.loadCompressedResource(myFhirContext, Bundle.class, "/tiny-patient-everything.json.gz");
Expand Down Expand Up @@ -251,38 +256,42 @@ public void testImmunizationOrder() {


@Nonnull
private static Composition findCompositionSectionByDisplay(Bundle output, String theDisplay) {
private static Composition findCompositionSectionByDisplay(Bundle output, @SuppressWarnings("SameParameterValue") String theDisplay) {
Composition composition = (Composition) output.getEntry().get(0).getResource();
Composition.SectionComponent section = composition
.getSection()
.stream()
.filter(t -> t.getCode().getCoding().get(0).getDisplay().equals(theDisplay))
.findFirst()
.orElseThrow();
assertNotNull(section);
return composition;
}


@Nonnull
private static List<String> extractSectionTitles(Bundle outcome) {
Composition composition = (Composition) outcome.getEntry().get(0).getResource();
List<String> sectionTitles = composition
return composition
.getSection()
.stream()
.map(Composition.SectionComponent::getTitle)
.toList();
return sectionTitles;
}

private void validateDocument(Bundle theOutcome) {
private void validateDocument(Bundle theOutcome) throws IOException {
FhirValidator validator = myFhirContext.newValidator();
FhirInstanceValidator instanceValidator = new FhirInstanceValidator(myFhirContext);
instanceValidator.setValidationSupport(new ValidationSupportChain(new IpsTerminologySvc(), myFhirContext.getValidationSupport()));

NpmPackageValidationSupport npmSupport = new NpmPackageValidationSupport(myFhirContext);
npmSupport.loadPackageFromClasspath("/ips-package-1.1.0.tgz");

instanceValidator.setValidationSupport(new ValidationSupportChain(npmSupport, new IpsTerminologySvc(), myFhirContext.getValidationSupport()));
validator.registerValidatorModule(instanceValidator);
ValidationResult validation = validator.validateWithResult(theOutcome);

Optional<SingleValidationMessage> failure = validation.getMessages().stream().filter(t -> t.getSeverity().ordinal() >= ResultSeverityEnum.ERROR.ordinal()).findFirst();
assertFalse(failure.isPresent(), () -> failure.get().toString());
assertFalse(failure.isPresent(), () -> failure.orElseThrow().toString());
}

@Configuration
Expand All @@ -294,7 +303,7 @@ public IIpsGenerationStrategy ipsGenerationStrategy() {
}

@Bean
public IIpsGeneratorSvc ipsGeneratorSvc(FhirContext theFhirContext, IIpsGenerationStrategy theGenerationStrategy, DaoRegistry theDaoRegistry) {
public IIpsGeneratorSvc ipsGeneratorSvc(FhirContext theFhirContext, IIpsGenerationStrategy theGenerationStrategy) {
return new IpsGeneratorSvcImpl(theFhirContext, theGenerationStrategy);
}

Expand Down
Binary file not shown.

0 comments on commit 14c364d

Please sign in to comment.