From eaad9e7b865a2eee49dda431f78b1c672f08a02e Mon Sep 17 00:00:00 2001 From: Jonathan Percival Date: Mon, 7 Oct 2024 15:16:47 -0600 Subject: [PATCH 01/10] Adding Tuple conversion and tests --- .../converter/Dstu2FhirTypeConverter.java | 26 ++++++++++++++++++- .../converter/Dstu3FhirTypeConverter.java | 23 +++++++++++++++- .../fhir/converter/R4FhirTypeConverter.java | 23 +++++++++++++++- .../fhir/converter/R5FhirTypeConverter.java | 23 +++++++++++++++- .../converter/Dstu2TypeConverterTests.java | 16 +++++++----- .../converter/Dstu3TypeConverterTests.java | 16 +++++++----- .../fhir/converter/R4TypeConverterTests.java | 16 +++++++----- .../fhir/converter/R5TypeConverterTests.java | 16 +++++++----- 8 files changed, 131 insertions(+), 28 deletions(-) diff --git a/Src/java/engine-fhir/src/main/java/org/opencds/cqf/cql/engine/fhir/converter/Dstu2FhirTypeConverter.java b/Src/java/engine-fhir/src/main/java/org/opencds/cqf/cql/engine/fhir/converter/Dstu2FhirTypeConverter.java index 1b1846617..8c59f0d3a 100644 --- a/Src/java/engine-fhir/src/main/java/org/opencds/cqf/cql/engine/fhir/converter/Dstu2FhirTypeConverter.java +++ b/Src/java/engine-fhir/src/main/java/org/opencds/cqf/cql/engine/fhir/converter/Dstu2FhirTypeConverter.java @@ -1,5 +1,8 @@ package org.opencds.cqf.cql.engine.fhir.converter; +import ca.uhn.fhir.model.api.IDatatype; +import ca.uhn.fhir.model.api.IResource; +import ca.uhn.fhir.model.dstu2.resource.Parameters; import java.math.BigDecimal; import java.util.Calendar; import java.util.GregorianCalendar; @@ -227,7 +230,28 @@ public IBase toFhirTuple(Tuple value) { return null; } - throw new NotImplementedException("can't convert Tuples"); + var parameters = new Parameters(); + if (value.getElements().isEmpty()) { + return parameters; + } + + // This parameters needs to be set to the definition name + // when it's rolled up to the final result + var param = parameters.addParameter(); + for (String key : value.getElements().keySet()) { + var part = param.addPart(); + part.setName(key); + var result = toFhirType(value); + if (result instanceof IResource) { + part.setResource((IResource) result); + } else if (result instanceof IDatatype) { + part.setValue((IDatatype) result); + } else { + throw new IllegalArgumentException("Tuple contains unsupported type"); + } + } + + return parameters; } @Override diff --git a/Src/java/engine-fhir/src/main/java/org/opencds/cqf/cql/engine/fhir/converter/Dstu3FhirTypeConverter.java b/Src/java/engine-fhir/src/main/java/org/opencds/cqf/cql/engine/fhir/converter/Dstu3FhirTypeConverter.java index c24dee528..85144e25e 100644 --- a/Src/java/engine-fhir/src/main/java/org/opencds/cqf/cql/engine/fhir/converter/Dstu3FhirTypeConverter.java +++ b/Src/java/engine-fhir/src/main/java/org/opencds/cqf/cql/engine/fhir/converter/Dstu3FhirTypeConverter.java @@ -226,7 +226,28 @@ public IBase toFhirTuple(Tuple value) { return null; } - throw new NotImplementedException("can't convert Tuples"); + var parameters = new Parameters(); + if (value.getElements().isEmpty()) { + return parameters; + } + + // This parameters needs to be set to the definition name + // when it's rolled up to the final result + var param = parameters.addParameter(); + for (String key : value.getElements().keySet()) { + var part = param.addPart(); + part.setName(key); + var result = toFhirType(value); + if (result instanceof Resource) { + part.setResource((Resource) result); + } else if (result instanceof Type) { + part.setValue((Type) result); + } else { + throw new IllegalArgumentException("Tuple contains unsupported type"); + } + } + + return parameters; } @Override diff --git a/Src/java/engine-fhir/src/main/java/org/opencds/cqf/cql/engine/fhir/converter/R4FhirTypeConverter.java b/Src/java/engine-fhir/src/main/java/org/opencds/cqf/cql/engine/fhir/converter/R4FhirTypeConverter.java index c24ef73b0..8b18b253c 100644 --- a/Src/java/engine-fhir/src/main/java/org/opencds/cqf/cql/engine/fhir/converter/R4FhirTypeConverter.java +++ b/Src/java/engine-fhir/src/main/java/org/opencds/cqf/cql/engine/fhir/converter/R4FhirTypeConverter.java @@ -218,7 +218,28 @@ public IBase toFhirTuple(Tuple value) { return null; } - throw new NotImplementedException("can't convert Tuples"); + var parameters = new Parameters(); + if (value.getElements().isEmpty()) { + return parameters; + } + + // This parameters needs to be set to the definition name + // when it's rolled up to the final result + var param = parameters.addParameter(); + for (String key : value.getElements().keySet()) { + var part = param.addPart(); + part.setName(key); + var result = toFhirType(value); + if (result instanceof Resource) { + part.setResource((Resource) result); + } else if (result instanceof Type) { + part.setValue((Type) result); + } else { + throw new IllegalArgumentException("Tuple contains unsupported type"); + } + } + + return parameters; } @Override diff --git a/Src/java/engine-fhir/src/main/java/org/opencds/cqf/cql/engine/fhir/converter/R5FhirTypeConverter.java b/Src/java/engine-fhir/src/main/java/org/opencds/cqf/cql/engine/fhir/converter/R5FhirTypeConverter.java index c53b694e2..09f1c25d0 100644 --- a/Src/java/engine-fhir/src/main/java/org/opencds/cqf/cql/engine/fhir/converter/R5FhirTypeConverter.java +++ b/Src/java/engine-fhir/src/main/java/org/opencds/cqf/cql/engine/fhir/converter/R5FhirTypeConverter.java @@ -218,7 +218,28 @@ public IBase toFhirTuple(Tuple value) { return null; } - throw new NotImplementedException("can't convert Tuples"); + var parameters = new Parameters(); + if (value.getElements().isEmpty()) { + return parameters; + } + + // This parameters needs to be set to the definition name + // when it's rolled up to the final result + var param = parameters.addParameter(); + for (String key : value.getElements().keySet()) { + var part = param.addPart(); + part.setName(key); + var result = toFhirType(value); + if (result instanceof Resource) { + part.setResource((Resource) result); + } else if (result instanceof DataType) { + part.setValue((DataType) result); + } else { + throw new IllegalArgumentException("Tuple contains unsupported type"); + } + } + + return parameters; } @Override diff --git a/Src/java/engine-fhir/src/test/java/org/opencds/cqf/cql/engine/fhir/converter/Dstu2TypeConverterTests.java b/Src/java/engine-fhir/src/test/java/org/opencds/cqf/cql/engine/fhir/converter/Dstu2TypeConverterTests.java index 44c468525..193507e6f 100644 --- a/Src/java/engine-fhir/src/test/java/org/opencds/cqf/cql/engine/fhir/converter/Dstu2TypeConverterTests.java +++ b/Src/java/engine-fhir/src/test/java/org/opencds/cqf/cql/engine/fhir/converter/Dstu2TypeConverterTests.java @@ -2,14 +2,17 @@ import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.instanceOf; +import static org.junit.Assert.assertNotNull; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertInstanceOf; import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.opencds.cqf.cql.engine.fhir.converter.ConverterTestUtils.*; import ca.uhn.fhir.model.api.TemporalPrecisionEnum; +import ca.uhn.fhir.model.dstu2.resource.Parameters; import java.math.BigDecimal; import java.time.*; import java.time.format.DateTimeFormatter; @@ -67,7 +70,7 @@ protected Boolean compareIterables(Iterable left, Iterable right return !leftIterator.hasNext() && !rightIterator.hasNext(); } - @SuppressWarnings("unchecked") + @SuppressWarnings({"unchecked", "null"}) protected Boolean compareObjects(Object left, Object right) { if (left == null ^ right == null) { return false; @@ -524,13 +527,14 @@ void invalidIntervalToFhirInterval() { @Test void tupleToFhirTuple() { - IBase expected = typeConverter.toFhirTuple(null); - assertNull(expected); + IBase actual = typeConverter.toFhirTuple(null); + assertNull(actual); var tuple = new Tuple(); - assertThrows(NotImplementedException.class, () -> { - typeConverter.toFhirTuple(tuple); - }); + actual = typeConverter.toFhirTuple(tuple); + assertNotNull(actual); + assertInstanceOf(Parameters.class, actual); + assertTrue(((Parameters) actual).isEmpty()); } // FHIR-to-CQL diff --git a/Src/java/engine-fhir/src/test/java/org/opencds/cqf/cql/engine/fhir/converter/Dstu3TypeConverterTests.java b/Src/java/engine-fhir/src/test/java/org/opencds/cqf/cql/engine/fhir/converter/Dstu3TypeConverterTests.java index 61cdc6519..61b9da065 100644 --- a/Src/java/engine-fhir/src/test/java/org/opencds/cqf/cql/engine/fhir/converter/Dstu3TypeConverterTests.java +++ b/Src/java/engine-fhir/src/test/java/org/opencds/cqf/cql/engine/fhir/converter/Dstu3TypeConverterTests.java @@ -4,6 +4,8 @@ import static org.hamcrest.Matchers.instanceOf; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertInstanceOf; +import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -40,6 +42,7 @@ import org.hl7.fhir.instance.model.api.ICompositeType; import org.hl7.fhir.instance.model.api.IIdType; import org.hl7.fhir.instance.model.api.IPrimitiveType; +import org.hl7.fhir.r4.model.Parameters; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; @@ -67,7 +70,7 @@ protected Boolean compareIterables(Iterable left, Iterable right return !leftIterator.hasNext() && !rightIterator.hasNext(); } - @SuppressWarnings("unchecked") + @SuppressWarnings({"unchecked", "null"}) protected Boolean compareObjects(Object left, Object right) { if (left == null ^ right == null) { return false; @@ -528,13 +531,14 @@ void invalidIntervalToFhirInterval() { @Test void tupleToFhirTuple() { - IBase expected = typeConverter.toFhirTuple(null); - assertNull(expected); + IBase actual = typeConverter.toFhirTuple(null); + assertNull(actual); var tuple = new Tuple(); - assertThrows(NotImplementedException.class, () -> { - typeConverter.toFhirTuple(tuple); - }); + actual = typeConverter.toFhirTuple(tuple); + assertNotNull(actual); + assertInstanceOf(Parameters.class, actual); + assertTrue(((Parameters) actual).isEmpty()); } // FHIR-to-CQL diff --git a/Src/java/engine-fhir/src/test/java/org/opencds/cqf/cql/engine/fhir/converter/R4TypeConverterTests.java b/Src/java/engine-fhir/src/test/java/org/opencds/cqf/cql/engine/fhir/converter/R4TypeConverterTests.java index a040bddf7..62535b799 100644 --- a/Src/java/engine-fhir/src/test/java/org/opencds/cqf/cql/engine/fhir/converter/R4TypeConverterTests.java +++ b/Src/java/engine-fhir/src/test/java/org/opencds/cqf/cql/engine/fhir/converter/R4TypeConverterTests.java @@ -4,6 +4,8 @@ import static org.hamcrest.Matchers.instanceOf; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertInstanceOf; +import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -34,6 +36,7 @@ import org.hl7.fhir.r4.model.IdType; import org.hl7.fhir.r4.model.InstantType; import org.hl7.fhir.r4.model.IntegerType; +import org.hl7.fhir.r4.model.Parameters; import org.hl7.fhir.r4.model.Patient; import org.hl7.fhir.r4.model.Period; import org.hl7.fhir.r4.model.Range; @@ -67,7 +70,7 @@ protected Boolean compareIterables(Iterable left, Iterable right return !leftIterator.hasNext() && !rightIterator.hasNext(); } - @SuppressWarnings("unchecked") + @SuppressWarnings({"unchecked", "null"}) protected Boolean compareObjects(Object left, Object right) { if (left == null ^ right == null) { return false; @@ -528,13 +531,14 @@ void invalidIntervalToFhirInterval() { @Test void tupleToFhirTuple() { - IBase expected = typeConverter.toFhirTuple(null); - assertNull(expected); + IBase actual = typeConverter.toFhirTuple(null); + assertNull(actual); var tuple = new Tuple(); - assertThrows(NotImplementedException.class, () -> { - typeConverter.toFhirTuple(tuple); - }); + actual = typeConverter.toFhirTuple(tuple); + assertNotNull(actual); + assertInstanceOf(Parameters.class, actual); + assertTrue(((Parameters) actual).isEmpty()); } // FHIR-to-CQL diff --git a/Src/java/engine-fhir/src/test/java/org/opencds/cqf/cql/engine/fhir/converter/R5TypeConverterTests.java b/Src/java/engine-fhir/src/test/java/org/opencds/cqf/cql/engine/fhir/converter/R5TypeConverterTests.java index ac055c092..3d299d772 100644 --- a/Src/java/engine-fhir/src/test/java/org/opencds/cqf/cql/engine/fhir/converter/R5TypeConverterTests.java +++ b/Src/java/engine-fhir/src/test/java/org/opencds/cqf/cql/engine/fhir/converter/R5TypeConverterTests.java @@ -4,6 +4,8 @@ import static org.hamcrest.Matchers.instanceOf; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertInstanceOf; +import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -23,6 +25,7 @@ import org.hl7.fhir.instance.model.api.ICompositeType; import org.hl7.fhir.instance.model.api.IIdType; import org.hl7.fhir.instance.model.api.IPrimitiveType; +import org.hl7.fhir.r4.model.Parameters; import org.hl7.fhir.r5.model.Attachment; import org.hl7.fhir.r5.model.Base; import org.hl7.fhir.r5.model.BooleanType; @@ -67,7 +70,7 @@ protected Boolean compareIterables(Iterable left, Iterable right return !leftIterator.hasNext() && !rightIterator.hasNext(); } - @SuppressWarnings("unchecked") + @SuppressWarnings({"unchecked", "null"}) protected Boolean compareObjects(Object left, Object right) { if (left == null ^ right == null) { return false; @@ -528,13 +531,14 @@ void invalidIntervalToFhirInterval() { @Test void tupleToFhirTuple() { - IBase expected = typeConverter.toFhirTuple(null); - assertNull(expected); + IBase actual = typeConverter.toFhirTuple(null); + assertNull(actual); var tuple = new Tuple(); - assertThrows(NotImplementedException.class, () -> { - typeConverter.toFhirTuple(tuple); - }); + actual = typeConverter.toFhirTuple(tuple); + assertNotNull(actual); + assertInstanceOf(Parameters.class, actual); + assertTrue(((Parameters) actual).isEmpty()); } // FHIR-to-CQL From e8fbd41769a970c25b920dc2348e5734f8e15fe6 Mon Sep 17 00:00:00 2001 From: Jonathan Percival Date: Mon, 7 Oct 2024 15:56:47 -0600 Subject: [PATCH 02/10] Conversion for CQL tuples to FHIR Parameters --- .../converter/Dstu2FhirTypeConverter.java | 16 ++++++- .../converter/Dstu3FhirTypeConverter.java | 14 +++++- .../fhir/converter/FhirTypeConverter.java | 3 ++ .../fhir/converter/R4FhirTypeConverter.java | 14 +++++- .../fhir/converter/R5FhirTypeConverter.java | 14 +++++- .../converter/Dstu2TypeConverterTests.java | 43 ++++++++++++++++--- .../converter/Dstu3TypeConverterTests.java | 43 ++++++++++++++++--- .../fhir/converter/R4TypeConverterTests.java | 41 +++++++++++++++--- .../fhir/converter/R5TypeConverterTests.java | 43 ++++++++++++++++--- 9 files changed, 204 insertions(+), 27 deletions(-) diff --git a/Src/java/engine-fhir/src/main/java/org/opencds/cqf/cql/engine/fhir/converter/Dstu2FhirTypeConverter.java b/Src/java/engine-fhir/src/main/java/org/opencds/cqf/cql/engine/fhir/converter/Dstu2FhirTypeConverter.java index 8c59f0d3a..68e1e0281 100644 --- a/Src/java/engine-fhir/src/main/java/org/opencds/cqf/cql/engine/fhir/converter/Dstu2FhirTypeConverter.java +++ b/Src/java/engine-fhir/src/main/java/org/opencds/cqf/cql/engine/fhir/converter/Dstu2FhirTypeConverter.java @@ -5,6 +5,7 @@ import ca.uhn.fhir.model.dstu2.resource.Parameters; import java.math.BigDecimal; import java.util.Calendar; +import java.util.Collection; import java.util.GregorianCalendar; import java.util.stream.Collectors; import org.apache.commons.lang3.NotImplementedException; @@ -235,13 +236,26 @@ public IBase toFhirTuple(Tuple value) { return parameters; } + // This parameters needs to be set to the definition name + // when it's rolled up to the final result // This parameters needs to be set to the definition name // when it's rolled up to the final result var param = parameters.addParameter(); for (String key : value.getElements().keySet()) { var part = param.addPart(); part.setName(key); - var result = toFhirType(value); + var element = value.getElements().get(key); + if (element == null) { + part.addUndeclaredExtension(false, NULL_EXT_URL, new BooleanType(true)); + continue; + } else if (element instanceof Collection) { + if (((Collection) element).isEmpty()) { + part.addUndeclaredExtension(false, EMPTY_EXT_URL, new BooleanType(true)); + continue; + } + } + + var result = toFhirType(element); if (result instanceof IResource) { part.setResource((IResource) result); } else if (result instanceof IDatatype) { diff --git a/Src/java/engine-fhir/src/main/java/org/opencds/cqf/cql/engine/fhir/converter/Dstu3FhirTypeConverter.java b/Src/java/engine-fhir/src/main/java/org/opencds/cqf/cql/engine/fhir/converter/Dstu3FhirTypeConverter.java index 85144e25e..72ab4db19 100644 --- a/Src/java/engine-fhir/src/main/java/org/opencds/cqf/cql/engine/fhir/converter/Dstu3FhirTypeConverter.java +++ b/Src/java/engine-fhir/src/main/java/org/opencds/cqf/cql/engine/fhir/converter/Dstu3FhirTypeConverter.java @@ -2,6 +2,7 @@ import java.math.BigDecimal; import java.time.format.DateTimeFormatter; +import java.util.Collection; import java.util.stream.Collectors; import org.apache.commons.lang3.NotImplementedException; import org.hl7.fhir.dstu3.model.*; @@ -237,7 +238,18 @@ public IBase toFhirTuple(Tuple value) { for (String key : value.getElements().keySet()) { var part = param.addPart(); part.setName(key); - var result = toFhirType(value); + var element = value.getElements().get(key); + if (element == null) { + part.addExtension().setUrl(NULL_EXT_URL).setValue(new BooleanType(true)); + continue; + } else if (element instanceof Collection) { + if (((Collection) element).isEmpty()) { + part.addExtension().setUrl(EMPTY_EXT_URL).setValue(new BooleanType(true)); + continue; + } + } + + var result = toFhirType(element); if (result instanceof Resource) { part.setResource((Resource) result); } else if (result instanceof Type) { diff --git a/Src/java/engine-fhir/src/main/java/org/opencds/cqf/cql/engine/fhir/converter/FhirTypeConverter.java b/Src/java/engine-fhir/src/main/java/org/opencds/cqf/cql/engine/fhir/converter/FhirTypeConverter.java index 835479e1c..d4ea05985 100644 --- a/Src/java/engine-fhir/src/main/java/org/opencds/cqf/cql/engine/fhir/converter/FhirTypeConverter.java +++ b/Src/java/engine-fhir/src/main/java/org/opencds/cqf/cql/engine/fhir/converter/FhirTypeConverter.java @@ -28,6 +28,9 @@ */ public interface FhirTypeConverter { + static final String EMPTY_EXT_URL = "http://hl7.org/fhir/StructureDefinition/cqf-isEmptyList"; + static final String NULL_EXT_URL = "http://hl7.org/fhir/StructureDefinition/cqf-isNull"; + // CQL-to-FHIR conversions /** diff --git a/Src/java/engine-fhir/src/main/java/org/opencds/cqf/cql/engine/fhir/converter/R4FhirTypeConverter.java b/Src/java/engine-fhir/src/main/java/org/opencds/cqf/cql/engine/fhir/converter/R4FhirTypeConverter.java index 8b18b253c..e62662302 100644 --- a/Src/java/engine-fhir/src/main/java/org/opencds/cqf/cql/engine/fhir/converter/R4FhirTypeConverter.java +++ b/Src/java/engine-fhir/src/main/java/org/opencds/cqf/cql/engine/fhir/converter/R4FhirTypeConverter.java @@ -2,6 +2,7 @@ import java.math.BigDecimal; import java.time.format.DateTimeFormatter; +import java.util.Collection; import java.util.stream.Collectors; import org.apache.commons.lang3.NotImplementedException; import org.hl7.fhir.instance.model.api.IBase; @@ -229,7 +230,18 @@ public IBase toFhirTuple(Tuple value) { for (String key : value.getElements().keySet()) { var part = param.addPart(); part.setName(key); - var result = toFhirType(value); + var element = value.getElements().get(key); + if (element == null) { + part.addExtension().setUrl(NULL_EXT_URL).setValue(new BooleanType(true)); + continue; + } else if (element instanceof Collection) { + if (((Collection) element).isEmpty()) { + part.addExtension().setUrl(EMPTY_EXT_URL).setValue(new BooleanType(true)); + continue; + } + } + + var result = toFhirType(element); if (result instanceof Resource) { part.setResource((Resource) result); } else if (result instanceof Type) { diff --git a/Src/java/engine-fhir/src/main/java/org/opencds/cqf/cql/engine/fhir/converter/R5FhirTypeConverter.java b/Src/java/engine-fhir/src/main/java/org/opencds/cqf/cql/engine/fhir/converter/R5FhirTypeConverter.java index 09f1c25d0..741bcf66a 100644 --- a/Src/java/engine-fhir/src/main/java/org/opencds/cqf/cql/engine/fhir/converter/R5FhirTypeConverter.java +++ b/Src/java/engine-fhir/src/main/java/org/opencds/cqf/cql/engine/fhir/converter/R5FhirTypeConverter.java @@ -2,6 +2,7 @@ import java.math.BigDecimal; import java.time.format.DateTimeFormatter; +import java.util.Collection; import java.util.stream.Collectors; import org.apache.commons.lang3.NotImplementedException; import org.hl7.fhir.instance.model.api.IBase; @@ -229,7 +230,18 @@ public IBase toFhirTuple(Tuple value) { for (String key : value.getElements().keySet()) { var part = param.addPart(); part.setName(key); - var result = toFhirType(value); + var element = value.getElements().get(key); + if (element == null) { + part.addExtension().setUrl(NULL_EXT_URL).setValue(new BooleanType(true)); + continue; + } else if (element instanceof Collection) { + if (((Collection) element).isEmpty()) { + part.addExtension().setUrl(EMPTY_EXT_URL).setValue(new BooleanType(true)); + continue; + } + } + + var result = toFhirType(element); if (result instanceof Resource) { part.setResource((Resource) result); } else if (result instanceof DataType) { diff --git a/Src/java/engine-fhir/src/test/java/org/opencds/cqf/cql/engine/fhir/converter/Dstu2TypeConverterTests.java b/Src/java/engine-fhir/src/test/java/org/opencds/cqf/cql/engine/fhir/converter/Dstu2TypeConverterTests.java index 193507e6f..1acf8fa38 100644 --- a/Src/java/engine-fhir/src/test/java/org/opencds/cqf/cql/engine/fhir/converter/Dstu2TypeConverterTests.java +++ b/Src/java/engine-fhir/src/test/java/org/opencds/cqf/cql/engine/fhir/converter/Dstu2TypeConverterTests.java @@ -5,14 +5,13 @@ import static org.junit.Assert.assertNotNull; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertInstanceOf; import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.opencds.cqf.cql.engine.fhir.converter.ConverterTestUtils.*; import ca.uhn.fhir.model.api.TemporalPrecisionEnum; -import ca.uhn.fhir.model.dstu2.resource.Parameters; +import ca.uhn.fhir.model.dstu2.resource.Parameters.Parameter; import java.math.BigDecimal; import java.time.*; import java.time.format.DateTimeFormatter; @@ -30,9 +29,11 @@ import org.hl7.fhir.dstu2.model.DateTimeType; import org.hl7.fhir.dstu2.model.DateType; import org.hl7.fhir.dstu2.model.DecimalType; +import org.hl7.fhir.dstu2.model.Encounter; import org.hl7.fhir.dstu2.model.IdType; import org.hl7.fhir.dstu2.model.InstantType; import org.hl7.fhir.dstu2.model.IntegerType; +import org.hl7.fhir.dstu2.model.Parameters.ParametersParameterComponent; import org.hl7.fhir.dstu2.model.Patient; import org.hl7.fhir.dstu2.model.Period; import org.hl7.fhir.dstu2.model.Range; @@ -525,16 +526,46 @@ void invalidIntervalToFhirInterval() { }); } + private static ParametersParameterComponent getPartByName(Parameter ppc, String name) { + return ppc.getPart().stream() + .filter(p -> p.getName().equals("name")) + .findFirst() + .get(); + } + @Test void tupleToFhirTuple() { - IBase actual = typeConverter.toFhirTuple(null); + Parameters actual = (Parameters) typeConverter.toFhirTuple(null); assertNull(actual); var tuple = new Tuple(); - actual = typeConverter.toFhirTuple(tuple); + actual = (Parameters) typeConverter.toFhirTuple(tuple); + assertNotNull(actual); + assertTrue(actual.isEmpty()); + + tuple.getElements().put("W", null); + tuple.getElements().put("X", 5); + tuple.getElements().put("Y", new Encounter().setId("123")); + tuple.getElements().put("Z", new ArrayList<>()); + + actual = (Parameters) typeConverter.toFhirTuple(tuple); assertNotNull(actual); - assertInstanceOf(Parameters.class, actual); - assertTrue(((Parameters) actual).isEmpty()); + assertEquals(1, actual.getParameter().size()); + + var first = actual.getParameterFirstRep(); + assertEquals(4, first.getPart().size()); + + var w = getPartByName(first, "W"); + assertEquals(FhirTypeConverter.NULL_EXT_URL, w.get.get(0).getUrl()); + + var x = getPartByName(first, "X"); + assertEquals(5, ((IntegerType) x.getValue()).getValue()); + + var y = getPartByName(first, "Y"); + assertEquals("123", y.getResource().getId()); + + var z = getPartByName(first, "Z"); + assertEquals(FhirTypeConverter.EMPTY_EXT_URL, z.getExtension().get(0).getUrl()); } // FHIR-to-CQL diff --git a/Src/java/engine-fhir/src/test/java/org/opencds/cqf/cql/engine/fhir/converter/Dstu3TypeConverterTests.java b/Src/java/engine-fhir/src/test/java/org/opencds/cqf/cql/engine/fhir/converter/Dstu3TypeConverterTests.java index 61b9da065..a7146813f 100644 --- a/Src/java/engine-fhir/src/test/java/org/opencds/cqf/cql/engine/fhir/converter/Dstu3TypeConverterTests.java +++ b/Src/java/engine-fhir/src/test/java/org/opencds/cqf/cql/engine/fhir/converter/Dstu3TypeConverterTests.java @@ -4,7 +4,6 @@ import static org.hamcrest.Matchers.instanceOf; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertInstanceOf; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertThrows; @@ -29,9 +28,12 @@ import org.hl7.fhir.dstu3.model.DateTimeType; import org.hl7.fhir.dstu3.model.DateType; import org.hl7.fhir.dstu3.model.DecimalType; +import org.hl7.fhir.dstu3.model.Encounter; import org.hl7.fhir.dstu3.model.IdType; import org.hl7.fhir.dstu3.model.InstantType; import org.hl7.fhir.dstu3.model.IntegerType; +import org.hl7.fhir.dstu3.model.Parameters; +import org.hl7.fhir.dstu3.model.Parameters.ParametersParameterComponent; import org.hl7.fhir.dstu3.model.Patient; import org.hl7.fhir.dstu3.model.Period; import org.hl7.fhir.dstu3.model.Range; @@ -42,7 +44,6 @@ import org.hl7.fhir.instance.model.api.ICompositeType; import org.hl7.fhir.instance.model.api.IIdType; import org.hl7.fhir.instance.model.api.IPrimitiveType; -import org.hl7.fhir.r4.model.Parameters; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; @@ -529,16 +530,46 @@ void invalidIntervalToFhirInterval() { }); } + private static ParametersParameterComponent getPartByName(ParametersParameterComponent ppc, String name) { + return ppc.getPart().stream() + .filter(p -> p.getName().equals("name")) + .findFirst() + .get(); + } + @Test void tupleToFhirTuple() { - IBase actual = typeConverter.toFhirTuple(null); + Parameters actual = (Parameters) typeConverter.toFhirTuple(null); assertNull(actual); var tuple = new Tuple(); - actual = typeConverter.toFhirTuple(tuple); + actual = (Parameters) typeConverter.toFhirTuple(tuple); + assertNotNull(actual); + assertTrue(actual.isEmpty()); + + tuple.getElements().put("W", null); + tuple.getElements().put("X", 5); + tuple.getElements().put("Y", new Encounter().setId("123")); + tuple.getElements().put("Z", new ArrayList<>()); + + actual = (Parameters) typeConverter.toFhirTuple(tuple); assertNotNull(actual); - assertInstanceOf(Parameters.class, actual); - assertTrue(((Parameters) actual).isEmpty()); + assertEquals(1, actual.getParameter().size()); + + var first = actual.getParameterFirstRep(); + assertEquals(4, first.getPart().size()); + + var w = getPartByName(first, "W"); + assertEquals(FhirTypeConverter.NULL_EXT_URL, w.getExtension().get(0).getUrl()); + + var x = getPartByName(first, "X"); + assertEquals(5, ((IntegerType) x.getValue()).getValue()); + + var y = getPartByName(first, "Y"); + assertEquals("123", y.getResource().getId()); + + var z = getPartByName(first, "Z"); + assertEquals(FhirTypeConverter.EMPTY_EXT_URL, z.getExtension().get(0).getUrl()); } // FHIR-to-CQL diff --git a/Src/java/engine-fhir/src/test/java/org/opencds/cqf/cql/engine/fhir/converter/R4TypeConverterTests.java b/Src/java/engine-fhir/src/test/java/org/opencds/cqf/cql/engine/fhir/converter/R4TypeConverterTests.java index 62535b799..adc714f31 100644 --- a/Src/java/engine-fhir/src/test/java/org/opencds/cqf/cql/engine/fhir/converter/R4TypeConverterTests.java +++ b/Src/java/engine-fhir/src/test/java/org/opencds/cqf/cql/engine/fhir/converter/R4TypeConverterTests.java @@ -4,7 +4,6 @@ import static org.hamcrest.Matchers.instanceOf; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertInstanceOf; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertThrows; @@ -33,10 +32,12 @@ import org.hl7.fhir.r4.model.DateTimeType; import org.hl7.fhir.r4.model.DateType; import org.hl7.fhir.r4.model.DecimalType; +import org.hl7.fhir.r4.model.Encounter; import org.hl7.fhir.r4.model.IdType; import org.hl7.fhir.r4.model.InstantType; import org.hl7.fhir.r4.model.IntegerType; import org.hl7.fhir.r4.model.Parameters; +import org.hl7.fhir.r4.model.Parameters.ParametersParameterComponent; import org.hl7.fhir.r4.model.Patient; import org.hl7.fhir.r4.model.Period; import org.hl7.fhir.r4.model.Range; @@ -529,16 +530,46 @@ void invalidIntervalToFhirInterval() { }); } + private static ParametersParameterComponent getPartByName(ParametersParameterComponent ppc, String name) { + return ppc.getPart().stream() + .filter(p -> p.getName().equals("name")) + .findFirst() + .get(); + } + @Test void tupleToFhirTuple() { - IBase actual = typeConverter.toFhirTuple(null); + Parameters actual = (Parameters) typeConverter.toFhirTuple(null); assertNull(actual); var tuple = new Tuple(); - actual = typeConverter.toFhirTuple(tuple); + actual = (Parameters) typeConverter.toFhirTuple(tuple); + assertNotNull(actual); + assertTrue(actual.isEmpty()); + + tuple.getElements().put("W", null); + tuple.getElements().put("X", 5); + tuple.getElements().put("Y", new Encounter().setId("123")); + tuple.getElements().put("Z", new ArrayList<>()); + + actual = (Parameters) typeConverter.toFhirTuple(tuple); assertNotNull(actual); - assertInstanceOf(Parameters.class, actual); - assertTrue(((Parameters) actual).isEmpty()); + assertEquals(1, actual.getParameter().size()); + + var first = actual.getParameterFirstRep(); + assertEquals(4, first.getPart().size()); + + var w = getPartByName(first, "W"); + assertEquals(FhirTypeConverter.NULL_EXT_URL, w.getExtension().get(0).getUrl()); + + var x = getPartByName(first, "X"); + assertEquals(5, ((IntegerType) x.getValue()).getValue()); + + var y = getPartByName(first, "Y"); + assertEquals("123", y.getResource().getId()); + + var z = getPartByName(first, "Z"); + assertEquals(FhirTypeConverter.EMPTY_EXT_URL, z.getExtension().get(0).getUrl()); } // FHIR-to-CQL diff --git a/Src/java/engine-fhir/src/test/java/org/opencds/cqf/cql/engine/fhir/converter/R5TypeConverterTests.java b/Src/java/engine-fhir/src/test/java/org/opencds/cqf/cql/engine/fhir/converter/R5TypeConverterTests.java index 3d299d772..2e42f9546 100644 --- a/Src/java/engine-fhir/src/test/java/org/opencds/cqf/cql/engine/fhir/converter/R5TypeConverterTests.java +++ b/Src/java/engine-fhir/src/test/java/org/opencds/cqf/cql/engine/fhir/converter/R5TypeConverterTests.java @@ -4,7 +4,6 @@ import static org.hamcrest.Matchers.instanceOf; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertInstanceOf; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertThrows; @@ -25,7 +24,6 @@ import org.hl7.fhir.instance.model.api.ICompositeType; import org.hl7.fhir.instance.model.api.IIdType; import org.hl7.fhir.instance.model.api.IPrimitiveType; -import org.hl7.fhir.r4.model.Parameters; import org.hl7.fhir.r5.model.Attachment; import org.hl7.fhir.r5.model.Base; import org.hl7.fhir.r5.model.BooleanType; @@ -34,9 +32,12 @@ import org.hl7.fhir.r5.model.DateTimeType; import org.hl7.fhir.r5.model.DateType; import org.hl7.fhir.r5.model.DecimalType; +import org.hl7.fhir.r5.model.Encounter; import org.hl7.fhir.r5.model.IdType; import org.hl7.fhir.r5.model.InstantType; import org.hl7.fhir.r5.model.IntegerType; +import org.hl7.fhir.r5.model.Parameters; +import org.hl7.fhir.r5.model.Parameters.ParametersParameterComponent; import org.hl7.fhir.r5.model.Patient; import org.hl7.fhir.r5.model.Period; import org.hl7.fhir.r5.model.Range; @@ -529,16 +530,46 @@ void invalidIntervalToFhirInterval() { }); } + private static ParametersParameterComponent getPartByName(ParametersParameterComponent ppc, String name) { + return ppc.getPart().stream() + .filter(p -> p.getName().equals("name")) + .findFirst() + .get(); + } + @Test void tupleToFhirTuple() { - IBase actual = typeConverter.toFhirTuple(null); + Parameters actual = (Parameters) typeConverter.toFhirTuple(null); assertNull(actual); var tuple = new Tuple(); - actual = typeConverter.toFhirTuple(tuple); + actual = (Parameters) typeConverter.toFhirTuple(tuple); + assertNotNull(actual); + assertTrue(actual.isEmpty()); + + tuple.getElements().put("W", null); + tuple.getElements().put("X", 5); + tuple.getElements().put("Y", new Encounter().setId("123")); + tuple.getElements().put("Z", new ArrayList<>()); + + actual = (Parameters) typeConverter.toFhirTuple(tuple); assertNotNull(actual); - assertInstanceOf(Parameters.class, actual); - assertTrue(((Parameters) actual).isEmpty()); + assertEquals(1, actual.getParameter().size()); + + var first = actual.getParameterFirstRep(); + assertEquals(4, first.getPart().size()); + + var w = getPartByName(first, "W"); + assertEquals(FhirTypeConverter.NULL_EXT_URL, w.getExtension().get(0).getUrl()); + + var x = getPartByName(first, "X"); + assertEquals(5, ((IntegerType) x.getValue()).getValue()); + + var y = getPartByName(first, "Y"); + assertEquals("123", y.getResource().getId()); + + var z = getPartByName(first, "Z"); + assertEquals(FhirTypeConverter.EMPTY_EXT_URL, z.getExtension().get(0).getUrl()); } // FHIR-to-CQL From 372d30661fb0885b452d60189d85765a1c1f5aee Mon Sep 17 00:00:00 2001 From: Jonathan Percival Date: Mon, 7 Oct 2024 16:05:56 -0600 Subject: [PATCH 03/10] Fix types --- .../fhir/converter/Dstu2TypeConverterTests.java | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/Src/java/engine-fhir/src/test/java/org/opencds/cqf/cql/engine/fhir/converter/Dstu2TypeConverterTests.java b/Src/java/engine-fhir/src/test/java/org/opencds/cqf/cql/engine/fhir/converter/Dstu2TypeConverterTests.java index 1acf8fa38..86bd9591d 100644 --- a/Src/java/engine-fhir/src/test/java/org/opencds/cqf/cql/engine/fhir/converter/Dstu2TypeConverterTests.java +++ b/Src/java/engine-fhir/src/test/java/org/opencds/cqf/cql/engine/fhir/converter/Dstu2TypeConverterTests.java @@ -11,6 +11,7 @@ import static org.opencds.cqf.cql.engine.fhir.converter.ConverterTestUtils.*; import ca.uhn.fhir.model.api.TemporalPrecisionEnum; +import ca.uhn.fhir.model.dstu2.resource.Parameters; import ca.uhn.fhir.model.dstu2.resource.Parameters.Parameter; import java.math.BigDecimal; import java.time.*; @@ -33,7 +34,6 @@ import org.hl7.fhir.dstu2.model.IdType; import org.hl7.fhir.dstu2.model.InstantType; import org.hl7.fhir.dstu2.model.IntegerType; -import org.hl7.fhir.dstu2.model.Parameters.ParametersParameterComponent; import org.hl7.fhir.dstu2.model.Patient; import org.hl7.fhir.dstu2.model.Period; import org.hl7.fhir.dstu2.model.Range; @@ -526,7 +526,7 @@ void invalidIntervalToFhirInterval() { }); } - private static ParametersParameterComponent getPartByName(Parameter ppc, String name) { + private static Parameters.Parameter getPartByName(Parameter ppc, String name) { return ppc.getPart().stream() .filter(p -> p.getName().equals("name")) .findFirst() @@ -556,7 +556,9 @@ void tupleToFhirTuple() { assertEquals(4, first.getPart().size()); var w = getPartByName(first, "W"); - assertEquals(FhirTypeConverter.NULL_EXT_URL, w.get.get(0).getUrl()); + assertEquals( + FhirTypeConverter.NULL_EXT_URL, + w.getAllUndeclaredExtensions().get(0).getUrl()); var x = getPartByName(first, "X"); assertEquals(5, ((IntegerType) x.getValue()).getValue()); @@ -565,7 +567,9 @@ void tupleToFhirTuple() { assertEquals("123", y.getResource().getId()); var z = getPartByName(first, "Z"); - assertEquals(FhirTypeConverter.EMPTY_EXT_URL, z.getExtension().get(0).getUrl()); + assertEquals( + FhirTypeConverter.EMPTY_EXT_URL, + z.getAllUndeclaredExtensions().get(0).getUrl()); } // FHIR-to-CQL From 2eb8c4b760dbc54c4d83ca0d965d9dfefb893d32 Mon Sep 17 00:00:00 2001 From: Jonathan Percival Date: Mon, 7 Oct 2024 16:17:01 -0600 Subject: [PATCH 04/10] Fix some mistakes on the tests. Whoops --- .../fhir/converter/Dstu2FhirTypeConverter.java | 15 ++++++--------- .../converter/Dstu2TypeConverterTests.java | 18 +++++++----------- .../converter/Dstu3TypeConverterTests.java | 2 +- .../fhir/converter/R4TypeConverterTests.java | 2 +- .../fhir/converter/R5TypeConverterTests.java | 2 +- 5 files changed, 16 insertions(+), 23 deletions(-) diff --git a/Src/java/engine-fhir/src/main/java/org/opencds/cqf/cql/engine/fhir/converter/Dstu2FhirTypeConverter.java b/Src/java/engine-fhir/src/main/java/org/opencds/cqf/cql/engine/fhir/converter/Dstu2FhirTypeConverter.java index 68e1e0281..212bf1d1c 100644 --- a/Src/java/engine-fhir/src/main/java/org/opencds/cqf/cql/engine/fhir/converter/Dstu2FhirTypeConverter.java +++ b/Src/java/engine-fhir/src/main/java/org/opencds/cqf/cql/engine/fhir/converter/Dstu2FhirTypeConverter.java @@ -1,8 +1,5 @@ package org.opencds.cqf.cql.engine.fhir.converter; -import ca.uhn.fhir.model.api.IDatatype; -import ca.uhn.fhir.model.api.IResource; -import ca.uhn.fhir.model.dstu2.resource.Parameters; import java.math.BigDecimal; import java.util.Calendar; import java.util.Collection; @@ -246,20 +243,20 @@ public IBase toFhirTuple(Tuple value) { part.setName(key); var element = value.getElements().get(key); if (element == null) { - part.addUndeclaredExtension(false, NULL_EXT_URL, new BooleanType(true)); + part.addExtension(NULL_EXT_URL, new BooleanType(true)); continue; } else if (element instanceof Collection) { if (((Collection) element).isEmpty()) { - part.addUndeclaredExtension(false, EMPTY_EXT_URL, new BooleanType(true)); + part.addExtension(EMPTY_EXT_URL, new BooleanType(true)); continue; } } var result = toFhirType(element); - if (result instanceof IResource) { - part.setResource((IResource) result); - } else if (result instanceof IDatatype) { - part.setValue((IDatatype) result); + if (result instanceof Resource) { + part.setResource((Resource) result); + } else if (result instanceof Type) { + part.setValue((Type) result); } else { throw new IllegalArgumentException("Tuple contains unsupported type"); } diff --git a/Src/java/engine-fhir/src/test/java/org/opencds/cqf/cql/engine/fhir/converter/Dstu2TypeConverterTests.java b/Src/java/engine-fhir/src/test/java/org/opencds/cqf/cql/engine/fhir/converter/Dstu2TypeConverterTests.java index 86bd9591d..65732d498 100644 --- a/Src/java/engine-fhir/src/test/java/org/opencds/cqf/cql/engine/fhir/converter/Dstu2TypeConverterTests.java +++ b/Src/java/engine-fhir/src/test/java/org/opencds/cqf/cql/engine/fhir/converter/Dstu2TypeConverterTests.java @@ -11,8 +11,6 @@ import static org.opencds.cqf.cql.engine.fhir.converter.ConverterTestUtils.*; import ca.uhn.fhir.model.api.TemporalPrecisionEnum; -import ca.uhn.fhir.model.dstu2.resource.Parameters; -import ca.uhn.fhir.model.dstu2.resource.Parameters.Parameter; import java.math.BigDecimal; import java.time.*; import java.time.format.DateTimeFormatter; @@ -34,6 +32,8 @@ import org.hl7.fhir.dstu2.model.IdType; import org.hl7.fhir.dstu2.model.InstantType; import org.hl7.fhir.dstu2.model.IntegerType; +import org.hl7.fhir.dstu2.model.Parameters; +import org.hl7.fhir.dstu2.model.Parameters.ParametersParameterComponent; import org.hl7.fhir.dstu2.model.Patient; import org.hl7.fhir.dstu2.model.Period; import org.hl7.fhir.dstu2.model.Range; @@ -526,9 +526,9 @@ void invalidIntervalToFhirInterval() { }); } - private static Parameters.Parameter getPartByName(Parameter ppc, String name) { + private static ParametersParameterComponent getPartByName(ParametersParameterComponent ppc, String name) { return ppc.getPart().stream() - .filter(p -> p.getName().equals("name")) + .filter(p -> p.getName().equals(name)) .findFirst() .get(); } @@ -552,13 +552,11 @@ void tupleToFhirTuple() { assertNotNull(actual); assertEquals(1, actual.getParameter().size()); - var first = actual.getParameterFirstRep(); + var first = actual.getParameter().get(0); assertEquals(4, first.getPart().size()); var w = getPartByName(first, "W"); - assertEquals( - FhirTypeConverter.NULL_EXT_URL, - w.getAllUndeclaredExtensions().get(0).getUrl()); + assertEquals(FhirTypeConverter.NULL_EXT_URL, w.getExtension().get(0).getUrl()); var x = getPartByName(first, "X"); assertEquals(5, ((IntegerType) x.getValue()).getValue()); @@ -567,9 +565,7 @@ void tupleToFhirTuple() { assertEquals("123", y.getResource().getId()); var z = getPartByName(first, "Z"); - assertEquals( - FhirTypeConverter.EMPTY_EXT_URL, - z.getAllUndeclaredExtensions().get(0).getUrl()); + assertEquals(FhirTypeConverter.EMPTY_EXT_URL, z.getExtension().get(0).getUrl()); } // FHIR-to-CQL diff --git a/Src/java/engine-fhir/src/test/java/org/opencds/cqf/cql/engine/fhir/converter/Dstu3TypeConverterTests.java b/Src/java/engine-fhir/src/test/java/org/opencds/cqf/cql/engine/fhir/converter/Dstu3TypeConverterTests.java index a7146813f..acb5e5f0b 100644 --- a/Src/java/engine-fhir/src/test/java/org/opencds/cqf/cql/engine/fhir/converter/Dstu3TypeConverterTests.java +++ b/Src/java/engine-fhir/src/test/java/org/opencds/cqf/cql/engine/fhir/converter/Dstu3TypeConverterTests.java @@ -532,7 +532,7 @@ void invalidIntervalToFhirInterval() { private static ParametersParameterComponent getPartByName(ParametersParameterComponent ppc, String name) { return ppc.getPart().stream() - .filter(p -> p.getName().equals("name")) + .filter(p -> p.getName().equals(name)) .findFirst() .get(); } diff --git a/Src/java/engine-fhir/src/test/java/org/opencds/cqf/cql/engine/fhir/converter/R4TypeConverterTests.java b/Src/java/engine-fhir/src/test/java/org/opencds/cqf/cql/engine/fhir/converter/R4TypeConverterTests.java index adc714f31..a86772d28 100644 --- a/Src/java/engine-fhir/src/test/java/org/opencds/cqf/cql/engine/fhir/converter/R4TypeConverterTests.java +++ b/Src/java/engine-fhir/src/test/java/org/opencds/cqf/cql/engine/fhir/converter/R4TypeConverterTests.java @@ -532,7 +532,7 @@ void invalidIntervalToFhirInterval() { private static ParametersParameterComponent getPartByName(ParametersParameterComponent ppc, String name) { return ppc.getPart().stream() - .filter(p -> p.getName().equals("name")) + .filter(p -> p.getName().equals(name)) .findFirst() .get(); } diff --git a/Src/java/engine-fhir/src/test/java/org/opencds/cqf/cql/engine/fhir/converter/R5TypeConverterTests.java b/Src/java/engine-fhir/src/test/java/org/opencds/cqf/cql/engine/fhir/converter/R5TypeConverterTests.java index 2e42f9546..cb3a5241f 100644 --- a/Src/java/engine-fhir/src/test/java/org/opencds/cqf/cql/engine/fhir/converter/R5TypeConverterTests.java +++ b/Src/java/engine-fhir/src/test/java/org/opencds/cqf/cql/engine/fhir/converter/R5TypeConverterTests.java @@ -532,7 +532,7 @@ void invalidIntervalToFhirInterval() { private static ParametersParameterComponent getPartByName(ParametersParameterComponent ppc, String name) { return ppc.getPart().stream() - .filter(p -> p.getName().equals("name")) + .filter(p -> p.getName().equals(name)) .findFirst() .get(); } From f8c0cbb23f44a2de2a3082b00e2d6087ccedb15f Mon Sep 17 00:00:00 2001 From: Jonathan Percival Date: Mon, 7 Oct 2024 18:41:10 -0600 Subject: [PATCH 05/10] Use data-absent extension --- .../converter/Dstu2FhirTypeConverter.java | 32 ++++++++----------- .../converter/Dstu3FhirTypeConverter.java | 30 ++++++++--------- .../fhir/converter/FhirTypeConverter.java | 5 +-- .../fhir/converter/R4FhirTypeConverter.java | 30 ++++++++--------- .../fhir/converter/R5FhirTypeConverter.java | 30 ++++++++--------- .../converter/Dstu2TypeConverterTests.java | 7 ++-- .../converter/Dstu3TypeConverterTests.java | 7 ++-- .../fhir/converter/R4TypeConverterTests.java | 7 ++-- .../fhir/converter/R5TypeConverterTests.java | 7 ++-- 9 files changed, 75 insertions(+), 80 deletions(-) diff --git a/Src/java/engine-fhir/src/main/java/org/opencds/cqf/cql/engine/fhir/converter/Dstu2FhirTypeConverter.java b/Src/java/engine-fhir/src/main/java/org/opencds/cqf/cql/engine/fhir/converter/Dstu2FhirTypeConverter.java index 212bf1d1c..3e8956c0b 100644 --- a/Src/java/engine-fhir/src/main/java/org/opencds/cqf/cql/engine/fhir/converter/Dstu2FhirTypeConverter.java +++ b/Src/java/engine-fhir/src/main/java/org/opencds/cqf/cql/engine/fhir/converter/Dstu2FhirTypeConverter.java @@ -233,32 +233,26 @@ public IBase toFhirTuple(Tuple value) { return parameters; } - // This parameters needs to be set to the definition name - // when it's rolled up to the final result - // This parameters needs to be set to the definition name - // when it's rolled up to the final result var param = parameters.addParameter(); for (String key : value.getElements().keySet()) { var part = param.addPart(); part.setName(key); var element = value.getElements().get(key); if (element == null) { - part.addExtension(NULL_EXT_URL, new BooleanType(true)); - continue; - } else if (element instanceof Collection) { - if (((Collection) element).isEmpty()) { - part.addExtension(EMPTY_EXT_URL, new BooleanType(true)); - continue; - } - } - - var result = toFhirType(element); - if (result instanceof Resource) { - part.setResource((Resource) result); - } else if (result instanceof Type) { - part.setValue((Type) result); + part.addExtension() + .setUrl(DATA_ABSENT_REASON_EXT_URL) + .setValue(new CodeType(DATA_ABSENT_REASON_UNKNOWN_CODE)); + } else if (element instanceof Collection && ((Collection) element).isEmpty()) { + part.addExtension().setUrl(EMPTY_LIST_EXT_URL).setValue(new BooleanType(true)); } else { - throw new IllegalArgumentException("Tuple contains unsupported type"); + var result = toFhirType(element); + if (result instanceof Resource) { + part.setResource((Resource) result); + } else if (result instanceof Type) { + part.setValue((Type) result); + } else { + throw new IllegalArgumentException("Tuple contains unsupported type"); + } } } diff --git a/Src/java/engine-fhir/src/main/java/org/opencds/cqf/cql/engine/fhir/converter/Dstu3FhirTypeConverter.java b/Src/java/engine-fhir/src/main/java/org/opencds/cqf/cql/engine/fhir/converter/Dstu3FhirTypeConverter.java index 72ab4db19..7604d1ea6 100644 --- a/Src/java/engine-fhir/src/main/java/org/opencds/cqf/cql/engine/fhir/converter/Dstu3FhirTypeConverter.java +++ b/Src/java/engine-fhir/src/main/java/org/opencds/cqf/cql/engine/fhir/converter/Dstu3FhirTypeConverter.java @@ -232,30 +232,26 @@ public IBase toFhirTuple(Tuple value) { return parameters; } - // This parameters needs to be set to the definition name - // when it's rolled up to the final result var param = parameters.addParameter(); for (String key : value.getElements().keySet()) { var part = param.addPart(); part.setName(key); var element = value.getElements().get(key); if (element == null) { - part.addExtension().setUrl(NULL_EXT_URL).setValue(new BooleanType(true)); - continue; - } else if (element instanceof Collection) { - if (((Collection) element).isEmpty()) { - part.addExtension().setUrl(EMPTY_EXT_URL).setValue(new BooleanType(true)); - continue; - } - } - - var result = toFhirType(element); - if (result instanceof Resource) { - part.setResource((Resource) result); - } else if (result instanceof Type) { - part.setValue((Type) result); + part.addExtension() + .setUrl(DATA_ABSENT_REASON_EXT_URL) + .setValue(new CodeType(DATA_ABSENT_REASON_UNKNOWN_CODE)); + } else if (element instanceof Collection && ((Collection) element).isEmpty()) { + part.addExtension().setUrl(EMPTY_LIST_EXT_URL).setValue(new BooleanType(true)); } else { - throw new IllegalArgumentException("Tuple contains unsupported type"); + var result = toFhirType(element); + if (result instanceof Resource) { + part.setResource((Resource) result); + } else if (result instanceof Type) { + part.setValue((Type) result); + } else { + throw new IllegalArgumentException("Tuple contains unsupported type"); + } } } diff --git a/Src/java/engine-fhir/src/main/java/org/opencds/cqf/cql/engine/fhir/converter/FhirTypeConverter.java b/Src/java/engine-fhir/src/main/java/org/opencds/cqf/cql/engine/fhir/converter/FhirTypeConverter.java index d4ea05985..60e2b32e4 100644 --- a/Src/java/engine-fhir/src/main/java/org/opencds/cqf/cql/engine/fhir/converter/FhirTypeConverter.java +++ b/Src/java/engine-fhir/src/main/java/org/opencds/cqf/cql/engine/fhir/converter/FhirTypeConverter.java @@ -28,8 +28,9 @@ */ public interface FhirTypeConverter { - static final String EMPTY_EXT_URL = "http://hl7.org/fhir/StructureDefinition/cqf-isEmptyList"; - static final String NULL_EXT_URL = "http://hl7.org/fhir/StructureDefinition/cqf-isNull"; + static final String EMPTY_LIST_EXT_URL = "http://hl7.org/fhir/StructureDefinition/cqf-isEmptyList"; + static final String DATA_ABSENT_REASON_EXT_URL = "http://hl7.org/fhir/StructureDefinition/data-absent-reason"; + static final String DATA_ABSENT_REASON_UNKNOWN_CODE = "unknown"; // CQL-to-FHIR conversions diff --git a/Src/java/engine-fhir/src/main/java/org/opencds/cqf/cql/engine/fhir/converter/R4FhirTypeConverter.java b/Src/java/engine-fhir/src/main/java/org/opencds/cqf/cql/engine/fhir/converter/R4FhirTypeConverter.java index e62662302..afcc37aa4 100644 --- a/Src/java/engine-fhir/src/main/java/org/opencds/cqf/cql/engine/fhir/converter/R4FhirTypeConverter.java +++ b/Src/java/engine-fhir/src/main/java/org/opencds/cqf/cql/engine/fhir/converter/R4FhirTypeConverter.java @@ -224,30 +224,26 @@ public IBase toFhirTuple(Tuple value) { return parameters; } - // This parameters needs to be set to the definition name - // when it's rolled up to the final result var param = parameters.addParameter(); for (String key : value.getElements().keySet()) { var part = param.addPart(); part.setName(key); var element = value.getElements().get(key); if (element == null) { - part.addExtension().setUrl(NULL_EXT_URL).setValue(new BooleanType(true)); - continue; - } else if (element instanceof Collection) { - if (((Collection) element).isEmpty()) { - part.addExtension().setUrl(EMPTY_EXT_URL).setValue(new BooleanType(true)); - continue; - } - } - - var result = toFhirType(element); - if (result instanceof Resource) { - part.setResource((Resource) result); - } else if (result instanceof Type) { - part.setValue((Type) result); + part.addExtension() + .setUrl(DATA_ABSENT_REASON_EXT_URL) + .setValue(new CodeType(DATA_ABSENT_REASON_UNKNOWN_CODE)); + } else if (element instanceof Collection && ((Collection) element).isEmpty()) { + part.addExtension().setUrl(EMPTY_LIST_EXT_URL).setValue(new BooleanType(true)); } else { - throw new IllegalArgumentException("Tuple contains unsupported type"); + var result = toFhirType(element); + if (result instanceof Resource) { + part.setResource((Resource) result); + } else if (result instanceof Type) { + part.setValue((Type) result); + } else { + throw new IllegalArgumentException("Tuple contains unsupported type"); + } } } diff --git a/Src/java/engine-fhir/src/main/java/org/opencds/cqf/cql/engine/fhir/converter/R5FhirTypeConverter.java b/Src/java/engine-fhir/src/main/java/org/opencds/cqf/cql/engine/fhir/converter/R5FhirTypeConverter.java index 741bcf66a..dc1366653 100644 --- a/Src/java/engine-fhir/src/main/java/org/opencds/cqf/cql/engine/fhir/converter/R5FhirTypeConverter.java +++ b/Src/java/engine-fhir/src/main/java/org/opencds/cqf/cql/engine/fhir/converter/R5FhirTypeConverter.java @@ -224,30 +224,26 @@ public IBase toFhirTuple(Tuple value) { return parameters; } - // This parameters needs to be set to the definition name - // when it's rolled up to the final result var param = parameters.addParameter(); for (String key : value.getElements().keySet()) { var part = param.addPart(); part.setName(key); var element = value.getElements().get(key); if (element == null) { - part.addExtension().setUrl(NULL_EXT_URL).setValue(new BooleanType(true)); - continue; - } else if (element instanceof Collection) { - if (((Collection) element).isEmpty()) { - part.addExtension().setUrl(EMPTY_EXT_URL).setValue(new BooleanType(true)); - continue; - } - } - - var result = toFhirType(element); - if (result instanceof Resource) { - part.setResource((Resource) result); - } else if (result instanceof DataType) { - part.setValue((DataType) result); + part.addExtension() + .setUrl(DATA_ABSENT_REASON_EXT_URL) + .setValue(new CodeType(DATA_ABSENT_REASON_UNKNOWN_CODE)); + } else if (element instanceof Collection && ((Collection) element).isEmpty()) { + part.addExtension().setUrl(EMPTY_LIST_EXT_URL).setValue(new BooleanType(true)); } else { - throw new IllegalArgumentException("Tuple contains unsupported type"); + var result = toFhirType(element); + if (result instanceof Resource) { + part.setResource((Resource) result); + } else if (result instanceof DataType) { + part.setValue((DataType) result); + } else { + throw new IllegalArgumentException("Tuple contains unsupported type"); + } } } diff --git a/Src/java/engine-fhir/src/test/java/org/opencds/cqf/cql/engine/fhir/converter/Dstu2TypeConverterTests.java b/Src/java/engine-fhir/src/test/java/org/opencds/cqf/cql/engine/fhir/converter/Dstu2TypeConverterTests.java index 65732d498..c54585616 100644 --- a/Src/java/engine-fhir/src/test/java/org/opencds/cqf/cql/engine/fhir/converter/Dstu2TypeConverterTests.java +++ b/Src/java/engine-fhir/src/test/java/org/opencds/cqf/cql/engine/fhir/converter/Dstu2TypeConverterTests.java @@ -556,7 +556,9 @@ void tupleToFhirTuple() { assertEquals(4, first.getPart().size()); var w = getPartByName(first, "W"); - assertEquals(FhirTypeConverter.NULL_EXT_URL, w.getExtension().get(0).getUrl()); + assertEquals( + FhirTypeConverter.DATA_ABSENT_REASON_EXT_URL, + w.getExtension().get(0).getUrl()); var x = getPartByName(first, "X"); assertEquals(5, ((IntegerType) x.getValue()).getValue()); @@ -565,7 +567,8 @@ void tupleToFhirTuple() { assertEquals("123", y.getResource().getId()); var z = getPartByName(first, "Z"); - assertEquals(FhirTypeConverter.EMPTY_EXT_URL, z.getExtension().get(0).getUrl()); + assertEquals( + FhirTypeConverter.EMPTY_LIST_EXT_URL, z.getExtension().get(0).getUrl()); } // FHIR-to-CQL diff --git a/Src/java/engine-fhir/src/test/java/org/opencds/cqf/cql/engine/fhir/converter/Dstu3TypeConverterTests.java b/Src/java/engine-fhir/src/test/java/org/opencds/cqf/cql/engine/fhir/converter/Dstu3TypeConverterTests.java index acb5e5f0b..31be3373e 100644 --- a/Src/java/engine-fhir/src/test/java/org/opencds/cqf/cql/engine/fhir/converter/Dstu3TypeConverterTests.java +++ b/Src/java/engine-fhir/src/test/java/org/opencds/cqf/cql/engine/fhir/converter/Dstu3TypeConverterTests.java @@ -560,7 +560,9 @@ void tupleToFhirTuple() { assertEquals(4, first.getPart().size()); var w = getPartByName(first, "W"); - assertEquals(FhirTypeConverter.NULL_EXT_URL, w.getExtension().get(0).getUrl()); + assertEquals( + FhirTypeConverter.DATA_ABSENT_REASON_EXT_URL, + w.getExtension().get(0).getUrl()); var x = getPartByName(first, "X"); assertEquals(5, ((IntegerType) x.getValue()).getValue()); @@ -569,7 +571,8 @@ void tupleToFhirTuple() { assertEquals("123", y.getResource().getId()); var z = getPartByName(first, "Z"); - assertEquals(FhirTypeConverter.EMPTY_EXT_URL, z.getExtension().get(0).getUrl()); + assertEquals( + FhirTypeConverter.EMPTY_LIST_EXT_URL, z.getExtension().get(0).getUrl()); } // FHIR-to-CQL diff --git a/Src/java/engine-fhir/src/test/java/org/opencds/cqf/cql/engine/fhir/converter/R4TypeConverterTests.java b/Src/java/engine-fhir/src/test/java/org/opencds/cqf/cql/engine/fhir/converter/R4TypeConverterTests.java index a86772d28..697bc5324 100644 --- a/Src/java/engine-fhir/src/test/java/org/opencds/cqf/cql/engine/fhir/converter/R4TypeConverterTests.java +++ b/Src/java/engine-fhir/src/test/java/org/opencds/cqf/cql/engine/fhir/converter/R4TypeConverterTests.java @@ -560,7 +560,9 @@ void tupleToFhirTuple() { assertEquals(4, first.getPart().size()); var w = getPartByName(first, "W"); - assertEquals(FhirTypeConverter.NULL_EXT_URL, w.getExtension().get(0).getUrl()); + assertEquals( + FhirTypeConverter.DATA_ABSENT_REASON_EXT_URL, + w.getExtension().get(0).getUrl()); var x = getPartByName(first, "X"); assertEquals(5, ((IntegerType) x.getValue()).getValue()); @@ -569,7 +571,8 @@ void tupleToFhirTuple() { assertEquals("123", y.getResource().getId()); var z = getPartByName(first, "Z"); - assertEquals(FhirTypeConverter.EMPTY_EXT_URL, z.getExtension().get(0).getUrl()); + assertEquals( + FhirTypeConverter.EMPTY_LIST_EXT_URL, z.getExtension().get(0).getUrl()); } // FHIR-to-CQL diff --git a/Src/java/engine-fhir/src/test/java/org/opencds/cqf/cql/engine/fhir/converter/R5TypeConverterTests.java b/Src/java/engine-fhir/src/test/java/org/opencds/cqf/cql/engine/fhir/converter/R5TypeConverterTests.java index cb3a5241f..8c1d291de 100644 --- a/Src/java/engine-fhir/src/test/java/org/opencds/cqf/cql/engine/fhir/converter/R5TypeConverterTests.java +++ b/Src/java/engine-fhir/src/test/java/org/opencds/cqf/cql/engine/fhir/converter/R5TypeConverterTests.java @@ -560,7 +560,9 @@ void tupleToFhirTuple() { assertEquals(4, first.getPart().size()); var w = getPartByName(first, "W"); - assertEquals(FhirTypeConverter.NULL_EXT_URL, w.getExtension().get(0).getUrl()); + assertEquals( + FhirTypeConverter.DATA_ABSENT_REASON_EXT_URL, + w.getExtension().get(0).getUrl()); var x = getPartByName(first, "X"); assertEquals(5, ((IntegerType) x.getValue()).getValue()); @@ -569,7 +571,8 @@ void tupleToFhirTuple() { assertEquals("123", y.getResource().getId()); var z = getPartByName(first, "Z"); - assertEquals(FhirTypeConverter.EMPTY_EXT_URL, z.getExtension().get(0).getUrl()); + assertEquals( + FhirTypeConverter.EMPTY_LIST_EXT_URL, z.getExtension().get(0).getUrl()); } // FHIR-to-CQL From 0951dfbff0df60fa24955969a80166cf3ce3b082 Mon Sep 17 00:00:00 2001 From: Jonathan Percival Date: Thu, 10 Oct 2024 09:55:21 -0600 Subject: [PATCH 06/10] Tuple updates --- .../fhir/converter/BaseFhirTypeConverter.java | 4 +- .../converter/Dstu2FhirTypeConverter.java | 62 ++++++++++++++----- .../converter/Dstu3FhirTypeConverter.java | 62 ++++++++++++++----- .../fhir/converter/FhirTypeConverter.java | 6 +- .../fhir/converter/R4FhirTypeConverter.java | 62 ++++++++++++++----- .../fhir/converter/R5FhirTypeConverter.java | 62 ++++++++++++++----- .../converter/Dstu2TypeConverterTests.java | 33 ++++++---- .../converter/Dstu3TypeConverterTests.java | 33 ++++++---- .../fhir/converter/R4TypeConverterTests.java | 33 ++++++---- .../fhir/converter/R5TypeConverterTests.java | 33 ++++++---- 10 files changed, 278 insertions(+), 112 deletions(-) diff --git a/Src/java/engine-fhir/src/main/java/org/opencds/cqf/cql/engine/fhir/converter/BaseFhirTypeConverter.java b/Src/java/engine-fhir/src/main/java/org/opencds/cqf/cql/engine/fhir/converter/BaseFhirTypeConverter.java index 4002d9d2b..0aeb647e6 100644 --- a/Src/java/engine-fhir/src/main/java/org/opencds/cqf/cql/engine/fhir/converter/BaseFhirTypeConverter.java +++ b/Src/java/engine-fhir/src/main/java/org/opencds/cqf/cql/engine/fhir/converter/BaseFhirTypeConverter.java @@ -42,7 +42,7 @@ public boolean isFhirType(Object value) { } @Override - public Iterable toFhirTypes(Iterable values) { + public List toFhirTypes(Iterable values) { List converted = new ArrayList<>(); for (Object value : values) { if (value == null) { @@ -50,7 +50,7 @@ public Iterable toFhirTypes(Iterable values) { } else if (value instanceof Iterable) { converted.add(toFhirTypes((Iterable) value)); } else if (isFhirType(value)) { - converted.add(value); + converted.add((IBase) value); } else if (isCqlType(value)) { converted.add(toFhirType(value)); } else { diff --git a/Src/java/engine-fhir/src/main/java/org/opencds/cqf/cql/engine/fhir/converter/Dstu2FhirTypeConverter.java b/Src/java/engine-fhir/src/main/java/org/opencds/cqf/cql/engine/fhir/converter/Dstu2FhirTypeConverter.java index 3e8956c0b..23f6ef0c7 100644 --- a/Src/java/engine-fhir/src/main/java/org/opencds/cqf/cql/engine/fhir/converter/Dstu2FhirTypeConverter.java +++ b/Src/java/engine-fhir/src/main/java/org/opencds/cqf/cql/engine/fhir/converter/Dstu2FhirTypeConverter.java @@ -2,7 +2,6 @@ import java.math.BigDecimal; import java.util.Calendar; -import java.util.Collection; import java.util.GregorianCalendar; import java.util.stream.Collectors; import org.apache.commons.lang3.NotImplementedException; @@ -222,12 +221,38 @@ public ICompositeType toFhirRange(Interval value) { return range; } + private static BooleanType emptyBooleanWithExtension(String url, Type value) { + var result = new BooleanType((String) null); + result.addExtension().setUrl(url).setValue(value); + return result; + } + + private static void addPartWithNameAndValue( + Parameters.ParametersParameterComponent param, String key, Object value) { + var part = param.addPart().setName(key); + if (value instanceof Resource) { + part.setResource((Resource) value); + } else if (value instanceof Type) { + part.setValue((Type) value); + } else { + throw new IllegalArgumentException( + "Unsupported FHIR type: " + value.getClass().getName()); + } + } + + private static Iterable asIterable(Object value) { + if (value instanceof Iterable) { + return (Iterable) value; + } else { + return null; + } + } + @Override public IBase toFhirTuple(Tuple value) { if (value == null) { return null; } - var parameters = new Parameters(); if (value.getElements().isEmpty()) { return parameters; @@ -235,23 +260,30 @@ public IBase toFhirTuple(Tuple value) { var param = parameters.addParameter(); for (String key : value.getElements().keySet()) { - var part = param.addPart(); - part.setName(key); var element = value.getElements().get(key); if (element == null) { - part.addExtension() - .setUrl(DATA_ABSENT_REASON_EXT_URL) - .setValue(new CodeType(DATA_ABSENT_REASON_UNKNOWN_CODE)); - } else if (element instanceof Collection && ((Collection) element).isEmpty()) { - part.addExtension().setUrl(EMPTY_LIST_EXT_URL).setValue(new BooleanType(true)); + // Null value, add a single empty value with an extension indicating the reason + var dataAbsentValue = emptyBooleanWithExtension( + DATA_ABSENT_REASON_EXT_URL, new CodeType(DATA_ABSENT_REASON_UNKNOWN_CODE)); + addPartWithNameAndValue(param, key, dataAbsentValue); + continue; + } + + var iterable = asIterable(element); + if (iterable == null) { + // Single value + addPartWithNameAndValue(param, key, toFhirType(element)); } else { - var result = toFhirType(element); - if (result instanceof Resource) { - part.setResource((Resource) result); - } else if (result instanceof Type) { - part.setValue((Type) result); + if (!iterable.iterator().hasNext()) { + // Empty list + var emptyListValue = emptyBooleanWithExtension(EMPTY_LIST_EXT_URL, new BooleanType(true)); + addPartWithNameAndValue(param, key, emptyListValue); } else { - throw new IllegalArgumentException("Tuple contains unsupported type"); + // Non-empty list, one part per value + var fhirTypes = this.toFhirTypes(iterable); + for (var fhirType : fhirTypes) { + addPartWithNameAndValue(param, key, fhirType); + } } } } diff --git a/Src/java/engine-fhir/src/main/java/org/opencds/cqf/cql/engine/fhir/converter/Dstu3FhirTypeConverter.java b/Src/java/engine-fhir/src/main/java/org/opencds/cqf/cql/engine/fhir/converter/Dstu3FhirTypeConverter.java index 7604d1ea6..90b14ecd7 100644 --- a/Src/java/engine-fhir/src/main/java/org/opencds/cqf/cql/engine/fhir/converter/Dstu3FhirTypeConverter.java +++ b/Src/java/engine-fhir/src/main/java/org/opencds/cqf/cql/engine/fhir/converter/Dstu3FhirTypeConverter.java @@ -2,7 +2,6 @@ import java.math.BigDecimal; import java.time.format.DateTimeFormatter; -import java.util.Collection; import java.util.stream.Collectors; import org.apache.commons.lang3.NotImplementedException; import org.hl7.fhir.dstu3.model.*; @@ -221,12 +220,38 @@ public ICompositeType toFhirRange(Interval value) { return range; } + private static BooleanType emptyBooleanWithExtension(String url, Type value) { + var result = new BooleanType((String) null); + result.addExtension().setUrl(url).setValue(value); + return result; + } + + private static void addPartWithNameAndValue( + Parameters.ParametersParameterComponent param, String key, Object value) { + var part = param.addPart().setName(key); + if (value instanceof Resource) { + part.setResource((Resource) value); + } else if (value instanceof Type) { + part.setValue((Type) value); + } else { + throw new IllegalArgumentException( + "Unsupported FHIR type: " + value.getClass().getName()); + } + } + + private static Iterable asIterable(Object value) { + if (value instanceof Iterable) { + return (Iterable) value; + } else { + return null; + } + } + @Override public IBase toFhirTuple(Tuple value) { if (value == null) { return null; } - var parameters = new Parameters(); if (value.getElements().isEmpty()) { return parameters; @@ -234,23 +259,30 @@ public IBase toFhirTuple(Tuple value) { var param = parameters.addParameter(); for (String key : value.getElements().keySet()) { - var part = param.addPart(); - part.setName(key); var element = value.getElements().get(key); if (element == null) { - part.addExtension() - .setUrl(DATA_ABSENT_REASON_EXT_URL) - .setValue(new CodeType(DATA_ABSENT_REASON_UNKNOWN_CODE)); - } else if (element instanceof Collection && ((Collection) element).isEmpty()) { - part.addExtension().setUrl(EMPTY_LIST_EXT_URL).setValue(new BooleanType(true)); + // Null value, add a single empty value with an extension indicating the reason + var dataAbsentValue = emptyBooleanWithExtension( + DATA_ABSENT_REASON_EXT_URL, new CodeType(DATA_ABSENT_REASON_UNKNOWN_CODE)); + addPartWithNameAndValue(param, key, dataAbsentValue); + continue; + } + + var iterable = asIterable(element); + if (iterable == null) { + // Single value + addPartWithNameAndValue(param, key, toFhirType(element)); } else { - var result = toFhirType(element); - if (result instanceof Resource) { - part.setResource((Resource) result); - } else if (result instanceof Type) { - part.setValue((Type) result); + if (!iterable.iterator().hasNext()) { + // Empty list + var emptyListValue = emptyBooleanWithExtension(EMPTY_LIST_EXT_URL, new BooleanType(true)); + addPartWithNameAndValue(param, key, emptyListValue); } else { - throw new IllegalArgumentException("Tuple contains unsupported type"); + // Non-empty list, one part per value + var fhirTypes = this.toFhirTypes(iterable); + for (var fhirType : fhirTypes) { + addPartWithNameAndValue(param, key, fhirType); + } } } } diff --git a/Src/java/engine-fhir/src/main/java/org/opencds/cqf/cql/engine/fhir/converter/FhirTypeConverter.java b/Src/java/engine-fhir/src/main/java/org/opencds/cqf/cql/engine/fhir/converter/FhirTypeConverter.java index 60e2b32e4..7d99e176a 100644 --- a/Src/java/engine-fhir/src/main/java/org/opencds/cqf/cql/engine/fhir/converter/FhirTypeConverter.java +++ b/Src/java/engine-fhir/src/main/java/org/opencds/cqf/cql/engine/fhir/converter/FhirTypeConverter.java @@ -1,6 +1,7 @@ package org.opencds.cqf.cql.engine.fhir.converter; import java.math.BigDecimal; +import java.util.List; import org.hl7.fhir.instance.model.api.IBase; import org.hl7.fhir.instance.model.api.IBaseCoding; import org.hl7.fhir.instance.model.api.ICompositeType; @@ -31,6 +32,7 @@ public interface FhirTypeConverter { static final String EMPTY_LIST_EXT_URL = "http://hl7.org/fhir/StructureDefinition/cqf-isEmptyList"; static final String DATA_ABSENT_REASON_EXT_URL = "http://hl7.org/fhir/StructureDefinition/data-absent-reason"; static final String DATA_ABSENT_REASON_UNKNOWN_CODE = "unknown"; + static final String CQL_TYPE_EXT_URL = "http://hl7.org/fhir/StructureDefinition/cqf-cqlType"; // CQL-to-FHIR conversions @@ -57,9 +59,9 @@ public interface FhirTypeConverter { * nulls, and sublist hierarchy * * @param values an Iterable containing CQL structures, nulls, or sublists - * @return an Iterable containing FHIR types, nulls, and sublists + * @return an List containing FHIR types, nulls, and sublists */ - public Iterable toFhirTypes(Iterable values); + public List toFhirTypes(Iterable values); /** * Converts a String to a FHIR Id diff --git a/Src/java/engine-fhir/src/main/java/org/opencds/cqf/cql/engine/fhir/converter/R4FhirTypeConverter.java b/Src/java/engine-fhir/src/main/java/org/opencds/cqf/cql/engine/fhir/converter/R4FhirTypeConverter.java index afcc37aa4..607c7cf7b 100644 --- a/Src/java/engine-fhir/src/main/java/org/opencds/cqf/cql/engine/fhir/converter/R4FhirTypeConverter.java +++ b/Src/java/engine-fhir/src/main/java/org/opencds/cqf/cql/engine/fhir/converter/R4FhirTypeConverter.java @@ -2,7 +2,6 @@ import java.math.BigDecimal; import java.time.format.DateTimeFormatter; -import java.util.Collection; import java.util.stream.Collectors; import org.apache.commons.lang3.NotImplementedException; import org.hl7.fhir.instance.model.api.IBase; @@ -213,12 +212,38 @@ public ICompositeType toFhirRange(Interval value) { return range; } + private static BooleanType emptyBooleanWithExtension(String url, Type value) { + var result = new BooleanType((String) null); + result.addExtension().setUrl(url).setValue(value); + return result; + } + + private static void addPartWithNameAndValue( + Parameters.ParametersParameterComponent param, String key, Object value) { + var part = param.addPart().setName(key); + if (value instanceof Resource) { + part.setResource((Resource) value); + } else if (value instanceof Type) { + part.setValue((Type) value); + } else { + throw new IllegalArgumentException( + "Unsupported FHIR type: " + value.getClass().getName()); + } + } + + private static Iterable asIterable(Object value) { + if (value instanceof Iterable) { + return (Iterable) value; + } else { + return null; + } + } + @Override public IBase toFhirTuple(Tuple value) { if (value == null) { return null; } - var parameters = new Parameters(); if (value.getElements().isEmpty()) { return parameters; @@ -226,23 +251,30 @@ public IBase toFhirTuple(Tuple value) { var param = parameters.addParameter(); for (String key : value.getElements().keySet()) { - var part = param.addPart(); - part.setName(key); var element = value.getElements().get(key); if (element == null) { - part.addExtension() - .setUrl(DATA_ABSENT_REASON_EXT_URL) - .setValue(new CodeType(DATA_ABSENT_REASON_UNKNOWN_CODE)); - } else if (element instanceof Collection && ((Collection) element).isEmpty()) { - part.addExtension().setUrl(EMPTY_LIST_EXT_URL).setValue(new BooleanType(true)); + // Null value, add a single empty value with an extension indicating the reason + var dataAbsentValue = emptyBooleanWithExtension( + DATA_ABSENT_REASON_EXT_URL, new CodeType(DATA_ABSENT_REASON_UNKNOWN_CODE)); + addPartWithNameAndValue(param, key, dataAbsentValue); + continue; + } + + var iterable = asIterable(element); + if (iterable == null) { + // Single value + addPartWithNameAndValue(param, key, toFhirType(element)); } else { - var result = toFhirType(element); - if (result instanceof Resource) { - part.setResource((Resource) result); - } else if (result instanceof Type) { - part.setValue((Type) result); + if (!iterable.iterator().hasNext()) { + // Empty list + var emptyListValue = emptyBooleanWithExtension(EMPTY_LIST_EXT_URL, new BooleanType(true)); + addPartWithNameAndValue(param, key, emptyListValue); } else { - throw new IllegalArgumentException("Tuple contains unsupported type"); + // Non-empty list, one part per value + var fhirTypes = this.toFhirTypes(iterable); + for (var fhirType : fhirTypes) { + addPartWithNameAndValue(param, key, fhirType); + } } } } diff --git a/Src/java/engine-fhir/src/main/java/org/opencds/cqf/cql/engine/fhir/converter/R5FhirTypeConverter.java b/Src/java/engine-fhir/src/main/java/org/opencds/cqf/cql/engine/fhir/converter/R5FhirTypeConverter.java index dc1366653..148935b0a 100644 --- a/Src/java/engine-fhir/src/main/java/org/opencds/cqf/cql/engine/fhir/converter/R5FhirTypeConverter.java +++ b/Src/java/engine-fhir/src/main/java/org/opencds/cqf/cql/engine/fhir/converter/R5FhirTypeConverter.java @@ -2,7 +2,6 @@ import java.math.BigDecimal; import java.time.format.DateTimeFormatter; -import java.util.Collection; import java.util.stream.Collectors; import org.apache.commons.lang3.NotImplementedException; import org.hl7.fhir.instance.model.api.IBase; @@ -213,12 +212,38 @@ public ICompositeType toFhirRange(Interval value) { return range; } + private static BooleanType emptyBooleanWithExtension(String url, DataType value) { + var result = new BooleanType((String) null); + result.addExtension().setUrl(url).setValue(value); + return result; + } + + private static void addPartWithNameAndValue( + Parameters.ParametersParameterComponent param, String key, Object value) { + var part = param.addPart().setName(key); + if (value instanceof Resource) { + part.setResource((Resource) value); + } else if (value instanceof DataType) { + part.setValue((DataType) value); + } else { + throw new IllegalArgumentException( + "Unsupported FHIR type: " + value.getClass().getName()); + } + } + + private static Iterable asIterable(Object value) { + if (value instanceof Iterable) { + return (Iterable) value; + } else { + return null; + } + } + @Override public IBase toFhirTuple(Tuple value) { if (value == null) { return null; } - var parameters = new Parameters(); if (value.getElements().isEmpty()) { return parameters; @@ -226,23 +251,30 @@ public IBase toFhirTuple(Tuple value) { var param = parameters.addParameter(); for (String key : value.getElements().keySet()) { - var part = param.addPart(); - part.setName(key); var element = value.getElements().get(key); if (element == null) { - part.addExtension() - .setUrl(DATA_ABSENT_REASON_EXT_URL) - .setValue(new CodeType(DATA_ABSENT_REASON_UNKNOWN_CODE)); - } else if (element instanceof Collection && ((Collection) element).isEmpty()) { - part.addExtension().setUrl(EMPTY_LIST_EXT_URL).setValue(new BooleanType(true)); + // Null value, add a single empty value with an extension indicating the reason + var dataAbsentValue = emptyBooleanWithExtension( + DATA_ABSENT_REASON_EXT_URL, new CodeType(DATA_ABSENT_REASON_UNKNOWN_CODE)); + addPartWithNameAndValue(param, key, dataAbsentValue); + continue; + } + + var iterable = asIterable(element); + if (iterable == null) { + // Single value + addPartWithNameAndValue(param, key, toFhirType(element)); } else { - var result = toFhirType(element); - if (result instanceof Resource) { - part.setResource((Resource) result); - } else if (result instanceof DataType) { - part.setValue((DataType) result); + if (!iterable.iterator().hasNext()) { + // Empty list + var emptyListValue = emptyBooleanWithExtension(EMPTY_LIST_EXT_URL, new BooleanType(true)); + addPartWithNameAndValue(param, key, emptyListValue); } else { - throw new IllegalArgumentException("Tuple contains unsupported type"); + // Non-empty list, one part per value + var fhirTypes = this.toFhirTypes(iterable); + for (var fhirType : fhirTypes) { + addPartWithNameAndValue(param, key, fhirType); + } } } } diff --git a/Src/java/engine-fhir/src/test/java/org/opencds/cqf/cql/engine/fhir/converter/Dstu2TypeConverterTests.java b/Src/java/engine-fhir/src/test/java/org/opencds/cqf/cql/engine/fhir/converter/Dstu2TypeConverterTests.java index c54585616..d9e90e393 100644 --- a/Src/java/engine-fhir/src/test/java/org/opencds/cqf/cql/engine/fhir/converter/Dstu2TypeConverterTests.java +++ b/Src/java/engine-fhir/src/test/java/org/opencds/cqf/cql/engine/fhir/converter/Dstu2TypeConverterTests.java @@ -19,6 +19,7 @@ import java.util.Iterator; import java.util.List; import java.util.TimeZone; +import java.util.stream.Collectors; import org.apache.commons.lang3.NotImplementedException; import org.hl7.fhir.dstu2.model.Attachment; import org.hl7.fhir.dstu2.model.Base; @@ -526,11 +527,8 @@ void invalidIntervalToFhirInterval() { }); } - private static ParametersParameterComponent getPartByName(ParametersParameterComponent ppc, String name) { - return ppc.getPart().stream() - .filter(p -> p.getName().equals(name)) - .findFirst() - .get(); + private static List getPartsByName(ParametersParameterComponent ppc, String name) { + return ppc.getPart().stream().filter(p -> p.getName().equals(name)).collect(Collectors.toList()); } @Test @@ -543,6 +541,12 @@ void tupleToFhirTuple() { assertNotNull(actual); assertTrue(actual.isEmpty()); + var ints = new ArrayList(); + for (int i = 0; i < 5; i++) { + ints.add(i); + } + + tuple.getElements().put("V", ints); tuple.getElements().put("W", null); tuple.getElements().put("X", 5); tuple.getElements().put("Y", new Encounter().setId("123")); @@ -553,22 +557,27 @@ void tupleToFhirTuple() { assertEquals(1, actual.getParameter().size()); var first = actual.getParameter().get(0); - assertEquals(4, first.getPart().size()); + assertEquals(9, first.getPart().size()); + + var v = getPartsByName(first, "V"); + assertEquals(5, v.size()); + assertEquals(0, ((IntegerType) v.get(0).getValue()).getValue()); - var w = getPartByName(first, "W"); + var w = getPartsByName(first, "W").get(0); assertEquals( FhirTypeConverter.DATA_ABSENT_REASON_EXT_URL, - w.getExtension().get(0).getUrl()); + w.getValue().getExtension().get(0).getUrl()); - var x = getPartByName(first, "X"); + var x = getPartsByName(first, "X").get(0); assertEquals(5, ((IntegerType) x.getValue()).getValue()); - var y = getPartByName(first, "Y"); + var y = getPartsByName(first, "Y").get(0); assertEquals("123", y.getResource().getId()); - var z = getPartByName(first, "Z"); + var z = getPartsByName(first, "Z").get(0); assertEquals( - FhirTypeConverter.EMPTY_LIST_EXT_URL, z.getExtension().get(0).getUrl()); + FhirTypeConverter.EMPTY_LIST_EXT_URL, + z.getValue().getExtension().get(0).getUrl()); } // FHIR-to-CQL diff --git a/Src/java/engine-fhir/src/test/java/org/opencds/cqf/cql/engine/fhir/converter/Dstu3TypeConverterTests.java b/Src/java/engine-fhir/src/test/java/org/opencds/cqf/cql/engine/fhir/converter/Dstu3TypeConverterTests.java index 31be3373e..a54fd5d59 100644 --- a/Src/java/engine-fhir/src/test/java/org/opencds/cqf/cql/engine/fhir/converter/Dstu3TypeConverterTests.java +++ b/Src/java/engine-fhir/src/test/java/org/opencds/cqf/cql/engine/fhir/converter/Dstu3TypeConverterTests.java @@ -19,6 +19,7 @@ import java.util.Iterator; import java.util.List; import java.util.TimeZone; +import java.util.stream.Collectors; import org.apache.commons.lang3.NotImplementedException; import org.hl7.fhir.dstu3.model.Attachment; import org.hl7.fhir.dstu3.model.Base; @@ -530,11 +531,8 @@ void invalidIntervalToFhirInterval() { }); } - private static ParametersParameterComponent getPartByName(ParametersParameterComponent ppc, String name) { - return ppc.getPart().stream() - .filter(p -> p.getName().equals(name)) - .findFirst() - .get(); + private static List getPartsByName(ParametersParameterComponent ppc, String name) { + return ppc.getPart().stream().filter(p -> p.getName().equals(name)).collect(Collectors.toList()); } @Test @@ -547,6 +545,12 @@ void tupleToFhirTuple() { assertNotNull(actual); assertTrue(actual.isEmpty()); + var ints = new ArrayList(); + for (int i = 0; i < 5; i++) { + ints.add(i); + } + + tuple.getElements().put("V", ints); tuple.getElements().put("W", null); tuple.getElements().put("X", 5); tuple.getElements().put("Y", new Encounter().setId("123")); @@ -557,22 +561,27 @@ void tupleToFhirTuple() { assertEquals(1, actual.getParameter().size()); var first = actual.getParameterFirstRep(); - assertEquals(4, first.getPart().size()); + assertEquals(9, first.getPart().size()); + + var v = getPartsByName(first, "V"); + assertEquals(5, v.size()); + assertEquals(0, ((IntegerType) v.get(0).getValue()).getValue()); - var w = getPartByName(first, "W"); + var w = getPartsByName(first, "W").get(0); assertEquals( FhirTypeConverter.DATA_ABSENT_REASON_EXT_URL, - w.getExtension().get(0).getUrl()); + w.getValue().getExtension().get(0).getUrl()); - var x = getPartByName(first, "X"); + var x = getPartsByName(first, "X").get(0); assertEquals(5, ((IntegerType) x.getValue()).getValue()); - var y = getPartByName(first, "Y"); + var y = getPartsByName(first, "Y").get(0); assertEquals("123", y.getResource().getId()); - var z = getPartByName(first, "Z"); + var z = getPartsByName(first, "Z").get(0); assertEquals( - FhirTypeConverter.EMPTY_LIST_EXT_URL, z.getExtension().get(0).getUrl()); + FhirTypeConverter.EMPTY_LIST_EXT_URL, + z.getValue().getExtension().get(0).getUrl()); } // FHIR-to-CQL diff --git a/Src/java/engine-fhir/src/test/java/org/opencds/cqf/cql/engine/fhir/converter/R4TypeConverterTests.java b/Src/java/engine-fhir/src/test/java/org/opencds/cqf/cql/engine/fhir/converter/R4TypeConverterTests.java index 697bc5324..1ec50cd77 100644 --- a/Src/java/engine-fhir/src/test/java/org/opencds/cqf/cql/engine/fhir/converter/R4TypeConverterTests.java +++ b/Src/java/engine-fhir/src/test/java/org/opencds/cqf/cql/engine/fhir/converter/R4TypeConverterTests.java @@ -19,6 +19,7 @@ import java.util.Iterator; import java.util.List; import java.util.TimeZone; +import java.util.stream.Collectors; import org.apache.commons.lang3.NotImplementedException; import org.hl7.fhir.instance.model.api.IBase; import org.hl7.fhir.instance.model.api.ICompositeType; @@ -530,11 +531,8 @@ void invalidIntervalToFhirInterval() { }); } - private static ParametersParameterComponent getPartByName(ParametersParameterComponent ppc, String name) { - return ppc.getPart().stream() - .filter(p -> p.getName().equals(name)) - .findFirst() - .get(); + private static List getPartsByName(ParametersParameterComponent ppc, String name) { + return ppc.getPart().stream().filter(p -> p.getName().equals(name)).collect(Collectors.toList()); } @Test @@ -547,6 +545,12 @@ void tupleToFhirTuple() { assertNotNull(actual); assertTrue(actual.isEmpty()); + var ints = new ArrayList(); + for (int i = 0; i < 5; i++) { + ints.add(i); + } + + tuple.getElements().put("V", ints); tuple.getElements().put("W", null); tuple.getElements().put("X", 5); tuple.getElements().put("Y", new Encounter().setId("123")); @@ -557,22 +561,27 @@ void tupleToFhirTuple() { assertEquals(1, actual.getParameter().size()); var first = actual.getParameterFirstRep(); - assertEquals(4, first.getPart().size()); + assertEquals(9, first.getPart().size()); + + var v = getPartsByName(first, "V"); + assertEquals(5, v.size()); + assertEquals(0, ((IntegerType) v.get(0).getValue()).getValue()); - var w = getPartByName(first, "W"); + var w = getPartsByName(first, "W").get(0); assertEquals( FhirTypeConverter.DATA_ABSENT_REASON_EXT_URL, - w.getExtension().get(0).getUrl()); + w.getValue().getExtension().get(0).getUrl()); - var x = getPartByName(first, "X"); + var x = getPartsByName(first, "X").get(0); assertEquals(5, ((IntegerType) x.getValue()).getValue()); - var y = getPartByName(first, "Y"); + var y = getPartsByName(first, "Y").get(0); assertEquals("123", y.getResource().getId()); - var z = getPartByName(first, "Z"); + var z = getPartsByName(first, "Z").get(0); assertEquals( - FhirTypeConverter.EMPTY_LIST_EXT_URL, z.getExtension().get(0).getUrl()); + FhirTypeConverter.EMPTY_LIST_EXT_URL, + z.getValue().getExtension().get(0).getUrl()); } // FHIR-to-CQL diff --git a/Src/java/engine-fhir/src/test/java/org/opencds/cqf/cql/engine/fhir/converter/R5TypeConverterTests.java b/Src/java/engine-fhir/src/test/java/org/opencds/cqf/cql/engine/fhir/converter/R5TypeConverterTests.java index 8c1d291de..673cdd438 100644 --- a/Src/java/engine-fhir/src/test/java/org/opencds/cqf/cql/engine/fhir/converter/R5TypeConverterTests.java +++ b/Src/java/engine-fhir/src/test/java/org/opencds/cqf/cql/engine/fhir/converter/R5TypeConverterTests.java @@ -19,6 +19,7 @@ import java.util.Iterator; import java.util.List; import java.util.TimeZone; +import java.util.stream.Collectors; import org.apache.commons.lang3.NotImplementedException; import org.hl7.fhir.instance.model.api.IBase; import org.hl7.fhir.instance.model.api.ICompositeType; @@ -530,11 +531,8 @@ void invalidIntervalToFhirInterval() { }); } - private static ParametersParameterComponent getPartByName(ParametersParameterComponent ppc, String name) { - return ppc.getPart().stream() - .filter(p -> p.getName().equals(name)) - .findFirst() - .get(); + private static List getPartsByName(ParametersParameterComponent ppc, String name) { + return ppc.getPart().stream().filter(p -> p.getName().equals(name)).collect(Collectors.toList()); } @Test @@ -547,6 +545,12 @@ void tupleToFhirTuple() { assertNotNull(actual); assertTrue(actual.isEmpty()); + var ints = new ArrayList(); + for (int i = 0; i < 5; i++) { + ints.add(i); + } + + tuple.getElements().put("V", ints); tuple.getElements().put("W", null); tuple.getElements().put("X", 5); tuple.getElements().put("Y", new Encounter().setId("123")); @@ -557,22 +561,27 @@ void tupleToFhirTuple() { assertEquals(1, actual.getParameter().size()); var first = actual.getParameterFirstRep(); - assertEquals(4, first.getPart().size()); + assertEquals(9, first.getPart().size()); + + var v = getPartsByName(first, "V"); + assertEquals(5, v.size()); + assertEquals(0, ((IntegerType) v.get(0).getValue()).getValue()); - var w = getPartByName(first, "W"); + var w = getPartsByName(first, "W").get(0); assertEquals( FhirTypeConverter.DATA_ABSENT_REASON_EXT_URL, - w.getExtension().get(0).getUrl()); + w.getValue().getExtension().get(0).getUrl()); - var x = getPartByName(first, "X"); + var x = getPartsByName(first, "X").get(0); assertEquals(5, ((IntegerType) x.getValue()).getValue()); - var y = getPartByName(first, "Y"); + var y = getPartsByName(first, "Y").get(0); assertEquals("123", y.getResource().getId()); - var z = getPartByName(first, "Z"); + var z = getPartsByName(first, "Z").get(0); assertEquals( - FhirTypeConverter.EMPTY_LIST_EXT_URL, z.getExtension().get(0).getUrl()); + FhirTypeConverter.EMPTY_LIST_EXT_URL, + z.getValue().getExtension().get(0).getUrl()); } // FHIR-to-CQL From 6262d0da8f8827f1f5332079b2ff1b166a71dda5 Mon Sep 17 00:00:00 2001 From: Jonathan Percival Date: Thu, 10 Oct 2024 10:17:59 -0600 Subject: [PATCH 07/10] Address SonarCloud warnings --- .../fhir/converter/BaseFhirTypeConverter.java | 2 +- .../converter/Dstu2FhirTypeConverter.java | 56 ++++++++++-------- .../converter/Dstu3FhirTypeConverter.java | 56 ++++++++++-------- .../fhir/converter/R4FhirTypeConverter.java | 59 ++++++++++--------- .../fhir/converter/R5FhirTypeConverter.java | 56 ++++++++++-------- 5 files changed, 123 insertions(+), 106 deletions(-) diff --git a/Src/java/engine-fhir/src/main/java/org/opencds/cqf/cql/engine/fhir/converter/BaseFhirTypeConverter.java b/Src/java/engine-fhir/src/main/java/org/opencds/cqf/cql/engine/fhir/converter/BaseFhirTypeConverter.java index 0aeb647e6..abc3a1828 100644 --- a/Src/java/engine-fhir/src/main/java/org/opencds/cqf/cql/engine/fhir/converter/BaseFhirTypeConverter.java +++ b/Src/java/engine-fhir/src/main/java/org/opencds/cqf/cql/engine/fhir/converter/BaseFhirTypeConverter.java @@ -50,7 +50,7 @@ public List toFhirTypes(Iterable values) { } else if (value instanceof Iterable) { converted.add(toFhirTypes((Iterable) value)); } else if (isFhirType(value)) { - converted.add((IBase) value); + converted.add(value); } else if (isCqlType(value)) { converted.add(toFhirType(value)); } else { diff --git a/Src/java/engine-fhir/src/main/java/org/opencds/cqf/cql/engine/fhir/converter/Dstu2FhirTypeConverter.java b/Src/java/engine-fhir/src/main/java/org/opencds/cqf/cql/engine/fhir/converter/Dstu2FhirTypeConverter.java index 23f6ef0c7..b9ea5136a 100644 --- a/Src/java/engine-fhir/src/main/java/org/opencds/cqf/cql/engine/fhir/converter/Dstu2FhirTypeConverter.java +++ b/Src/java/engine-fhir/src/main/java/org/opencds/cqf/cql/engine/fhir/converter/Dstu2FhirTypeConverter.java @@ -248,6 +248,35 @@ private static Iterable asIterable(Object value) { } } + private void addElementToParameter(Parameters.ParametersParameterComponent param, String key, Object value) { + if (value == null) { + // Null value, add a single empty value with an extension indicating the reason + var dataAbsentValue = emptyBooleanWithExtension( + DATA_ABSENT_REASON_EXT_URL, new CodeType(DATA_ABSENT_REASON_UNKNOWN_CODE)); + addPartWithNameAndValue(param, key, dataAbsentValue); + return; + } + + var iterable = asIterable(value); + if (iterable == null) { + // Single, non-null value + addPartWithNameAndValue(param, key, toFhirType(value)); + return; + } + + if (!iterable.iterator().hasNext()) { + // Empty list + var emptyListValue = emptyBooleanWithExtension(EMPTY_LIST_EXT_URL, new BooleanType(true)); + addPartWithNameAndValue(param, key, emptyListValue); + } else { + // Non-empty list, one part per value + var fhirTypes = this.toFhirTypes(iterable); + for (var fhirType : fhirTypes) { + addPartWithNameAndValue(param, key, fhirType); + } + } + } + @Override public IBase toFhirTuple(Tuple value) { if (value == null) { @@ -260,32 +289,7 @@ public IBase toFhirTuple(Tuple value) { var param = parameters.addParameter(); for (String key : value.getElements().keySet()) { - var element = value.getElements().get(key); - if (element == null) { - // Null value, add a single empty value with an extension indicating the reason - var dataAbsentValue = emptyBooleanWithExtension( - DATA_ABSENT_REASON_EXT_URL, new CodeType(DATA_ABSENT_REASON_UNKNOWN_CODE)); - addPartWithNameAndValue(param, key, dataAbsentValue); - continue; - } - - var iterable = asIterable(element); - if (iterable == null) { - // Single value - addPartWithNameAndValue(param, key, toFhirType(element)); - } else { - if (!iterable.iterator().hasNext()) { - // Empty list - var emptyListValue = emptyBooleanWithExtension(EMPTY_LIST_EXT_URL, new BooleanType(true)); - addPartWithNameAndValue(param, key, emptyListValue); - } else { - // Non-empty list, one part per value - var fhirTypes = this.toFhirTypes(iterable); - for (var fhirType : fhirTypes) { - addPartWithNameAndValue(param, key, fhirType); - } - } - } + addElementToParameter(param, key, value.getElements().get(key)); } return parameters; diff --git a/Src/java/engine-fhir/src/main/java/org/opencds/cqf/cql/engine/fhir/converter/Dstu3FhirTypeConverter.java b/Src/java/engine-fhir/src/main/java/org/opencds/cqf/cql/engine/fhir/converter/Dstu3FhirTypeConverter.java index 90b14ecd7..23926e681 100644 --- a/Src/java/engine-fhir/src/main/java/org/opencds/cqf/cql/engine/fhir/converter/Dstu3FhirTypeConverter.java +++ b/Src/java/engine-fhir/src/main/java/org/opencds/cqf/cql/engine/fhir/converter/Dstu3FhirTypeConverter.java @@ -247,6 +247,35 @@ private static Iterable asIterable(Object value) { } } + private void addElementToParameter(Parameters.ParametersParameterComponent param, String key, Object value) { + if (value == null) { + // Null value, add a single empty value with an extension indicating the reason + var dataAbsentValue = emptyBooleanWithExtension( + DATA_ABSENT_REASON_EXT_URL, new CodeType(DATA_ABSENT_REASON_UNKNOWN_CODE)); + addPartWithNameAndValue(param, key, dataAbsentValue); + return; + } + + var iterable = asIterable(value); + if (iterable == null) { + // Single, non-null value + addPartWithNameAndValue(param, key, toFhirType(value)); + return; + } + + if (!iterable.iterator().hasNext()) { + // Empty list + var emptyListValue = emptyBooleanWithExtension(EMPTY_LIST_EXT_URL, new BooleanType(true)); + addPartWithNameAndValue(param, key, emptyListValue); + } else { + // Non-empty list, one part per value + var fhirTypes = this.toFhirTypes(iterable); + for (var fhirType : fhirTypes) { + addPartWithNameAndValue(param, key, fhirType); + } + } + } + @Override public IBase toFhirTuple(Tuple value) { if (value == null) { @@ -259,32 +288,7 @@ public IBase toFhirTuple(Tuple value) { var param = parameters.addParameter(); for (String key : value.getElements().keySet()) { - var element = value.getElements().get(key); - if (element == null) { - // Null value, add a single empty value with an extension indicating the reason - var dataAbsentValue = emptyBooleanWithExtension( - DATA_ABSENT_REASON_EXT_URL, new CodeType(DATA_ABSENT_REASON_UNKNOWN_CODE)); - addPartWithNameAndValue(param, key, dataAbsentValue); - continue; - } - - var iterable = asIterable(element); - if (iterable == null) { - // Single value - addPartWithNameAndValue(param, key, toFhirType(element)); - } else { - if (!iterable.iterator().hasNext()) { - // Empty list - var emptyListValue = emptyBooleanWithExtension(EMPTY_LIST_EXT_URL, new BooleanType(true)); - addPartWithNameAndValue(param, key, emptyListValue); - } else { - // Non-empty list, one part per value - var fhirTypes = this.toFhirTypes(iterable); - for (var fhirType : fhirTypes) { - addPartWithNameAndValue(param, key, fhirType); - } - } - } + addElementToParameter(param, key, value.getElements().get(key)); } return parameters; diff --git a/Src/java/engine-fhir/src/main/java/org/opencds/cqf/cql/engine/fhir/converter/R4FhirTypeConverter.java b/Src/java/engine-fhir/src/main/java/org/opencds/cqf/cql/engine/fhir/converter/R4FhirTypeConverter.java index 607c7cf7b..ab5090e4b 100644 --- a/Src/java/engine-fhir/src/main/java/org/opencds/cqf/cql/engine/fhir/converter/R4FhirTypeConverter.java +++ b/Src/java/engine-fhir/src/main/java/org/opencds/cqf/cql/engine/fhir/converter/R4FhirTypeConverter.java @@ -179,7 +179,8 @@ public ICompositeType toFhirPeriod(Interval value) { return period; } else if (getSimpleName(value.getPointType().getTypeName()).equals("Date")) { - // TODO: This will construct DateTimeType values in FHIR with the system timezone id, not the + // TODO: This will construct DateTimeType values in FHIR with the system + // timezone id, not the // timezoneoffset of the evaluation request..... this is a bug waiting to happen if (value.getStart() != null) { period.setStart(toFhirDate((Date) value.getStart()).getValue()); @@ -239,6 +240,35 @@ private static Iterable asIterable(Object value) { } } + private void addElementToParameter(Parameters.ParametersParameterComponent param, String key, Object value) { + if (value == null) { + // Null value, add a single empty value with an extension indicating the reason + var dataAbsentValue = emptyBooleanWithExtension( + DATA_ABSENT_REASON_EXT_URL, new CodeType(DATA_ABSENT_REASON_UNKNOWN_CODE)); + addPartWithNameAndValue(param, key, dataAbsentValue); + return; + } + + var iterable = asIterable(value); + if (iterable == null) { + // Single, non-null value + addPartWithNameAndValue(param, key, toFhirType(value)); + return; + } + + if (!iterable.iterator().hasNext()) { + // Empty list + var emptyListValue = emptyBooleanWithExtension(EMPTY_LIST_EXT_URL, new BooleanType(true)); + addPartWithNameAndValue(param, key, emptyListValue); + } else { + // Non-empty list, one part per value + var fhirTypes = this.toFhirTypes(iterable); + for (var fhirType : fhirTypes) { + addPartWithNameAndValue(param, key, fhirType); + } + } + } + @Override public IBase toFhirTuple(Tuple value) { if (value == null) { @@ -251,32 +281,7 @@ public IBase toFhirTuple(Tuple value) { var param = parameters.addParameter(); for (String key : value.getElements().keySet()) { - var element = value.getElements().get(key); - if (element == null) { - // Null value, add a single empty value with an extension indicating the reason - var dataAbsentValue = emptyBooleanWithExtension( - DATA_ABSENT_REASON_EXT_URL, new CodeType(DATA_ABSENT_REASON_UNKNOWN_CODE)); - addPartWithNameAndValue(param, key, dataAbsentValue); - continue; - } - - var iterable = asIterable(element); - if (iterable == null) { - // Single value - addPartWithNameAndValue(param, key, toFhirType(element)); - } else { - if (!iterable.iterator().hasNext()) { - // Empty list - var emptyListValue = emptyBooleanWithExtension(EMPTY_LIST_EXT_URL, new BooleanType(true)); - addPartWithNameAndValue(param, key, emptyListValue); - } else { - // Non-empty list, one part per value - var fhirTypes = this.toFhirTypes(iterable); - for (var fhirType : fhirTypes) { - addPartWithNameAndValue(param, key, fhirType); - } - } - } + addElementToParameter(param, key, value.getElements().get(key)); } return parameters; diff --git a/Src/java/engine-fhir/src/main/java/org/opencds/cqf/cql/engine/fhir/converter/R5FhirTypeConverter.java b/Src/java/engine-fhir/src/main/java/org/opencds/cqf/cql/engine/fhir/converter/R5FhirTypeConverter.java index 148935b0a..59dbe2c95 100644 --- a/Src/java/engine-fhir/src/main/java/org/opencds/cqf/cql/engine/fhir/converter/R5FhirTypeConverter.java +++ b/Src/java/engine-fhir/src/main/java/org/opencds/cqf/cql/engine/fhir/converter/R5FhirTypeConverter.java @@ -239,6 +239,35 @@ private static Iterable asIterable(Object value) { } } + private void addElementToParameter(Parameters.ParametersParameterComponent param, String key, Object value) { + if (value == null) { + // Null value, add a single empty value with an extension indicating the reason + var dataAbsentValue = emptyBooleanWithExtension( + DATA_ABSENT_REASON_EXT_URL, new CodeType(DATA_ABSENT_REASON_UNKNOWN_CODE)); + addPartWithNameAndValue(param, key, dataAbsentValue); + return; + } + + var iterable = asIterable(value); + if (iterable == null) { + // Single, non-null value + addPartWithNameAndValue(param, key, toFhirType(value)); + return; + } + + if (!iterable.iterator().hasNext()) { + // Empty list + var emptyListValue = emptyBooleanWithExtension(EMPTY_LIST_EXT_URL, new BooleanType(true)); + addPartWithNameAndValue(param, key, emptyListValue); + } else { + // Non-empty list, one part per value + var fhirTypes = this.toFhirTypes(iterable); + for (var fhirType : fhirTypes) { + addPartWithNameAndValue(param, key, fhirType); + } + } + } + @Override public IBase toFhirTuple(Tuple value) { if (value == null) { @@ -251,32 +280,7 @@ public IBase toFhirTuple(Tuple value) { var param = parameters.addParameter(); for (String key : value.getElements().keySet()) { - var element = value.getElements().get(key); - if (element == null) { - // Null value, add a single empty value with an extension indicating the reason - var dataAbsentValue = emptyBooleanWithExtension( - DATA_ABSENT_REASON_EXT_URL, new CodeType(DATA_ABSENT_REASON_UNKNOWN_CODE)); - addPartWithNameAndValue(param, key, dataAbsentValue); - continue; - } - - var iterable = asIterable(element); - if (iterable == null) { - // Single value - addPartWithNameAndValue(param, key, toFhirType(element)); - } else { - if (!iterable.iterator().hasNext()) { - // Empty list - var emptyListValue = emptyBooleanWithExtension(EMPTY_LIST_EXT_URL, new BooleanType(true)); - addPartWithNameAndValue(param, key, emptyListValue); - } else { - // Non-empty list, one part per value - var fhirTypes = this.toFhirTypes(iterable); - for (var fhirType : fhirTypes) { - addPartWithNameAndValue(param, key, fhirType); - } - } - } + addElementToParameter(param, key, value.getElements().get(key)); } return parameters; From 3a0703646f260e76187418a67b9ffa6fe1752933 Mon Sep 17 00:00:00 2001 From: Bryn Rhodes Date: Thu, 10 Oct 2024 15:29:16 -0600 Subject: [PATCH 08/10] Added nested tuple and empty tuple handling --- .../converter/Dstu2FhirTypeConverter.java | 28 ++++++++++++------- .../converter/Dstu3FhirTypeConverter.java | 28 ++++++++++++------- .../fhir/converter/FhirTypeConverter.java | 1 + .../fhir/converter/R4FhirTypeConverter.java | 28 ++++++++++++------- .../fhir/converter/R5FhirTypeConverter.java | 28 ++++++++++++------- 5 files changed, 73 insertions(+), 40 deletions(-) diff --git a/Src/java/engine-fhir/src/main/java/org/opencds/cqf/cql/engine/fhir/converter/Dstu2FhirTypeConverter.java b/Src/java/engine-fhir/src/main/java/org/opencds/cqf/cql/engine/fhir/converter/Dstu2FhirTypeConverter.java index b9ea5136a..753580553 100644 --- a/Src/java/engine-fhir/src/main/java/org/opencds/cqf/cql/engine/fhir/converter/Dstu2FhirTypeConverter.java +++ b/Src/java/engine-fhir/src/main/java/org/opencds/cqf/cql/engine/fhir/converter/Dstu2FhirTypeConverter.java @@ -229,14 +229,20 @@ private static BooleanType emptyBooleanWithExtension(String url, Type value) { private static void addPartWithNameAndValue( Parameters.ParametersParameterComponent param, String key, Object value) { - var part = param.addPart().setName(key); - if (value instanceof Resource) { - part.setResource((Resource) value); - } else if (value instanceof Type) { - part.setValue((Type) value); + if (value instanceof Parameters.ParametersParameterComponent) { + var part = (Parameters.ParametersParameterComponent)value; + part.setName(key); + param.addPart(part); } else { - throw new IllegalArgumentException( - "Unsupported FHIR type: " + value.getClass().getName()); + var part = param.addPart().setName(key); + if (value instanceof Resource) { + part.setResource((Resource) value); + } else if (value instanceof Type) { + part.setValue((Type) value); + } else { + throw new IllegalArgumentException( + "Unsupported FHIR type: " + value.getClass().getName()); + } } } @@ -282,17 +288,19 @@ public IBase toFhirTuple(Tuple value) { if (value == null) { return null; } + var parameters = new Parameters(); + var param = parameters.addParameter(); + if (value.getElements().isEmpty()) { - return parameters; + param.setValue(emptyBooleanWithExtension(EMPTY_TUPLE_EXT_URL, new BooleanType(true))); } - var param = parameters.addParameter(); for (String key : value.getElements().keySet()) { addElementToParameter(param, key, value.getElements().get(key)); } - return parameters; + return param; } @Override diff --git a/Src/java/engine-fhir/src/main/java/org/opencds/cqf/cql/engine/fhir/converter/Dstu3FhirTypeConverter.java b/Src/java/engine-fhir/src/main/java/org/opencds/cqf/cql/engine/fhir/converter/Dstu3FhirTypeConverter.java index 23926e681..1ccab474f 100644 --- a/Src/java/engine-fhir/src/main/java/org/opencds/cqf/cql/engine/fhir/converter/Dstu3FhirTypeConverter.java +++ b/Src/java/engine-fhir/src/main/java/org/opencds/cqf/cql/engine/fhir/converter/Dstu3FhirTypeConverter.java @@ -228,14 +228,20 @@ private static BooleanType emptyBooleanWithExtension(String url, Type value) { private static void addPartWithNameAndValue( Parameters.ParametersParameterComponent param, String key, Object value) { - var part = param.addPart().setName(key); - if (value instanceof Resource) { - part.setResource((Resource) value); - } else if (value instanceof Type) { - part.setValue((Type) value); + if (value instanceof Parameters.ParametersParameterComponent) { + var part = (Parameters.ParametersParameterComponent)value; + part.setName(key); + param.addPart(part); } else { - throw new IllegalArgumentException( - "Unsupported FHIR type: " + value.getClass().getName()); + var part = param.addPart().setName(key); + if (value instanceof Resource) { + part.setResource((Resource) value); + } else if (value instanceof Type) { + part.setValue((Type) value); + } else { + throw new IllegalArgumentException( + "Unsupported FHIR type: " + value.getClass().getName()); + } } } @@ -281,17 +287,19 @@ public IBase toFhirTuple(Tuple value) { if (value == null) { return null; } + var parameters = new Parameters(); + var param = parameters.addParameter(); + if (value.getElements().isEmpty()) { - return parameters; + param.setValue(emptyBooleanWithExtension(EMPTY_TUPLE_EXT_URL, new BooleanType(true))); } - var param = parameters.addParameter(); for (String key : value.getElements().keySet()) { addElementToParameter(param, key, value.getElements().get(key)); } - return parameters; + return param; } @Override diff --git a/Src/java/engine-fhir/src/main/java/org/opencds/cqf/cql/engine/fhir/converter/FhirTypeConverter.java b/Src/java/engine-fhir/src/main/java/org/opencds/cqf/cql/engine/fhir/converter/FhirTypeConverter.java index 7d99e176a..c81c3e48f 100644 --- a/Src/java/engine-fhir/src/main/java/org/opencds/cqf/cql/engine/fhir/converter/FhirTypeConverter.java +++ b/Src/java/engine-fhir/src/main/java/org/opencds/cqf/cql/engine/fhir/converter/FhirTypeConverter.java @@ -30,6 +30,7 @@ public interface FhirTypeConverter { static final String EMPTY_LIST_EXT_URL = "http://hl7.org/fhir/StructureDefinition/cqf-isEmptyList"; + static final String EMPTY_TUPLE_EXT_URL = "http://hl7.org/fhir/StructureDefinition/cqf-isEmptyTuple"; static final String DATA_ABSENT_REASON_EXT_URL = "http://hl7.org/fhir/StructureDefinition/data-absent-reason"; static final String DATA_ABSENT_REASON_UNKNOWN_CODE = "unknown"; static final String CQL_TYPE_EXT_URL = "http://hl7.org/fhir/StructureDefinition/cqf-cqlType"; diff --git a/Src/java/engine-fhir/src/main/java/org/opencds/cqf/cql/engine/fhir/converter/R4FhirTypeConverter.java b/Src/java/engine-fhir/src/main/java/org/opencds/cqf/cql/engine/fhir/converter/R4FhirTypeConverter.java index ab5090e4b..c1b199a7d 100644 --- a/Src/java/engine-fhir/src/main/java/org/opencds/cqf/cql/engine/fhir/converter/R4FhirTypeConverter.java +++ b/Src/java/engine-fhir/src/main/java/org/opencds/cqf/cql/engine/fhir/converter/R4FhirTypeConverter.java @@ -221,14 +221,20 @@ private static BooleanType emptyBooleanWithExtension(String url, Type value) { private static void addPartWithNameAndValue( Parameters.ParametersParameterComponent param, String key, Object value) { - var part = param.addPart().setName(key); - if (value instanceof Resource) { - part.setResource((Resource) value); - } else if (value instanceof Type) { - part.setValue((Type) value); + if (value instanceof Parameters.ParametersParameterComponent) { + var part = (Parameters.ParametersParameterComponent)value; + part.setName(key); + param.addPart(part); } else { - throw new IllegalArgumentException( - "Unsupported FHIR type: " + value.getClass().getName()); + var part = param.addPart().setName(key); + if (value instanceof Resource) { + part.setResource((Resource) value); + } else if (value instanceof Type) { + part.setValue((Type) value); + } else { + throw new IllegalArgumentException( + "Unsupported FHIR type: " + value.getClass().getName()); + } } } @@ -274,17 +280,19 @@ public IBase toFhirTuple(Tuple value) { if (value == null) { return null; } + var parameters = new Parameters(); + var param = parameters.addParameter(); + if (value.getElements().isEmpty()) { - return parameters; + param.setValue(emptyBooleanWithExtension(EMPTY_TUPLE_EXT_URL, new BooleanType(true))); } - var param = parameters.addParameter(); for (String key : value.getElements().keySet()) { addElementToParameter(param, key, value.getElements().get(key)); } - return parameters; + return param; } @Override diff --git a/Src/java/engine-fhir/src/main/java/org/opencds/cqf/cql/engine/fhir/converter/R5FhirTypeConverter.java b/Src/java/engine-fhir/src/main/java/org/opencds/cqf/cql/engine/fhir/converter/R5FhirTypeConverter.java index 59dbe2c95..f93bb38c5 100644 --- a/Src/java/engine-fhir/src/main/java/org/opencds/cqf/cql/engine/fhir/converter/R5FhirTypeConverter.java +++ b/Src/java/engine-fhir/src/main/java/org/opencds/cqf/cql/engine/fhir/converter/R5FhirTypeConverter.java @@ -220,14 +220,20 @@ private static BooleanType emptyBooleanWithExtension(String url, DataType value) private static void addPartWithNameAndValue( Parameters.ParametersParameterComponent param, String key, Object value) { - var part = param.addPart().setName(key); - if (value instanceof Resource) { - part.setResource((Resource) value); - } else if (value instanceof DataType) { - part.setValue((DataType) value); + if (value instanceof Parameters.ParametersParameterComponent) { + var part = (Parameters.ParametersParameterComponent)value; + part.setName(key); + param.addPart(part); } else { - throw new IllegalArgumentException( - "Unsupported FHIR type: " + value.getClass().getName()); + var part = param.addPart().setName(key); + if (value instanceof Resource) { + part.setResource((Resource) value); + } else if (value instanceof DataType) { + part.setValue((DataType) value); + } else { + throw new IllegalArgumentException( + "Unsupported FHIR type: " + value.getClass().getName()); + } } } @@ -273,17 +279,19 @@ public IBase toFhirTuple(Tuple value) { if (value == null) { return null; } + var parameters = new Parameters(); + var param = parameters.addParameter(); + if (value.getElements().isEmpty()) { - return parameters; + param.setValue(emptyBooleanWithExtension(EMPTY_TUPLE_EXT_URL, new BooleanType(true))); } - var param = parameters.addParameter(); for (String key : value.getElements().keySet()) { addElementToParameter(param, key, value.getElements().get(key)); } - return parameters; + return param; } @Override From e5e6fd6d9d740a1ad890cafbbb3a9df865968aa1 Mon Sep 17 00:00:00 2001 From: Bryn Rhodes Date: Thu, 10 Oct 2024 15:32:42 -0600 Subject: [PATCH 09/10] Nested and empty tuple tests --- .../converter/Dstu2TypeConverterTests.java | 65 ++++++++++++++++--- .../converter/Dstu3TypeConverterTests.java | 61 ++++++++++++++--- .../fhir/converter/R4TypeConverterTests.java | 61 ++++++++++++++--- .../fhir/converter/R5TypeConverterTests.java | 61 ++++++++++++++--- 4 files changed, 214 insertions(+), 34 deletions(-) diff --git a/Src/java/engine-fhir/src/test/java/org/opencds/cqf/cql/engine/fhir/converter/Dstu2TypeConverterTests.java b/Src/java/engine-fhir/src/test/java/org/opencds/cqf/cql/engine/fhir/converter/Dstu2TypeConverterTests.java index d9e90e393..e35315c88 100644 --- a/Src/java/engine-fhir/src/test/java/org/opencds/cqf/cql/engine/fhir/converter/Dstu2TypeConverterTests.java +++ b/Src/java/engine-fhir/src/test/java/org/opencds/cqf/cql/engine/fhir/converter/Dstu2TypeConverterTests.java @@ -2,7 +2,6 @@ import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.instanceOf; -import static org.junit.Assert.assertNotNull; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNull; @@ -45,6 +44,7 @@ import org.hl7.fhir.instance.model.api.ICompositeType; import org.hl7.fhir.instance.model.api.IIdType; import org.hl7.fhir.instance.model.api.IPrimitiveType; +import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; @@ -533,13 +533,16 @@ private static List getPartsByName(ParametersParam @Test void tupleToFhirTuple() { - Parameters actual = (Parameters) typeConverter.toFhirTuple(null); + Parameters.ParametersParameterComponent actual = + (Parameters.ParametersParameterComponent) typeConverter.toFhirTuple(null); assertNull(actual); var tuple = new Tuple(); - actual = (Parameters) typeConverter.toFhirTuple(tuple); - assertNotNull(actual); - assertTrue(actual.isEmpty()); + actual = (Parameters.ParametersParameterComponent) typeConverter.toFhirTuple(tuple); + Assertions.assertNotNull(actual); + assertEquals( + FhirTypeConverter.EMPTY_TUPLE_EXT_URL, + actual.getValue().getExtension().get(0).getUrl()); var ints = new ArrayList(); for (int i = 0; i < 5; i++) { @@ -552,11 +555,8 @@ void tupleToFhirTuple() { tuple.getElements().put("Y", new Encounter().setId("123")); tuple.getElements().put("Z", new ArrayList<>()); - actual = (Parameters) typeConverter.toFhirTuple(tuple); - assertNotNull(actual); - assertEquals(1, actual.getParameter().size()); - - var first = actual.getParameter().get(0); + actual = (Parameters.ParametersParameterComponent) typeConverter.toFhirTuple(tuple); + var first = actual; assertEquals(9, first.getPart().size()); var v = getPartsByName(first, "V"); @@ -580,6 +580,51 @@ void tupleToFhirTuple() { z.getValue().getExtension().get(0).getUrl()); } + @Test + void complexTupleToFhirTuple() { + var innerTuple = new Tuple(); + innerTuple.getElements().put("X", 1); + innerTuple.getElements().put("Y", 2); + innerTuple.getElements().put("Z", null); + var outerTuple = new Tuple(); + outerTuple.getElements().put("A", innerTuple); + var tupleList = new ArrayList(); + for (int i = 0; i < 3; i++) { + var elementTuple = new Tuple(); + elementTuple.getElements().put("P", i); + elementTuple.getElements().put("Q", i + 1); + tupleList.add(elementTuple); + } + outerTuple.getElements().put("B", tupleList); + + Parameters.ParametersParameterComponent actual = + (Parameters.ParametersParameterComponent) typeConverter.toFhirTuple(outerTuple); + var first = actual; + assertEquals(4, first.getPart().size()); + + var a = getPartsByName(first, "A"); + assertEquals(1, a.size()); + assertEquals(3, a.get(0).getPart().size()); + var x = a.get(0).getPart().get(0); + assertEquals(1, ((IntegerType) x.getValue()).getValue()); + var y = a.get(0).getPart().get(1); + assertEquals(2, ((IntegerType) y.getValue()).getValue()); + var z = a.get(0).getPart().get(2); + assertEquals( + FhirTypeConverter.DATA_ABSENT_REASON_EXT_URL, + z.getValue().getExtension().get(0).getUrl()); + + var b = getPartsByName(first, "B"); + assertEquals(3, b.size()); + var b1 = b.get(0); + var p = getPartsByName(b1, "P"); + assertEquals(1, p.size()); + assertEquals(0, ((IntegerType) p.get(0).getValue()).getValue()); + var q = getPartsByName(b1, "Q"); + assertEquals(1, q.size()); + assertEquals(1, ((IntegerType) q.get(0).getValue()).getValue()); + } + // FHIR-to-CQL @Test void isCqlType() { diff --git a/Src/java/engine-fhir/src/test/java/org/opencds/cqf/cql/engine/fhir/converter/Dstu3TypeConverterTests.java b/Src/java/engine-fhir/src/test/java/org/opencds/cqf/cql/engine/fhir/converter/Dstu3TypeConverterTests.java index a54fd5d59..38a75bce3 100644 --- a/Src/java/engine-fhir/src/test/java/org/opencds/cqf/cql/engine/fhir/converter/Dstu3TypeConverterTests.java +++ b/Src/java/engine-fhir/src/test/java/org/opencds/cqf/cql/engine/fhir/converter/Dstu3TypeConverterTests.java @@ -537,13 +537,16 @@ private static List getPartsByName(ParametersParam @Test void tupleToFhirTuple() { - Parameters actual = (Parameters) typeConverter.toFhirTuple(null); + Parameters.ParametersParameterComponent actual = + (Parameters.ParametersParameterComponent) typeConverter.toFhirTuple(null); assertNull(actual); var tuple = new Tuple(); - actual = (Parameters) typeConverter.toFhirTuple(tuple); + actual = (Parameters.ParametersParameterComponent) typeConverter.toFhirTuple(tuple); assertNotNull(actual); - assertTrue(actual.isEmpty()); + assertEquals( + FhirTypeConverter.EMPTY_TUPLE_EXT_URL, + actual.getValue().getExtension().get(0).getUrl()); var ints = new ArrayList(); for (int i = 0; i < 5; i++) { @@ -556,11 +559,8 @@ void tupleToFhirTuple() { tuple.getElements().put("Y", new Encounter().setId("123")); tuple.getElements().put("Z", new ArrayList<>()); - actual = (Parameters) typeConverter.toFhirTuple(tuple); - assertNotNull(actual); - assertEquals(1, actual.getParameter().size()); - - var first = actual.getParameterFirstRep(); + actual = (Parameters.ParametersParameterComponent) typeConverter.toFhirTuple(tuple); + var first = actual; assertEquals(9, first.getPart().size()); var v = getPartsByName(first, "V"); @@ -584,6 +584,51 @@ void tupleToFhirTuple() { z.getValue().getExtension().get(0).getUrl()); } + @Test + void complexTupleToFhirTuple() { + var innerTuple = new Tuple(); + innerTuple.getElements().put("X", 1); + innerTuple.getElements().put("Y", 2); + innerTuple.getElements().put("Z", null); + var outerTuple = new Tuple(); + outerTuple.getElements().put("A", innerTuple); + var tupleList = new ArrayList(); + for (int i = 0; i < 3; i++) { + var elementTuple = new Tuple(); + elementTuple.getElements().put("P", i); + elementTuple.getElements().put("Q", i + 1); + tupleList.add(elementTuple); + } + outerTuple.getElements().put("B", tupleList); + + Parameters.ParametersParameterComponent actual = + (Parameters.ParametersParameterComponent) typeConverter.toFhirTuple(outerTuple); + var first = actual; + assertEquals(4, first.getPart().size()); + + var a = getPartsByName(first, "A"); + assertEquals(1, a.size()); + assertEquals(3, a.get(0).getPart().size()); + var x = a.get(0).getPart().get(0); + assertEquals(1, ((IntegerType) x.getValue()).getValue()); + var y = a.get(0).getPart().get(1); + assertEquals(2, ((IntegerType) y.getValue()).getValue()); + var z = a.get(0).getPart().get(2); + assertEquals( + FhirTypeConverter.DATA_ABSENT_REASON_EXT_URL, + z.getValue().getExtension().get(0).getUrl()); + + var b = getPartsByName(first, "B"); + assertEquals(3, b.size()); + var b1 = b.get(0); + var p = getPartsByName(b1, "P"); + assertEquals(1, p.size()); + assertEquals(0, ((IntegerType) p.get(0).getValue()).getValue()); + var q = getPartsByName(b1, "Q"); + assertEquals(1, q.size()); + assertEquals(1, ((IntegerType) q.get(0).getValue()).getValue()); + } + // FHIR-to-CQL @Test void isCqlType() { diff --git a/Src/java/engine-fhir/src/test/java/org/opencds/cqf/cql/engine/fhir/converter/R4TypeConverterTests.java b/Src/java/engine-fhir/src/test/java/org/opencds/cqf/cql/engine/fhir/converter/R4TypeConverterTests.java index 1ec50cd77..0e446722c 100644 --- a/Src/java/engine-fhir/src/test/java/org/opencds/cqf/cql/engine/fhir/converter/R4TypeConverterTests.java +++ b/Src/java/engine-fhir/src/test/java/org/opencds/cqf/cql/engine/fhir/converter/R4TypeConverterTests.java @@ -537,13 +537,16 @@ private static List getPartsByName(ParametersParam @Test void tupleToFhirTuple() { - Parameters actual = (Parameters) typeConverter.toFhirTuple(null); + Parameters.ParametersParameterComponent actual = + (Parameters.ParametersParameterComponent) typeConverter.toFhirTuple(null); assertNull(actual); var tuple = new Tuple(); - actual = (Parameters) typeConverter.toFhirTuple(tuple); + actual = (Parameters.ParametersParameterComponent) typeConverter.toFhirTuple(tuple); assertNotNull(actual); - assertTrue(actual.isEmpty()); + assertEquals( + FhirTypeConverter.EMPTY_TUPLE_EXT_URL, + actual.getValue().getExtension().get(0).getUrl()); var ints = new ArrayList(); for (int i = 0; i < 5; i++) { @@ -556,11 +559,8 @@ void tupleToFhirTuple() { tuple.getElements().put("Y", new Encounter().setId("123")); tuple.getElements().put("Z", new ArrayList<>()); - actual = (Parameters) typeConverter.toFhirTuple(tuple); - assertNotNull(actual); - assertEquals(1, actual.getParameter().size()); - - var first = actual.getParameterFirstRep(); + actual = (Parameters.ParametersParameterComponent) typeConverter.toFhirTuple(tuple); + var first = actual; assertEquals(9, first.getPart().size()); var v = getPartsByName(first, "V"); @@ -584,6 +584,51 @@ void tupleToFhirTuple() { z.getValue().getExtension().get(0).getUrl()); } + @Test + void complexTupleToFhirTuple() { + var innerTuple = new Tuple(); + innerTuple.getElements().put("X", 1); + innerTuple.getElements().put("Y", 2); + innerTuple.getElements().put("Z", null); + var outerTuple = new Tuple(); + outerTuple.getElements().put("A", innerTuple); + var tupleList = new ArrayList(); + for (int i = 0; i < 3; i++) { + var elementTuple = new Tuple(); + elementTuple.getElements().put("P", i); + elementTuple.getElements().put("Q", i + 1); + tupleList.add(elementTuple); + } + outerTuple.getElements().put("B", tupleList); + + Parameters.ParametersParameterComponent actual = + (Parameters.ParametersParameterComponent) typeConverter.toFhirTuple(outerTuple); + var first = actual; + assertEquals(4, first.getPart().size()); + + var a = getPartsByName(first, "A"); + assertEquals(1, a.size()); + assertEquals(3, a.get(0).getPart().size()); + var x = a.get(0).getPart().get(0); + assertEquals(1, ((IntegerType) x.getValue()).getValue()); + var y = a.get(0).getPart().get(1); + assertEquals(2, ((IntegerType) y.getValue()).getValue()); + var z = a.get(0).getPart().get(2); + assertEquals( + FhirTypeConverter.DATA_ABSENT_REASON_EXT_URL, + z.getValue().getExtension().get(0).getUrl()); + + var b = getPartsByName(first, "B"); + assertEquals(3, b.size()); + var b1 = b.get(0); + var p = getPartsByName(b1, "P"); + assertEquals(1, p.size()); + assertEquals(0, ((IntegerType) p.get(0).getValue()).getValue()); + var q = getPartsByName(b1, "Q"); + assertEquals(1, q.size()); + assertEquals(1, ((IntegerType) q.get(0).getValue()).getValue()); + } + // FHIR-to-CQL @Test void isCqlType() { diff --git a/Src/java/engine-fhir/src/test/java/org/opencds/cqf/cql/engine/fhir/converter/R5TypeConverterTests.java b/Src/java/engine-fhir/src/test/java/org/opencds/cqf/cql/engine/fhir/converter/R5TypeConverterTests.java index 673cdd438..b80bfb695 100644 --- a/Src/java/engine-fhir/src/test/java/org/opencds/cqf/cql/engine/fhir/converter/R5TypeConverterTests.java +++ b/Src/java/engine-fhir/src/test/java/org/opencds/cqf/cql/engine/fhir/converter/R5TypeConverterTests.java @@ -537,13 +537,16 @@ private static List getPartsByName(ParametersParam @Test void tupleToFhirTuple() { - Parameters actual = (Parameters) typeConverter.toFhirTuple(null); + Parameters.ParametersParameterComponent actual = + (Parameters.ParametersParameterComponent) typeConverter.toFhirTuple(null); assertNull(actual); var tuple = new Tuple(); - actual = (Parameters) typeConverter.toFhirTuple(tuple); + actual = (Parameters.ParametersParameterComponent) typeConverter.toFhirTuple(tuple); assertNotNull(actual); - assertTrue(actual.isEmpty()); + assertEquals( + FhirTypeConverter.EMPTY_TUPLE_EXT_URL, + actual.getValue().getExtension().get(0).getUrl()); var ints = new ArrayList(); for (int i = 0; i < 5; i++) { @@ -556,11 +559,8 @@ void tupleToFhirTuple() { tuple.getElements().put("Y", new Encounter().setId("123")); tuple.getElements().put("Z", new ArrayList<>()); - actual = (Parameters) typeConverter.toFhirTuple(tuple); - assertNotNull(actual); - assertEquals(1, actual.getParameter().size()); - - var first = actual.getParameterFirstRep(); + actual = (Parameters.ParametersParameterComponent) typeConverter.toFhirTuple(tuple); + var first = actual; assertEquals(9, first.getPart().size()); var v = getPartsByName(first, "V"); @@ -584,6 +584,51 @@ void tupleToFhirTuple() { z.getValue().getExtension().get(0).getUrl()); } + @Test + void complexTupleToFhirTuple() { + var innerTuple = new Tuple(); + innerTuple.getElements().put("X", 1); + innerTuple.getElements().put("Y", 2); + innerTuple.getElements().put("Z", null); + var outerTuple = new Tuple(); + outerTuple.getElements().put("A", innerTuple); + var tupleList = new ArrayList(); + for (int i = 0; i < 3; i++) { + var elementTuple = new Tuple(); + elementTuple.getElements().put("P", i); + elementTuple.getElements().put("Q", i + 1); + tupleList.add(elementTuple); + } + outerTuple.getElements().put("B", tupleList); + + Parameters.ParametersParameterComponent actual = + (Parameters.ParametersParameterComponent) typeConverter.toFhirTuple(outerTuple); + var first = actual; + assertEquals(4, first.getPart().size()); + + var a = getPartsByName(first, "A"); + assertEquals(1, a.size()); + assertEquals(3, a.get(0).getPart().size()); + var x = a.get(0).getPart().get(0); + assertEquals(1, ((IntegerType) x.getValue()).getValue()); + var y = a.get(0).getPart().get(1); + assertEquals(2, ((IntegerType) y.getValue()).getValue()); + var z = a.get(0).getPart().get(2); + assertEquals( + FhirTypeConverter.DATA_ABSENT_REASON_EXT_URL, + z.getValue().getExtension().get(0).getUrl()); + + var b = getPartsByName(first, "B"); + assertEquals(3, b.size()); + var b1 = b.get(0); + var p = getPartsByName(b1, "P"); + assertEquals(1, p.size()); + assertEquals(0, ((IntegerType) p.get(0).getValue()).getValue()); + var q = getPartsByName(b1, "Q"); + assertEquals(1, q.size()); + assertEquals(1, ((IntegerType) q.get(0).getValue()).getValue()); + } + // FHIR-to-CQL @Test void isCqlType() { From 8f790d35b0d73bcc87b0dfd20513a6bcb1095ad2 Mon Sep 17 00:00:00 2001 From: Jonathan Percival Date: Thu, 10 Oct 2024 15:48:58 -0600 Subject: [PATCH 10/10] Updated formatting --- .../cqf/cql/engine/fhir/converter/Dstu2FhirTypeConverter.java | 2 +- .../cqf/cql/engine/fhir/converter/Dstu3FhirTypeConverter.java | 2 +- .../cqf/cql/engine/fhir/converter/R4FhirTypeConverter.java | 2 +- .../cqf/cql/engine/fhir/converter/R5FhirTypeConverter.java | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Src/java/engine-fhir/src/main/java/org/opencds/cqf/cql/engine/fhir/converter/Dstu2FhirTypeConverter.java b/Src/java/engine-fhir/src/main/java/org/opencds/cqf/cql/engine/fhir/converter/Dstu2FhirTypeConverter.java index 753580553..b5813fbea 100644 --- a/Src/java/engine-fhir/src/main/java/org/opencds/cqf/cql/engine/fhir/converter/Dstu2FhirTypeConverter.java +++ b/Src/java/engine-fhir/src/main/java/org/opencds/cqf/cql/engine/fhir/converter/Dstu2FhirTypeConverter.java @@ -230,7 +230,7 @@ private static BooleanType emptyBooleanWithExtension(String url, Type value) { private static void addPartWithNameAndValue( Parameters.ParametersParameterComponent param, String key, Object value) { if (value instanceof Parameters.ParametersParameterComponent) { - var part = (Parameters.ParametersParameterComponent)value; + var part = (Parameters.ParametersParameterComponent) value; part.setName(key); param.addPart(part); } else { diff --git a/Src/java/engine-fhir/src/main/java/org/opencds/cqf/cql/engine/fhir/converter/Dstu3FhirTypeConverter.java b/Src/java/engine-fhir/src/main/java/org/opencds/cqf/cql/engine/fhir/converter/Dstu3FhirTypeConverter.java index 1ccab474f..d58927482 100644 --- a/Src/java/engine-fhir/src/main/java/org/opencds/cqf/cql/engine/fhir/converter/Dstu3FhirTypeConverter.java +++ b/Src/java/engine-fhir/src/main/java/org/opencds/cqf/cql/engine/fhir/converter/Dstu3FhirTypeConverter.java @@ -229,7 +229,7 @@ private static BooleanType emptyBooleanWithExtension(String url, Type value) { private static void addPartWithNameAndValue( Parameters.ParametersParameterComponent param, String key, Object value) { if (value instanceof Parameters.ParametersParameterComponent) { - var part = (Parameters.ParametersParameterComponent)value; + var part = (Parameters.ParametersParameterComponent) value; part.setName(key); param.addPart(part); } else { diff --git a/Src/java/engine-fhir/src/main/java/org/opencds/cqf/cql/engine/fhir/converter/R4FhirTypeConverter.java b/Src/java/engine-fhir/src/main/java/org/opencds/cqf/cql/engine/fhir/converter/R4FhirTypeConverter.java index c1b199a7d..b69f1f8d6 100644 --- a/Src/java/engine-fhir/src/main/java/org/opencds/cqf/cql/engine/fhir/converter/R4FhirTypeConverter.java +++ b/Src/java/engine-fhir/src/main/java/org/opencds/cqf/cql/engine/fhir/converter/R4FhirTypeConverter.java @@ -222,7 +222,7 @@ private static BooleanType emptyBooleanWithExtension(String url, Type value) { private static void addPartWithNameAndValue( Parameters.ParametersParameterComponent param, String key, Object value) { if (value instanceof Parameters.ParametersParameterComponent) { - var part = (Parameters.ParametersParameterComponent)value; + var part = (Parameters.ParametersParameterComponent) value; part.setName(key); param.addPart(part); } else { diff --git a/Src/java/engine-fhir/src/main/java/org/opencds/cqf/cql/engine/fhir/converter/R5FhirTypeConverter.java b/Src/java/engine-fhir/src/main/java/org/opencds/cqf/cql/engine/fhir/converter/R5FhirTypeConverter.java index f93bb38c5..c8c53194e 100644 --- a/Src/java/engine-fhir/src/main/java/org/opencds/cqf/cql/engine/fhir/converter/R5FhirTypeConverter.java +++ b/Src/java/engine-fhir/src/main/java/org/opencds/cqf/cql/engine/fhir/converter/R5FhirTypeConverter.java @@ -221,7 +221,7 @@ private static BooleanType emptyBooleanWithExtension(String url, DataType value) private static void addPartWithNameAndValue( Parameters.ParametersParameterComponent param, String key, Object value) { if (value instanceof Parameters.ParametersParameterComponent) { - var part = (Parameters.ParametersParameterComponent)value; + var part = (Parameters.ParametersParameterComponent) value; part.setName(key); param.addPart(part); } else {