* Additional tweaks for #4509 * More teaks * format imports
This commit is contained in:
parent
26a7009277
commit
765fedfefa
|
@ -22,6 +22,7 @@ package ca.uhn.fhir.jpa.ips.generator;
|
|||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.context.RuntimeResourceDefinition;
|
||||
import ca.uhn.fhir.context.RuntimeSearchParam;
|
||||
import ca.uhn.fhir.fhirpath.IFhirPathEvaluationContext;
|
||||
import ca.uhn.fhir.jpa.api.dao.DaoRegistry;
|
||||
import ca.uhn.fhir.jpa.api.dao.IFhirResourceDao;
|
||||
|
@ -32,6 +33,7 @@ import ca.uhn.fhir.jpa.ips.api.SectionRegistry;
|
|||
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
||||
import ca.uhn.fhir.model.api.Include;
|
||||
import ca.uhn.fhir.model.api.ResourceMetadataKeyEnum;
|
||||
import ca.uhn.fhir.model.dstu2.resource.Observation;
|
||||
import ca.uhn.fhir.model.valueset.BundleEntrySearchModeEnum;
|
||||
import ca.uhn.fhir.narrative.CustomThymeleafNarrativeGenerator;
|
||||
import ca.uhn.fhir.rest.api.server.IBundleProvider;
|
||||
|
@ -42,6 +44,10 @@ import ca.uhn.fhir.util.BundleBuilder;
|
|||
import ca.uhn.fhir.util.CompositionBuilder;
|
||||
import ca.uhn.fhir.util.ResourceReferenceInfo;
|
||||
import ca.uhn.fhir.util.ValidateUtil;
|
||||
import com.google.common.collect.BiMap;
|
||||
import com.google.common.collect.HashBiMap;
|
||||
import org.apache.commons.collections4.BidiMap;
|
||||
import org.apache.commons.collections4.bidimap.DualHashBidiMap;
|
||||
import org.hl7.fhir.instance.model.api.IBase;
|
||||
import org.hl7.fhir.instance.model.api.IBaseBundle;
|
||||
import org.hl7.fhir.instance.model.api.IBaseExtension;
|
||||
|
@ -66,6 +72,7 @@ import java.util.List;
|
|||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static ca.uhn.fhir.jpa.term.api.ITermLoaderSvc.LOINC_URI;
|
||||
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||
|
@ -214,6 +221,8 @@ public class IpsGeneratorSvcImpl implements IIpsGeneratorSvc {
|
|||
|
||||
nextCandidate = previouslyExistingResource;
|
||||
sectionResourcesToInclude.addResourceIfNotAlreadyPresent(nextCandidate, originalResourceId);
|
||||
} else if (theGlobalResourcesToInclude.hasResourceWithReplacementId(originalResourceId)) {
|
||||
sectionResourcesToInclude.addResourceIfNotAlreadyPresent(nextCandidate, originalResourceId);
|
||||
} else {
|
||||
IIdType id = myGenerationStrategy.massageResourceId(theIpsContext, nextCandidate);
|
||||
nextCandidate.setId(id);
|
||||
|
@ -226,33 +235,6 @@ public class IpsGeneratorSvcImpl implements IIpsGeneratorSvc {
|
|||
|
||||
}
|
||||
|
||||
/*
|
||||
* Update any references within the added candidates - This is important
|
||||
* because we might be replacing resource IDs before including them in
|
||||
* the summary, so we need to also update the references to those
|
||||
* resources.
|
||||
*/
|
||||
for (IBaseResource nextResource : sectionResourcesToInclude.getResources()) {
|
||||
List<ResourceReferenceInfo> references = myFhirContext.newTerser().getAllResourceReferences(nextResource);
|
||||
for (ResourceReferenceInfo nextReference : references) {
|
||||
String existingReference = nextReference.getResourceReference().getReferenceElement().getValue();
|
||||
if (isNotBlank(existingReference)) {
|
||||
existingReference = new IdType(existingReference).toUnqualifiedVersionless().getValue();
|
||||
String replacement = theGlobalResourcesToInclude.getIdSubstitution(existingReference);
|
||||
if (isNotBlank(replacement)) {
|
||||
if (!replacement.equals(existingReference)) {
|
||||
nextReference.getResourceReference().setReference(replacement);
|
||||
}
|
||||
} else if (theGlobalResourcesToInclude.getResourceById(existingReference) == null) {
|
||||
// If this reference doesn't point to something we have actually
|
||||
// included in the bundle, clear the reference.
|
||||
nextReference.getResourceReference().setReference(null);
|
||||
nextReference.getResourceReference().setResource(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (sectionResourcesToInclude.isEmpty() && theSection.getNoInfoGenerator() != null) {
|
||||
|
@ -266,6 +248,33 @@ public class IpsGeneratorSvcImpl implements IIpsGeneratorSvc {
|
|||
sectionResourcesToInclude.addResourceIfNotAlreadyPresent(noInfoResource, id);
|
||||
}
|
||||
|
||||
/*
|
||||
* Update any references within the added candidates - This is important
|
||||
* because we might be replacing resource IDs before including them in
|
||||
* the summary, so we need to also update the references to those
|
||||
* resources.
|
||||
*/
|
||||
for (IBaseResource nextResource : sectionResourcesToInclude.getResources()) {
|
||||
List<ResourceReferenceInfo> references = myFhirContext.newTerser().getAllResourceReferences(nextResource);
|
||||
for (ResourceReferenceInfo nextReference : references) {
|
||||
String existingReference = nextReference.getResourceReference().getReferenceElement().getValue();
|
||||
if (isNotBlank(existingReference)) {
|
||||
existingReference = new IdType(existingReference).toUnqualifiedVersionless().getValue();
|
||||
String replacement = theGlobalResourcesToInclude.getIdSubstitution(existingReference);
|
||||
if (isNotBlank(replacement)) {
|
||||
if (!replacement.equals(existingReference)) {
|
||||
nextReference.getResourceReference().setReference(replacement);
|
||||
}
|
||||
} else if (theGlobalResourcesToInclude.getResourceById(existingReference) == null) {
|
||||
// If this reference doesn't point to something we have actually
|
||||
// included in the bundle, clear the reference.
|
||||
nextReference.getResourceReference().setReference(null);
|
||||
nextReference.getResourceReference().setResource(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
addSection(theSection, theCompositionBuilder, sectionResourcesToInclude, theGlobalResourcesToInclude);
|
||||
}
|
||||
|
||||
|
@ -278,6 +287,9 @@ public class IpsGeneratorSvcImpl implements IIpsGeneratorSvc {
|
|||
sectionBuilder.addCodeCoding(LOINC_URI, theSection.getSectionCode(), theSection.getSectionDisplay());
|
||||
|
||||
for (IBaseResource next : theResourcesToInclude.getResources()) {
|
||||
if (ResourceMetadataKeyEnum.ENTRY_SEARCH_MODE.get(next) == BundleEntrySearchModeEnum.INCLUDE) {
|
||||
continue;
|
||||
}
|
||||
|
||||
IBaseExtension<?, ?> narrativeLink = ((IBaseHasExtensions) next).addExtension();
|
||||
narrativeLink.setUrl("http://hl7.org/fhir/StructureDefinition/narrativeLink");
|
||||
|
@ -314,7 +326,18 @@ public class IpsGeneratorSvcImpl implements IIpsGeneratorSvc {
|
|||
|
||||
private String determinePatientCompartmentSearchParameterName(String theResourceType) {
|
||||
RuntimeResourceDefinition resourceDef = myFhirContext.getResourceDefinition(theResourceType);
|
||||
return resourceDef.getSearchParamsForCompartmentName("Patient").get(0).getName();
|
||||
Set<String> searchParams = resourceDef.getSearchParamsForCompartmentName("Patient")
|
||||
.stream()
|
||||
.map(RuntimeSearchParam::getName)
|
||||
.collect(Collectors.toSet());
|
||||
// Prefer "patient", then "subject" then anything else
|
||||
if (searchParams.contains(Observation.SP_PATIENT)) {
|
||||
return Observation.SP_PATIENT;
|
||||
}
|
||||
if (searchParams.contains(Observation.SP_SUBJECT)) {
|
||||
return Observation.SP_SUBJECT;
|
||||
}
|
||||
return searchParams.iterator().next();
|
||||
}
|
||||
|
||||
private void massageResourceId(IpsContext theIpsContext, IBaseResource theResource) {
|
||||
|
@ -519,7 +542,7 @@ public class IpsGeneratorSvcImpl implements IIpsGeneratorSvc {
|
|||
|
||||
private final List<IBaseResource> myResources = new ArrayList<>();
|
||||
private final Map<String, IBaseResource> myIdToResource = new HashMap<>();
|
||||
private final Map<String, String> myOriginalIdToNewId = new HashMap<>();
|
||||
private final BiMap<String, String> myOriginalIdToNewId = HashBiMap.create();
|
||||
|
||||
public List<IBaseResource> getResources() {
|
||||
return myResources;
|
||||
|
@ -549,6 +572,10 @@ public class IpsGeneratorSvcImpl implements IIpsGeneratorSvc {
|
|||
return getResourceById(theReference.toUnqualifiedVersionless().getValue());
|
||||
}
|
||||
|
||||
public boolean hasResourceWithReplacementId(String theReplacementId) {
|
||||
return myOriginalIdToNewId.containsValue(theReplacementId);
|
||||
}
|
||||
|
||||
public IBaseResource getResourceById(String theReference) {
|
||||
return myIdToResource.get(theReference);
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
package ca.uhn.fhir.jpa.ips.generator;
|
||||
|
||||
import ca.uhn.fhir.batch2.jobs.models.BatchResourceId;
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.jpa.api.config.DaoConfig;
|
||||
import ca.uhn.fhir.jpa.api.dao.DaoRegistry;
|
||||
import ca.uhn.fhir.jpa.ips.api.IIpsGenerationStrategy;
|
||||
import ca.uhn.fhir.jpa.ips.provider.IpsOperationProvider;
|
||||
|
@ -9,11 +9,16 @@ import ca.uhn.fhir.jpa.ips.strategy.DefaultIpsGenerationStrategy;
|
|||
import ca.uhn.fhir.jpa.model.util.JpaConstants;
|
||||
import ca.uhn.fhir.jpa.provider.BaseResourceProviderR4Test;
|
||||
import ca.uhn.fhir.util.ClasspathUtil;
|
||||
import ca.uhn.fhir.validation.FhirValidator;
|
||||
import ca.uhn.fhir.validation.ValidationResult;
|
||||
import org.hl7.fhir.common.hapi.validation.validator.FhirInstanceValidator;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.hl7.fhir.r4.model.Bundle;
|
||||
import org.hl7.fhir.r4.model.Condition;
|
||||
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.Resource;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
@ -22,10 +27,13 @@ import org.springframework.context.annotation.Bean;
|
|||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.matchesPattern;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
@ContextConfiguration(classes = {IpsGenerationTest.IpsConfig.class})
|
||||
public class IpsGenerationTest extends BaseResourceProviderR4Test {
|
||||
|
@ -41,6 +49,7 @@ public class IpsGenerationTest extends BaseResourceProviderR4Test {
|
|||
@AfterEach
|
||||
public void afterEach() {
|
||||
myServer.withServer(t -> t.unregisterProvider(myIpsOperationProvider));
|
||||
myDaoConfig.setResourceClientIdStrategy(DaoConfig.ClientIdStrategyEnum.ALPHANUMERIC);
|
||||
}
|
||||
|
||||
|
||||
|
@ -65,26 +74,52 @@ public class IpsGenerationTest extends BaseResourceProviderR4Test {
|
|||
ourLog.info("Output: {}", myFhirContext.newJsonParser().setPrettyPrint(true).encodeResourceToString(output));
|
||||
|
||||
// Verify
|
||||
|
||||
assertEquals(37, output.getEntry().size());
|
||||
String patientId = findFirstEntryResource(output, Patient.class).getId();
|
||||
validateDocument(outcome);
|
||||
assertEquals(117, output.getEntry().size());
|
||||
String patientId = findFirstEntryResource(output, Patient.class, 1).getId();
|
||||
assertThat(patientId, matchesPattern("urn:uuid:.*"));
|
||||
MedicationStatement medicationStatement = findFirstEntryResource(output, MedicationStatement.class);
|
||||
MedicationStatement medicationStatement = findFirstEntryResource(output, MedicationStatement.class, 2);
|
||||
assertEquals(patientId, medicationStatement.getSubject().getReference());
|
||||
assertNull(medicationStatement.getInformationSource().getReference());
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private <T extends IBaseResource> T findFirstEntryResource(Bundle theBundle, Class<T> theType) {
|
||||
return (T) theBundle
|
||||
.getEntry()
|
||||
.stream()
|
||||
.filter(t -> theType.isAssignableFrom(t.getResource().getClass()))
|
||||
.findFirst()
|
||||
.orElseThrow()
|
||||
.getResource();
|
||||
@Test
|
||||
public void testGenerateTinyPatientSummary() {
|
||||
myDaoConfig.setResourceClientIdStrategy(DaoConfig.ClientIdStrategyEnum.ANY);
|
||||
|
||||
Bundle sourceData = ClasspathUtil.loadCompressedResource(myFhirContext, Bundle.class, "/tiny-patient-everything.json.gz");
|
||||
sourceData.setType(Bundle.BundleType.TRANSACTION);
|
||||
for (Bundle.BundleEntryComponent nextEntry : sourceData.getEntry()) {
|
||||
nextEntry.getRequest().setMethod(Bundle.HTTPVerb.PUT);
|
||||
nextEntry.getRequest().setUrl(nextEntry.getResource().getIdElement().toUnqualifiedVersionless().getValue());
|
||||
}
|
||||
Bundle outcome = mySystemDao.transaction(mySrd, sourceData);
|
||||
ourLog.info("Created {} resources", outcome.getEntry().size());
|
||||
|
||||
Bundle output = myClient
|
||||
.operation()
|
||||
.onInstance("Patient/5342998")
|
||||
.named(JpaConstants.OPERATION_SUMMARY)
|
||||
.withNoParameters(Parameters.class)
|
||||
.returnResourceType(Bundle.class)
|
||||
.execute();
|
||||
ourLog.info("Output: {}", myFhirContext.newJsonParser().setPrettyPrint(true).encodeResourceToString(output));
|
||||
|
||||
// Verify
|
||||
validateDocument(outcome);
|
||||
assertEquals(7, output.getEntry().size());
|
||||
String patientId = findFirstEntryResource(output, Patient.class, 1).getId();
|
||||
assertThat(patientId, matchesPattern("urn:uuid:.*"));
|
||||
assertEquals(patientId, findEntryResource(output, Condition.class, 0, 2).getSubject().getReference());
|
||||
assertEquals(patientId, findEntryResource(output, Condition.class, 1, 2).getSubject().getReference());
|
||||
}
|
||||
|
||||
private void validateDocument(Bundle theOutcome) {
|
||||
FhirValidator validator = myFhirContext.newValidator();
|
||||
validator.registerValidatorModule(new FhirInstanceValidator(myFhirContext));
|
||||
ValidationResult validation = validator.validateWithResult(theOutcome);
|
||||
assertTrue(validation.isSuccessful(), () -> myFhirContext.newJsonParser().setPrettyPrint(true).encodeResourceToString(validation.toOperationOutcome()));
|
||||
}
|
||||
|
||||
@Configuration
|
||||
public static class IpsConfig {
|
||||
|
@ -107,5 +142,21 @@ public class IpsGenerationTest extends BaseResourceProviderR4Test {
|
|||
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private static <T extends IBaseResource> T findFirstEntryResource(Bundle theBundle, Class<T> theType, int theExpectedCount) {
|
||||
return findEntryResource(theBundle, theType, 0, theExpectedCount);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
static <T extends IBaseResource> T findEntryResource(Bundle theBundle, Class<T> theType, int index, int theExpectedCount) {
|
||||
List<Resource> resources = theBundle
|
||||
.getEntry()
|
||||
.stream()
|
||||
.map(Bundle.BundleEntryComponent::getResource)
|
||||
.filter(r -> theType.isAssignableFrom(r.getClass()))
|
||||
.toList();
|
||||
assertEquals(theExpectedCount, resources.size());
|
||||
return (T) resources.get(index);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -33,6 +33,7 @@ import org.hl7.fhir.r4.model.DateTimeType;
|
|||
import org.hl7.fhir.r4.model.Device;
|
||||
import org.hl7.fhir.r4.model.DeviceUseStatement;
|
||||
import org.hl7.fhir.r4.model.DiagnosticReport;
|
||||
import org.hl7.fhir.r4.model.Encounter;
|
||||
import org.hl7.fhir.r4.model.IdType;
|
||||
import org.hl7.fhir.r4.model.Immunization;
|
||||
import org.hl7.fhir.r4.model.Medication;
|
||||
|
@ -60,12 +61,15 @@ import java.util.Collections;
|
|||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static ca.uhn.fhir.jpa.ips.generator.IpsGenerationTest.findEntryResource;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.hamcrest.Matchers.startsWith;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
|
@ -74,6 +78,8 @@ public class IpsGeneratorSvcImplTest {
|
|||
public static final String MEDICATION_ID = "Medication/tyl";
|
||||
public static final String MEDICATION_STATEMENT_ID = "MedicationStatement/meds";
|
||||
public static final String MEDICATION_STATEMENT_ID2 = "MedicationStatement/meds2";
|
||||
public static final String PATIENT_ID = "Patient/123";
|
||||
public static final String ENCOUNTER_ID = "Encounter/encounter";
|
||||
private static final List<Class<? extends IBaseResource>> RESOURCE_TYPES = Lists.newArrayList(
|
||||
AllergyIntolerance.class,
|
||||
CarePlan.class,
|
||||
|
@ -157,7 +163,7 @@ public class IpsGeneratorSvcImplTest {
|
|||
registerRemainingResourceDaos();
|
||||
|
||||
// Test
|
||||
Bundle outcome = (Bundle) mySvc.generateIps(new SystemRequestDetails(), new IdType("Patient/123"));
|
||||
Bundle outcome = (Bundle) mySvc.generateIps(new SystemRequestDetails(), new IdType(PATIENT_ID));
|
||||
|
||||
// Verify Bundle Contents
|
||||
List<String> contentResourceTypes = toEntryResourceTypeStrings(outcome);
|
||||
|
@ -170,12 +176,7 @@ public class IpsGeneratorSvcImplTest {
|
|||
|
||||
// Verify
|
||||
Composition compositions = (Composition) outcome.getEntry().get(0).getResource();
|
||||
Composition.SectionComponent section = compositions
|
||||
.getSection()
|
||||
.stream()
|
||||
.filter(t -> t.getTitle().equals(myStrategy.getSectionRegistry().getSection(IpsSectionEnum.MEDICATION_SUMMARY).getTitle()))
|
||||
.findFirst()
|
||||
.orElseThrow();
|
||||
Composition.SectionComponent section = findSection(compositions, IpsSectionEnum.MEDICATION_SUMMARY);
|
||||
|
||||
HtmlPage narrativeHtml = HtmlUtil.parseAsHtml(section.getText().getDivAsString());
|
||||
ourLog.info("Narrative:\n{}", narrativeHtml.asXml());
|
||||
|
@ -191,6 +192,17 @@ public class IpsGeneratorSvcImplTest {
|
|||
assertThat(row.getCell(4).asNormalizedText(), containsString("2023"));
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
private Composition.SectionComponent findSection(Composition compositions, IpsSectionEnum sectionEnum) {
|
||||
Composition.SectionComponent section = compositions
|
||||
.getSection()
|
||||
.stream()
|
||||
.filter(t -> t.getTitle().equals(myStrategy.getSectionRegistry().getSection(sectionEnum).getTitle()))
|
||||
.findFirst()
|
||||
.orElseThrow();
|
||||
return section;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMedicationSummary_DuplicateSecondaryResources() {
|
||||
myStrategy.setSectionRegistry(new SectionRegistry().addGlobalCustomizer(t -> t.withNoInfoGenerator(null)));
|
||||
|
@ -209,7 +221,7 @@ public class IpsGeneratorSvcImplTest {
|
|||
registerRemainingResourceDaos();
|
||||
|
||||
// Test
|
||||
Bundle outcome = (Bundle) mySvc.generateIps(new SystemRequestDetails(), new IdType("Patient/123"));
|
||||
Bundle outcome = (Bundle) mySvc.generateIps(new SystemRequestDetails(), new IdType(PATIENT_ID));
|
||||
|
||||
// Verify Bundle Contents
|
||||
List<String> contentResourceTypes = toEntryResourceTypeStrings(outcome);
|
||||
|
@ -248,7 +260,7 @@ public class IpsGeneratorSvcImplTest {
|
|||
registerRemainingResourceDaos();
|
||||
|
||||
// Test
|
||||
Bundle outcome = (Bundle) mySvc.generateIps(new SystemRequestDetails(), new IdType("Patient/123"));
|
||||
Bundle outcome = (Bundle) mySvc.generateIps(new SystemRequestDetails(), new IdType(PATIENT_ID));
|
||||
|
||||
// Verify Bundle Contents
|
||||
List<String> contentResourceTypes = toEntryResourceTypeStrings(outcome);
|
||||
|
@ -263,12 +275,7 @@ public class IpsGeneratorSvcImplTest {
|
|||
|
||||
// Verify narrative - should have 2 rows (one for each primary MedicationStatement)
|
||||
Composition compositions = (Composition) outcome.getEntry().get(0).getResource();
|
||||
Composition.SectionComponent section = compositions
|
||||
.getSection()
|
||||
.stream()
|
||||
.filter(t -> t.getTitle().equals(myStrategy.getSectionRegistry().getSection(IpsSectionEnum.MEDICATION_SUMMARY).getTitle()))
|
||||
.findFirst()
|
||||
.orElseThrow();
|
||||
Composition.SectionComponent section = findSection(compositions, IpsSectionEnum.MEDICATION_SUMMARY);
|
||||
|
||||
HtmlPage narrativeHtml = HtmlUtil.parseAsHtml(section.getText().getDivAsString());
|
||||
ourLog.info("Narrative:\n{}", narrativeHtml.asXml());
|
||||
|
@ -304,16 +311,11 @@ public class IpsGeneratorSvcImplTest {
|
|||
registerRemainingResourceDaos();
|
||||
|
||||
// Test
|
||||
Bundle outcome = (Bundle) mySvc.generateIps(new SystemRequestDetails(), new IdType("Patient/123"));
|
||||
Bundle outcome = (Bundle) mySvc.generateIps(new SystemRequestDetails(), new IdType(PATIENT_ID));
|
||||
|
||||
// Verify
|
||||
Composition compositions = (Composition) outcome.getEntry().get(0).getResource();
|
||||
Composition.SectionComponent section = compositions
|
||||
.getSection()
|
||||
.stream()
|
||||
.filter(t -> t.getTitle().equals(myStrategy.getSectionRegistry().getSection(IpsSectionEnum.MEDICAL_DEVICES).getTitle()))
|
||||
.findFirst()
|
||||
.orElseThrow();
|
||||
Composition.SectionComponent section = findSection(compositions, IpsSectionEnum.MEDICAL_DEVICES);
|
||||
|
||||
HtmlPage narrativeHtml = HtmlUtil.parseAsHtml(section.getText().getDivAsString());
|
||||
ourLog.info("Narrative:\n{}", narrativeHtml.asXml());
|
||||
|
@ -356,16 +358,11 @@ public class IpsGeneratorSvcImplTest {
|
|||
registerRemainingResourceDaos();
|
||||
|
||||
// Test
|
||||
Bundle outcome = (Bundle) mySvc.generateIps(new SystemRequestDetails(), new IdType("Patient/123"));
|
||||
Bundle outcome = (Bundle) mySvc.generateIps(new SystemRequestDetails(), new IdType(PATIENT_ID));
|
||||
|
||||
// Verify
|
||||
Composition compositions = (Composition) outcome.getEntry().get(0).getResource();
|
||||
Composition.SectionComponent section = compositions
|
||||
.getSection()
|
||||
.stream()
|
||||
.filter(t -> t.getTitle().equals(myStrategy.getSectionRegistry().getSection(IpsSectionEnum.IMMUNIZATIONS).getTitle()))
|
||||
.findFirst()
|
||||
.orElseThrow();
|
||||
Composition.SectionComponent section = findSection(compositions, IpsSectionEnum.IMMUNIZATIONS);
|
||||
|
||||
HtmlPage narrativeHtml = HtmlUtil.parseAsHtml(section.getText().getDivAsString());
|
||||
ourLog.info("Narrative:\n{}", narrativeHtml.asXml());
|
||||
|
@ -383,10 +380,82 @@ public class IpsGeneratorSvcImplTest {
|
|||
assertThat(row.getCell(6).asNormalizedText(), containsString("2023"));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testReferencesUpdatedInSecondaryInclusions() {
|
||||
// Setup Patient
|
||||
registerPatientDaoWithRead();
|
||||
|
||||
// Setup Medication + MedicationStatement
|
||||
Encounter encounter = new Encounter();
|
||||
encounter.setId(new IdType(ENCOUNTER_ID));
|
||||
encounter.setSubject(new Reference(PATIENT_ID));
|
||||
ResourceMetadataKeyEnum.ENTRY_SEARCH_MODE.put(encounter, BundleEntrySearchModeEnum.INCLUDE);
|
||||
|
||||
Condition conditionActive = new Condition();
|
||||
conditionActive.setId("Condition/conditionActive");
|
||||
conditionActive.getClinicalStatus().addCoding()
|
||||
.setSystem("http://terminology.hl7.org/CodeSystem/condition-clinical")
|
||||
.setCode("active");
|
||||
conditionActive.setSubject(new Reference(PATIENT_ID));
|
||||
conditionActive.setEncounter(new Reference(ENCOUNTER_ID));
|
||||
ResourceMetadataKeyEnum.ENTRY_SEARCH_MODE.put(conditionActive, BundleEntrySearchModeEnum.MATCH);
|
||||
|
||||
Condition conditionResolved = new Condition();
|
||||
conditionResolved.setId("Condition/conditionResolved");
|
||||
conditionResolved.getClinicalStatus().addCoding()
|
||||
.setSystem("http://terminology.hl7.org/CodeSystem/condition-clinical")
|
||||
.setCode("resolved");
|
||||
conditionResolved.setSubject(new Reference(PATIENT_ID));
|
||||
conditionResolved.setEncounter(new Reference(ENCOUNTER_ID));
|
||||
ResourceMetadataKeyEnum.ENTRY_SEARCH_MODE.put(conditionResolved, BundleEntrySearchModeEnum.MATCH);
|
||||
|
||||
// Conditions will be loaded from two sections (problem list and illness history) so
|
||||
// we return an active condition the first time and a resolved one the second
|
||||
IFhirResourceDao<Condition> conditionDao = registerResourceDaoWithNoData(Condition.class);
|
||||
when(conditionDao.search(any(), any())).thenReturn(
|
||||
new SimpleBundleProvider(Lists.newArrayList(conditionActive, encounter)),
|
||||
new SimpleBundleProvider(Lists.newArrayList(conditionResolved, encounter))
|
||||
);
|
||||
|
||||
registerRemainingResourceDaos();
|
||||
|
||||
// Test
|
||||
Bundle outcome = (Bundle) mySvc.generateIps(new SystemRequestDetails(), new IdType(PATIENT_ID));
|
||||
|
||||
// Verify cross-references
|
||||
Patient addedPatient = findEntryResource(outcome, Patient.class, 0, 1);
|
||||
assertThat(addedPatient.getId(), startsWith("urn:uuid:"));
|
||||
Condition addedCondition = findEntryResource(outcome, Condition.class, 0, 2);
|
||||
assertThat(addedCondition.getId(), startsWith("urn:uuid:"));
|
||||
Condition addedCondition2 = findEntryResource(outcome, Condition.class, 1, 2);
|
||||
assertThat(addedCondition2.getId(), startsWith("urn:uuid:"));
|
||||
Encounter addedEncounter = findEntryResource(outcome, Encounter.class, 0, 1);
|
||||
assertThat(addedEncounter.getId(), startsWith("urn:uuid:"));
|
||||
MedicationStatement addedMedicationStatement = findEntryResource(outcome, MedicationStatement.class, 0, 1);
|
||||
assertThat(addedMedicationStatement.getId(), startsWith("urn:uuid:"));
|
||||
assertEquals("no-medication-info", addedMedicationStatement.getMedicationCodeableConcept().getCodingFirstRep().getCode());
|
||||
assertEquals(addedPatient.getId(), addedCondition.getSubject().getReference());
|
||||
assertEquals(addedEncounter.getId(), addedCondition.getEncounter().getReference());
|
||||
assertEquals(addedPatient.getId(), addedEncounter.getSubject().getReference());
|
||||
assertEquals(addedPatient.getId(), addedMedicationStatement.getSubject().getReference());
|
||||
|
||||
// Verify sections
|
||||
ourLog.info("Resource: {}", myFhirContext.newJsonParser().setPrettyPrint(true).encodeResourceToString(outcome));
|
||||
verify(conditionDao, times(2)).search(any(), any());
|
||||
Composition composition = (Composition) outcome.getEntry().get(0).getResource();
|
||||
Composition.SectionComponent problemListSection = findSection(composition, IpsSectionEnum.PROBLEM_LIST);
|
||||
assertEquals(addedCondition.getId(), problemListSection.getEntry().get(0).getReference());
|
||||
assertEquals(1, problemListSection.getEntry().size());
|
||||
Composition.SectionComponent illnessHistorySection = findSection(composition, IpsSectionEnum.ILLNESS_HISTORY);
|
||||
assertEquals(addedCondition2.getId(), illnessHistorySection.getEntry().get(0).getReference());
|
||||
assertEquals(1, illnessHistorySection.getEntry().size());
|
||||
}
|
||||
|
||||
private void registerPatientDaoWithRead() {
|
||||
IFhirResourceDao<Patient> patientDao = registerResourceDaoWithNoData(Patient.class);
|
||||
Patient patient = new Patient();
|
||||
patient.setId("Patient/123");
|
||||
patient.setId(PATIENT_ID);
|
||||
when(patientDao.read(any(), any())).thenReturn(patient);
|
||||
}
|
||||
|
||||
|
@ -432,12 +501,11 @@ public class IpsGeneratorSvcImplTest {
|
|||
|
||||
@Nonnull
|
||||
private static List<String> toEntryResourceTypeStrings(Bundle outcome) {
|
||||
List<String> contentResourceTypes = outcome
|
||||
return outcome
|
||||
.getEntry()
|
||||
.stream()
|
||||
.map(t -> t.getResource().getResourceType().name())
|
||||
.collect(Collectors.toList());
|
||||
return contentResourceTypes;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
|
|
Binary file not shown.
|
@ -1,5 +1,5 @@
|
|||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
|
@ -48,11 +48,16 @@
|
|||
<version>${project.version}</version>
|
||||
<classifier>classes</classifier>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-server-openapi</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-server-openapi</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-jpaserver-ips</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.helger</groupId>
|
||||
|
|
|
@ -12,6 +12,7 @@ import ca.uhn.fhir.jpa.bulk.export.provider.BulkDataExportProvider;
|
|||
import ca.uhn.fhir.jpa.delete.ThreadSafeResourceDeleterSvc;
|
||||
import ca.uhn.fhir.jpa.graphql.GraphQLProvider;
|
||||
import ca.uhn.fhir.jpa.interceptor.CascadingDeleteInterceptor;
|
||||
import ca.uhn.fhir.jpa.ips.provider.IpsOperationProvider;
|
||||
import ca.uhn.fhir.jpa.provider.DiffProvider;
|
||||
import ca.uhn.fhir.jpa.provider.JpaCapabilityStatementProvider;
|
||||
import ca.uhn.fhir.jpa.provider.JpaConformanceProviderDstu2;
|
||||
|
@ -152,6 +153,7 @@ public class TestRestfulServer extends RestfulServer {
|
|||
setServerConformanceProvider(confProvider);
|
||||
providers.add(myAppCtx.getBean(TerminologyUploaderProvider.class));
|
||||
providers.add(myAppCtx.getBean(GraphQLProvider.class));
|
||||
providers.add(myAppCtx.getBean(IpsOperationProvider.class));
|
||||
break;
|
||||
}
|
||||
case "R4B": {
|
||||
|
|
|
@ -2,9 +2,15 @@ package ca.uhn.fhirtest.config;
|
|||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.jpa.api.config.DaoConfig;
|
||||
import ca.uhn.fhir.jpa.api.dao.DaoRegistry;
|
||||
import ca.uhn.fhir.jpa.config.HapiJpaConfig;
|
||||
import ca.uhn.fhir.jpa.config.r4.JpaR4Config;
|
||||
import ca.uhn.fhir.jpa.config.util.HapiEntityManagerFactoryUtil;
|
||||
import ca.uhn.fhir.jpa.ips.api.IIpsGenerationStrategy;
|
||||
import ca.uhn.fhir.jpa.ips.generator.IIpsGeneratorSvc;
|
||||
import ca.uhn.fhir.jpa.ips.generator.IpsGeneratorSvcImpl;
|
||||
import ca.uhn.fhir.jpa.ips.provider.IpsOperationProvider;
|
||||
import ca.uhn.fhir.jpa.ips.strategy.DefaultIpsGenerationStrategy;
|
||||
import ca.uhn.fhir.jpa.model.dialect.HapiFhirH2Dialect;
|
||||
import ca.uhn.fhir.jpa.model.dialect.HapiFhirPostgres94Dialect;
|
||||
import ca.uhn.fhir.jpa.model.entity.ModelConfig;
|
||||
|
@ -196,5 +202,19 @@ public class TestR4Config {
|
|||
return new PropertySourcesPlaceholderConfigurer();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public IIpsGenerationStrategy ipsGenerationStrategy() {
|
||||
return new DefaultIpsGenerationStrategy();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public IIpsGeneratorSvc ipsGeneratorSvc(FhirContext theFhirContext, IIpsGenerationStrategy theGenerationStrategy, DaoRegistry theDaoRegistry) {
|
||||
return new IpsGeneratorSvcImpl(theFhirContext, theGenerationStrategy, theDaoRegistry);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public IpsOperationProvider ipsOperationProvider(IIpsGeneratorSvc theIpsGeneratorSvc) {
|
||||
return new IpsOperationProvider(theIpsGeneratorSvc);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue