Skip to content

Commit cb96e2d

Browse files
Update functionality to correctly handle PQ Quantities in ObservationValueQuantityMapper
Update Tests for these changes. Remove the source XML files no longer required
1 parent 3e6ff09 commit cb96e2d

10 files changed

Lines changed: 198 additions & 126 deletions

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

Lines changed: 60 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,27 @@ public final class ObservationValueQuantityMapper {
1111

1212
private static final String UNITS_OF_MEASURE_SYSTEM = "http://unitsofmeasure.org";
1313
private static final String UNCERTAINTY_EXTENSION = "https://fhir.hl7.org.uk/STU3/StructureDefinition/Extension-CareConnect-ValueApproximation-1";
14-
private static final String IVL_PQ_ELEMENT = "<value xsi:type=\"IVL_PQ\">";
1514

16-
private static final String NO_COMPARATOR_VALUE_TEMPLATE = "<value xsi:type=\"PQ\" value=\"%s\" unit=\"%s\"/>";
15+
public static final String PQ_WITH_UOM_SYSTEM_AND_CODE_TEMPLATE = """
16+
<value xsi:type="PQ" value="%s" unit="%s" />""";
17+
public static final String PQ_WITH_NON_UOM_SYSTEM_AND_CODE_AND_UNIT_TEMPLATE = """
18+
<value xsi:type="PQ" value="%s" unit="1">%n\
19+
<translation value="%s" code="%s" codeSystem="%s" displayName="%s" />%n\
20+
</value>""";
21+
public static final String PQ_WITH_NON_UOM_SYSTEM_AND_CODE_TEMPLATE = """
22+
<value xsi:type="PQ" value="%s" unit="1">%n\
23+
<translation value="%s" code="%s" codeSystem="%s" />%n\
24+
</value>""";
25+
public static final String PQ_WITH_ANY_SYSTEM_AND_UNIT_TEMPLATE = """
26+
<value xsi:type="PQ" value="%s" unit="1">%n\
27+
<translation value="%s">%n\
28+
<originalText>%s</originalText>%n\
29+
</translation>%n\
30+
</value>""";
31+
private static final String PQ_WITH_ONLY_VALUE_TEMPLATE =
32+
"<value xsi:type=\"PQ\" value=\"%s\" unit=\"1\" />";
33+
private static final String IVL_PQ_ELEMENT =
34+
"<value xsi:type=\"IVL_PQ\">";
1735
private static final String LESS_COMPARATOR_VALUE_TEMPLATE = IVL_PQ_ELEMENT
1836
+ "<high value=\"%s\" unit=\"%s\" inclusive=\"false\"/></value>";
1937
private static final String LESS_OR_EQUAL_COMPARATOR_VALUE_TEMPLATE = IVL_PQ_ELEMENT
@@ -22,8 +40,6 @@ public final class ObservationValueQuantityMapper {
2240
+ "unit=\"%s\" inclusive=\"false\"/></value>";
2341
private static final String GREATER_OR_EQUAL_COMPARATOR_VALUE_TEMPLATE = "<value xsi:type=\"IVL_PQ\"><low value=\"%s\" "
2442
+ "unit=\"%s\" inclusive=\"true\"/></value>";
25-
private static final String NO_COMPARATOR_NO_SYSTEM_VALUE_TEMPLATE = "<value xsi:type=\"PQ\" value=\"%s\" unit=\"1\">"
26-
+ "<translation value=\"%s\">%s</translation></value>";
2743
private static final String LESS_COMPARATOR_NO_SYSTEM_VALUE_TEMPLATE = IVL_PQ_ELEMENT
2844
+ "<high value=\"%s\" unit=\"1\" inclusive=\"false\"><translation value=\"%s\">"
2945
+ "%s</translation></high></value>";
@@ -36,36 +52,63 @@ public final class ObservationValueQuantityMapper {
3652
private static final String GREATER_OR_EQUAL_COMPARATOR_NO_SYSTEM_VALUE_TEMPLATE = IVL_PQ_ELEMENT
3753
+ "<low value=\"%s\" unit=\"1\" inclusive=\"true\"><translation value=\"%s\">"
3854
+ "%s</translation></low></value>";
39-
private static final String UNCERTAINTY_CODE = "<uncertaintyCode code=\"U\" "
40-
+ "codeSystem=\"2.16.840.1.113883.5.1053\" displayName=\"Recorded as uncertain\"/>";
55+
private static final String UNCERTAINTY_CODE = """
56+
<uncertaintyCode code="U" codeSystem="2.16.840.1.113883.5.1053" displayName="Recorded as uncertain"/>
57+
""";
4158
private static final String QUANTITY_UNIT = "<originalText>%s</originalText>";
4259

4360

4461
private ObservationValueQuantityMapper() {
4562
}
4663

4764
public static String processQuantity(Quantity valueQuantity) {
48-
String result = StringUtils.EMPTY;
65+
var stringBuilder = new StringBuilder();
66+
4967
if (isUncertaintyCodePresent(valueQuantity)) {
50-
result += UNCERTAINTY_CODE;
68+
stringBuilder.append(UNCERTAINTY_CODE);
5169
}
5270

5371
if (!valueQuantity.hasComparator()) {
54-
result += prepareQuantityValueWithoutComparator(valueQuantity);
72+
var result = prepareQuantityValueWithoutComparator(valueQuantity);
73+
stringBuilder.append(result);
5574
} else {
56-
result += prepareQuantityValueAccordingToComparator(valueQuantity);
75+
var result = prepareQuantityValueAccordingToComparator(valueQuantity);
76+
stringBuilder.append(result);
5777
}
5878

59-
return result;
79+
return stringBuilder.toString();
6080
}
6181

6282
private static String prepareQuantityValueWithoutComparator(Quantity valueQuantity) {
63-
BigDecimal value = valueQuantity.getValue();
64-
if (valueQuantity.hasSystem() && valueQuantity.getSystem().equals(UNITS_OF_MEASURE_SYSTEM)) {
65-
return String.format(NO_COMPARATOR_VALUE_TEMPLATE, value, valueQuantity.getUnit());
66-
} else {
67-
return String.format(NO_COMPARATOR_NO_SYSTEM_VALUE_TEMPLATE, value, value, prepareUnit(valueQuantity));
68-
}
83+
return switch (valueQuantity) {
84+
case Quantity vq when UNITS_OF_MEASURE_SYSTEM.equals(vq.getSystem()) && vq.hasCode() ->
85+
PQ_WITH_UOM_SYSTEM_AND_CODE_TEMPLATE.formatted(
86+
valueQuantity.getValue(),
87+
valueQuantity.getCode()
88+
);
89+
case Quantity vq when vq.hasSystem() && vq.hasCode() && vq.hasUnit() ->
90+
PQ_WITH_NON_UOM_SYSTEM_AND_CODE_AND_UNIT_TEMPLATE.formatted(
91+
vq.getValue(),
92+
vq.getValue(),
93+
vq.getCode(),
94+
vq.getSystem(),
95+
vq.getUnit()
96+
);
97+
case Quantity vq when vq.hasSystem() && vq.hasCode() ->
98+
PQ_WITH_NON_UOM_SYSTEM_AND_CODE_TEMPLATE.formatted(
99+
vq.getValue(),
100+
vq.getValue(),
101+
vq.getCode(),
102+
vq.getSystem()
103+
);
104+
case Quantity vq when vq.hasSystem() && vq.hasUnit() ->
105+
PQ_WITH_ANY_SYSTEM_AND_UNIT_TEMPLATE.formatted(
106+
vq.getValue(),
107+
vq.getValue(),
108+
vq.getUnit()
109+
);
110+
default -> PQ_WITH_ONLY_VALUE_TEMPLATE.formatted(valueQuantity.getValue());
111+
};
69112
}
70113

71114
private static String prepareUnit(Quantity valueQuantity) {

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

Lines changed: 138 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,23 @@
11
package uk.nhs.adaptors.gp2gp.ehr.mapper;
22

3-
import static org.assertj.core.api.Assertions.assertThat;
4-
53
import java.io.IOException;
64
import java.util.stream.Stream;
75

86
import org.hl7.fhir.dstu3.model.Observation;
7+
import org.hl7.fhir.dstu3.model.Quantity;
8+
import org.junit.jupiter.api.Test;
99
import org.junit.jupiter.params.ParameterizedTest;
1010
import org.junit.jupiter.params.provider.Arguments;
1111
import org.junit.jupiter.params.provider.MethodSource;
1212

1313
import uk.nhs.adaptors.gp2gp.common.service.FhirParseService;
1414
import uk.nhs.adaptors.gp2gp.utils.ResourceTestFileUtils;
1515

16+
import static org.assertj.core.api.Assertions.assertThat;
17+
1618
public class ObservationValueQuantityMapperTest {
1719
private static final String TEST_FILES_DIRECTORY = "/ehr/mapper/observation/quantity/";
1820

19-
private static final String INPUT_JSON_WITH_UNIT_OF_MEASURE_SYSTEM_NO_COMPARATOR = TEST_FILES_DIRECTORY
20-
+ "example-observation-resource-with-quantity-1.json";
21-
private static final String OUTPUT_XML_WITH_UNIT_OF_MEASURE_SYSTEM_NO_COMPARATOR = TEST_FILES_DIRECTORY
22-
+ "expected-output-quantity-1.xml";
2321
private static final String INPUT_JSON_WITH_UNIT_OF_MEASURE_SYSTEM_WITH_LESS_COMPARATOR = TEST_FILES_DIRECTORY
2422
+ "example-observation-resource-with-quantity-2.json";
2523
private static final String OUTPUT_XML_WITH_UNIT_OF_MEASURE_SYSTEM_WITH_LESS_COMPARATOR = TEST_FILES_DIRECTORY
@@ -36,10 +34,6 @@ public class ObservationValueQuantityMapperTest {
3634
+ "example-observation-resource-with-quantity-5.json";
3735
private static final String OUTPUT_XML_WITH_UNIT_OF_MEASURE_SYSTEM_WITH_GREATER_EQUAL_COMPARATOR = TEST_FILES_DIRECTORY
3836
+ "expected-output-quantity-5.xml";
39-
private static final String INPUT_JSON_WITH_NO_SYSTEM_AND_NO_COMPARATOR = TEST_FILES_DIRECTORY
40-
+ "example-observation-resource-with-quantity-6.json";
41-
private static final String OUTPUT_XML_WITH_NO_SYSTEM_AND_NO_COMPARATOR = TEST_FILES_DIRECTORY
42-
+ "expected-output-quantity-6.xml";
4337
private static final String INPUT_JSON_WITH_NO_SYSTEM_AND_LESS_COMPARATOR = TEST_FILES_DIRECTORY
4438
+ "example-observation-resource-with-quantity-7.json";
4539
private static final String OUTPUT_XML_WITH_NO_SYSTEM_AND_LESS_COMPARATOR = TEST_FILES_DIRECTORY
@@ -56,10 +50,6 @@ public class ObservationValueQuantityMapperTest {
5650
+ "example-observation-resource-with-quantity-10.json";
5751
private static final String OUTPUT_XML_WITH_NO_SYSTEM_AND_EQUAL_GREATER_COMPARATOR = TEST_FILES_DIRECTORY
5852
+ "expected-output-quantity-10.xml";
59-
private static final String INPUT_JSON_WITH_NO_UNIT = TEST_FILES_DIRECTORY
60-
+ "example-observation-resource-with-quantity-11.json";
61-
private static final String OUTPUT_XML_WITH_NO_UNIT = TEST_FILES_DIRECTORY
62-
+ "expected-output-quantity-11.xml";
6353
private static final String INPUT_JSON_WITH_COMPARATOR_AND_NO_UNIT = TEST_FILES_DIRECTORY
6454
+ "example-observation-resource-with-quantity-12.json";
6555
private static final String OUTPUT_XML_WITH_COMPARATOR_AND_NO_UNIT = TEST_FILES_DIRECTORY
@@ -80,10 +70,11 @@ public class ObservationValueQuantityMapperTest {
8070
+ "example-observation-resource-with-quantity-16.json";
8171
private static final String OUTPUT_XML_WITH_NO_SYSTEM_NO_UNIT_AND_EQUAL_GREATER_COMPARATOR = TEST_FILES_DIRECTORY
8272
+ "expected-output-quantity-16.xml";
83-
private static final String INPUT_JSON_WITH_UNIT_OF_MEASURE_SYSTEM_NO_COMPARATOR_NO_CODE = TEST_FILES_DIRECTORY
84-
+ "example-observation-resource-with-quantity-17.json";
85-
private static final String OUTPUT_JSON_WITH_UNIT_OF_MEASURE_SYSTEM_NO_COMPARATOR_NO_CODE = TEST_FILES_DIRECTORY
86-
+ "expected-output-quantity-17.xml";
73+
public static final double VALUE_37_1 = 37.1;
74+
public static final String UOM_SYSTEM = "http://unitsofmeasure.org";
75+
public static final String CODE_CEL = "Cel";
76+
public static final String UNIT_C = "C";
77+
public static final String NON_UOM_SYSTEM = "Non-UOM system";
8778

8879
@ParameterizedTest
8980
@MethodSource("testFilePaths")
@@ -97,10 +88,136 @@ public void When_MappingParsedQuantityJson_Expect_CorrectXmlOutput(String input,
9788
assertThat(outputMessage).isEqualToIgnoringWhitespace(expectedOutputMessage);
9889
}
9990

91+
@Test
92+
public void When_MappingQuantityWithUOMSystemAndCode_Expect_XmlWithValueAndQuantitySetAndNoTranslation() {
93+
var quantity = new Quantity()
94+
.setSystem(UOM_SYSTEM)
95+
.setValue(VALUE_37_1)
96+
.setCode(CODE_CEL);
97+
98+
var expectedXml = """
99+
<value xsi:type="PQ" value="37.1" unit="Cel" />""";
100+
101+
var mappedQuantity = ObservationValueQuantityMapper.processQuantity(quantity);
102+
103+
assertThat(mappedQuantity).isEqualTo(expectedXml);
104+
}
105+
106+
@Test
107+
public void When_MappingQuantityWithUOMSystemAndUnit_Expect_XmlWithValueAndQuantitySetAndNoTranslation() {
108+
var quantity = new Quantity()
109+
.setSystem(UOM_SYSTEM)
110+
.setValue(VALUE_37_1)
111+
.setUnit(UNIT_C);
112+
113+
var expectedXml = """
114+
<value xsi:type="PQ" value="37.1" unit="1">
115+
<translation value="37.1">
116+
<originalText>C</originalText>
117+
</translation>
118+
</value>""";
119+
var mappedQuantity = ObservationValueQuantityMapper.processQuantity(quantity);
120+
121+
assertThat(mappedQuantity).isEqualTo(expectedXml);
122+
}
123+
124+
@Test
125+
public void When_MappingQuantityWithUOMSystemWithoutUnitOrCode_Expect_XmlWithValueSetAndUnitSetToOne() {
126+
var quantity = new Quantity()
127+
.setSystem(UOM_SYSTEM)
128+
.setValue(VALUE_37_1);
129+
130+
var expectedXml = """
131+
<value xsi:type="PQ" value="37.1" unit="1" />""";
132+
133+
var mappedQuantity = ObservationValueQuantityMapper.processQuantity(quantity);
134+
135+
assertThat(mappedQuantity).isEqualTo(expectedXml);
136+
}
137+
138+
@Test
139+
public void When_MappingQuantityWithNonUOMSystemAndCodeAndUnit_Expect_XmlContainsTranslationWithDisplayName() {
140+
var quantity = new Quantity()
141+
.setSystem(NON_UOM_SYSTEM)
142+
.setValue(VALUE_37_1)
143+
.setCode(CODE_CEL)
144+
.setUnit(UNIT_C);
145+
146+
var expectedXml = """
147+
<value xsi:type="PQ" value="37.1" unit="1">
148+
<translation value="37.1" code="Cel" codeSystem="Non-UOM system" displayName="C" />
149+
</value>""";
150+
151+
var mappedQuantity = ObservationValueQuantityMapper.processQuantity(quantity);
152+
153+
assertThat(mappedQuantity).isEqualTo(expectedXml);
154+
}
155+
156+
@Test
157+
public void When_MappingQuantityWithNonUOMSystemAndCode_Expect_XmlContainsTranslation() {
158+
var quantity = new Quantity()
159+
.setSystem(NON_UOM_SYSTEM)
160+
.setValue(VALUE_37_1)
161+
.setCode(CODE_CEL);
162+
163+
var expectedXml = """
164+
<value xsi:type="PQ" value="37.1" unit="1">
165+
<translation value="37.1" code="Cel" codeSystem="Non-UOM system" />
166+
</value>""";
167+
168+
var mappedQuantity = ObservationValueQuantityMapper.processQuantity(quantity);
169+
170+
assertThat(mappedQuantity).isEqualTo(expectedXml);
171+
}
172+
173+
@Test
174+
public void When_MappingQuantityWithNonUOMSystemAndUnit_Expect_XmlContainsTranslationAndOriginalText() {
175+
var quantity = new Quantity()
176+
.setSystem(NON_UOM_SYSTEM)
177+
.setValue(VALUE_37_1)
178+
.setUnit(UNIT_C);
179+
180+
var expectedXml = """
181+
<value xsi:type="PQ" value="37.1" unit="1">
182+
<translation value="37.1">
183+
<originalText>C</originalText>
184+
</translation>
185+
</value>""";
186+
187+
var mappedQuantity = ObservationValueQuantityMapper.processQuantity(quantity);
188+
189+
assertThat(mappedQuantity).isEqualTo(expectedXml);
190+
}
191+
192+
@Test
193+
public void When_MappingQuantityWithNonUOMSystemWithoutUnitOrCode_Expect_XmlWithValueSetAndUnitSetToOne() {
194+
var quantity = new Quantity()
195+
.setSystem(NON_UOM_SYSTEM)
196+
.setValue(VALUE_37_1);
197+
198+
var expectedXml = """
199+
<value xsi:type="PQ" value="37.1" unit="1" />""";
200+
201+
var mappedQuantity = ObservationValueQuantityMapper.processQuantity(quantity);
202+
203+
assertThat(mappedQuantity).isEqualTo(expectedXml);
204+
}
205+
206+
@Test
207+
public void When_MappingQuantityWithoutSystemOrUnitOrCode_Expect_XmlWithValueSetAndUnitSetToOne() {
208+
var quantity = new Quantity()
209+
.setValue(VALUE_37_1);
210+
211+
var expectedXml = """
212+
<value xsi:type="PQ" value="37.1" unit="1" />""";
213+
214+
var mappedQuantity = ObservationValueQuantityMapper.processQuantity(quantity);
215+
216+
assertThat(mappedQuantity).isEqualTo(expectedXml);
217+
}
218+
100219
private static Stream<Arguments> testFilePaths() {
101220
return Stream.of(
102-
Arguments.of(INPUT_JSON_WITH_UNIT_OF_MEASURE_SYSTEM_NO_COMPARATOR,
103-
OUTPUT_XML_WITH_UNIT_OF_MEASURE_SYSTEM_NO_COMPARATOR),
104221
Arguments.of(INPUT_JSON_WITH_UNIT_OF_MEASURE_SYSTEM_WITH_LESS_COMPARATOR,
105222
OUTPUT_XML_WITH_UNIT_OF_MEASURE_SYSTEM_WITH_LESS_COMPARATOR),
106223
Arguments.of(INPUT_JSON_WITH_UNIT_OF_MEASURE_SYSTEM_WITH_EQUAL_LESS_COMPARATOR,
@@ -109,8 +226,6 @@ private static Stream<Arguments> testFilePaths() {
109226
OUTPUT_XML_WITH_UNIT_OF_MEASURE_SYSTEM_WITH_GREATER_COMPARATOR),
110227
Arguments.of(INPUT_JSON_WITH_UNIT_OF_MEASURE_SYSTEM_WITH_GREATER_EQUAL_COMPARATOR,
111228
OUTPUT_XML_WITH_UNIT_OF_MEASURE_SYSTEM_WITH_GREATER_EQUAL_COMPARATOR),
112-
Arguments.of(INPUT_JSON_WITH_NO_SYSTEM_AND_NO_COMPARATOR,
113-
OUTPUT_XML_WITH_NO_SYSTEM_AND_NO_COMPARATOR),
114229
Arguments.of(INPUT_JSON_WITH_NO_SYSTEM_AND_LESS_COMPARATOR,
115230
OUTPUT_XML_WITH_NO_SYSTEM_AND_LESS_COMPARATOR),
116231
Arguments.of(INPUT_JSON_WITH_NO_SYSTEM_AND_EQUAL_LESS_COMPARATOR,
@@ -119,8 +234,6 @@ private static Stream<Arguments> testFilePaths() {
119234
OUTPUT_XML_WITH_NO_SYSTEM_AND_GREATER_COMPARATOR),
120235
Arguments.of(INPUT_JSON_WITH_NO_SYSTEM_AND_EQUAL_GREATER_COMPARATOR,
121236
OUTPUT_XML_WITH_NO_SYSTEM_AND_EQUAL_GREATER_COMPARATOR),
122-
Arguments.of(INPUT_JSON_WITH_NO_UNIT,
123-
OUTPUT_XML_WITH_NO_UNIT),
124237
Arguments.of(INPUT_JSON_WITH_COMPARATOR_AND_NO_UNIT,
125238
OUTPUT_XML_WITH_COMPARATOR_AND_NO_UNIT),
126239
Arguments.of(INPUT_JSON_WITH_NO_SYSTEM_NO_UNIT_AND_LESS_COMPARATOR,
@@ -130,9 +243,7 @@ private static Stream<Arguments> testFilePaths() {
130243
Arguments.of(INPUT_JSON_WITH_NO_SYSTEM_NO_UNIT_AND_GREATER_COMPARATOR,
131244
OUTPUT_XML_WITH_NO_SYSTEM_NO_UNIT_AND_GREATER_COMPARATOR),
132245
Arguments.of(INPUT_JSON_WITH_NO_SYSTEM_NO_UNIT_AND_EQUAL_GREATER_COMPARATOR,
133-
OUTPUT_XML_WITH_NO_SYSTEM_NO_UNIT_AND_EQUAL_GREATER_COMPARATOR),
134-
Arguments.of(INPUT_JSON_WITH_UNIT_OF_MEASURE_SYSTEM_NO_COMPARATOR_NO_CODE,
135-
OUTPUT_JSON_WITH_UNIT_OF_MEASURE_SYSTEM_NO_COMPARATOR_NO_CODE)
246+
OUTPUT_XML_WITH_NO_SYSTEM_NO_UNIT_AND_EQUAL_GREATER_COMPARATOR)
136247
);
137248
}
138249
}

service/src/test/resources/ehr/mapper/observation/quantity/example-observation-resource-with-quantity-1.json

Lines changed: 0 additions & 12 deletions
This file was deleted.

service/src/test/resources/ehr/mapper/observation/quantity/example-observation-resource-with-quantity-11.json

Lines changed: 0 additions & 9 deletions
This file was deleted.

0 commit comments

Comments
 (0)