diff --git a/Src/java/cql-to-elm/src/main/java/org/cqframework/cql/cql2elm/LibraryBuilder.java b/Src/java/cql-to-elm/src/main/java/org/cqframework/cql/cql2elm/LibraryBuilder.java index a4fc5efcf..cb8ef899d 100644 --- a/Src/java/cql-to-elm/src/main/java/org/cqframework/cql/cql2elm/LibraryBuilder.java +++ b/Src/java/cql-to-elm/src/main/java/org/cqframework/cql/cql2elm/LibraryBuilder.java @@ -2743,6 +2743,22 @@ public Expression applyTargetMap(Expression source, String targetMap) { String functionArgument = targetMap.substring(invocationStart + 1, targetMap.lastIndexOf(')')); Expression argumentSource = functionArgument.equals("%value") ? source : applyTargetMap(source, functionArgument); + + // NOTE: This is needed to work around the mapping for ToInterval + // FHIRHelpers defines multiple overloads of ToInterval, but the type mapping + // does not have the type of the source data type. + // All the mappings for ToInterval use FHIR.Period, so this is safe to assume + // In addition, no other FHIRHelpers functions use overloads (except ToString and ToDateTime, + // but those mappings expand the value element directly, rather than invoking the FHIRHelpers function) + TypeSpecifier argumentSignature = null; + if (this.options.getSignatureLevel() != SignatureLevel.None) { + if (qualifiedFunctionName.equals("FHIRHelpers.ToInterval")) { + NamedTypeSpecifier namedTypeSpecifier = + new NamedTypeSpecifier().withName(dataTypeToQName(resolveTypeName("FHIR", "Period"))); + argumentSignature = namedTypeSpecifier; + } + } + if (argumentSource.getResultType() instanceof ListType) { Query query = of.createQuery() .withSource(of.createAliasedQuerySource() @@ -2752,6 +2768,11 @@ public Expression applyTargetMap(Expression source, String targetMap) { .withLibraryName(libraryName) .withName(functionName) .withOperand(of.createAliasRef().withName("$this")); + + if (argumentSignature != null) { + fr.getSignature().add(argumentSignature); + } + // This doesn't quite work because the US.Core types aren't subtypes of FHIR types. // resolveCall(libraryName, functionName, new FunctionRefInvocation(fr), false, false); query.setReturn(of.createReturnClause().withDistinct(false).withExpression(fr)); @@ -2763,6 +2784,11 @@ public Expression applyTargetMap(Expression source, String targetMap) { .withName(functionName) .withOperand(argumentSource); fr.setResultType(source.getResultType()); + + if (argumentSignature != null) { + fr.getSignature().add(argumentSignature); + } + return fr; // This doesn't quite work because the US.Core types aren't subtypes of FHIR types, // or they are defined as System types and not FHIR types diff --git a/Src/java/cql-to-elm/src/test/java/org/cqframework/cql/cql2elm/TranslationTests.java b/Src/java/cql-to-elm/src/test/java/org/cqframework/cql/cql2elm/TranslationTests.java index 876205432..cb254e449 100644 --- a/Src/java/cql-to-elm/src/test/java/org/cqframework/cql/cql2elm/TranslationTests.java +++ b/Src/java/cql-to-elm/src/test/java/org/cqframework/cql/cql2elm/TranslationTests.java @@ -467,4 +467,38 @@ void abstractClassNotRetrievable() throws IOException { errors.stream().map(Throwable::getMessage).collect(Collectors.toList()); assertThat(errorMessages, contains("Specified data type DomainResource does not support retrieval.")); } + + @Test + void mappingExpansionsRespectSignatureLevel() throws IOException { + // See: https://github.com/cqframework/clinical_quality_language/issues/1475 + final CqlTranslator translator = TestUtils.runSemanticTest( + "MappingExpansionsRespectSignatureLevel.cql", 0, LibraryBuilder.SignatureLevel.Overloads); + /* + ExpressionDef: EncounterPeriod + expression is Query + return + expression is FunctionRef + name FHIRHelpers.ToInterval + signature is NamedTypeSpecifier FHIR.Period + */ + + Library compiledLibrary = translator.getTranslatedLibrary().getLibrary(); + List statements = compiledLibrary.getStatements().getDef(); + + assertThat(statements.size(), is(2)); + ExpressionDef encounterPeriod = statements.get(1); + assertThat(encounterPeriod.getName(), is("EncounterPeriod")); + assertThat(encounterPeriod.getExpression(), instanceOf(Query.class)); + Query query = (Query) encounterPeriod.getExpression(); + assertThat(query.getReturn().getExpression(), instanceOf(FunctionRef.class)); + FunctionRef functionRef = (FunctionRef) query.getReturn().getExpression(); + assertThat(functionRef.getLibraryName(), is("FHIRHelpers")); + assertThat(functionRef.getName(), is("ToInterval")); + assertThat(functionRef.getSignature(), notNullValue()); + assertThat(functionRef.getSignature().size(), is(1)); + assertThat(functionRef.getSignature().get(0), instanceOf(NamedTypeSpecifier.class)); + NamedTypeSpecifier namedTypeSpecifier = + (NamedTypeSpecifier) functionRef.getSignature().get(0); + assertThat(namedTypeSpecifier.getName().getLocalPart(), is("Period")); + } } diff --git a/Src/java/cql-to-elm/src/test/resources/org/cqframework/cql/cql2elm/MappingExpansionsRespectSignatureLevel.cql b/Src/java/cql-to-elm/src/test/resources/org/cqframework/cql/cql2elm/MappingExpansionsRespectSignatureLevel.cql new file mode 100644 index 000000000..77752b2ba --- /dev/null +++ b/Src/java/cql-to-elm/src/test/resources/org/cqframework/cql/cql2elm/MappingExpansionsRespectSignatureLevel.cql @@ -0,0 +1,15 @@ +library MappingExpansionsRespectSignatureLevel + +// https://github.com/cqframework/clinical_quality_language/issues/1475 + +using QICore version '4.1.1' + +include FHIRHelpers version '4.0.1' + +parameter "Measurement Period" Interval default Interval[@2024-01-01T00:00:00.0Z, @2025-01-01T00:00:00.0Z) + +context Patient + +define EncounterPeriod: + [Encounter] E + return E.period \ No newline at end of file