11package uk .nhs .adaptors .gp2gp .ehr .mapper ;
22
3- import java .math .BigDecimal ;
4-
53import org .apache .commons .lang3 .StringUtils ;
64import org .hl7 .fhir .dstu3 .model .BooleanType ;
75import org .hl7 .fhir .dstu3 .model .Extension ;
86import org .hl7 .fhir .dstu3 .model .Quantity ;
97
10- public final class ObservationValueQuantityMapper {
8+ import static org .hl7 .fhir .dstu3 .model .Quantity .QuantityComparator .GREATER_OR_EQUAL ;
9+ import static org .hl7 .fhir .dstu3 .model .Quantity .QuantityComparator .LESS_OR_EQUAL ;
10+ import static org .hl7 .fhir .dstu3 .model .Quantity .QuantityComparator .LESS_THAN ;
1111
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" ;
14- private static final String IVL_PQ_ELEMENT = "<value xsi:type=\" IVL_PQ\" >" ;
15-
16- private static final String NO_COMPARATOR_VALUE_TEMPLATE = "<value xsi:type=\" PQ\" value=\" %s\" unit=\" %s\" />" ;
17- private static final String LESS_COMPARATOR_VALUE_TEMPLATE = IVL_PQ_ELEMENT
18- + "<high value=\" %s\" unit=\" %s\" inclusive=\" false\" /></value>" ;
19- private static final String LESS_OR_EQUAL_COMPARATOR_VALUE_TEMPLATE = IVL_PQ_ELEMENT
20- + "<high value=\" %s\" unit=\" %s\" inclusive=\" true\" /></value>" ;
21- private static final String GREATER_COMPARATOR_VALUE_TEMPLATE = IVL_PQ_ELEMENT + "<low value=\" %s\" "
22- + "unit=\" %s\" inclusive=\" false\" /></value>" ;
23- private static final String GREATER_OR_EQUAL_COMPARATOR_VALUE_TEMPLATE = "<value xsi:type=\" IVL_PQ\" ><low value=\" %s\" "
24- + "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>" ;
27- private static final String LESS_COMPARATOR_NO_SYSTEM_VALUE_TEMPLATE = IVL_PQ_ELEMENT
28- + "<high value=\" %s\" unit=\" 1\" inclusive=\" false\" ><translation value=\" %s\" >"
29- + "%s</translation></high></value>" ;
30- private static final String LESS_OR_EQUAL_COMPARATOR_NO_SYSTEM_VALUE_TEMPLATE = "<value xsi:type=\" IVL_PQ\" ><high "
31- + "value=\" %s\" unit=\" 1\" inclusive=\" true\" ><translation value=\" %s\" >"
32- + "%s</translation></high></value>" ;
33- private static final String GREATER_COMPARATOR_NO_SYSTEM_VALUE_TEMPLATE = IVL_PQ_ELEMENT
34- + "<low value=\" %s\" unit=\" 1\" inclusive=\" false\" ><translation value=\" %s\" >%s"
35- + "</translation></low></value>" ;
36- private static final String GREATER_OR_EQUAL_COMPARATOR_NO_SYSTEM_VALUE_TEMPLATE = IVL_PQ_ELEMENT
37- + "<low value=\" %s\" unit=\" 1\" inclusive=\" true\" ><translation value=\" %s\" >"
38- + "%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\" />" ;
41- private static final String QUANTITY_UNIT = "<originalText>%s</originalText>" ;
12+ public final class ObservationValueQuantityMapper {
4213
14+ private static final String UNITS_OF_MEASURE_SYSTEM =
15+ "http://unitsofmeasure.org" ;
16+ public static final String URN_OID_PREFIX =
17+ "urn:oid:" ;
18+ public static final String URN_UUID_PREFIX =
19+ "urn:uuid:" ;
20+ public static final String OID_REGEX =
21+ "(urn:oid:)?[0-2](\\ .[1-9]\\ d*)+" ;
22+ public static final String UUID_REGEX =
23+ "(urn:uuid:)?[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$" ;
24+
25+ private static final String UNCERTAINTY_EXTENSION =
26+ "https://fhir.hl7.org.uk/STU3/StructureDefinition/Extension-CareConnect-ValueApproximation-1" ;
27+ private static final String UNCERTAINTY_CODE = """
28+ <uncertaintyCode code="U" codeSystem="2.16.840.1.113883.5.1053" displayName="Recorded as uncertain" />
29+ """ ;
4330
4431 private ObservationValueQuantityMapper () {
4532 }
4633
4734 public static String processQuantity (Quantity valueQuantity ) {
48- String result = StringUtils .EMPTY ;
49- if (isUncertaintyCodePresent (valueQuantity )) {
50- result += UNCERTAINTY_CODE ;
51- }
52-
53- if (!valueQuantity .hasComparator ()) {
54- result += prepareQuantityValueWithoutComparator (valueQuantity );
55- } else {
56- result += prepareQuantityValueAccordingToComparator (valueQuantity );
35+ if (!valueQuantity .hasValue ()) {
36+ return StringUtils .EMPTY ;
5737 }
5838
59- return result ;
60- }
39+ var stringBuilder = new StringBuilder ();
6140
62- 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 ));
41+ if (isUncertaintyCodePresent (valueQuantity )) {
42+ stringBuilder .append (UNCERTAINTY_CODE );
6843 }
69- }
7044
71- private static String prepareUnit (Quantity valueQuantity ) {
72- return valueQuantity .hasUnit () ? String .format (QUANTITY_UNIT , valueQuantity .getUnit ()) : StringUtils .EMPTY ;
45+ var quantityXml = valueQuantity .hasComparator ()
46+ ? getPhysicalQuantityIntervalXml (valueQuantity )
47+ : getPhysicalQuantityXml (valueQuantity );
48+
49+ return stringBuilder
50+ .append (quantityXml )
51+ .toString ();
7352 }
7453
75- private static String prepareQuantityValueAccordingToComparator (Quantity valueQuantity ) {
76- if (valueQuantity .getComparator () == Quantity .QuantityComparator .LESS_THAN ) {
77- return prepareQuantityValueByComparator (valueQuantity ,
78- LESS_COMPARATOR_VALUE_TEMPLATE ,
79- LESS_COMPARATOR_NO_SYSTEM_VALUE_TEMPLATE );
80- } else if (valueQuantity .getComparator () == Quantity .QuantityComparator .LESS_OR_EQUAL ) {
81- return prepareQuantityValueByComparator (valueQuantity ,
82- LESS_OR_EQUAL_COMPARATOR_VALUE_TEMPLATE ,
83- LESS_OR_EQUAL_COMPARATOR_NO_SYSTEM_VALUE_TEMPLATE );
84- } else if (valueQuantity .getComparator () == Quantity .QuantityComparator .GREATER_THAN ) {
85- return prepareQuantityValueByComparator (valueQuantity ,
86- GREATER_COMPARATOR_VALUE_TEMPLATE ,
87- GREATER_COMPARATOR_NO_SYSTEM_VALUE_TEMPLATE );
88- } else if (valueQuantity .getComparator () == Quantity .QuantityComparator .GREATER_OR_EQUAL ) {
89- return prepareQuantityValueByComparator (valueQuantity ,
90- GREATER_OR_EQUAL_COMPARATOR_VALUE_TEMPLATE ,
91- GREATER_OR_EQUAL_COMPARATOR_NO_SYSTEM_VALUE_TEMPLATE );
54+ private static String getPhysicalQuantityXml (Quantity valueQuantity ) {
55+ if (UNITS_OF_MEASURE_SYSTEM .equals (valueQuantity .getSystem ()) && valueQuantity .hasCode ()) {
56+ return """
57+ <value xsi:type="PQ" value="%s" unit="%s" />"""
58+ .formatted (
59+ valueQuantity .getValue (),
60+ valueQuantity .getCode ()
61+ );
62+ }
63+ if (hasValidSystem (valueQuantity ) && valueQuantity .hasCode () && valueQuantity .hasUnit ()) {
64+ return """
65+ <value xsi:type="PQ" value="%s" unit="1">%n\
66+ <translation value="%s" code="%s" codeSystem="%s" displayName="%s" />%n\
67+ </value>"""
68+ .formatted (
69+ valueQuantity .getValue (),
70+ valueQuantity .getValue (),
71+ valueQuantity .getCode (),
72+ getSystemWithoutPrefix (valueQuantity .getSystem ()),
73+ valueQuantity .getUnit ()
74+ );
75+ }
76+ if (hasValidSystem (valueQuantity ) && valueQuantity .hasCode ()) {
77+ return """
78+ <value xsi:type="PQ" value="%s" unit="1">%n\
79+ <translation value="%s" code="%s" codeSystem="%s" />%n\
80+ </value>"""
81+ .formatted (
82+ valueQuantity .getValue (),
83+ valueQuantity .getValue (),
84+ valueQuantity .getCode (),
85+ getSystemWithoutPrefix (valueQuantity .getSystem ())
86+ );
87+ }
88+ if (valueQuantity .hasUnit ()) {
89+ return """
90+ <value xsi:type="PQ" value="%s" unit="1">%n\
91+ <translation value="%s">%n\
92+ <originalText>%s</originalText>%n\
93+ </translation>%n\
94+ </value>"""
95+ .formatted (
96+ valueQuantity .getValue (),
97+ valueQuantity .getValue (),
98+ valueQuantity .getUnit ()
99+ );
92100 }
93101
94- return StringUtils .EMPTY ;
102+ return """
103+ <value xsi:type="PQ" value="%s" unit="1" />"""
104+ .formatted (valueQuantity .getValue ());
95105 }
96106
97- private static String prepareQuantityValueByComparator (Quantity valueQuantity , String systemTemplate , String nonSystemTemplate ) {
98- if (valueQuantity .hasSystem () && valueQuantity .getSystem ().equals (UNITS_OF_MEASURE_SYSTEM )) {
99- return formatSystemTemplate (systemTemplate , valueQuantity .getValue (), valueQuantity .getCode ());
107+ private static String getPhysicalQuantityIntervalXml (Quantity valueQuantity ) {
108+ if (UNITS_OF_MEASURE_SYSTEM .equals (valueQuantity .getSystem ()) && valueQuantity .hasCode ()) {
109+ return """
110+ <value xsi:type="IVL_PQ">%n\
111+ <%s value="%s" unit="%s" inclusive="%s" />%n\
112+ </value>"""
113+ .formatted (
114+ getHighOrLow (valueQuantity ),
115+ valueQuantity .getValue (),
116+ valueQuantity .getCode (),
117+ isInclusive (valueQuantity )
118+ );
119+ }
120+ if (hasValidSystem (valueQuantity ) && valueQuantity .hasCode () && valueQuantity .hasUnit ()) {
121+ return """
122+ <value xsi:type="IVL_PQ">%n\
123+ <%s value="%s" unit="1" inclusive="%s">%n\
124+ <translation value="%s" code="%s" codeSystem="%s" displayName="%s" />%n\
125+ </%s>%n\
126+ </value>"""
127+ .formatted (
128+ getHighOrLow (valueQuantity ),
129+ valueQuantity .getValue (),
130+ isInclusive (valueQuantity ),
131+ valueQuantity .getValue (),
132+ valueQuantity .getCode (),
133+ getSystemWithoutPrefix (valueQuantity .getSystem ()),
134+ valueQuantity .getUnit (),
135+ getHighOrLow (valueQuantity )
136+ );
137+ }
138+ if (hasValidSystem (valueQuantity ) && valueQuantity .hasCode ()) {
139+ return """
140+ <value xsi:type="IVL_PQ">%n\
141+ <%s value="%s" unit="1" inclusive="%s">%n\
142+ <translation value="%s" code="%s" codeSystem="%s" />%n\
143+ </%s>%n\
144+ </value>"""
145+ .formatted (
146+ getHighOrLow (valueQuantity ),
147+ valueQuantity .getValue (),
148+ isInclusive (valueQuantity ),
149+ valueQuantity .getValue (),
150+ valueQuantity .getCode (),
151+ getSystemWithoutPrefix (valueQuantity .getSystem ()),
152+ getHighOrLow (valueQuantity )
153+ );
154+ }
155+ if (valueQuantity .hasUnit ()) {
156+ return """
157+ <value xsi:type="IVL_PQ">%n\
158+ <%s value="%s" unit="1" inclusive="%s">%n\
159+ <translation value="%s">%n\
160+ <originalText>%s</originalText>%n\
161+ </translation>%n\
162+ </%s>%n\
163+ </value>"""
164+ .formatted (
165+ getHighOrLow (valueQuantity ),
166+ valueQuantity .getValue (),
167+ isInclusive (valueQuantity ),
168+ valueQuantity .getValue (),
169+ valueQuantity .getUnit (),
170+ getHighOrLow (valueQuantity )
171+ );
100172 }
101173
102- return formatNoSystemTemplate (nonSystemTemplate , valueQuantity .getValue (), prepareUnit (valueQuantity ));
174+ return """
175+ <value xsi:type="IVL_PQ">%n\
176+ <%s value="%s" unit="1" inclusive="%s" />%n\
177+ </value>"""
178+ .formatted (
179+ getHighOrLow (valueQuantity ),
180+ valueQuantity .getValue (),
181+ isInclusive (valueQuantity )
182+ );
103183 }
104184
105- private static String formatSystemTemplate ( String template , BigDecimal value , String code ) {
106- return String . format ( template , value , code ) ;
185+ private static boolean isInclusive ( Quantity valueQuantity ) {
186+ return valueQuantity . getComparator () == GREATER_OR_EQUAL || valueQuantity . getComparator () == LESS_OR_EQUAL ;
107187 }
108188
109- private static String formatNoSystemTemplate (String template , BigDecimal value , String unit ) {
110- return String .format (template , value , value , unit );
189+ private static String getHighOrLow (Quantity valueQuantity ) {
190+ return valueQuantity .getComparator () == LESS_THAN || valueQuantity .getComparator () == LESS_OR_EQUAL
191+ ? "high"
192+ : "low" ;
111193 }
112194
113195 private static boolean isUncertaintyCodePresent (Quantity valueQuantity ) {
@@ -118,7 +200,6 @@ private static boolean isUncertaintyCodePresent(Quantity valueQuantity) {
118200 }
119201 }
120202 }
121-
122203 return false ;
123204 }
124205
@@ -128,4 +209,23 @@ private static boolean isUncertaintyExtension(Extension extension) {
128209 && extension .getValue () instanceof BooleanType
129210 && ((BooleanType ) extension .getValue ()).booleanValue ();
130211 }
212+
213+ private static boolean hasValidSystem (Quantity valueQuantity ) {
214+ return valueQuantity .hasSystem () && (
215+ valueQuantity .getSystem ().equals (UNITS_OF_MEASURE_SYSTEM )
216+ || valueQuantity .getSystem ().matches (OID_REGEX )
217+ || valueQuantity .getSystem ().matches (UUID_REGEX )
218+ );
219+ }
220+
221+ private static String getSystemWithoutPrefix (String system ) {
222+ if (system .startsWith (URN_OID_PREFIX )) {
223+ return StringUtils .removeStart (system , URN_OID_PREFIX );
224+ }
225+ if (system .startsWith (URN_UUID_PREFIX )) {
226+ return StringUtils .removeStart (system , URN_UUID_PREFIX );
227+ }
228+
229+ return system ;
230+ }
131231}
0 commit comments