From cd5ab4fa10fe25a51b546ac8da29752d24120c34 Mon Sep 17 00:00:00 2001 From: Bryn Rhodes Date: Thu, 16 Jun 2022 20:45:11 -0600 Subject: [PATCH 1/3] #761: Fixed now(), today(), and timeOfDay() not resolving as FHIRPath functions --- .../cql/cql2elm/SystemFunctionResolver.java | 9 +- .../cql/cql2elm/SystemMethodResolver.java | 9 +- .../cql2elm/model/SystemLibraryHelper.java | 3 + .../cql/cql2elm/fhir/r401/BaseTest.java | 108 ++++++++++++++++++ .../cql/cql2elm/fhir/r401/TestFHIRPath.cql | 20 ++++ 5 files changed, 143 insertions(+), 6 deletions(-) create mode 100644 Src/java/cql-to-elm/src/test/resources/org/cqframework/cql/cql2elm/fhir/r401/TestFHIRPath.cql diff --git a/Src/java/cql-to-elm/src/main/java/org/cqframework/cql/cql2elm/SystemFunctionResolver.java b/Src/java/cql-to-elm/src/main/java/org/cqframework/cql/cql2elm/SystemFunctionResolver.java index ed2a5a484..f9488cc94 100644 --- a/Src/java/cql-to-elm/src/main/java/org/cqframework/cql/cql2elm/SystemFunctionResolver.java +++ b/Src/java/cql-to-elm/src/main/java/org/cqframework/cql/cql2elm/SystemFunctionResolver.java @@ -176,15 +176,18 @@ else if (dateTimeConversion != null) { return resolveTime(fun); } - case "Now": { + case "Now": + case "now": { return resolveNow(fun); } - case "Today": { + case "Today": + case "today": { return resolveToday(fun); } - case "TimeOfDay": { + case "TimeOfDay": + case "timeOfDay": { return resolveTimeOfDay(fun); } diff --git a/Src/java/cql-to-elm/src/main/java/org/cqframework/cql/cql2elm/SystemMethodResolver.java b/Src/java/cql-to-elm/src/main/java/org/cqframework/cql/cql2elm/SystemMethodResolver.java index 58232773e..d08ef272b 100644 --- a/Src/java/cql-to-elm/src/main/java/org/cqframework/cql/cql2elm/SystemMethodResolver.java +++ b/Src/java/cql-to-elm/src/main/java/org/cqframework/cql/cql2elm/SystemMethodResolver.java @@ -451,7 +451,8 @@ public Expression resolveMethod(Expression target, String functionName, cqlParse case "matches": return builder.resolveFunction(null, "Matches", getParams(target, ctx)); case "memberOf": return builder.resolveFunction(null, "InValueSet", getParams(target, ctx)); case "not": return builder.resolveFunction(null, "Not", getParams(target, ctx)); - case "now": return builder.resolveFunction(null, "Now", getParams(target, ctx)); + //now could never resolve as a method because it has no arguments + //case "now": return builder.resolveFunction(null, "Now", getParams(target, ctx)); case "ofType": return createOfType(target, functionName, ctx); case "power": return builder.resolveFunction(null, "Power", getParams(target, ctx)); case "repeat": return createRepeat(target, functionName, ctx); @@ -478,12 +479,14 @@ public Expression resolveMethod(Expression target, String functionName, cqlParse case "supersetOf": return builder.resolveFunction(null, "Includes", getParams(target, ctx)); case "tail": return builder.resolveFunction(null, "Tail", getParams(target, ctx)); case "take": return builder.resolveFunction(null, "Take", getParams(target, ctx)); - case "timeOfDay": return builder.resolveFunction(null, "TimeOfDay", getParams(target, ctx)); + //timeOfDay could never resolve as a method because it has no arguments + //case "timeOfDay": return builder.resolveFunction(null, "TimeOfDay", getParams(target, ctx)); case "toBoolean": return builder.resolveFunction(null, "ToBoolean", getParams(target, ctx)); case "toChars": return builder.resolveFunction(null, "ToChars", getParams(target, ctx)); case "toDate": return builder.resolveFunction(null, "ToDate", getParams(target, ctx)); case "toDateTime": return builder.resolveFunction(null, "ToDateTime", getParams(target, ctx)); - case "today": return builder.resolveFunction(null, "Today", getParams(target, ctx)); + //today could never resolve as a method because it has no arguments + //case "today": return builder.resolveFunction(null, "Today", getParams(target, ctx)); case "toDecimal": return builder.resolveFunction(null, "ToDecimal", getParams(target, ctx)); case "toInteger": return builder.resolveFunction(null, "ToInteger", getParams(target, ctx)); case "toQuantity": return builder.resolveFunction(null, "ToQuantity", getParams(target, ctx)); diff --git a/Src/java/cql-to-elm/src/main/java/org/cqframework/cql/cql2elm/model/SystemLibraryHelper.java b/Src/java/cql-to-elm/src/main/java/org/cqframework/cql/cql2elm/model/SystemLibraryHelper.java index 5b55ee710..ed6ef4369 100644 --- a/Src/java/cql-to-elm/src/main/java/org/cqframework/cql/cql2elm/model/SystemLibraryHelper.java +++ b/Src/java/cql-to-elm/src/main/java/org/cqframework/cql/cql2elm/model/SystemLibraryHelper.java @@ -496,6 +496,7 @@ public static TranslatedLibrary load(SystemModel systemModel, TypeBuilder tb) { add(system, tb, new Operator("DurationBetween", new Signature(systemModel.getDate(), systemModel.getDate()), systemModel.getInteger())); add(system, tb, new Operator("DurationBetween", new Signature(systemModel.getTime(), systemModel.getTime()), systemModel.getInteger())); add(system, tb, new Operator("Now", new Signature(), systemModel.getDateTime())); + add(system, tb, new Operator("now", new Signature(), systemModel.getDateTime())); add(system, tb, new Operator("SameAs", new Signature(systemModel.getDateTime(), systemModel.getDateTime()), systemModel.getBoolean())); add(system, tb, new Operator("SameAs", new Signature(systemModel.getDate(), systemModel.getDate()), systemModel.getBoolean())); add(system, tb, new Operator("SameAs", new Signature(systemModel.getTime(), systemModel.getTime()), systemModel.getBoolean())); @@ -509,11 +510,13 @@ public static TranslatedLibrary load(SystemModel systemModel, TypeBuilder tb) { add(system, tb, new Operator("Subtract", new Signature(systemModel.getDate(), systemModel.getQuantity()), systemModel.getDate())); add(system, tb, new Operator("Subtract", new Signature(systemModel.getTime(), systemModel.getQuantity()), systemModel.getTime())); add(system, tb, new Operator("Today", new Signature(), systemModel.getDate())); + add(system, tb, new Operator("today", new Signature(), systemModel.getDate())); add(system, tb, new Operator("Time", new Signature(systemModel.getInteger()), systemModel.getTime())); add(system, tb, new Operator("Time", new Signature(systemModel.getInteger(), systemModel.getInteger()), systemModel.getTime())); add(system, tb, new Operator("Time", new Signature(systemModel.getInteger(), systemModel.getInteger(), systemModel.getInteger()), systemModel.getTime())); add(system, tb, new Operator("Time", new Signature(systemModel.getInteger(), systemModel.getInteger(), systemModel.getInteger(), systemModel.getInteger()), systemModel.getTime())); add(system, tb, new Operator("TimeOfDay", new Signature(), systemModel.getTime())); + add(system, tb, new Operator("timeOfDay", new Signature(), systemModel.getTime())); // Interval Operators // After(interval, interval) : Boolean diff --git a/Src/java/cql-to-elm/src/test/java/org/cqframework/cql/cql2elm/fhir/r401/BaseTest.java b/Src/java/cql-to-elm/src/test/java/org/cqframework/cql/cql2elm/fhir/r401/BaseTest.java index 50b8471dc..71fd4bda3 100644 --- a/Src/java/cql-to-elm/src/test/java/org/cqframework/cql/cql2elm/fhir/r401/BaseTest.java +++ b/Src/java/cql-to-elm/src/test/java/org/cqframework/cql/cql2elm/fhir/r401/BaseTest.java @@ -410,6 +410,114 @@ public void testFHIRWithoutNamespaces() throws IOException { assertThat(includeDef.getVersion(), is("4.0.1")); } + @Test + public void testFHIRPath() throws IOException { + CqlTranslator translator = TestUtils.runSemanticTest("fhir/r401/TestFHIRPath.cql", 0); + TranslatedLibrary library = translator.getTranslatedLibrary(); + ExpressionDef expressionDef = library.resolveExpressionRef("TestNow"); + assertThat(expressionDef, notNullValue()); + assertThat(expressionDef.getExpression(), instanceOf(Now.class)); + expressionDef = library.resolveExpressionRef("TestToday"); + assertThat(expressionDef, notNullValue()); + assertThat(expressionDef.getExpression(), instanceOf(Today.class)); + expressionDef = library.resolveExpressionRef("TestTimeOfDay"); + assertThat(expressionDef.getExpression(), instanceOf(TimeOfDay.class)); + String xml = translator.toXml(); + assertThat(xml, notNullValue()); + /* + // Doesn't work because this literal adds carriage returns + assertThat(xml, is("\n" + + "\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + "\n")); + */ + } + @Test public void testFHIRPathLiteralStringEscapes() throws IOException { CqlTranslator translator = TestUtils.runSemanticTest("fhir/r401/TestFHIRPathLiteralStringEscapes.cql", 0); diff --git a/Src/java/cql-to-elm/src/test/resources/org/cqframework/cql/cql2elm/fhir/r401/TestFHIRPath.cql b/Src/java/cql-to-elm/src/test/resources/org/cqframework/cql/cql2elm/fhir/r401/TestFHIRPath.cql new file mode 100644 index 000000000..f9c3d1883 --- /dev/null +++ b/Src/java/cql-to-elm/src/test/resources/org/cqframework/cql/cql2elm/fhir/r401/TestFHIRPath.cql @@ -0,0 +1,20 @@ +library TestFHIRPath + +using FHIR version '4.0.1' + +include FHIRHelpers version '4.0.1' + +context Patient + +define TestToday: today() + +define TestNow: now() + +define TestTimeOfDay: timeOfDay() + +define Encounters: [Encounter] + +define TestTodayInWhere: Encounters.where(status = 'in-progress' and period.end <= today() - 72 hours) + +define TestNowInWhere: Encounters.where(status = 'in-progress' and period.end <= now() - 72 hours) + From c8b5f4e9e3362b76a8a08b9280b4f3e215981b35 Mon Sep 17 00:00:00 2001 From: Bryn Rhodes Date: Fri, 17 Jun 2022 13:35:49 -0600 Subject: [PATCH 2/3] Added additional implicit conversions from FHIR.date to DateTime and FHIR.integer to Decimal --- .../org/cqframework/cql/cql2elm/fhir/r401/TestFHIRPath.cql | 1 + .../quick/src/main/resources/org/hl7/fhir/FHIRHelpers-4.0.1.cql | 2 ++ .../src/main/resources/org/hl7/fhir/fhir-modelinfo-4.0.1.xml | 2 ++ 3 files changed, 5 insertions(+) diff --git a/Src/java/cql-to-elm/src/test/resources/org/cqframework/cql/cql2elm/fhir/r401/TestFHIRPath.cql b/Src/java/cql-to-elm/src/test/resources/org/cqframework/cql/cql2elm/fhir/r401/TestFHIRPath.cql index f9c3d1883..189f6c3ce 100644 --- a/Src/java/cql-to-elm/src/test/resources/org/cqframework/cql/cql2elm/fhir/r401/TestFHIRPath.cql +++ b/Src/java/cql-to-elm/src/test/resources/org/cqframework/cql/cql2elm/fhir/r401/TestFHIRPath.cql @@ -18,3 +18,4 @@ define TestTodayInWhere: Encounters.where(status = 'in-progress' and period.end define TestNowInWhere: Encounters.where(status = 'in-progress' and period.end <= now() - 72 hours) +define TestNow2: Patient.birthDate < now() \ No newline at end of file diff --git a/Src/java/quick/src/main/resources/org/hl7/fhir/FHIRHelpers-4.0.1.cql b/Src/java/quick/src/main/resources/org/hl7/fhir/FHIRHelpers-4.0.1.cql index 8261163ad..cae14c960 100644 --- a/Src/java/quick/src/main/resources/org/hl7/fhir/FHIRHelpers-4.0.1.cql +++ b/Src/java/quick/src/main/resources/org/hl7/fhir/FHIRHelpers-4.0.1.cql @@ -503,7 +503,9 @@ define function ToString(value base64Binary): value.value define function ToBoolean(value boolean): value.value define function ToDate(value date): value.value define function ToDateTime(value dateTime): value.value +define function ToDateTime(value date): ToDateTime(value.value) define function ToDecimal(value decimal): value.value +define function ToDecimal(value integer): ToDecimal(value.value) define function ToDateTime(value instant): value.value define function ToInteger(value integer): value.value define function ToString(value string): value.value diff --git a/Src/java/quick/src/main/resources/org/hl7/fhir/fhir-modelinfo-4.0.1.xml b/Src/java/quick/src/main/resources/org/hl7/fhir/fhir-modelinfo-4.0.1.xml index c4a8caba7..b4f7e5196 100644 --- a/Src/java/quick/src/main/resources/org/hl7/fhir/fhir-modelinfo-4.0.1.xml +++ b/Src/java/quick/src/main/resources/org/hl7/fhir/fhir-modelinfo-4.0.1.xml @@ -28798,6 +28798,7 @@ + @@ -28897,6 +28898,7 @@ + From b46949cc13eacad2579282b57ae5801dc20fd49c Mon Sep 17 00:00:00 2001 From: Bryn Rhodes Date: Fri, 17 Jun 2022 14:16:17 -0600 Subject: [PATCH 3/3] Backing out additional implicit conversions, they cause ambiguous resolutions with other areas. --- .../org/cqframework/cql/cql2elm/fhir/r401/TestFHIRPath.cql | 2 +- .../quick/src/main/resources/org/hl7/fhir/FHIRHelpers-4.0.1.cql | 2 -- .../src/main/resources/org/hl7/fhir/fhir-modelinfo-4.0.1.xml | 2 -- 3 files changed, 1 insertion(+), 5 deletions(-) diff --git a/Src/java/cql-to-elm/src/test/resources/org/cqframework/cql/cql2elm/fhir/r401/TestFHIRPath.cql b/Src/java/cql-to-elm/src/test/resources/org/cqframework/cql/cql2elm/fhir/r401/TestFHIRPath.cql index 189f6c3ce..0f27a1624 100644 --- a/Src/java/cql-to-elm/src/test/resources/org/cqframework/cql/cql2elm/fhir/r401/TestFHIRPath.cql +++ b/Src/java/cql-to-elm/src/test/resources/org/cqframework/cql/cql2elm/fhir/r401/TestFHIRPath.cql @@ -18,4 +18,4 @@ define TestTodayInWhere: Encounters.where(status = 'in-progress' and period.end define TestNowInWhere: Encounters.where(status = 'in-progress' and period.end <= now() - 72 hours) -define TestNow2: Patient.birthDate < now() \ No newline at end of file +define TestNow2: Patient.birthDate < date from now() \ No newline at end of file diff --git a/Src/java/quick/src/main/resources/org/hl7/fhir/FHIRHelpers-4.0.1.cql b/Src/java/quick/src/main/resources/org/hl7/fhir/FHIRHelpers-4.0.1.cql index cae14c960..8261163ad 100644 --- a/Src/java/quick/src/main/resources/org/hl7/fhir/FHIRHelpers-4.0.1.cql +++ b/Src/java/quick/src/main/resources/org/hl7/fhir/FHIRHelpers-4.0.1.cql @@ -503,9 +503,7 @@ define function ToString(value base64Binary): value.value define function ToBoolean(value boolean): value.value define function ToDate(value date): value.value define function ToDateTime(value dateTime): value.value -define function ToDateTime(value date): ToDateTime(value.value) define function ToDecimal(value decimal): value.value -define function ToDecimal(value integer): ToDecimal(value.value) define function ToDateTime(value instant): value.value define function ToInteger(value integer): value.value define function ToString(value string): value.value diff --git a/Src/java/quick/src/main/resources/org/hl7/fhir/fhir-modelinfo-4.0.1.xml b/Src/java/quick/src/main/resources/org/hl7/fhir/fhir-modelinfo-4.0.1.xml index b4f7e5196..c4a8caba7 100644 --- a/Src/java/quick/src/main/resources/org/hl7/fhir/fhir-modelinfo-4.0.1.xml +++ b/Src/java/quick/src/main/resources/org/hl7/fhir/fhir-modelinfo-4.0.1.xml @@ -28798,7 +28798,6 @@ - @@ -28898,7 +28897,6 @@ -