Search in sources :

Example 41 with DataType

use of org.hl7.fhir.r5.model.DataType in project clinical_quality_language by cqframework.

the class DataRequirementsProcessor method toFhirValue.

private DataType toFhirValue(ElmRequirementsContext context, Expression value) {
    if (value == null) {
        return null;
    }
    if (value instanceof Interval) {
        // TODO: Handle lowclosed/highclosed
        return new Period().setStartElement(toFhirDateTimeValue(context, ((Interval) value).getLow())).setEndElement(toFhirDateTimeValue(context, ((Interval) value).getHigh()));
    } else if (value instanceof Literal) {
        if (context.getTypeResolver().isDateTimeType(value.getResultType())) {
            return new DateTimeType(((Literal) value).getValue());
        } else if (context.getTypeResolver().isDateType(value.getResultType())) {
            return new DateType(((Literal) value).getValue());
        } else if (context.getTypeResolver().isIntegerType(value.getResultType())) {
            return new IntegerType(((Literal) value).getValue());
        } else if (context.getTypeResolver().isDecimalType(value.getResultType())) {
            return new DecimalType(((Literal) value).getValue());
        } else if (context.getTypeResolver().isStringType(value.getResultType())) {
            return new StringType(((Literal) value).getValue());
        }
    } else if (value instanceof DateTime) {
        DateTime dateTime = (DateTime) value;
        return new DateTimeType(toDateTimeString(toFhirValue(context, dateTime.getYear()), toFhirValue(context, dateTime.getMonth()), toFhirValue(context, dateTime.getDay()), toFhirValue(context, dateTime.getHour()), toFhirValue(context, dateTime.getMinute()), toFhirValue(context, dateTime.getSecond()), toFhirValue(context, dateTime.getMillisecond()), toFhirValue(context, dateTime.getTimezoneOffset())));
    } else if (value instanceof org.hl7.elm.r1.Date) {
        org.hl7.elm.r1.Date date = (org.hl7.elm.r1.Date) value;
        return new DateType(toDateString(toFhirValue(context, date.getYear()), toFhirValue(context, date.getMonth()), toFhirValue(context, date.getDay())));
    } else if (value instanceof Start) {
        DataType operand = toFhirValue(context, ((Start) value).getOperand());
        if (operand != null) {
            Period period = (Period) operand;
            return period.getStartElement();
        }
    } else if (value instanceof End) {
        DataType operand = toFhirValue(context, ((End) value).getOperand());
        if (operand != null) {
            Period period = (Period) operand;
            return period.getEndElement();
        }
    } else if (value instanceof ParameterRef) {
        if (context.getTypeResolver().isIntervalType(value.getResultType())) {
            Extension e = toExpression(context, (ParameterRef) value);
            org.hl7.cql.model.DataType pointType = ((IntervalType) value.getResultType()).getPointType();
            if (context.getTypeResolver().isDateTimeType(pointType) || context.getTypeResolver().isDateType(pointType)) {
                Period period = new Period();
                period.addExtension(e);
                return period;
            } else if (context.getTypeResolver().isQuantityType(pointType) || context.getTypeResolver().isIntegerType(pointType) || context.getTypeResolver().isDecimalType(pointType)) {
                Range range = new Range();
                range.addExtension(e);
                return range;
            } else {
                throw new IllegalArgumentException(String.format("toFhirValue not implemented for interval of %s", pointType.toString()));
            }
        } else // Boolean, Integer, Decimal, String, Quantity, Date, DateTime, Time, Coding, CodeableConcept
        if (context.getTypeResolver().isBooleanType(value.getResultType())) {
            BooleanType result = new BooleanType();
            result.addExtension(toExpression(context, (ParameterRef) value));
            return result;
        } else if (context.getTypeResolver().isIntegerType(value.getResultType())) {
            IntegerType result = new IntegerType();
            result.addExtension(toExpression(context, (ParameterRef) value));
            return result;
        } else if (context.getTypeResolver().isDecimalType(value.getResultType())) {
            DecimalType result = new DecimalType();
            result.addExtension(toExpression(context, (ParameterRef) value));
            return result;
        } else if (context.getTypeResolver().isQuantityType(value.getResultType())) {
            Quantity result = new Quantity();
            result.addExtension(toExpression(context, (ParameterRef) value));
            return result;
        } else if (context.getTypeResolver().isCodeType(value.getResultType())) {
            Coding result = new Coding();
            result.addExtension(toExpression(context, (ParameterRef) value));
            return result;
        } else if (context.getTypeResolver().isConceptType(value.getResultType())) {
            CodeableConcept result = new CodeableConcept();
            result.addExtension(toExpression(context, (ParameterRef) value));
            return result;
        } else if (context.getTypeResolver().isDateType(value.getResultType())) {
            DateType result = new DateType();
            result.addExtension(toExpression(context, (ParameterRef) value));
            return result;
        } else if (context.getTypeResolver().isDateTimeType(value.getResultType())) {
            DateTimeType result = new DateTimeType();
            result.addExtension(toExpression(context, (ParameterRef) value));
            return result;
        } else if (context.getTypeResolver().isTimeType(value.getResultType())) {
            TimeType result = new TimeType();
            result.addExtension(toExpression(context, (ParameterRef) value));
            return result;
        } else {
            throw new IllegalArgumentException(String.format("toFhirValue not implemented for parameter of type %s", value.getResultType().toString()));
        }
    }
    throw new IllegalArgumentException(String.format("toFhirValue not implemented for %s", value.getClass().getSimpleName()));
}
Also used : IntervalType(org.hl7.cql.model.IntervalType) org.hl7.fhir.r5.model(org.hl7.fhir.r5.model) Quantity(org.hl7.fhir.r5.model.Quantity) org.hl7.elm.r1(org.hl7.elm.r1)

Example 42 with DataType

use of org.hl7.fhir.r5.model.DataType in project clinical_quality_language by cqframework.

the class BaseTest method testFHIRHelpers.

@Test
public void testFHIRHelpers() throws IOException {
    CqlTranslator translator = TestUtils.runSemanticTest("fhir/r401/TestFHIRHelpers.cql", 0);
    CompiledLibrary translatedLibrary = translator.getTranslatedLibrary();
    assertResultType(translatedLibrary, "TestExtensions", "FHIR", "Extension");
    assertResultType(translatedLibrary, "TestElementExtensions", "FHIR", "Extension");
    assertResultType(translatedLibrary, "TestModifierExtensions", "FHIR", "Extension");
    assertResultType(translatedLibrary, "TestElementModifierExtensions", "FHIR", "Extension");
    ExpressionDef ed = translatedLibrary.resolveExpressionRef("TestChoiceConverts");
    DataType resultType = ed.getExpression().getResultType();
    assertThat(resultType, instanceOf(ChoiceType.class));
    assertThat(resultType.toString(), equalTo("choice<System.String,System.Boolean,System.Date,System.DateTime,System.Decimal,System.Integer,System.Time,System.Quantity,System.Concept,System.Code,interval<System.Quantity>,interval<System.DateTime>,System.Ratio,FHIR.Address,FHIR.Annotation,FHIR.Attachment,FHIR.ContactPoint,FHIR.HumanName,FHIR.Identifier,FHIR.Money,FHIR.Reference,FHIR.SampledData,FHIR.Signature,FHIR.Timing,FHIR.ContactDetail,FHIR.Contributor,FHIR.DataRequirement,FHIR.Expression,FHIR.ParameterDefinition,FHIR.RelatedArtifact,FHIR.TriggerDefinition,FHIR.UsageContext,FHIR.Dosage,FHIR.Meta>"));
}
Also used : CompiledLibrary(org.cqframework.cql.cql2elm.model.CompiledLibrary) ChoiceType(org.hl7.cql.model.ChoiceType) CqlTranslator(org.cqframework.cql.cql2elm.CqlTranslator) QuickDataType.quickDataType(org.cqframework.cql.cql2elm.matchers.QuickDataType.quickDataType) DataType(org.hl7.cql.model.DataType) Test(org.testng.annotations.Test)

Example 43 with DataType

use of org.hl7.fhir.r5.model.DataType in project clinical_quality_language by cqframework.

the class BaseTest method assertResultType.

private void assertResultType(CompiledLibrary translatedLibrary, String expressionName, String namespace, String name) {
    ExpressionDef ed = translatedLibrary.resolveExpressionRef(expressionName);
    DataType resultType = ed.getExpression().getResultType();
    assertThat(resultType, instanceOf(ClassType.class));
    ClassType resultClassType = (ClassType) resultType;
    assertThat(resultClassType.getNamespace(), equalTo(namespace));
    assertThat(resultClassType.getSimpleName(), equalTo(name));
}
Also used : QuickDataType.quickDataType(org.cqframework.cql.cql2elm.matchers.QuickDataType.quickDataType) DataType(org.hl7.cql.model.DataType) ClassType(org.hl7.cql.model.ClassType)

Example 44 with DataType

use of org.hl7.fhir.r5.model.DataType in project clinical_quality_language by cqframework.

the class SemanticTests method testTypeOperators.

@Test
public void testTypeOperators() throws IOException {
    CqlTranslator translator = runSemanticTest("OperatorTests/TypeOperators.cql");
    org.hl7.elm.r1.Library library = translator.toELM();
    Map<String, ExpressionDef> defs = new HashMap<>();
    if (library.getStatements() != null) {
        for (ExpressionDef def : library.getStatements().getDef()) {
            defs.put(def.getName(), def);
        }
    }
    ExpressionDef def = defs.get("TestIf");
    assertThat(def.getResultType(), instanceOf(ChoiceType.class));
    ChoiceType choiceType = (ChoiceType) def.getResultType();
    DataType type = null;
    for (DataType dt : choiceType.getTypes()) {
        if (type == null) {
            type = dt;
            assertThat(dt, instanceOf(NamedType.class));
            assertThat(((NamedType) dt).getName(), equalTo("System.String"));
        } else {
            assertThat(dt, instanceOf(NamedType.class));
            assertThat(((NamedType) dt).getName(), equalTo("System.Boolean"));
        }
    }
    def = defs.get("TestCase");
    assertThat(def.getResultType(), instanceOf(ChoiceType.class));
    choiceType = (ChoiceType) def.getResultType();
    type = null;
    for (DataType dt : choiceType.getTypes()) {
        if (type == null) {
            type = dt;
            assertThat(dt, instanceOf(NamedType.class));
            assertThat(((NamedType) dt).getName(), equalTo("System.String"));
        } else {
            assertThat(dt, instanceOf(NamedType.class));
            assertThat(((NamedType) dt).getName(), equalTo("System.Boolean"));
        }
    }
}
Also used : HashMap(java.util.HashMap) ChoiceType(org.hl7.cql.model.ChoiceType) NamedType(org.hl7.cql.model.NamedType) DataType(org.hl7.cql.model.DataType) org.hl7.elm.r1(org.hl7.elm.r1) Test(org.testng.annotations.Test)

Example 45 with DataType

use of org.hl7.fhir.r5.model.DataType in project clinical_quality_language by cqframework.

the class Cql2ElmVisitor method visitRetrieve.

@Override
@SuppressWarnings("unchecked")
public Retrieve visitRetrieve(cqlParser.RetrieveContext ctx) {
    libraryBuilder.checkLiteralContext();
    List<String> qualifiers = parseQualifiers(ctx.namedTypeSpecifier());
    String model = getModelIdentifier(qualifiers);
    String label = getTypeIdentifier(qualifiers, parseString(ctx.namedTypeSpecifier().referentialOrTypeNameIdentifier()));
    DataType dataType = libraryBuilder.resolveTypeName(model, label);
    if (dataType == null) {
        // ERROR:
        throw new IllegalArgumentException(String.format("Could not resolve type name %s.", label));
    }
    if (!(dataType instanceof ClassType) || !((ClassType) dataType).isRetrievable()) {
        // ERROR:
        throw new IllegalArgumentException(String.format("Specified data type %s does not support retrieval.", label));
    }
    ClassType classType = (ClassType) dataType;
    // BTR -> The original intent of this code was to have the retrieve return the base type, and use the "templateId"
    // element of the retrieve to communicate the "positive" or "negative" profile to the data access layer.
    // However, because this notion of carrying the "profile" through a type is not general, it causes inconsistencies
    // when using retrieve results with functions defined in terms of the same type (see GitHub Issue #131).
    // Based on the discussion there, the retrieve will now return the declared type, whether it is a profile or not.
    // ProfileType profileType = dataType instanceof ProfileType ? (ProfileType)dataType : null;
    // NamedType namedType = profileType == null ? classType : (NamedType)classType.getBaseType();
    NamedType namedType = classType;
    ModelInfo modelInfo = libraryBuilder.getModel(namedType.getNamespace()).getModelInfo();
    boolean useStrictRetrieveTyping = modelInfo.isStrictRetrieveTyping() != null && modelInfo.isStrictRetrieveTyping();
    Retrieve retrieve = of.createRetrieve().withDataType(libraryBuilder.dataTypeToQName((DataType) namedType)).withTemplateId(classType.getIdentifier());
    if (ctx.contextIdentifier() != null) {
        List<String> identifiers = (List<String>) visit(ctx.contextIdentifier());
        Expression contextExpression = resolveQualifiedIdentifier(identifiers);
        retrieve.setContext(contextExpression);
    }
    if (ctx.terminology() != null) {
        if (ctx.codePath() != null) {
            String identifiers = (String) visit(ctx.codePath());
            retrieve.setCodeProperty(identifiers);
        } else if (classType.getPrimaryCodePath() != null) {
            retrieve.setCodeProperty(classType.getPrimaryCodePath());
        }
        Property property = null;
        CqlCompilerException propertyException = null;
        if (retrieve.getCodeProperty() == null) {
            // ERROR:
            // WARNING:
            propertyException = new CqlSemanticException("Retrieve has a terminology target but does not specify a code path and the type of the retrieve does not have a primary code path defined.", useStrictRetrieveTyping ? CqlCompilerException.ErrorSeverity.Error : CqlCompilerException.ErrorSeverity.Warning, getTrackBack(ctx));
            libraryBuilder.recordParsingException(propertyException);
        } else {
            try {
                DataType codeType = libraryBuilder.resolvePath((DataType) namedType, retrieve.getCodeProperty());
                property = of.createProperty().withPath(retrieve.getCodeProperty());
                property.setResultType(codeType);
            } catch (Exception e) {
                // ERROR:
                // WARNING:
                propertyException = new CqlSemanticException(String.format("Could not resolve code path %s for the type of the retrieve %s.", retrieve.getCodeProperty(), namedType.getName()), useStrictRetrieveTyping ? CqlCompilerException.ErrorSeverity.Error : CqlCompilerException.ErrorSeverity.Warning, getTrackBack(ctx), e);
                libraryBuilder.recordParsingException(propertyException);
            }
        }
        Expression terminology = null;
        if (ctx.terminology().qualifiedIdentifierExpression() != null) {
            List<String> identifiers = (List<String>) visit(ctx.terminology());
            terminology = resolveQualifiedIdentifier(identifiers);
            track(terminology, ctx.terminology().qualifiedIdentifierExpression());
        } else {
            terminology = parseExpression(ctx.terminology().expression());
        }
        String codeComparator = ctx.codeComparator() != null ? (String) visit(ctx.codeComparator()) : null;
        // Resolve the terminology target using an in or ~ operator
        try {
            if (codeComparator == null) {
                codeComparator = (terminology.getResultType() instanceof ListType || (libraryBuilder.isCompatibleWith("1.5") && terminology.getResultType().isSubTypeOf(libraryBuilder.resolveTypeName("System", "Vocabulary")))) ? "in" : "~";
            }
            if (property == null) {
                throw propertyException;
            }
            switch(codeComparator) {
                case "in":
                    {
                        Expression in = libraryBuilder.resolveIn(property, terminology);
                        if (in instanceof In) {
                            retrieve.setCodes(((In) in).getOperand().get(1));
                        } else if (in instanceof InValueSet) {
                            retrieve.setCodes(((InValueSet) in).getValueset());
                        } else if (in instanceof InCodeSystem) {
                            retrieve.setCodes(((InCodeSystem) in).getCodesystem());
                        } else if (in instanceof AnyInValueSet) {
                            retrieve.setCodes(((AnyInValueSet) in).getValueset());
                        } else if (in instanceof AnyInCodeSystem) {
                            retrieve.setCodes(((AnyInCodeSystem) in).getCodesystem());
                        } else {
                            // ERROR:
                            // WARNING:
                            libraryBuilder.recordParsingException(new CqlSemanticException(String.format("Unexpected membership operator %s in retrieve", in.getClass().getSimpleName()), useStrictRetrieveTyping ? CqlCompilerException.ErrorSeverity.Error : CqlCompilerException.ErrorSeverity.Warning, getTrackBack(ctx)));
                        }
                    }
                    break;
                case "~":
                    {
                        // Resolve with equivalent to verify the type of the target
                        BinaryExpression equivalent = of.createEquivalent().withOperand(property, terminology);
                        libraryBuilder.resolveBinaryCall("System", "Equivalent", equivalent);
                        // Automatically promote to a list for use in the retrieve target
                        if (!(equivalent.getOperand().get(1).getResultType() instanceof ListType)) {
                            retrieve.setCodes(libraryBuilder.resolveToList(equivalent.getOperand().get(1)));
                        } else {
                            retrieve.setCodes(equivalent.getOperand().get(1));
                        }
                    }
                    break;
                case "=":
                    {
                        // Resolve with equality to verify the type of the source and target
                        BinaryExpression equal = of.createEqual().withOperand(property, terminology);
                        libraryBuilder.resolveBinaryCall("System", "Equal", equal);
                        // Automatically promote to a list for use in the retrieve target
                        if (!(equal.getOperand().get(1).getResultType() instanceof ListType)) {
                            retrieve.setCodes(libraryBuilder.resolveToList(equal.getOperand().get(1)));
                        } else {
                            retrieve.setCodes(equal.getOperand().get(1));
                        }
                    }
                    break;
                default:
                    // ERROR:
                    // WARNING:
                    libraryBuilder.recordParsingException(new CqlSemanticException(String.format("Unknown code comparator % in retrieve", codeComparator), useStrictRetrieveTyping ? CqlCompilerException.ErrorSeverity.Error : CqlCompilerException.ErrorSeverity.Warning, getTrackBack(ctx.codeComparator())));
            }
            retrieve.setCodeComparator(codeComparator);
            // In that case, convert to a list of code (Union the Code elements of the Concepts in the list)
            if (retrieve.getCodes() != null && retrieve.getCodes().getResultType() != null && retrieve.getCodes().getResultType() instanceof ListType && ((ListType) retrieve.getCodes().getResultType()).getElementType().equals(libraryBuilder.resolveTypeName("System", "Concept"))) {
                if (retrieve.getCodes() instanceof ToList) {
                    // ToList will always have a single argument
                    ToList toList = (ToList) retrieve.getCodes();
                    // If that argument is a ToConcept, replace the ToList argument with the code (skip the implicit conversion, the data access layer is responsible for it)
                    if (toList.getOperand() instanceof ToConcept) {
                        toList.setOperand(((ToConcept) toList.getOperand()).getOperand());
                    } else {
                        // Otherwise, access the codes property of the resulting Concept
                        Expression codesAccessor = libraryBuilder.buildProperty(toList.getOperand(), "codes", false, toList.getOperand().getResultType());
                        retrieve.setCodes(codesAccessor);
                    }
                } else {
                    // WARNING:
                    libraryBuilder.recordParsingException(new CqlSemanticException("Terminology target is a list of concepts, but expects a list of codes", CqlCompilerException.ErrorSeverity.Warning, getTrackBack(ctx)));
                }
            }
        } catch (Exception e) {
            // it shouldn't prevent translation unless the modelinfo indicates strict retrieve typing
            if ((libraryBuilder.isCompatibleWith("1.5") && !(terminology.getResultType().isSubTypeOf(libraryBuilder.resolveTypeName("System", "Vocabulary")))) || (!libraryBuilder.isCompatibleWith("1.5") && !(terminology.getResultType() instanceof ListType))) {
                retrieve.setCodes(libraryBuilder.resolveToList(terminology));
            } else {
                retrieve.setCodes(terminology);
            }
            retrieve.setCodeComparator(codeComparator);
            // ERROR:
            // WARNING:
            libraryBuilder.recordParsingException(new CqlSemanticException("Could not resolve membership operator for terminology target of the retrieve.", useStrictRetrieveTyping ? CqlCompilerException.ErrorSeverity.Error : CqlCompilerException.ErrorSeverity.Warning, getTrackBack(ctx), e));
        }
    }
    retrieves.add(retrieve);
    retrieve.setResultType(new ListType((DataType) namedType));
    return retrieve;
}
Also used : ModelInfo(org.hl7.elm_modelinfo.r1.ModelInfo) List(java.util.List)

Aggregations

DataType (org.hl7.fhir.r5.model.DataType)14 FHIRException (org.hl7.fhir.exceptions.FHIRException)11 XhtmlNode (org.hl7.fhir.utilities.xhtml.XhtmlNode)11 DefinitionException (org.hl7.fhir.exceptions.DefinitionException)8 HashMap (java.util.HashMap)7 List (java.util.List)7 Map (java.util.Map)7 FHIRFormatError (org.hl7.fhir.exceptions.FHIRFormatError)7 Collectors (java.util.stream.Collectors)6 DataType (org.hl7.cql.model.DataType)6 ModelInfo (org.hl7.elm_modelinfo.r1.ModelInfo)6 Piece (org.hl7.fhir.utilities.xhtml.HierarchicalTableGenerator.Piece)6 ArrayList (java.util.ArrayList)5 StructType (org.apache.spark.sql.types.StructType)5 BooleanType (org.hl7.fhir.r5.model.BooleanType)5 ValueSet (org.hl7.fhir.r5.model.ValueSet)5 Arrays (java.util.Arrays)4 QName (javax.xml.namespace.QName)4 DataType (org.hl7.fhir.r4b.model.DataType)4 ByteArrayOutputStream (java.io.ByteArrayOutputStream)3