Skip to content

Commit 49c2a6a

Browse files
Update ObservationMapperTest, ObservationStatementMapperTest, BloodPressureMapperTest to ignore the whitespace changes in XML formatting for Quantities.
Update ObservationValueQuantityMapper to ensure correct mapping of interval physical quantities Add Unit tests for uncertainty Update unit tests to check for any system or none. Update tests files for interval tests to reflect new mapping.
1 parent 135d9bc commit 49c2a6a

10 files changed

Lines changed: 182 additions & 102 deletions

File tree

service/src/main/java/uk/nhs/adaptors/gp2gp/ehr/mapper/ObservationValueQuantityMapper.java

Lines changed: 103 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,22 @@
11
package uk.nhs.adaptors.gp2gp.ehr.mapper;
22

3-
import java.math.BigDecimal;
4-
5-
import org.apache.commons.lang3.StringUtils;
63
import org.hl7.fhir.dstu3.model.BooleanType;
74
import org.hl7.fhir.dstu3.model.Extension;
85
import org.hl7.fhir.dstu3.model.Quantity;
96

7+
import static org.hl7.fhir.dstu3.model.Quantity.QuantityComparator.GREATER_OR_EQUAL;
8+
import static org.hl7.fhir.dstu3.model.Quantity.QuantityComparator.LESS_OR_EQUAL;
9+
import static org.hl7.fhir.dstu3.model.Quantity.QuantityComparator.LESS_THAN;
10+
1011
public final class ObservationValueQuantityMapper {
1112

12-
private static final String UNITS_OF_MEASURE_SYSTEM = "http://unitsofmeasure.org";
13-
private static final String UNCERTAINTY_EXTENSION = "https://fhir.hl7.org.uk/STU3/StructureDefinition/Extension-CareConnect-ValueApproximation-1";
13+
private static final String UNITS_OF_MEASURE_SYSTEM =
14+
"http://unitsofmeasure.org";
15+
private static final String UNCERTAINTY_EXTENSION =
16+
"https://fhir.hl7.org.uk/STU3/StructureDefinition/Extension-CareConnect-ValueApproximation-1";
17+
private static final String UNCERTAINTY_CODE = """
18+
<uncertaintyCode code="U" codeSystem="2.16.840.1.113883.5.1053" displayName="Recorded as uncertain" />
19+
""";
1420

1521
public static final String PQ_WITH_UOM_SYSTEM_AND_CODE_TEMPLATE = """
1622
<value xsi:type="PQ" value="%s" unit="%s" />""";
@@ -22,41 +28,44 @@ public final class ObservationValueQuantityMapper {
2228
<value xsi:type="PQ" value="%s" unit="1">%n\
2329
<translation value="%s" code="%s" codeSystem="%s" />%n\
2430
</value>""";
25-
public static final String PQ_WITH_ANY_SYSTEM_AND_UNIT_TEMPLATE = """
31+
public static final String PQ_WITH_ANY_OR_NO_SYSTEM_AND_UNIT_TEMPLATE = """
2632
<value xsi:type="PQ" value="%s" unit="1">%n\
2733
<translation value="%s">%n\
2834
<originalText>%s</originalText>%n\
2935
</translation>%n\
3036
</value>""";
3137
private static final String PQ_WITH_ONLY_VALUE_TEMPLATE =
3238
"<value xsi:type=\"PQ\" value=\"%s\" unit=\"1\" />";
33-
private static final String IVL_PQ_ELEMENT =
34-
"<value xsi:type=\"IVL_PQ\">";
35-
private static final String LESS_COMPARATOR_VALUE_TEMPLATE = IVL_PQ_ELEMENT
36-
+ "<high value=\"%s\" unit=\"%s\" inclusive=\"false\"/></value>";
37-
private static final String LESS_OR_EQUAL_COMPARATOR_VALUE_TEMPLATE = IVL_PQ_ELEMENT
38-
+ "<high value=\"%s\" unit=\"%s\" inclusive=\"true\"/></value>";
39-
private static final String GREATER_COMPARATOR_VALUE_TEMPLATE = IVL_PQ_ELEMENT + "<low value=\"%s\" "
40-
+ "unit=\"%s\" inclusive=\"false\"/></value>";
41-
private static final String GREATER_OR_EQUAL_COMPARATOR_VALUE_TEMPLATE = "<value xsi:type=\"IVL_PQ\"><low value=\"%s\" "
42-
+ "unit=\"%s\" inclusive=\"true\"/></value>";
43-
private static final String LESS_COMPARATOR_NO_SYSTEM_VALUE_TEMPLATE = IVL_PQ_ELEMENT
44-
+ "<high value=\"%s\" unit=\"1\" inclusive=\"false\"><translation value=\"%s\">"
45-
+ "%s</translation></high></value>";
46-
private static final String LESS_OR_EQUAL_COMPARATOR_NO_SYSTEM_VALUE_TEMPLATE = "<value xsi:type=\"IVL_PQ\"><high "
47-
+ "value=\"%s\" unit=\"1\" inclusive=\"true\"><translation value=\"%s\">"
48-
+ "%s</translation></high></value>";
49-
private static final String GREATER_COMPARATOR_NO_SYSTEM_VALUE_TEMPLATE = IVL_PQ_ELEMENT
50-
+ "<low value=\"%s\" unit=\"1\" inclusive=\"false\"><translation value=\"%s\">%s"
51-
+ "</translation></low></value>";
52-
private static final String GREATER_OR_EQUAL_COMPARATOR_NO_SYSTEM_VALUE_TEMPLATE = IVL_PQ_ELEMENT
53-
+ "<low value=\"%s\" unit=\"1\" inclusive=\"true\"><translation value=\"%s\">"
54-
+ "%s</translation></low></value>";
55-
private static final String UNCERTAINTY_CODE = """
56-
<uncertaintyCode code="U" codeSystem="2.16.840.1.113883.5.1053" displayName="Recorded as uncertain"/>
57-
""";
58-
private static final String QUANTITY_UNIT = "<originalText>%s</originalText>";
5939

40+
private static final String IVL_PQ_WITH_UOM_SYSTEM_AND_CODE_TEMPLATE = """
41+
<value xsi:type="IVL_PQ">%n\
42+
<%s value="%s" unit="%s" inclusive="%s" />%n\
43+
</value>""";
44+
45+
public static final String IVL_PQ_WITH_NON_UOM_SYSTEM_AND_CODE_AND_UNIT_TEMPLATE = """
46+
<value xsi:type="IVL_PQ">%n\
47+
<%s value="%s" unit="%s" inclusive="%s">%n\
48+
<translation value="%s" code="%s" codeSystem="%s" displayName="%s" />%n\
49+
</%s>%n\
50+
</value>""";
51+
public static final String IVL_PQ_WITH_NON_UOM_SYSTEM_AND_CODE_TEMPLATE = """
52+
<value xsi:type="IVL_PQ">%n\
53+
<%s value="%s" unit="%s" inclusive="%s">%n\
54+
<translation value="%s" code="%s" codeSystem="%s" />%n\
55+
</%s>%n\
56+
</value>""";
57+
public static final String IVL_PQ_WITH_ANY_OR_NO_SYSTEM_AND_UNIT_TEMPLATE = """
58+
<value xsi:type="IVL_PQ">%n\
59+
<%s value="%s" unit="1" inclusive="%s">%n\
60+
<translation value="%s">%n\
61+
<originalText>%s</originalText>%n\
62+
</translation>%n\
63+
</%s>%n\
64+
</value>""";
65+
public static final String IVL_PQ_WITH_ONLY_VALUE_TEMPLATE = """
66+
<value xsi:type="IVL_PQ">%n\
67+
<%s value="%s" unit="1" inclusive="%s" />%n\
68+
</value>""";
6069

6170
private ObservationValueQuantityMapper() {
6271
}
@@ -68,18 +77,16 @@ public static String processQuantity(Quantity valueQuantity) {
6877
stringBuilder.append(UNCERTAINTY_CODE);
6978
}
7079

71-
if (!valueQuantity.hasComparator()) {
72-
var result = prepareQuantityValueWithoutComparator(valueQuantity);
73-
stringBuilder.append(result);
74-
} else {
75-
var result = prepareQuantityValueAccordingToComparator(valueQuantity);
76-
stringBuilder.append(result);
77-
}
80+
var quantityXml = valueQuantity.hasComparator()
81+
? getPhysicalQuantityIntervalXml(valueQuantity)
82+
: getPhysicalQuantityXml(valueQuantity);
7883

79-
return stringBuilder.toString();
84+
return stringBuilder
85+
.append(quantityXml)
86+
.toString();
8087
}
8188

82-
private static String prepareQuantityValueWithoutComparator(Quantity valueQuantity) {
89+
private static String getPhysicalQuantityXml(Quantity valueQuantity) {
8390
if (UNITS_OF_MEASURE_SYSTEM.equals(valueQuantity.getSystem()) && valueQuantity.hasCode()) {
8491
return PQ_WITH_UOM_SYSTEM_AND_CODE_TEMPLATE.formatted(
8592
valueQuantity.getValue(),
@@ -103,8 +110,8 @@ private static String prepareQuantityValueWithoutComparator(Quantity valueQuanti
103110
valueQuantity.getSystem()
104111
);
105112
}
106-
if (valueQuantity.hasSystem() && valueQuantity.hasUnit()) {
107-
return PQ_WITH_ANY_SYSTEM_AND_UNIT_TEMPLATE.formatted(
113+
if (valueQuantity.hasUnit()) {
114+
return PQ_WITH_ANY_OR_NO_SYSTEM_AND_UNIT_TEMPLATE.formatted(
108115
valueQuantity.getValue(),
109116
valueQuantity.getValue(),
110117
valueQuantity.getUnit()
@@ -114,46 +121,66 @@ private static String prepareQuantityValueWithoutComparator(Quantity valueQuanti
114121
return PQ_WITH_ONLY_VALUE_TEMPLATE.formatted(valueQuantity.getValue());
115122
}
116123

117-
private static String prepareUnit(Quantity valueQuantity) {
118-
return valueQuantity.hasUnit() ? String.format(QUANTITY_UNIT, valueQuantity.getUnit()) : StringUtils.EMPTY;
119-
}
120-
121-
private static String prepareQuantityValueAccordingToComparator(Quantity valueQuantity) {
122-
if (valueQuantity.getComparator() == Quantity.QuantityComparator.LESS_THAN) {
123-
return prepareQuantityValueByComparator(valueQuantity,
124-
LESS_COMPARATOR_VALUE_TEMPLATE,
125-
LESS_COMPARATOR_NO_SYSTEM_VALUE_TEMPLATE);
126-
} else if (valueQuantity.getComparator() == Quantity.QuantityComparator.LESS_OR_EQUAL) {
127-
return prepareQuantityValueByComparator(valueQuantity,
128-
LESS_OR_EQUAL_COMPARATOR_VALUE_TEMPLATE,
129-
LESS_OR_EQUAL_COMPARATOR_NO_SYSTEM_VALUE_TEMPLATE);
130-
} else if (valueQuantity.getComparator() == Quantity.QuantityComparator.GREATER_THAN) {
131-
return prepareQuantityValueByComparator(valueQuantity,
132-
GREATER_COMPARATOR_VALUE_TEMPLATE,
133-
GREATER_COMPARATOR_NO_SYSTEM_VALUE_TEMPLATE);
134-
} else if (valueQuantity.getComparator() == Quantity.QuantityComparator.GREATER_OR_EQUAL) {
135-
return prepareQuantityValueByComparator(valueQuantity,
136-
GREATER_OR_EQUAL_COMPARATOR_VALUE_TEMPLATE,
137-
GREATER_OR_EQUAL_COMPARATOR_NO_SYSTEM_VALUE_TEMPLATE);
138-
}
139-
140-
return StringUtils.EMPTY;
141-
}
142-
143-
private static String prepareQuantityValueByComparator(Quantity valueQuantity, String systemTemplate, String nonSystemTemplate) {
124+
private static String getPhysicalQuantityIntervalXml(Quantity valueQuantity) {
144125
if (valueQuantity.hasSystem() && valueQuantity.getSystem().equals(UNITS_OF_MEASURE_SYSTEM)) {
145-
return formatSystemTemplate(systemTemplate, valueQuantity.getValue(), valueQuantity.getCode());
126+
return IVL_PQ_WITH_UOM_SYSTEM_AND_CODE_TEMPLATE.formatted(
127+
getHighOrLow(valueQuantity),
128+
valueQuantity.getValue(),
129+
valueQuantity.getCode(),
130+
isInclusive(valueQuantity)
131+
);
132+
}
133+
if (valueQuantity.hasSystem() && valueQuantity.hasCode() && valueQuantity.hasUnit()) {
134+
return IVL_PQ_WITH_NON_UOM_SYSTEM_AND_CODE_AND_UNIT_TEMPLATE.formatted(
135+
getHighOrLow(valueQuantity),
136+
valueQuantity.getValue(),
137+
valueQuantity.getCode(),
138+
isInclusive(valueQuantity),
139+
valueQuantity.getValue(),
140+
valueQuantity.getCode(),
141+
valueQuantity.getSystem(),
142+
valueQuantity.getUnit(),
143+
getHighOrLow(valueQuantity)
144+
);
145+
}
146+
if (valueQuantity.hasSystem() && valueQuantity.hasCode()) {
147+
return IVL_PQ_WITH_NON_UOM_SYSTEM_AND_CODE_TEMPLATE.formatted(
148+
getHighOrLow(valueQuantity),
149+
valueQuantity.getValue(),
150+
valueQuantity.getCode(),
151+
isInclusive(valueQuantity),
152+
valueQuantity.getValue(),
153+
valueQuantity.getCode(),
154+
valueQuantity.getSystem(),
155+
getHighOrLow(valueQuantity)
156+
);
157+
}
158+
if (valueQuantity.hasUnit()) {
159+
return IVL_PQ_WITH_ANY_OR_NO_SYSTEM_AND_UNIT_TEMPLATE.formatted(
160+
getHighOrLow(valueQuantity),
161+
valueQuantity.getValue(),
162+
isInclusive(valueQuantity),
163+
valueQuantity.getValue(),
164+
valueQuantity.getUnit(),
165+
getHighOrLow(valueQuantity)
166+
);
146167
}
147168

148-
return formatNoSystemTemplate(nonSystemTemplate, valueQuantity.getValue(), prepareUnit(valueQuantity));
169+
return IVL_PQ_WITH_ONLY_VALUE_TEMPLATE.formatted(
170+
getHighOrLow(valueQuantity),
171+
valueQuantity.getValue(),
172+
isInclusive(valueQuantity)
173+
);
149174
}
150175

151-
private static String formatSystemTemplate(String template, BigDecimal value, String code) {
152-
return String.format(template, value, code);
176+
private static boolean isInclusive(Quantity valueQuantity) {
177+
return valueQuantity.getComparator() == GREATER_OR_EQUAL || valueQuantity.getComparator() == LESS_OR_EQUAL;
153178
}
154179

155-
private static String formatNoSystemTemplate(String template, BigDecimal value, String unit) {
156-
return String.format(template, value, value, unit);
180+
private static String getHighOrLow(Quantity valueQuantity) {
181+
return valueQuantity.getComparator() == LESS_THAN || valueQuantity.getComparator() == LESS_OR_EQUAL
182+
? "high"
183+
: "low";
157184
}
158185

159186
private static boolean isUncertaintyCodePresent(Quantity valueQuantity) {
@@ -164,7 +191,6 @@ private static boolean isUncertaintyCodePresent(Quantity valueQuantity) {
164191
}
165192
}
166193
}
167-
168194
return false;
169195
}
170196

service/src/test/java/uk/nhs/adaptors/gp2gp/ehr/mapper/BloodPressureMapperTest.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ public void When_MappingBloodPressureWithNestedTrue_Expect_CompoundStatementXmlR
109109
Observation observation = new FhirParseService().parseResource(jsonInput, Observation.class);
110110
var outputMessage = bloodPressureMapper.mapBloodPressure(observation, true);
111111

112-
assertThat(outputMessage).isEqualTo(expectedOutput);
112+
assertThat(outputMessage).isEqualToIgnoringWhitespace(expectedOutput);
113113
}
114114

115115
@ParameterizedTest
@@ -126,7 +126,7 @@ public void When_MappingBloodPressure_Expect_CompoundStatementXmlReturned(String
126126

127127
assertThat(outputMessage)
128128
.describedAs(TestArgumentsLoaderUtil.FAIL_MESSAGE, inputJson, outputXml)
129-
.isEqualTo(expectedOutput);
129+
.isEqualToIgnoringWhitespace(expectedOutput);
130130
}
131131

132132
private static Stream<Arguments> testArguments() {
@@ -160,7 +160,7 @@ messageContext, randomIdGeneratorService, new StructuredObservationValueMapper()
160160
Observation observation = new FhirParseService().parseResource(jsonInput, Observation.class);
161161
var outputMessage = bloodPressureMapper.mapBloodPressure(observation, true);
162162

163-
assertThat(outputMessage).isEqualTo(expectedOutput);
163+
assertThat(outputMessage).isEqualToIgnoringWhitespace(expectedOutput);
164164
}
165165

166166
@Test

service/src/test/java/uk/nhs/adaptors/gp2gp/ehr/mapper/ObservationStatementMapperTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -226,7 +226,7 @@ public void When_MappingObservationJson_Expect_ObservationStatementXmlOutput(Str
226226
Observation parsedObservation = new FhirParseService().parseResource(jsonInput, Observation.class);
227227

228228
String outputMessage = observationStatementMapper.mapObservationToObservationStatement(parsedObservation, false);
229-
assertThat(outputMessage).isEqualTo(expectedOutputMessage);
229+
assertThat(outputMessage).isEqualToIgnoringWhitespace(expectedOutputMessage);
230230
}
231231

232232
@ParameterizedTest

0 commit comments

Comments
 (0)