Merge branch 'rel_6_4' into nd-4123-bulk-export-stuck-in-finalize-state

This commit is contained in:
nathaniel.doef 2023-02-08 15:44:46 -05:00
commit 1e8a7977b5
11 changed files with 66 additions and 13 deletions

View File

@ -42,7 +42,7 @@ FhirContext ctx = FhirContext.forDstu2();
ctx.setNarrativeGenerator(new DefaultThymeleafNarrativeGenerator()); ctx.setNarrativeGenerator(new DefaultThymeleafNarrativeGenerator());
// Encode the output, including the narrative // Encode the output, including the narrative
String output = ctx.newJsonParser().setPrettyPrint(true).encodeResourceToString(patient); String output = ctx.newXmlParser().setPrettyPrint(true).encodeResourceToString(patient);
System.out.println(output); System.out.println(output);
//END SNIPPET: example1 //END SNIPPET: example1

View File

@ -21,6 +21,7 @@ package ca.uhn.hapi.fhir.docs;
*/ */
import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.model.dstu2.resource.Patient;
import ca.uhn.fhir.narrative.CustomThymeleafNarrativeGenerator; import ca.uhn.fhir.narrative.CustomThymeleafNarrativeGenerator;
@SuppressWarnings("unused") @SuppressWarnings("unused")
@ -33,7 +34,11 @@ FhirContext ctx = FhirContext.forDstu2();
String propFile = "classpath:/com/foo/customnarrative.properties"; String propFile = "classpath:/com/foo/customnarrative.properties";
CustomThymeleafNarrativeGenerator gen = new CustomThymeleafNarrativeGenerator(propFile); CustomThymeleafNarrativeGenerator gen = new CustomThymeleafNarrativeGenerator(propFile);
Patient patient = new Patient();
ctx.setNarrativeGenerator(gen); ctx.setNarrativeGenerator(gen);
String output = ctx.newJsonParser().encodeResourceToString(patient);
System.out.println(output);
//END SNIPPET: gen //END SNIPPET: gen

View File

@ -0,0 +1,5 @@
---
type: fix
issue: 4090
title: "Previously, mdm links that connected resources and golden resources that were newly created had a link score of null,
this changes it to 1.0 as the golden resource should be a perfect match with the source resource it was created from."

View File

@ -0,0 +1,5 @@
---
type: fix
issue: 4520
jira: SMILE-4406
title: "Updating documentation related to narrative generation."

View File

@ -2,7 +2,7 @@
HAPI provides several ways to add [Narrative Text](http://hl7.org/fhir/narrative.html) to your encoded messages. HAPI provides several ways to add [Narrative Text](http://hl7.org/fhir/narrative.html) to your encoded messages.
The simplest way is to simply place the narrative text directly in the resource via the `setDivAsString()` method. The simplest way is to place the narrative text directly in the resource via the `setDivAsString()` method.
```java ```java
{{snippet:classpath:/ca/uhn/hapi/fhir/docs/Narrative.java|simple}} {{snippet:classpath:/ca/uhn/hapi/fhir/docs/Narrative.java|simple}}
@ -18,7 +18,7 @@ HAPI's built-in narrative generation uses the [Thymeleaf](http://www.thymeleaf.o
## A Simple Example ## A Simple Example
Activating HAPI's built-in narrative generator is as simple as calling [setNarrativeGenerator](/hapi-fhir/apidocs/hapi-fhir-base/ca/uhn/fhir/context/FhirContext.html#setNarrativeGenerator(ca.uhn.fhir.narrative.INarrativeGenerator). Activating HAPI's built-in narrative generator is as simple as calling [setNarrativeGenerator](/hapi-fhir/apidocs/hapi-fhir-base/ca/uhn/fhir/context/FhirContext.html#setNarrativeGenerator(ca.uhn.fhir.narrative.INarrativeGenerator)).
```java ```java
{{snippet:classpath:/ca/uhn/hapi/fhir/docs/Narrative.java|example1}} {{snippet:classpath:/ca/uhn/hapi/fhir/docs/Narrative.java|example1}}
@ -79,13 +79,16 @@ vitalsigns.profile=http://hl7.org/fhir/StructureDefinition/vitalsigns
vitalsigns.narrative=classpath:com/example/narrative/Observation_Vitals.html vitalsigns.narrative=classpath:com/example/narrative/Observation_Vitals.html
``` ```
You may also override/define behaviour for datatypes and other structures. These datatype narrative definitions will be used as content within <code>th:narrative</code> blocks in resource templates. See the example resource template above for an example. You may also override/define behaviour for datatypes and other structures. These datatype narrative definitions will be used as content within <code>th:narrative</code> blocks in resource templates. See the [example above](#creating-your-own-templates).
```properties ```properties
# You can create a template based on a type name # You can create a template based on a type name
quantity.dataType=Quantity quantity.dataType=Quantity
quantity.narrative=classpath:com/example/narrative/Quantity.html quantity.narrative=classpath:com/example/narrative/Quantity.html
string.dataType=String
string.narrative=classpath:com/example/narrative/String.html
# Or by class name, which can be useful for custom datatypes and structures # Or by class name, which can be useful for custom datatypes and structures
custom_extension.class=com.example.model.MyCustomExtension custom_extension.class=com.example.model.MyCustomExtension
custom_extension.narrative=classpath:com/example/narrative/CustomExtension.html custom_extension.narrative=classpath:com/example/narrative/CustomExtension.html
@ -105,13 +108,13 @@ Thymeleaf has a concept called Fragments, which allow reusable template portions
{{snippet:classpath:ca/uhn/fhir/narrative/narrative-with-fragment.properties}} {{snippet:classpath:ca/uhn/fhir/narrative/narrative-with-fragment.properties}}
``` ```
The following template declares a fragment (this is `narrative-with-fragment-child.html` in the example above): The following template declares `Fragment1` and `Fragment2` as part of file `narrative-with-fragment-child.html`:
```html ```html
{{snippet:classpath:ca/uhn/fhir/narrative/narrative-with-fragment-child.html}} {{snippet:classpath:ca/uhn/fhir/narrative/narrative-with-fragment-child.html}}
``` ```
And the following template uses it (this is `narrative-with-fragment-child.html` in the example above): And the following parent template (`narrative-with-fragment-parent.html`) imports `Fragment1` with parameter 'blah':
```html ```html
{{snippet:classpath:ca/uhn/fhir/narrative/narrative-with-fragment-parent.html}} {{snippet:classpath:ca/uhn/fhir/narrative/narrative-with-fragment-parent.html}}

View File

@ -569,6 +569,10 @@ abstract public class BaseMdmR4Test extends BaseJpaR4Test {
assertFields(MdmLink::getEidMatch, theExpectedValues); assertFields(MdmLink::getEidMatch, theExpectedValues);
} }
protected void assertLinksMatchScore(Double... theExpectedValues) {
assertFields(MdmLink::getScore, theExpectedValues);
}
public SearchParameterMap buildGoldenResourceSearchParameterMap() { public SearchParameterMap buildGoldenResourceSearchParameterMap() {
SearchParameterMap spMap = new SearchParameterMap(); SearchParameterMap spMap = new SearchParameterMap();
spMap.setLoadSynchronous(true); spMap.setLoadSynchronous(true);

View File

@ -77,9 +77,12 @@ public class MdmProviderQueryLinkR4Test extends BaseLinkR4Test {
JpaPid sourcePatient2Pid = runInTransaction(()->myIdHelperService.getPidOrNull(RequestPartitionId.allPartitions(), sourcePatient2)); JpaPid sourcePatient2Pid = runInTransaction(()->myIdHelperService.getPidOrNull(RequestPartitionId.allPartitions(), sourcePatient2));
MdmLink possibleDuplicateMdmLink = (MdmLink) myMdmLinkDaoSvc.newMdmLink(); MdmLink possibleDuplicateMdmLink = (MdmLink) myMdmLinkDaoSvc.newMdmLink();
possibleDuplicateMdmLink.setGoldenResourcePersistenceId(sourcePatient1Pid); possibleDuplicateMdmLink.setGoldenResourcePersistenceId(sourcePatient1Pid)
possibleDuplicateMdmLink.setSourcePersistenceId(sourcePatient2Pid); .setSourcePersistenceId(sourcePatient2Pid)
possibleDuplicateMdmLink.setMatchResult(MdmMatchResultEnum.POSSIBLE_DUPLICATE).setLinkSource(MdmLinkSourceEnum.AUTO); .setMatchResult(MdmMatchResultEnum.POSSIBLE_DUPLICATE)
.setLinkSource(MdmLinkSourceEnum.AUTO)
.setScore(1.0)
.setRuleCount(1L);
saveLink(possibleDuplicateMdmLink); saveLink(possibleDuplicateMdmLink);
} }
@ -90,7 +93,7 @@ public class MdmProviderQueryLinkR4Test extends BaseLinkR4Test {
List<Parameters.ParametersParameterComponent> list = getParametersByName(result, "link"); List<Parameters.ParametersParameterComponent> list = getParametersByName(result, "link");
assertThat(list, hasSize(1)); assertThat(list, hasSize(1));
List<Parameters.ParametersParameterComponent> part = list.get(0).getPart(); List<Parameters.ParametersParameterComponent> part = list.get(0).getPart();
assertMdmLink(MDM_LINK_PROPERTY_COUNT, part, mySourcePatientId.getValue(), myPatientId.getValue(), MdmMatchResultEnum.POSSIBLE_MATCH, "false", "true", null); assertMdmLink(MDM_LINK_PROPERTY_COUNT, part, mySourcePatientId.getValue(), myPatientId.getValue(), MdmMatchResultEnum.POSSIBLE_MATCH, "false", "true", "1");
} }
@Test @Test
@ -100,7 +103,7 @@ public class MdmProviderQueryLinkR4Test extends BaseLinkR4Test {
List<Parameters.ParametersParameterComponent> list = getParametersByName(result, "link"); List<Parameters.ParametersParameterComponent> list = getParametersByName(result, "link");
assertThat("All resources with Patient type found", list, hasSize(3)); assertThat("All resources with Patient type found", list, hasSize(3));
List<Parameters.ParametersParameterComponent> part = list.get(0).getPart(); List<Parameters.ParametersParameterComponent> part = list.get(0).getPart();
assertMdmLink(MDM_LINK_PROPERTY_COUNT, part, mySourcePatientId.getValue(), myPatientId.getValue(), MdmMatchResultEnum.POSSIBLE_MATCH, "false", "true", null); assertMdmLink(MDM_LINK_PROPERTY_COUNT, part, mySourcePatientId.getValue(), myPatientId.getValue(), MdmMatchResultEnum.POSSIBLE_MATCH, "false", "true", "1");
} }

View File

@ -68,6 +68,7 @@ public class MdmMatchLinkSvcTest extends BaseMdmR4Test {
assertLinksMatchResult(MATCH); assertLinksMatchResult(MATCH);
assertLinksCreatedNewResource(true); assertLinksCreatedNewResource(true);
assertLinksMatchedByEid(false); assertLinksMatchedByEid(false);
assertLinksMatchScore(1.0);
} }
@Test @Test
@ -79,6 +80,7 @@ public class MdmMatchLinkSvcTest extends BaseMdmR4Test {
assertLinksMatchResult(MATCH); assertLinksMatchResult(MATCH);
assertLinksCreatedNewResource(true); assertLinksCreatedNewResource(true);
assertLinksMatchedByEid(false); assertLinksMatchedByEid(false);
assertLinksMatchScore(1.0);
} }
@Test @Test
@ -93,6 +95,7 @@ public class MdmMatchLinkSvcTest extends BaseMdmR4Test {
assertLinksMatchResult(MATCH, MATCH); assertLinksMatchResult(MATCH, MATCH);
assertLinksCreatedNewResource(true, true); assertLinksCreatedNewResource(true, true);
assertLinksMatchedByEid(false, false); assertLinksMatchedByEid(false, false);
assertLinksMatchScore(1.0, 1.0);
} }
@Test @Test
@ -107,6 +110,7 @@ public class MdmMatchLinkSvcTest extends BaseMdmR4Test {
assertLinksMatchResult(MATCH, MATCH); assertLinksMatchResult(MATCH, MATCH);
assertLinksCreatedNewResource(true, false); assertLinksCreatedNewResource(true, false);
assertLinksMatchedByEid(false, false); assertLinksMatchedByEid(false, false);
assertLinksMatchScore(1.0, 2.0/3.0);
} }
@Test @Test

View File

@ -29,7 +29,7 @@ public final class MdmMatchOutcome {
public static final MdmMatchOutcome POSSIBLE_DUPLICATE = new MdmMatchOutcome(null, null).setMatchResultEnum(MdmMatchResultEnum.POSSIBLE_DUPLICATE); public static final MdmMatchOutcome POSSIBLE_DUPLICATE = new MdmMatchOutcome(null, null).setMatchResultEnum(MdmMatchResultEnum.POSSIBLE_DUPLICATE);
public static final MdmMatchOutcome NO_MATCH = new MdmMatchOutcome(null, null).setMatchResultEnum(MdmMatchResultEnum.NO_MATCH); public static final MdmMatchOutcome NO_MATCH = new MdmMatchOutcome(null, null).setMatchResultEnum(MdmMatchResultEnum.NO_MATCH);
public static final MdmMatchOutcome NEW_GOLDEN_RESOURCE_MATCH = new MdmMatchOutcome(null, null).setMatchResultEnum(MdmMatchResultEnum.MATCH).setCreatedNewResource(true); public static final MdmMatchOutcome NEW_GOLDEN_RESOURCE_MATCH = new MdmMatchOutcome(null, 1.0).setMatchResultEnum(MdmMatchResultEnum.MATCH).setCreatedNewResource(true);
public static final MdmMatchOutcome EID_MATCH = new MdmMatchOutcome(null, null).setMatchResultEnum(MdmMatchResultEnum.MATCH).setEidMatch(true); public static final MdmMatchOutcome EID_MATCH = new MdmMatchOutcome(null, null).setMatchResultEnum(MdmMatchResultEnum.MATCH).setEidMatch(true);
public static final MdmMatchOutcome POSSIBLE_MATCH = new MdmMatchOutcome(null, null).setMatchResultEnum(MdmMatchResultEnum.POSSIBLE_MATCH); public static final MdmMatchOutcome POSSIBLE_MATCH = new MdmMatchOutcome(null, null).setMatchResultEnum(MdmMatchResultEnum.POSSIBLE_MATCH);
@ -145,7 +145,10 @@ public final class MdmMatchOutcome {
* Returns the normalized score * Returns the normalized score
*/ */
public Double getNormalizedScore() { public Double getNormalizedScore() {
if (myMdmRuleCount == 0) { if (myCreatedNewResource) {
// If we created a new golden resource from this match, the match score must be 1.00
return 1.0;
} else if (myMdmRuleCount == 0) {
return 0.0; return 0.0;
} }
return score / myMdmRuleCount; return score / myMdmRuleCount;

View File

@ -1,5 +1,25 @@
package ca.uhn.fhir.batch2.jobs.export; package ca.uhn.fhir.batch2.jobs.export;
/*-
* #%L
* hapi-fhir-storage-batch2-jobs
* %%
* Copyright (C) 2014 - 2023 Smile CDR, Inc.
* %%
* 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.batch2.model.StatusEnum; import ca.uhn.fhir.batch2.model.StatusEnum;
import ca.uhn.fhir.jpa.api.svc.IBatch2JobRunner; import ca.uhn.fhir.jpa.api.svc.IBatch2JobRunner;
import ca.uhn.fhir.jpa.bulk.export.model.BulkExportJobStatusEnum; import ca.uhn.fhir.jpa.bulk.export.model.BulkExportJobStatusEnum;

View File

@ -4,6 +4,7 @@ bundle.resourceType = Bundle
bundle.style = thymeleaf bundle.style = thymeleaf
bundle.narrative = classpath:ca/uhn/fhir/narrative/narrative-with-fragment-parent.html bundle.narrative = classpath:ca/uhn/fhir/narrative/narrative-with-fragment-parent.html
# Fragment template
fragment1.fragmentName = MyFragment fragment1.fragmentName = MyFragment
fragment1.style = thymeleaf fragment1.style = thymeleaf
fragment1.narrative = classpath:ca/uhn/fhir/narrative/narrative-with-fragment-child.html fragment1.narrative = classpath:ca/uhn/fhir/narrative/narrative-with-fragment-child.html