From 4f78eb033ca178c4494aace401e134377311cc85 Mon Sep 17 00:00:00 2001 From: Lloyd McKenzie Date: Sun, 8 Dec 2024 09:24:17 -0700 Subject: [PATCH 1/2] Fixed bad URL in inter-version extension conversion of ValueSet for ValueSet property. Also added the inter-version conversion rules to R4B<->R5, rather than just R4<->R5 --- .../resources40_50/ValueSet40_50.java | 8 ++--- .../resources43_50/ValueSet43_50.java | 29 ++++++++++++++++++- 2 files changed, 32 insertions(+), 5 deletions(-) diff --git a/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/conv40_50/resources40_50/ValueSet40_50.java b/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/conv40_50/resources40_50/ValueSet40_50.java index 533072ccc..fe263f9c1 100644 --- a/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/conv40_50/resources40_50/ValueSet40_50.java +++ b/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/conv40_50/resources40_50/ValueSet40_50.java @@ -466,9 +466,9 @@ public class ValueSet40_50 { for (org.hl7.fhir.r4.model.Extension t : src.getExtension()) { if ("http://hl7.org/fhir/5.0/StructureDefinition/extension-ValueSet.expansion.contains.property".equals(t.getUrl())) { ConceptPropertyComponent prop = tgt.addProperty(); - ConversionContext40_50.INSTANCE.getVersionConvertor_40_50().copyElement(t, prop, "code", "value"); + ConversionContext40_50.INSTANCE.getVersionConvertor_40_50().copyElement(t, prop, "code", "value[x]"); prop.setCode(t.getExtensionString("code")); - prop.setValue(ConversionContext40_50.INSTANCE.getVersionConvertor_40_50().convertType(t.getExtensionByUrl("value").getValue())); + prop.setValue(ConversionContext40_50.INSTANCE.getVersionConvertor_40_50().convertType(t.getExtensionByUrl("value[x]").getValue())); } } @@ -498,9 +498,9 @@ public class ValueSet40_50 { tgt.addDesignation(convertConceptReferenceDesignationComponent(t)); for (org.hl7.fhir.r5.model.ValueSet.ConceptPropertyComponent t : src.getProperty()) { org.hl7.fhir.r4.model.Extension ext = tgt.addExtension().setUrl("http://hl7.org/fhir/5.0/StructureDefinition/extension-ValueSet.expansion.contains.property"); - ConversionContext40_50.INSTANCE.getVersionConvertor_40_50().copyElement(t, ext, "code", "value"); + ConversionContext40_50.INSTANCE.getVersionConvertor_40_50().copyElement(t, ext, "code", "value[x]"); ext.addExtension().setUrl("code").setValue(ConversionContext40_50.INSTANCE.getVersionConvertor_40_50().convertType(t.getCodeElement())); - ext.addExtension().setUrl("value").setValue(ConversionContext40_50.INSTANCE.getVersionConvertor_40_50().convertType(t.getValue())); + ext.addExtension().setUrl("value[x]").setValue(ConversionContext40_50.INSTANCE.getVersionConvertor_40_50().convertType(t.getValue())); } for (org.hl7.fhir.r5.model.ValueSet.ValueSetExpansionContainsComponent t : src.getContains()) tgt.addContains(convertValueSetExpansionContainsComponent(t)); diff --git a/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/conv43_50/resources43_50/ValueSet43_50.java b/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/conv43_50/resources43_50/ValueSet43_50.java index d075c99c0..332b090f2 100644 --- a/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/conv43_50/resources43_50/ValueSet43_50.java +++ b/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/conv43_50/resources43_50/ValueSet43_50.java @@ -1,5 +1,6 @@ package org.hl7.fhir.convertors.conv43_50.resources43_50; +import org.hl7.fhir.convertors.context.ConversionContext40_50; import org.hl7.fhir.convertors.context.ConversionContext43_50; import org.hl7.fhir.convertors.conv43_50.datatypes43_50.general43_50.CodeableConcept43_50; import org.hl7.fhir.convertors.conv43_50.datatypes43_50.general43_50.Coding43_50; @@ -16,6 +17,7 @@ import org.hl7.fhir.convertors.conv43_50.datatypes43_50.primitive43_50.MarkDown4 import org.hl7.fhir.convertors.conv43_50.datatypes43_50.primitive43_50.String43_50; import org.hl7.fhir.convertors.conv43_50.datatypes43_50.primitive43_50.Uri43_50; import org.hl7.fhir.exceptions.FHIRException; +import org.hl7.fhir.r5.model.ValueSet; /* Copyright (c) 2011+, HL7, Inc. @@ -372,7 +374,7 @@ public class ValueSet43_50 { if (src == null) return null; org.hl7.fhir.r5.model.ValueSet.ValueSetExpansionComponent tgt = new org.hl7.fhir.r5.model.ValueSet.ValueSetExpansionComponent(); - ConversionContext43_50.INSTANCE.getVersionConvertor_43_50().copyBackboneElement(src, tgt); + ConversionContext43_50.INSTANCE.getVersionConvertor_43_50().copyBackboneElement(src, tgt, "http://hl7.org/fhir/5.0/StructureDefinition/extension-ValueSet.expansion.property"); if (src.hasIdentifier()) tgt.setIdentifierElement(Uri43_50.convertUri(src.getIdentifierElement())); if (src.hasTimestamp()) @@ -383,6 +385,11 @@ public class ValueSet43_50 { tgt.setOffsetElement(Integer43_50.convertInteger(src.getOffsetElement())); for (org.hl7.fhir.r4b.model.ValueSet.ValueSetExpansionParameterComponent t : src.getParameter()) tgt.addParameter(convertValueSetExpansionParameterComponent(t)); + for (org.hl7.fhir.r4b.model.Extension t : src.getExtension()) { + if ("http://hl7.org/fhir/5.0/StructureDefinition/extension-ValueSet.expansion.property".equals(t.getUrl())) { + tgt.addProperty().setCode(t.getExtensionString("code")).setUri(t.getExtensionString("uri")); + } + } for (org.hl7.fhir.r4b.model.ValueSet.ValueSetExpansionContainsComponent t : src.getContains()) tgt.addContains(convertValueSetExpansionContainsComponent(t)); return tgt; @@ -403,6 +410,11 @@ public class ValueSet43_50 { tgt.setOffsetElement(Integer43_50.convertInteger(src.getOffsetElement())); for (org.hl7.fhir.r5.model.ValueSet.ValueSetExpansionParameterComponent t : src.getParameter()) tgt.addParameter(convertValueSetExpansionParameterComponent(t)); + for (ValueSet.ValueSetExpansionPropertyComponent t : src.getProperty()) { + org.hl7.fhir.r4b.model.Extension ext = tgt.addExtension().setUrl("http://hl7.org/fhir/5.0/StructureDefinition/extension-ValueSet.expansion.property"); + ext.addExtension().setUrl("code").setValue(ConversionContext43_50.INSTANCE.getVersionConvertor_43_50().convertType(t.getCodeElement())); + ext.addExtension().setUrl("uri").setValue(ConversionContext43_50.INSTANCE.getVersionConvertor_43_50().convertType(t.getUriElement())); + } for (org.hl7.fhir.r5.model.ValueSet.ValueSetExpansionContainsComponent t : src.getContains()) tgt.addContains(convertValueSetExpansionContainsComponent(t)); return tgt; @@ -451,6 +463,15 @@ public class ValueSet43_50 { tgt.setDisplayElement(String43_50.convertString(src.getDisplayElement())); for (org.hl7.fhir.r4b.model.ValueSet.ConceptReferenceDesignationComponent t : src.getDesignation()) tgt.addDesignation(convertConceptReferenceDesignationComponent(t)); + for (org.hl7.fhir.r4b.model.Extension t : src.getExtension()) { + if ("http://hl7.org/fhir/5.0/StructureDefinition/extension-ValueSet.expansion.contains.property".equals(t.getUrl())) { + ValueSet.ConceptPropertyComponent prop = tgt.addProperty(); + ConversionContext43_50.INSTANCE.getVersionConvertor_43_50().copyElement(t, prop, "code", "value[x]"); + prop.setCode(t.getExtensionString("code")); + prop.setValue(ConversionContext43_50.INSTANCE.getVersionConvertor_43_50().convertType(t.getExtensionByUrl("value[x]").getValue())); + + } + } for (org.hl7.fhir.r4b.model.ValueSet.ValueSetExpansionContainsComponent t : src.getContains()) tgt.addContains(convertValueSetExpansionContainsComponent(t)); return tgt; @@ -475,6 +496,12 @@ public class ValueSet43_50 { tgt.setDisplayElement(String43_50.convertString(src.getDisplayElement())); for (org.hl7.fhir.r5.model.ValueSet.ConceptReferenceDesignationComponent t : src.getDesignation()) tgt.addDesignation(convertConceptReferenceDesignationComponent(t)); + for (org.hl7.fhir.r5.model.ValueSet.ConceptPropertyComponent t : src.getProperty()) { + org.hl7.fhir.r4b.model.Extension ext = tgt.addExtension().setUrl("http://hl7.org/fhir/5.0/StructureDefinition/extension-ValueSet.expansion.contains.property"); + ConversionContext43_50.INSTANCE.getVersionConvertor_43_50().copyElement(t, ext, "code", "value[x]"); + ext.addExtension().setUrl("code").setValue(ConversionContext43_50.INSTANCE.getVersionConvertor_43_50().convertType(t.getCodeElement())); + ext.addExtension().setUrl("value[x]").setValue(ConversionContext43_50.INSTANCE.getVersionConvertor_43_50().convertType(t.getValue())); + } for (org.hl7.fhir.r5.model.ValueSet.ValueSetExpansionContainsComponent t : src.getContains()) tgt.addContains(convertValueSetExpansionContainsComponent(t)); return tgt; From 7d0822a0d895f031b0f0fdac2fe300e65490c997 Mon Sep 17 00:00:00 2001 From: Lloyd McKenzie Date: Sun, 8 Dec 2024 12:36:50 -0700 Subject: [PATCH 2/2] Added test scripts for ValueSet conversion --- .../conv40_50/TestScript40_50Test.java | 2 +- .../conv40_50/ValueSet40_50Test.java | 47 ++++++++ .../src/test/resources/value_set_r4.json | 103 ++++++++++++++++++ .../src/test/resources/value_set_r5.json | 68 ++++++++++++ 4 files changed, 219 insertions(+), 1 deletion(-) create mode 100644 org.hl7.fhir.convertors/src/test/java/org/hl7/fhir/convertors/conv40_50/ValueSet40_50Test.java create mode 100644 org.hl7.fhir.convertors/src/test/resources/value_set_r4.json create mode 100644 org.hl7.fhir.convertors/src/test/resources/value_set_r5.json diff --git a/org.hl7.fhir.convertors/src/test/java/org/hl7/fhir/convertors/conv40_50/TestScript40_50Test.java b/org.hl7.fhir.convertors/src/test/java/org/hl7/fhir/convertors/conv40_50/TestScript40_50Test.java index 6504403dc..27cc77d82 100644 --- a/org.hl7.fhir.convertors/src/test/java/org/hl7/fhir/convertors/conv40_50/TestScript40_50Test.java +++ b/org.hl7.fhir.convertors/src/test/java/org/hl7/fhir/convertors/conv40_50/TestScript40_50Test.java @@ -13,7 +13,7 @@ public class TestScript40_50Test { @Test - @DisplayName("Test TestScript R4 <-> R5 with resoutce scope extension") + @DisplayName("Test TestScript R4 <-> R5 with resource scope extension") public void testValueExpressionConversion40_10() throws IOException { InputStream r4_stream = this.getClass().getResourceAsStream("/test_script_r4.json"); org.hl7.fhir.r4.model.TestScript r4_input = (org.hl7.fhir.r4.model.TestScript) new org.hl7.fhir.r4.formats.JsonParser().parse(r4_stream); diff --git a/org.hl7.fhir.convertors/src/test/java/org/hl7/fhir/convertors/conv40_50/ValueSet40_50Test.java b/org.hl7.fhir.convertors/src/test/java/org/hl7/fhir/convertors/conv40_50/ValueSet40_50Test.java new file mode 100644 index 000000000..d16a52841 --- /dev/null +++ b/org.hl7.fhir.convertors/src/test/java/org/hl7/fhir/convertors/conv40_50/ValueSet40_50Test.java @@ -0,0 +1,47 @@ +package org.hl7.fhir.convertors.conv40_50; + +import org.hl7.fhir.convertors.factory.VersionConvertorFactory_40_50; +import org.hl7.fhir.r5.formats.IParser.OutputStyle; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import java.io.IOException; +import java.io.InputStream; + +public class ValueSet40_50Test { + + + @Test + @DisplayName("Test ValueSet R4 <-> R5 with property extensions") + public void testValueExpressionConversion40_10() throws IOException { + InputStream r4_stream = this.getClass().getResourceAsStream("/value_set_r4.json"); + org.hl7.fhir.r4.model.ValueSet r4_input = (org.hl7.fhir.r4.model.ValueSet) new org.hl7.fhir.r4.formats.JsonParser().parse(r4_stream); + + InputStream r5_stream = this.getClass().getResourceAsStream("/value_set_r5.json"); + org.hl7.fhir.r5.model.ValueSet r5_input = (org.hl7.fhir.r5.model.ValueSet) new org.hl7.fhir.r5.formats.JsonParser().parse(r5_stream); + + org.hl7.fhir.r5.model.ValueSet r5_output = (org.hl7.fhir.r5.model.ValueSet) VersionConvertorFactory_40_50.convertResource(r4_input); + org.hl7.fhir.r4.model.ValueSet r4_output = (org.hl7.fhir.r4.model.ValueSet) VersionConvertorFactory_40_50.convertResource(r5_input); + + org.hl7.fhir.r5.formats.JsonParser r5_parser = new org.hl7.fhir.r5.formats.JsonParser(); + String r5_in = r5_parser.setOutputStyle(OutputStyle.PRETTY).composeString(r5_input); + String r5_out = r5_parser.composeString(r5_output); + boolean pass = r5_input.equalsDeep(r5_output); + if (!pass) { + System.out.println("R5. Expected out ->\n"+ r5_in + "\n\nActual out ->\n" + r5_out); + } + Assertions.assertTrue(pass); + + org.hl7.fhir.r4.formats.JsonParser r4_parser = new org.hl7.fhir.r4.formats.JsonParser(); + String r4_in = r4_parser.composeString(r4_input); + String r4_out = r4_parser.composeString(r4_output); + pass = r4_input.equalsDeep(r4_output); + if (!pass) { + System.out.println("R4. Expected out ->\n"+ r4_in + "\n\nActual out ->\n" + r4_out); + } + Assertions.assertTrue(pass); + } + + +} diff --git a/org.hl7.fhir.convertors/src/test/resources/value_set_r4.json b/org.hl7.fhir.convertors/src/test/resources/value_set_r4.json new file mode 100644 index 000000000..feed1a9c1 --- /dev/null +++ b/org.hl7.fhir.convertors/src/test/resources/value_set_r4.json @@ -0,0 +1,103 @@ +{ + "resourceType" : "ValueSet", + "id" : "VSPHQ9", + "url" : "http://example.org/ValueSet/VSPHQ9", + "name" : "VSPHQ9", + "status" : "active", + "immutable" : true, + "compose" : { + "include" : [{ + "system" : "http://example.org/CodeSystem/CSPHQ9", + "concept" : [{ + "code" : "Not-at-all", + "display" : "Not at all" + }, + { + "code" : "Several-days", + "display" : "Several days" + }, + { + "code" : "More than half the days", + "display" : "More than half the days" + }, + { + "code" : "Nearly every day", + "display" : "Nearly every day" + }] + }] + }, + "expansion" : { + "extension" : [{ + "extension" : [{ + "url" : "code", + "valueCode" : "itemWeight" + }, + { + "url" : "uri", + "valueUri" : "http://hl7.org/fhir/concept-properties#itemWeight" + }], + "url" : "http://hl7.org/fhir/5.0/StructureDefinition/extension-ValueSet.expansion.property" + }], + "timestamp" : "2024-12-06T22:52:00-07:00", + "contains" : [{ + "extension" : [{ + "extension" : [{ + "url" : "code", + "valueCode" : "itemWeight" + }, + { + "url" : "value[x]", + "valueDecimal" : 0 + }], + "url" : "http://hl7.org/fhir/5.0/StructureDefinition/extension-ValueSet.expansion.contains.property" + }], + "code" : "not-at-all", + "display" : "Not at all" + }, + { + "extension" : [{ + "extension" : [{ + "url" : "code", + "valueCode" : "itemWeight" + }, + { + "url" : "value[x]", + "valueDecimal" : 1 + }], + "url" : "http://hl7.org/fhir/5.0/StructureDefinition/extension-ValueSet.expansion.contains.property" + }], + "code" : "Several-days", + "display" : "Several days" + }, + { + "extension" : [{ + "extension" : [{ + "url" : "code", + "valueCode" : "itemWeight" + }, + { + "url" : "value[x]", + "valueDecimal" : 2 + }], + "url" : "http://hl7.org/fhir/5.0/StructureDefinition/extension-ValueSet.expansion.contains.property" + }], + "code" : "More than half the days", + "display" : "More than half the days" + }, + { + "extension" : [{ + "extension" : [{ + "url" : "code", + "valueCode" : "itemWeight" + }, + { + "url" : "value[x]", + "valueDecimal" : 4 + }], + "url" : "http://hl7.org/fhir/5.0/StructureDefinition/extension-ValueSet.expansion.contains.property" + }], + "code" : "Nearly every day", + "display" : "Nearly every day" + }] + } +} \ No newline at end of file diff --git a/org.hl7.fhir.convertors/src/test/resources/value_set_r5.json b/org.hl7.fhir.convertors/src/test/resources/value_set_r5.json new file mode 100644 index 000000000..0938a5ae8 --- /dev/null +++ b/org.hl7.fhir.convertors/src/test/resources/value_set_r5.json @@ -0,0 +1,68 @@ +{ + "resourceType" : "ValueSet", + "id" : "VSPHQ9", + "url" : "http://example.org/ValueSet/VSPHQ9", + "name" : "VSPHQ9", + "status" : "active", + "immutable" : true, + "compose" : { + "include" : [{ + "system" : "http://example.org/CodeSystem/CSPHQ9", + "concept" : [{ + "code" : "Not-at-all", + "display" : "Not at all" + }, + { + "code" : "Several-days", + "display" : "Several days" + }, + { + "code" : "More than half the days", + "display" : "More than half the days" + }, + { + "code" : "Nearly every day", + "display" : "Nearly every day" + }] + }] + }, + "expansion" : { + "timestamp" : "2024-12-06T22:52:00-07:00", + "property" : [{ + "code" : "itemWeight", + "uri" : "http://hl7.org/fhir/concept-properties#itemWeight" + }], + "contains" : [{ + "code" : "not-at-all", + "display" : "Not at all", + "property" : [{ + "code" : "itemWeight", + "valueDecimal" : 0 + }] + }, + { + "code" : "Several-days", + "display" : "Several days", + "property" : [{ + "code" : "itemWeight", + "valueDecimal" : 1 + }] + }, + { + "code" : "More than half the days", + "display" : "More than half the days", + "property" : [{ + "code" : "itemWeight", + "valueDecimal" : 2 + }] + }, + { + "code" : "Nearly every day", + "display" : "Nearly every day", + "property" : [{ + "code" : "itemWeight", + "valueDecimal" : 4 + }] + }] + } +} \ No newline at end of file