From 92124b7c8fd93ba08d2a9e3f49a32684df47e3ba Mon Sep 17 00:00:00 2001 From: Alexander Kiel Date: Tue, 30 Jul 2024 12:27:53 +0200 Subject: [PATCH] Optimize CQL Logical Expressions Closes: #1944 --- cljfmt.edn | 1 + .../blaze/elm/compiler/logical_operators.clj | 46 ++++- modules/cql/src/blaze/elm/compiler/macros.clj | 10 +- .../compiler/arithmetic_operators_test.clj | 109 ++++++++++- .../compiler/conditional_operators_test.clj | 20 +-- .../elm/compiler/date_time_operators_test.clj | 11 +- .../elm/compiler/interval_operators_test.clj | 23 ++- .../test/blaze/elm/compiler/library_test.clj | 114 +++++++++++- .../elm/compiler/list_operators_test.clj | 60 ++++--- .../elm/compiler/logical_operators_test.clj | 167 +++++++++++++++-- .../compiler/nullological_operators_test.clj | 37 +++- .../blaze/elm/compiler/reusing_logic_test.clj | 8 +- .../elm/compiler/string_operators_test.clj | 44 ++++- .../cql/test/blaze/elm/compiler/test_util.clj | 59 ++++-- .../elm/compiler/type_operators_test.clj | 170 +++++++++++++++--- modules/cql/test/data_readers.clj | 4 +- 16 files changed, 763 insertions(+), 120 deletions(-) diff --git a/cljfmt.edn b/cljfmt.edn index f65b7b03c..01b8feb27 100644 --- a/cljfmt.edn +++ b/cljfmt.edn @@ -8,6 +8,7 @@ do-sync [[:block 1]] do-async [[:block 1]] has-form [[:block 1]] + testing-optimize [[:block 1]] reg-collector [[:block 1]] deftests [[:block 1]] satisfies-prop [[:block 1]] diff --git a/modules/cql/src/blaze/elm/compiler/logical_operators.clj b/modules/cql/src/blaze/elm/compiler/logical_operators.clj index ff0a87017..1511f9d16 100644 --- a/modules/cql/src/blaze/elm/compiler/logical_operators.clj +++ b/modules/cql/src/blaze/elm/compiler/logical_operators.clj @@ -23,7 +23,12 @@ (-resolve-params [_ parameters] (core/resolve-params-helper and-nil-op parameters x)) (-optimize [_ node] - (core/optimize-helper and-nil-op node x)) + (let [x (core/-optimize x node)] + (condp identical? x + true nil + false false + nil nil + (and-nil-op x)))) (-eval [_ context resource scope] (when (false? (core/-eval x context resource scope)) false)) @@ -68,6 +73,8 @@ b-count (or (core/-patient-count b-op) Long/MAX_VALUE)] (- a-count b-count))) +(declare dynamic-and) + (defn and-op [a b] (reify-expr core/Expression (-attach-cache [_ cache] @@ -105,7 +112,12 @@ (-resolve-params [_ parameters] (core/resolve-params-helper and-op parameters a b)) (-optimize [_ node] - (core/optimize-helper and-op node a b)) + (let [a (core/-optimize a node)] + (condp identical? a + true (core/-optimize b node) + false false + nil (nil-and (core/-optimize b node)) + (dynamic-and a (core/-optimize b node))))) (-eval [_ context resource scope] (let [a (core/-eval a context resource scope)] (if (false? a) @@ -160,7 +172,12 @@ (-resolve-params [_ parameters] (core/resolve-params-helper or-nil-op parameters x)) (-optimize [_ node] - (core/optimize-helper or-nil-op node x)) + (let [x (core/-optimize x node)] + (condp identical? x + true true + false nil + nil nil + (or-nil-op x)))) (-eval [_ context resource scope] (when (true? (core/-eval x context resource scope)) true)) @@ -212,6 +229,8 @@ b-count (or (core/-patient-count b-op) Long/MAX_VALUE)] (- b-count a-count))) +(declare dynamic-or) + (defn or-op [a b] (reify-expr core/Expression (-attach-cache [_ cache] @@ -249,7 +268,12 @@ (-resolve-params [_ parameters] (core/resolve-params-helper or-op parameters a b)) (-optimize [_ node] - (core/optimize-helper or-op node a b)) + (let [a (core/-optimize a node)] + (condp identical? a + true true + false (core/-optimize b node) + nil (nil-or (core/-optimize b node)) + (dynamic-or a (core/-optimize b node))))) (-eval [_ context resource scope] (let [a (core/-eval a context resource scope)] (if (true? a) @@ -281,6 +305,8 @@ (dynamic-or a (core/compile* context b))))) ;; 13.5 Xor +(declare dynamic-xor) + (defn- xor-op [a b] (reify-expr core/Expression (-attach-cache [_ cache] @@ -290,7 +316,17 @@ (-resolve-params [_ parameters] (core/resolve-params-helper xor-op parameters a b)) (-optimize [_ node] - (core/optimize-helper xor-op node a b)) + (let [a (core/-optimize a node)] + (condp identical? a + true (let [b (core/-optimize b node)] + (condp identical? b + true false + false true + nil nil + (not-op b))) + false (core/-optimize b node) + nil nil + (dynamic-xor a (core/-optimize b node))))) (-eval [_ context resource scope] (when-some [a (core/-eval a context resource scope)] (when-some [b (core/-eval b context resource scope)] diff --git a/modules/cql/src/blaze/elm/compiler/macros.clj b/modules/cql/src/blaze/elm/compiler/macros.clj index a2b507b7e..b6ff369dc 100644 --- a/modules/cql/src/blaze/elm/compiler/macros.clj +++ b/modules/cql/src/blaze/elm/compiler/macros.clj @@ -239,13 +239,15 @@ ~elm-expr) `(~op (core/-resolve-params ~operand ~'parameters)))) - (~'-optimize [~'_ ~'node] + (~'-optimize [~'_ ~node] ~(if elm-expr-binding `(~op - (core/-optimize ~operand ~'node) + (core/-optimize ~operand ~node) ~elm-expr) - `(~op - (core/-optimize ~operand ~'node)))) + `(let [~operand (core/-optimize ~operand ~node)] + (if (core/static? ~operand) + (let [~operand-binding ~operand] ~@body) + (~op ~operand))))) (~'-eval [~'_ ~context ~resource ~scope] (let ~(generate-binding-vector operand-binding `(core/-eval ~operand ~context ~resource ~scope) diff --git a/modules/cql/test/blaze/elm/compiler/arithmetic_operators_test.clj b/modules/cql/test/blaze/elm/compiler/arithmetic_operators_test.clj index 25d5cae43..7903e8ccb 100644 --- a/modules/cql/test/blaze/elm/compiler/arithmetic_operators_test.clj +++ b/modules/cql/test/blaze/elm/compiler/arithmetic_operators_test.clj @@ -91,7 +91,17 @@ (ctu/testing-unary-null elm/abs) - (ctu/testing-unary-op elm/abs)) + (ctu/testing-unary-op elm/abs) + + (ctu/testing-optimize elm/abs + (testing "0" + #ctu/optimize-to 0 + 0) + + (testing "-1, 1" + #ctu/optimize-to -1 + #ctu/optimize-to 1 + 1))) ;; 16.2. Add ;; @@ -377,7 +387,16 @@ (ctu/testing-unary-null elm/ceiling) - (ctu/testing-unary-op elm/ceiling)) + (ctu/testing-unary-op elm/ceiling) + + (ctu/testing-optimize elm/ceiling + (testing "1" + #ctu/optimize-to 1 + 1) + + (testing "1.1" + #ctu/optimize-to 1.1M + 2))) ;; 16.4. Divide ;; @@ -476,11 +495,21 @@ (deftest compile-exp-test (are [x res] (= res (c/compile {} (elm/exp x))) #elm/integer "0" 1M + #elm/integer "1" 2.71828183M #elm/decimal "0" 1M) (ctu/testing-unary-null elm/exp) - (ctu/testing-unary-op elm/exp)) + (ctu/testing-unary-op elm/exp) + + (ctu/testing-optimize elm/exp + (testing "0" + #ctu/optimize-to 0 + 1M) + + (testing "1" + #ctu/optimize-to 1 + 2.71828183M))) ;; 16.6. Floor ;; @@ -495,7 +524,16 @@ (ctu/testing-unary-null elm/floor) - (ctu/testing-unary-op elm/floor)) + (ctu/testing-unary-op elm/floor) + + (ctu/testing-optimize elm/floor + (testing "1" + #ctu/optimize-to 1 + 1) + + (testing "1.1" + #ctu/optimize-to 1.1M + 1))) ;; 16.7. HighBoundary ;; @@ -579,7 +617,16 @@ (ctu/testing-unary-null elm/ln) - (ctu/testing-unary-op elm/ln)) + (ctu/testing-unary-op elm/ln) + + (ctu/testing-optimize elm/ln + (testing "1" + #ctu/optimize-to 1 + 0M) + + (testing "2" + #ctu/optimize-to 2 + 0.69314718M))) ;; 16.11. MaxValue ;; @@ -774,7 +821,16 @@ (ctu/testing-unary-null elm/negate) - (ctu/testing-unary-op elm/negate)) + (ctu/testing-unary-op elm/negate) + + (ctu/testing-optimize elm/negate + (testing "1" + #ctu/optimize-to 1 + -1) + + (testing "1M" + #ctu/optimize-to 1M + -1M))) ;; 16.16. Power ;; @@ -889,7 +945,20 @@ (ctu/testing-unary-null elm/predecessor) - (ctu/testing-unary-op elm/predecessor)) + (ctu/testing-unary-op elm/predecessor) + + (ctu/testing-optimize elm/predecessor + (testing "Integer 0" + #ctu/optimize-to 0 + -1) + + (testing "Decimal 0" + #ctu/optimize-to 0M + -1E-8M) + + (testing "Date 2019" + #ctu/optimize-to (system/date 2019) + (system/date 2018)))) ;; 16.19. Round ;; @@ -1227,7 +1296,20 @@ (ctu/testing-unary-null elm/successor) - (ctu/testing-unary-op elm/successor)) + (ctu/testing-unary-op elm/successor) + + (ctu/testing-optimize elm/successor + (testing "Integer 0" + #ctu/optimize-to 0 + 1) + + (testing "Decimal 0" + #ctu/optimize-to 0M + 1E-8M) + + (testing "Date 2019" + #ctu/optimize-to (system/date 2019) + (system/date 2020)))) ;; 16.22. Truncate ;; @@ -1242,7 +1324,16 @@ (ctu/testing-unary-null elm/truncate) - (ctu/testing-unary-op elm/truncate)) + (ctu/testing-unary-op elm/truncate) + + (ctu/testing-optimize elm/truncate + (testing "Integer 1" + #ctu/optimize-to 1 + 1) + + (testing "Decimal 1.1" + #ctu/optimize-to 1.1M + 1))) ;; 16.23. TruncatedDivide ;; diff --git a/modules/cql/test/blaze/elm/compiler/conditional_operators_test.clj b/modules/cql/test/blaze/elm/compiler/conditional_operators_test.clj index 999eb16b7..ef39f7284 100644 --- a/modules/cql/test/blaze/elm/compiler/conditional_operators_test.clj +++ b/modules/cql/test/blaze/elm/compiler/conditional_operators_test.clj @@ -223,19 +223,19 @@ (testing "multi-conditional" (let [elm {:type "Case" :caseItem - [{:when {:type "Optimizeable" :id "w"} - :then {:type "Optimizeable" :id "t"}}] - :else {:type "Optimizeable" :id "e"}} + [{:when #ctu/optimizeable "w" + :then #ctu/optimizeable "t"}] + :else #ctu/optimizeable "e"} expr (st/with-instrument-disabled (c/optimize nil (c/compile {} elm)))] (has-form expr '(case (optimized "w") (optimized "t") (optimized "e"))))) (testing "comparand-based" (let [elm {:type "Case" - :comparand {:type "Optimizeable" :id "c"} + :comparand #ctu/optimizeable "c" :caseItem - [{:when {:type "Optimizeable" :id "w"} - :then {:type "Optimizeable" :id "t"}}] - :else {:type "Optimizeable" :id "e"}} + [{:when #ctu/optimizeable "w" + :then #ctu/optimizeable "t"}] + :else #ctu/optimizeable "e"} expr (st/with-instrument-disabled (c/optimize nil (c/compile {} elm)))] (has-form expr '(case (optimized "c") (optimized "w") (optimized "t") (optimized "e")))))) @@ -333,9 +333,9 @@ (has-form expr '(if "c" "t" "e")))) (testing "optimize" - (let [elm #elm/if [{:type "Optimizeable" :id "c"} - {:type "Optimizeable" :id "t"} - {:type "Optimizeable" :id "e"}] + (let [elm #elm/if [#ctu/optimizeable "c" + #ctu/optimizeable "t" + #ctu/optimizeable "e"] expr (st/with-instrument-disabled (c/optimize nil (c/compile {} elm)))] (has-form expr '(if (optimized "c") (optimized "t") (optimized "e"))))) diff --git a/modules/cql/test/blaze/elm/compiler/date_time_operators_test.clj b/modules/cql/test/blaze/elm/compiler/date_time_operators_test.clj index eceb96b75..1863a74b0 100644 --- a/modules/cql/test/blaze/elm/compiler/date_time_operators_test.clj +++ b/modules/cql/test/blaze/elm/compiler/date_time_operators_test.clj @@ -272,7 +272,16 @@ (ctu/testing-unary-null elm/date-from) - (ctu/testing-unary-op elm/date-from)) + (ctu/testing-unary-op elm/date-from) + + (ctu/testing-optimize elm/date-from + (testing "2019" + #ctu/optimize-to (system/date 2019) + (system/date 2019)) + + (testing "2019-04-17T12:48" + #ctu/optimize-to (system/date-time 2019 4 17 12 48) + (system/date 2019 4 17)))) ;; 18.8. DateTime ;; diff --git a/modules/cql/test/blaze/elm/compiler/interval_operators_test.clj b/modules/cql/test/blaze/elm/compiler/interval_operators_test.clj index 5152577b3..7a7404141 100644 --- a/modules/cql/test/blaze/elm/compiler/interval_operators_test.clj +++ b/modules/cql/test/blaze/elm/compiler/interval_operators_test.clj @@ -573,7 +573,12 @@ (ctu/testing-unary-null elm/end) - (ctu/testing-unary-op elm/end)) + (ctu/testing-unary-op elm/end) + + (ctu/testing-optimize elm/end + (testing "[1 2]" + #ctu/optimize-to (interval 1 2) + 2))) ;; 19.7. Ends ;; @@ -1103,7 +1108,12 @@ (ctu/testing-unary-null elm/start) - (ctu/testing-unary-op elm/start)) + (ctu/testing-unary-op elm/start) + + (ctu/testing-optimize elm/start + (testing "[1 2]" + #ctu/optimize-to (interval 1 2) + 1))) ;; 19.30. Starts ;; @@ -1178,8 +1188,13 @@ (deftest compile-width-test (testing "Integer" (are [x res] (= res (ctu/compile-unop elm/width elm/interval x)) - [#elm/integer "1" #elm/integer "2"] 1)) + [#elm/integer "-1" #elm/integer "1"] 2)) (ctu/testing-unary-null elm/width) - (ctu/testing-unary-op elm/width)) + (ctu/testing-unary-op elm/width) + + (ctu/testing-optimize elm/width + (testing "[-1 1]" + #ctu/optimize-to (interval -1 1) + 2))) diff --git a/modules/cql/test/blaze/elm/compiler/library_test.clj b/modules/cql/test/blaze/elm/compiler/library_test.clj index b692a8343..3c7f886bc 100644 --- a/modules/cql/test/blaze/elm/compiler/library_test.clj +++ b/modules/cql/test/blaze/elm/compiler/library_test.clj @@ -401,7 +401,119 @@ (library/resolve-all-refs) (library/optimize node)) ["InInitialPopulation" :context] := "Patient" - ["InInitialPopulation" expr-form] := false))))))) + ["InInitialPopulation" expr-form] := false))))) + + (testing "with a disjunction of two such queries" + (let [library (t/translate "library Retrieve + using FHIR version '4.0.0' + include FHIRHelpers version '4.0.0' + + codesystem atc: 'http://fhir.de/CodeSystem/bfarm/atc' + + context Unfiltered + + define MedicationRefsA: + from [Medication: Code 'A10BF01' from atc] M + return 'Medication/' + M.id + + define MedicationRefsB: + from [Medication: Code 'A10BB31' from atc] M + return 'Medication/' + M.id + + context Patient + + define InInitialPopulation: + exists (from [MedicationAdministration] M + where M.medication.reference in MedicationRefsA) or + exists (from [MedicationAdministration] M + where M.medication.reference in MedicationRefsB)")] + (with-system [{:blaze.db/keys [node]} mem-node-config] + (let [{:keys [expression-defs]} (library/compile-library node library default-opts)] + (given expression-defs + ["InInitialPopulation" :context] := "Patient" + ["InInitialPopulation" expr-form] := + '(or + (exists + (eduction-query + (filter + (fn [M] + (contains + (expr-ref "MedicationRefsA") + (call "ToString" (:reference (:medication M)))))) + (retrieve "MedicationAdministration"))) + (exists + (eduction-query + (filter + (fn [M] + (contains + (expr-ref "MedicationRefsB") + (call "ToString" (:reference (:medication M)))))) + (retrieve "MedicationAdministration"))))) + + (testing "the whole exists expression optimizes to false" + (given (->> (library/eval-unfiltered {:db (d/db node) + :now (OffsetDateTime/now)} + expression-defs) + (library/resolve-all-refs) + (library/optimize node)) + ["InInitialPopulation" :context] := "Patient" + ["InInitialPopulation" expr-form] := false)))))) + + (testing "with the second query having Medication refs" + (let [library (t/translate "library Retrieve + using FHIR version '4.0.0' + include FHIRHelpers version '4.0.0' + + codesystem atc: 'http://fhir.de/CodeSystem/bfarm/atc' + + context Unfiltered + + define MedicationRefsA: + from [Medication: Code 'A10BF01' from atc] M + return 'Medication/' + M.id + + context Patient + + define InInitialPopulation: + exists (from [MedicationAdministration] M + where M.medication.reference in MedicationRefsA) or + exists (from [MedicationAdministration] M + where M.medication.reference in {'Medication/0'})")] + (with-system [{:blaze.db/keys [node]} mem-node-config] + (let [{:keys [expression-defs]} (library/compile-library node library default-opts)] + (given expression-defs + ["InInitialPopulation" :context] := "Patient" + ["InInitialPopulation" expr-form] := + '(or + (exists + (eduction-query + (filter + (fn [M] + (contains + (expr-ref "MedicationRefsA") + (call "ToString" (:reference (:medication M)))))) + (retrieve "MedicationAdministration"))) + (exists + (eduction-query + (filter + (fn [M] + (contains + ["Medication/0"] + (call "ToString" (:reference (:medication M)))))) + (retrieve "MedicationAdministration"))))) + + (testing "the first query optimizes away" + (given (->> (library/eval-unfiltered {:db (d/db node) + :now (OffsetDateTime/now)} + expression-defs) + (library/resolve-all-refs) + (library/optimize node)) + ["InInitialPopulation" :context] := "Patient" + ["InInitialPopulation" expr-form] := + '(exists + (eduction-query + (matcher [["medication" "Medication/0"]]) + (retrieve "MedicationAdministration"))))))))))) (testing "with compile-time error" (testing "function" diff --git a/modules/cql/test/blaze/elm/compiler/list_operators_test.clj b/modules/cql/test/blaze/elm/compiler/list_operators_test.clj index f3eb6a1e4..77f192602 100644 --- a/modules/cql/test/blaze/elm/compiler/list_operators_test.clj +++ b/modules/cql/test/blaze/elm/compiler/list_operators_test.clj @@ -12,6 +12,7 @@ [blaze.elm.compiler-spec] [blaze.elm.compiler.core :as core] [blaze.elm.compiler.core-spec] + [blaze.elm.compiler.list-operators] [blaze.elm.compiler.macros :refer [reify-expr]] [blaze.elm.compiler.test-util :as ctu :refer [has-form]] [blaze.elm.expression :as expr] @@ -126,7 +127,7 @@ (has-form expr '(list 1)))) (testing "optimize" - (let [elm #elm/list [{:type "Optimizeable" :id "x"}] + (let [elm #elm/list [#ctu/optimizeable "x"] expr (st/with-instrument-disabled (c/optimize nil (c/compile {} elm)))] (has-form expr '(list (optimized "x"))))) @@ -224,7 +225,12 @@ (ctu/testing-unary-null elm/distinct) - (ctu/testing-unary-op elm/distinct)) + (ctu/testing-unary-op elm/distinct) + + (ctu/testing-optimize elm/distinct + (testing "[1 1]" + #ctu/optimize-to [1 1] + [1]))) ;; 20.5. Equal ;; @@ -263,16 +269,6 @@ (-form [_] 'exists-test))) -(defmethod elm-spec/expression :elm.spec.type/optimize-to-empty-list [_] - map?) - -(defmethod core/compile* :elm.compiler.type/optimize-to-empty-list [_ _] - (reify-expr core/Expression - (-optimize [_ _] - []) - (-form [_] - (list 'optimize-to-empty-list)))) - (deftest compile-exists-test (testing "Static" (are [list res] (= res (c/compile {} (elm/exists list))) @@ -397,11 +393,16 @@ (ctu/testing-unary-optimize elm/exists) (testing "optimize to false if operand optimizes to an empty list" - (let [elm (elm/exists {:type "OptimizeToEmptyList"}) + (let [elm (elm/exists #ctu/optimize-to []) expr (c/compile {:eval-context "Patient"} elm) expr (st/with-instrument-disabled (c/optimize nil expr))] (has-form expr false))) + (ctu/testing-optimize elm/exists + (testing "empty list" + #ctu/optimize-to [] + false)) + (ctu/testing-unary-equals-hash-code elm/exists) (ctu/testing-unary-form elm/exists)) @@ -466,8 +467,8 @@ (testing "optimize" (let [elm {:type "Filter" - :source {:type "Optimizeable" :id "x"} - :condition {:type "Optimizeable" :id "y"} + :source #ctu/optimizeable "x" + :condition #ctu/optimizeable "y" :scope "A"} expr (st/with-instrument-disabled (c/optimize nil (c/compile {} elm)))] (has-form expr '(filter (optimized "x") (optimized "y") "A")))) @@ -510,8 +511,8 @@ (testing "optimize" (let [elm {:type "Filter" - :source {:type "Optimizeable" :id "x"} - :condition {:type "Optimizeable" :id "y"}} + :source #ctu/optimizeable "x" + :condition #ctu/optimizeable "y"} expr (st/with-instrument-disabled (c/optimize nil (c/compile {} elm)))] (has-form expr '(filter (optimized "x") (optimized "y"))))) @@ -542,7 +543,12 @@ (ctu/testing-unary-null elm/first) - (ctu/testing-unary-op elm/first)) + (ctu/testing-unary-op elm/first) + + (ctu/testing-optimize elm/first + (testing "[1 2]" + #ctu/optimize-to [1 2] + 1))) ;; 20.11. Flatten ;; @@ -560,7 +566,12 @@ (ctu/testing-unary-null elm/flatten) - (ctu/testing-unary-op elm/flatten)) + (ctu/testing-unary-op elm/flatten) + + (ctu/testing-optimize elm/flatten + (testing "[1 [2]]" + #ctu/optimize-to [1 [2]] + [1 2]))) ;; 20.12. ForEach ;; @@ -625,7 +636,7 @@ (testing "optimize" (let [elm {:type "ForEach" - :source {:type "Optimizeable" :id "x"} + :source #ctu/optimizeable "x" :element #elm/current "A" :scope "A"} expr (st/with-instrument-disabled (c/optimize nil (c/compile {} elm)))] @@ -667,7 +678,7 @@ (testing "optimize" (let [elm {:type "ForEach" - :source {:type "Optimizeable" :id "x"} + :source #ctu/optimizeable "x" :element #elm/current nil} expr (st/with-instrument-disabled (c/optimize nil (c/compile {} elm)))] (has-form expr '(for-each (optimized "x") current)))) @@ -742,7 +753,12 @@ (ctu/testing-unary-null elm/last) - (ctu/testing-unary-op elm/last)) + (ctu/testing-unary-op elm/last) + + (ctu/testing-optimize elm/last + (testing "[1 2]" + #ctu/optimize-to [1 2] + 2))) ;; 20.19. Not Equal ;; diff --git a/modules/cql/test/blaze/elm/compiler/logical_operators_test.clj b/modules/cql/test/blaze/elm/compiler/logical_operators_test.clj index 8cb4e1753..d78d5ee86 100644 --- a/modules/cql/test/blaze/elm/compiler/logical_operators_test.clj +++ b/modules/cql/test/blaze/elm/compiler/logical_operators_test.clj @@ -9,7 +9,7 @@ [blaze.elm.compiler.core :as core] [blaze.elm.compiler.logical-operators :as ops] [blaze.elm.compiler.macros :refer [reify-expr]] - [blaze.elm.compiler.test-util :as ctu :refer [has-form]] + [blaze.elm.compiler.test-util :as ctu] [blaze.elm.expression.cache :as ec] [blaze.elm.expression.cache.bloom-filter :as bloom-filter] [blaze.elm.literal :as elm] @@ -247,12 +247,49 @@ (ctu/testing-binary-op elm/and) - (testing "optimize" - (doseq [ops [[{:type "Optimizeable" :id "x"} {:type "Null"}] - [{:type "Null"} {:type "Optimizeable" :id "x"}]]] - (let [elm (elm/and ops) - expr (st/with-instrument-disabled (c/optimize nil (c/compile {} elm)))] - (has-form expr '(and nil (optimized "x"))))))) + (ctu/testing-optimize elm/and + (testing "with one null operand" + [#ctu/optimizeable "x" {:type "Null"}] + [{:type "Null"} #ctu/optimizeable "x"] + '(and nil (optimized "x"))) + + (testing "with one null operand and the other operand optimizing to true" + [#ctu/optimize-to true {:type "Null"}] + [{:type "Null"} #ctu/optimize-to true] + nil) + + (testing "with one null operand and the other operand optimizing to false" + [#ctu/optimize-to false {:type "Null"}] + [{:type "Null"} #ctu/optimize-to false] + false) + + (testing "with one null operand and the other operand optimizing to nil" + [#ctu/optimize-to nil {:type "Null"}] + [{:type "Null"} #ctu/optimize-to nil] + nil) + + (testing "with two null operands" + [{:type "Null"} {:type "Null"}] + nil) + + (testing "with one operand optimizing to true" + [#ctu/optimize-to true #ctu/optimizeable "x"] + [#ctu/optimizeable "x" #ctu/optimize-to true] + '(optimized "x")) + + (testing "with both operands optimizing to true" + [#ctu/optimize-to true #ctu/optimize-to true] + true) + + (testing "with one operand optimizing to false" + [#ctu/optimize-to false #ctu/optimizeable "x"] + [#ctu/optimizeable "x" #ctu/optimize-to false] + false) + + (testing "with one operand optimizing to nil" + [#ctu/optimize-to nil #ctu/optimizeable "x"] + [#ctu/optimizeable "x" #ctu/optimize-to nil] + '(and nil (optimized "x"))))) (deftest and-op-patient-count-test (testing "both nil" @@ -315,7 +352,20 @@ (ctu/testing-unary-null elm/not) - (ctu/testing-unary-op elm/not)) + (ctu/testing-unary-op elm/not) + + (ctu/testing-optimize elm/not + (testing "with the operand optimizing to true" + #ctu/optimize-to true + false) + + (testing "with the operand optimizing to false" + #ctu/optimize-to false + true) + + (testing "with the operand optimizing to nil" + #ctu/optimize-to nil + nil))) ;; 13.4. Or ;; @@ -351,6 +401,7 @@ #elm/parameter-ref "false" #elm/boolean "false" false? #elm/parameter-ref "false" #elm/parameter-ref "false" false? #elm/parameter-ref "false" {:type "Null"} nil? + #elm/parameter-ref "false" #elm/parameter-ref "nil" nil? {:type "Null"} #elm/parameter-ref "false" nil? #elm/boolean "true" #elm/parameter-ref "nil" true? @@ -538,12 +589,54 @@ (ctu/testing-binary-optimize elm/or) - (testing "optimize" - (doseq [ops [[{:type "Optimizeable" :id "x"} {:type "Null"}] - [{:type "Null"} {:type "Optimizeable" :id "x"}]]] - (let [elm (elm/or ops) - expr (st/with-instrument-disabled (c/optimize nil (c/compile {} elm)))] - (has-form expr '(or nil (optimized "x")))))) + (ctu/testing-optimize elm/or + (testing "with one null operand" + [#ctu/optimizeable "x" {:type "Null"}] + [{:type "Null"} #ctu/optimizeable "x"] + '(or nil (optimized "x"))) + + (testing "with one null operand and the other operand optimizing to true" + [#ctu/optimize-to true {:type "Null"}] + [{:type "Null"} #ctu/optimize-to true] + true) + + (testing "with one null operand and the other operand optimizing to false" + [#ctu/optimize-to false {:type "Null"}] + [{:type "Null"} #ctu/optimize-to false] + nil) + + (testing "with one null operand and the other operand optimizing to nil" + [#ctu/optimize-to nil {:type "Null"}] + [{:type "Null"} #ctu/optimize-to nil] + nil) + + (testing "with two null operands" + [{:type "Null"} {:type "Null"}] + nil) + + (testing "with the other operand optimizing to true" + [#ctu/optimize-to true {:type "Null"}] + [{:type "Null"} #ctu/optimize-to true] + true) + + (testing "with one operand optimizing to true" + [#ctu/optimize-to true #ctu/optimizeable "x"] + [#ctu/optimizeable "x" #ctu/optimize-to true] + true) + + (testing "with one operand optimizing to false" + [#ctu/optimize-to false #ctu/optimizeable "x"] + [#ctu/optimizeable "x" #ctu/optimize-to false] + '(optimized "x")) + + (testing "with both operands optimizing to false" + [#ctu/optimize-to false #ctu/optimize-to false] + false) + + (testing "with one operand optimizing to nil" + [#ctu/optimize-to nil #ctu/optimizeable "x"] + [#ctu/optimizeable "x" #ctu/optimize-to nil] + '(or nil (optimized "x")))) (ctu/testing-binary-equals-hash-code elm/or) @@ -625,8 +718,12 @@ #elm/boolean "true" #elm/parameter-ref "nil" nil? #elm/parameter-ref "nil" #elm/boolean "true" nil? + #elm/parameter-ref "true" #elm/parameter-ref "nil" nil? + #elm/parameter-ref "nil" #elm/parameter-ref "true" nil? #elm/boolean "false" #elm/parameter-ref "nil" nil? #elm/parameter-ref "nil" #elm/boolean "false" nil? + #elm/parameter-ref "false" #elm/parameter-ref "nil" nil? + #elm/parameter-ref "nil" #elm/parameter-ref "false" nil? {:type "Null"} #elm/parameter-ref "nil" nil? #elm/parameter-ref "nil" {:type "Null"} nil? #elm/parameter-ref "nil" #elm/parameter-ref "nil" nil?)) @@ -675,4 +772,44 @@ #elm/parameter-ref "a" {:type "Null"} true? #elm/parameter-ref "a" #elm/parameter-ref "b" false?)) - (ctu/testing-binary-op elm/xor)) + (ctu/testing-binary-op elm/xor) + + (ctu/testing-optimize elm/xor + (testing "with one null operand" + [#ctu/optimizeable "x" {:type "Null"}] + [{:type "Null"} #ctu/optimizeable "x"] + nil) + + (testing "with two null operands" + [{:type "Null"} {:type "Null"}] + nil) + + (testing "with one operand optimizing to true" + [#ctu/optimize-to true #ctu/optimizeable "x"] + [#ctu/optimizeable "x" #ctu/optimize-to true] + '(not (optimized "x"))) + + (testing "with one operand optimizing to false" + [#ctu/optimize-to false #ctu/optimizeable "x"] + [#ctu/optimizeable "x" #ctu/optimize-to false] + '(optimized "x")) + + (testing "with both operands optimizing to true or false" + [#ctu/optimize-to true #ctu/optimize-to true] + [#ctu/optimize-to false #ctu/optimize-to false] + false) + + (testing "with one operand optimizing to true and the other to false" + [#ctu/optimize-to true #ctu/optimize-to false] + [#ctu/optimize-to false #ctu/optimize-to true] + true) + + (testing "with at least one operand optimizing to nil" + [#ctu/optimize-to nil #ctu/optimizeable "x"] + [#ctu/optimizeable "x" #ctu/optimize-to nil] + [#ctu/optimize-to nil #ctu/optimize-to true] + [#ctu/optimize-to true #ctu/optimize-to nil] + [#ctu/optimize-to nil #ctu/optimize-to false] + [#ctu/optimize-to false #ctu/optimize-to nil] + [#ctu/optimize-to nil #ctu/optimize-to nil] + nil))) diff --git a/modules/cql/test/blaze/elm/compiler/nullological_operators_test.clj b/modules/cql/test/blaze/elm/compiler/nullological_operators_test.clj index 9bdc6bccc..1e76066a5 100644 --- a/modules/cql/test/blaze/elm/compiler/nullological_operators_test.clj +++ b/modules/cql/test/blaze/elm/compiler/nullological_operators_test.clj @@ -7,6 +7,7 @@ [blaze.elm.compiler :as c] [blaze.elm.compiler.core :as core] [blaze.elm.compiler.core-spec] + [blaze.elm.compiler.nullological-operators] [blaze.elm.compiler.test-util :as ctu] [blaze.elm.literal :as elm] [blaze.elm.literal-spec] @@ -73,7 +74,17 @@ #elm/parameter-ref "false" true? #elm/parameter-ref "nil" false?)) - (ctu/testing-unary-op elm/is-false)) + (ctu/testing-unary-op elm/is-false) + + (ctu/testing-optimize elm/is-false + (testing "false" + #ctu/optimize-to true + #ctu/optimize-to nil + false) + + (testing "true" + #ctu/optimize-to false + true))) ;; 14.4. IsNull ;; @@ -93,7 +104,17 @@ #elm/parameter-ref "false" false? #elm/parameter-ref "nil" true?)) - (ctu/testing-unary-op elm/is-null)) + (ctu/testing-unary-op elm/is-null) + + (ctu/testing-optimize elm/is-null + (testing "false" + #ctu/optimize-to true + #ctu/optimize-to false + false) + + (testing "true" + #ctu/optimize-to nil + true))) ;; 14.5. IsTrue ;; @@ -113,4 +134,14 @@ #elm/parameter-ref "false" false? #elm/parameter-ref "nil" false?)) - (ctu/testing-unary-op elm/is-true)) + (ctu/testing-unary-op elm/is-true) + + (ctu/testing-optimize elm/is-true + (testing "false" + #ctu/optimize-to false + #ctu/optimize-to nil + false) + + (testing "true" + #ctu/optimize-to true + true))) diff --git a/modules/cql/test/blaze/elm/compiler/reusing_logic_test.clj b/modules/cql/test/blaze/elm/compiler/reusing_logic_test.clj index f9b48f4e1..7fa837aae 100644 --- a/modules/cql/test/blaze/elm/compiler/reusing_logic_test.clj +++ b/modules/cql/test/blaze/elm/compiler/reusing_logic_test.clj @@ -95,7 +95,7 @@ (defmacro testing-function-ref-optimize [name] `(testing "optimize" - (let [elm# #elm/function-ref [~name {:type "Optimizeable" :id "x"}] + (let [elm# #elm/function-ref [~name #ctu/optimizeable "x"] expr# (st/with-instrument-disabled (c/optimize nil (c/compile {} elm#)))] (has-form expr# (list '~'call ~name '~'(optimized "x")))))) @@ -185,7 +185,7 @@ (list 'call function-name '(param-ref "a")))) (testing "optimize" - (let [elm (elm/function-ref [function-name {:type "Optimizeable" :id "x"}]) + (let [elm (elm/function-ref [function-name #ctu/optimizeable "x"]) expr (st/with-instrument-disabled (c/optimize nil (c/compile compile-ctx elm)))] (has-form expr (list 'call function-name '(optimized "x"))))) @@ -245,8 +245,8 @@ (list 'call function-name '(param-ref "a") '(param-ref "b")))) (testing "optimize" - (let [elm (elm/function-ref [function-name {:type "Optimizeable" :id "x"} - {:type "Optimizeable" :id "y"}]) + (let [elm (elm/function-ref [function-name #ctu/optimizeable "x" + #ctu/optimizeable "y"]) expr (st/with-instrument-disabled (c/optimize nil (c/compile compile-ctx elm)))] (has-form expr (list 'call function-name '(optimized "x") '(optimized "y"))))) diff --git a/modules/cql/test/blaze/elm/compiler/string_operators_test.clj b/modules/cql/test/blaze/elm/compiler/string_operators_test.clj index 9b398f916..8e5cec9d3 100644 --- a/modules/cql/test/blaze/elm/compiler/string_operators_test.clj +++ b/modules/cql/test/blaze/elm/compiler/string_operators_test.clj @@ -238,7 +238,17 @@ (is (identical? count (core/-eval expr {:db db} patient nil))))))) - (ctu/testing-unary-op elm/length)) + (ctu/testing-unary-op elm/length) + + (ctu/testing-optimize elm/length + (testing "empty and nil" + #ctu/optimize-to "" + #ctu/optimize-to nil + 0) + + (testing "a" + #ctu/optimize-to "a" + 1))) ;; 17.9. Lower ;; @@ -264,7 +274,20 @@ (ctu/testing-unary-null elm/lower) - (ctu/testing-unary-op elm/lower)) + (ctu/testing-unary-op elm/lower) + + (ctu/testing-optimize elm/lower + (testing "" + #ctu/optimize-to "" + "") + + (testing "A" + #ctu/optimize-to "A" + "a") + + (testing "nil" + #ctu/optimize-to nil + nil))) ;; 17.10. Matches ;; @@ -480,4 +503,19 @@ #elm/parameter-ref "empty-string" "" #elm/parameter-ref "a" "A")) - (ctu/testing-unary-op elm/upper)) + (ctu/testing-unary-null elm/upper) + + (ctu/testing-unary-op elm/upper) + + (ctu/testing-optimize elm/upper + (testing "" + #ctu/optimize-to "" + "") + + (testing "a" + #ctu/optimize-to "a" + "A") + + (testing "nil" + #ctu/optimize-to nil + nil))) diff --git a/modules/cql/test/blaze/elm/compiler/test_util.clj b/modules/cql/test/blaze/elm/compiler/test_util.clj index bf85c5dac..16e708b0d 100644 --- a/modules/cql/test/blaze/elm/compiler/test_util.clj +++ b/modules/cql/test/blaze/elm/compiler/test_util.clj @@ -11,7 +11,7 @@ [blaze.elm.literal :as elm] [blaze.elm.literal-spec] [blaze.elm.resource :as cr] - [blaze.elm.spec] + [blaze.elm.spec :as elm-spec] [blaze.fhir.spec.type.system :as system] [clojure.spec.alpha :as s] [clojure.spec.test.alpha :as st] @@ -343,17 +343,37 @@ (s/def ::id string?) -(defmethod blaze.elm.spec/expression :elm.spec.type/optimizeable [_] +(defmethod elm-spec/expression :elm.spec.type/optimizeable [_] (s/keys :req-un [::id])) (defmethod core/compile* :elm.compiler.type/optimizeable [_ {:keys [id]}] (optimizeable-expr id)) +(defn optimizeable [id] + {:type "Optimizeable" :id id}) + +(s/def ::value + any?) + +(defmethod elm-spec/expression :elm.spec.type/optimize-to [_] + (s/keys :req-un [::value])) + +(defmethod core/compile* :elm.compiler.type/optimize-to + [_ {:keys [value]}] + (reify-expr core/Expression + (-optimize [_ _] + value) + (-form [_] + (list 'optimize-to value)))) + +(defn optimize-to [value] + {:type "OptimizeTo" :value value}) + (defmacro testing-unary-optimize [elm-constructor] (let [form-name (symbol (name elm-constructor))] `(testing "optimize" - (let [elm# (~elm-constructor {:type "Optimizeable" :id "x"}) + (let [elm# (~elm-constructor #ctu/optimizeable "x") expr# (st/with-instrument-disabled (c/optimize nil (c/compile {} elm#)))] (has-form expr# (list '~form-name (list '~'optimized "x"))))))) @@ -374,7 +394,7 @@ (let [form-name (symbol (name elm-constructor))] `(testing "optimize" (doseq [precision# ~(vec precisions)] - (let [elm# (~elm-constructor [{:type "Optimizeable" :id "x"} precision#]) + (let [elm# (~elm-constructor [#ctu/optimizeable "x" precision#]) expr# (st/with-instrument-disabled (c/optimize nil (c/compile {} elm#)))] (has-form expr# (list '~form-name (list '~'optimized "x") precision#))))))) @@ -630,8 +650,8 @@ (defmacro testing-binary-optimize [elm-constructor] (let [form-name (symbol (name elm-constructor))] `(testing "optimize" - (let [elm# (~elm-constructor [{:type "Optimizeable" :id "a"} - {:type "Optimizeable" :id "b"}]) + (let [elm# (~elm-constructor [#ctu/optimizeable "a" + #ctu/optimizeable "b"]) expr# (st/with-instrument-disabled (c/optimize nil (c/compile {} elm#)))] (has-form expr# (list (quote ~form-name) (list (quote ~'optimized) "a") (list (quote ~'optimized) "b"))))))) @@ -647,9 +667,9 @@ (defmacro testing-ternary-optimize [elm-constructor] (let [form-name (symbol (name elm-constructor))] `(testing "optimize" - (let [elm# (~elm-constructor [{:type "Optimizeable" :id "x"} - {:type "Optimizeable" :id "y"} - {:type "Optimizeable" :id "z"}]) + (let [elm# (~elm-constructor [#ctu/optimizeable "x" + #ctu/optimizeable "y" + #ctu/optimizeable "z"]) expr# (st/with-instrument-disabled (c/optimize nil (c/compile {} elm#)))] (has-form expr# (list (quote ~form-name) (list (quote ~'optimized) "x") @@ -710,8 +730,8 @@ `(testing "optimize" (doseq [precision# ~(vec precisions)] (let [elm# (~elm-constructor - [{:type "Optimizeable" :id "x"} - {:type "Optimizeable" :id "y"} + [#ctu/optimizeable "x" + #ctu/optimizeable "y" precision#]) expr# (st/with-instrument-disabled (c/optimize nil (c/compile {} elm#)))] (has-form expr# (list '~form-name (list '~'optimized "x") (list '~'optimized "y") precision#)))))))) @@ -856,5 +876,18 @@ (defn resource [db type id] (cr/mk-resource db (d/resource-handle db type id))) -(defn eval-unfiltered [elm] - (core/-eval (c/compile {:eval-context "Unfiltered"} elm) {} nil nil)) +(defmacro testing-optimize + "Generates testing forms for the expression with `elm-constructor`. + + Each `test-case` is a testing form with a description followed by one or more + vectors of elm operators followed by one expected form." + [elm-constructor & test-cases] + `(testing "optimize" + ~@(for [[_ test-name & more] test-cases + :let [ops (butlast more) + expected (last more)]] + `(testing ~test-name + ~@(for [op ops] + `(let [elm# (~elm-constructor ~op) + expr# (st/with-instrument-disabled (c/optimize nil (c/compile {} elm#)))] + (has-form expr# ~expected))))))) diff --git a/modules/cql/test/blaze/elm/compiler/type_operators_test.clj b/modules/cql/test/blaze/elm/compiler/type_operators_test.clj index 6ad183caa..33496f08a 100644 --- a/modules/cql/test/blaze/elm/compiler/type_operators_test.clj +++ b/modules/cql/test/blaze/elm/compiler/type_operators_test.clj @@ -220,7 +220,12 @@ (ctu/testing-unary-null elm/children) - (ctu/testing-unary-op elm/children)) + (ctu/testing-unary-op elm/children) + + (ctu/testing-optimize elm/children + (testing "Code" + #ctu/optimize-to (code/code "system-164913" "version-164919" "code-164924") + ["code-164924" nil "system-164913" "version-164919"]))) ;; TODO 22.5. Convert ;; @@ -371,7 +376,23 @@ (ctu/testing-unary-null elm/converts-to-boolean) - (ctu/testing-unary-op elm/converts-to-boolean)) + (ctu/testing-unary-op elm/converts-to-boolean) + + (ctu/testing-optimize elm/converts-to-boolean + (testing "String" + #ctu/optimize-to "true" + #ctu/optimize-to "false" + true) + + (testing "Integer - true" + #ctu/optimize-to "0" + #ctu/optimize-to "1" + true) + + (testing "Integer - false" + #ctu/optimize-to "2" + #ctu/optimize-to "-1" + false))) ;; 22.8. ConvertsToDate ;; @@ -534,7 +555,14 @@ (ctu/testing-unary-null elm/converts-to-decimal) - (ctu/testing-unary-op elm/converts-to-decimal)) + (ctu/testing-unary-op elm/converts-to-decimal) + + (ctu/testing-optimize elm/converts-to-decimal + (testing "String" + #ctu/optimize-to "-1" + #ctu/optimize-to "0" + #ctu/optimize-to "1" + true))) ;; 22.11. ConvertsToLong ;; @@ -589,7 +617,14 @@ (ctu/testing-unary-null elm/converts-to-long) - (ctu/testing-unary-op elm/converts-to-long)) + (ctu/testing-unary-op elm/converts-to-long) + + (ctu/testing-optimize elm/converts-to-long + (testing "String" + #ctu/optimize-to "-1" + #ctu/optimize-to "0" + #ctu/optimize-to "1" + true))) ;; 22.12. ConvertsToInteger ;; @@ -643,7 +678,14 @@ (ctu/testing-unary-null elm/converts-to-integer) - (ctu/testing-unary-op elm/converts-to-integer)) + (ctu/testing-unary-op elm/converts-to-integer) + + (ctu/testing-optimize elm/converts-to-integer + (testing "String" + #ctu/optimize-to "-1" + #ctu/optimize-to "0" + #ctu/optimize-to "1" + true))) ;; 22.13. ConvertsToQuantity ;; @@ -713,7 +755,14 @@ (ctu/testing-unary-null elm/converts-to-quantity) - (ctu/testing-unary-op elm/converts-to-quantity)) + (ctu/testing-unary-op elm/converts-to-quantity) + + (ctu/testing-optimize elm/converts-to-quantity + (testing "String" + #ctu/optimize-to "-1'm'" + #ctu/optimize-to "0'm'" + #ctu/optimize-to "1'm'" + true))) ;; 22.14. ConvertsToRatio ;; @@ -749,7 +798,14 @@ (ctu/testing-unary-null elm/converts-to-ratio) - (ctu/testing-unary-op elm/converts-to-ratio)) + (ctu/testing-unary-op elm/converts-to-ratio) + + (ctu/testing-optimize elm/converts-to-ratio + (testing "String" + #ctu/optimize-to "-1'm':-1'm'" + #ctu/optimize-to "0'm':0'm'" + #ctu/optimize-to "1'm':1'm'" + true))) ;; 22.15. ConvertsToString ;; @@ -821,7 +877,12 @@ (ctu/testing-unary-null elm/converts-to-string) - (ctu/testing-unary-op elm/converts-to-string)) + (ctu/testing-unary-op elm/converts-to-string) + + (ctu/testing-optimize elm/converts-to-string + (testing "String" + #ctu/optimize-to "foo" + true))) ;; 22.16. ConvertsToTime ;; @@ -910,7 +971,12 @@ (ctu/testing-unary-null elm/descendents) - (ctu/testing-unary-op elm/descendents)) + (ctu/testing-unary-op elm/descendents) + + (ctu/testing-optimize elm/descendents + (testing "Code" + #ctu/optimize-to (code/code "system-164913" "version-164919" "code-164924") + ["code-164924" nil "system-164913" "version-164919"]))) ;; 22.18. Is ;; @@ -1171,7 +1237,16 @@ (ctu/testing-unary-null elm/to-boolean) - (ctu/testing-unary-op elm/to-boolean)) + (ctu/testing-unary-op elm/to-boolean) + + (ctu/testing-optimize elm/to-boolean + (testing "String - true" + #ctu/optimize-to "true" + true) + + (testing "String - false" + #ctu/optimize-to "false" + false))) ;; 22.20. ToChars ;; @@ -1183,9 +1258,9 @@ (deftest compile-to-chars-test (testing "String" (are [x res] (= res (ctu/compile-unop elm/to-chars elm/string x)) - "A" '("A") - "ab" '("a" "b") - "" '())) + "A" ["A"] + "ab" ["a" "b"] + "" [])) (testing "Integer" (are [x] (nil? (ctu/compile-unop elm/to-chars elm/integer x)) @@ -1193,13 +1268,18 @@ (testing "Dynamic" (are [x res] (= res (ctu/dynamic-compile-eval (elm/to-chars x))) - #elm/parameter-ref "A" '("A") - #elm/parameter-ref "ab" '("a" "b") - #elm/parameter-ref "empty-string" '())) + #elm/parameter-ref "A" ["A"] + #elm/parameter-ref "ab" ["a" "b"] + #elm/parameter-ref "empty-string" [])) (ctu/testing-unary-null elm/to-chars) - (ctu/testing-unary-op elm/to-chars)) + (ctu/testing-unary-op elm/to-chars) + + (ctu/testing-optimize elm/to-chars + (testing "String" + #ctu/optimize-to "ab" + ["a" "b"]))) ;; 22.21. ToConcept ;; @@ -1226,7 +1306,12 @@ (ctu/testing-unary-null elm/to-concept) - (ctu/testing-unary-op elm/to-concept)) + (ctu/testing-unary-op elm/to-concept) + + (ctu/testing-optimize elm/to-concept + (testing "String" + #ctu/optimize-to (code/code "system-134534" "version-171346" "code-134551") + '(concept (code "system-134534" "version-171346" "code-134551"))))) ;; 22.22. ToDate ;; @@ -1414,7 +1499,12 @@ (ctu/testing-unary-null elm/to-decimal) - (ctu/testing-unary-op elm/to-decimal)) + (ctu/testing-unary-op elm/to-decimal) + + (ctu/testing-optimize elm/to-decimal + (testing "String" + #ctu/optimize-to "0" + 0M))) ;; 22.25. ToInteger ;; @@ -1455,7 +1545,12 @@ (ctu/testing-unary-null elm/to-integer) - (ctu/testing-unary-op elm/to-integer)) + (ctu/testing-unary-op elm/to-integer) + + (ctu/testing-optimize elm/to-integer + (testing "String" + #ctu/optimize-to "0" + 0))) ;; 22.26. ToList ;; @@ -1487,7 +1582,12 @@ #elm/parameter-ref "nil" [] #elm/parameter-ref "a" ["a"])) - (ctu/testing-unary-op elm/to-list)) + (ctu/testing-unary-op elm/to-list) + + (ctu/testing-optimize elm/to-list + (testing "String" + #ctu/optimize-to "a" + ["a"]))) ;; 22.27. ToLong ;; @@ -1532,7 +1632,12 @@ (ctu/testing-unary-null elm/to-long) - (ctu/testing-unary-op elm/to-long)) + (ctu/testing-unary-op elm/to-long) + + (ctu/testing-optimize elm/to-long + (testing "String" + #ctu/optimize-to "0" + 0))) ;; 22.28. ToQuantity ;; @@ -1609,7 +1714,12 @@ (ctu/testing-unary-null elm/to-quantity) - (ctu/testing-unary-op elm/to-quantity)) + (ctu/testing-unary-op elm/to-quantity) + + (ctu/testing-optimize elm/to-quantity + (testing "String" + #ctu/optimize-to "1'm'" + '(quantity 1M "m")))) ;; 22.29. ToRatio ;; @@ -1658,7 +1768,12 @@ (ctu/testing-unary-null elm/to-ratio) - (ctu/testing-unary-op elm/to-ratio)) + (ctu/testing-unary-op elm/to-ratio) + + (ctu/testing-optimize elm/to-ratio + (testing "String" + #ctu/optimize-to "1:2" + '(ratio (quantity 1M "1") (quantity 2M "1"))))) ;; 22.30. ToString ;; @@ -1735,7 +1850,12 @@ (ctu/testing-unary-null elm/to-string) - (ctu/testing-unary-op elm/to-string)) + (ctu/testing-unary-op elm/to-string) + + (ctu/testing-optimize elm/to-string + (testing "Boolean" + #ctu/optimize-to true + "true"))) ;; 22.31. ToTime ;; diff --git a/modules/cql/test/data_readers.clj b/modules/cql/test/data_readers.clj index d6a586eb6..cac8a87ea 100644 --- a/modules/cql/test/data_readers.clj +++ b/modules/cql/test/data_readers.clj @@ -127,4 +127,6 @@ elm/to-quantity blaze.elm.literal/to-quantity elm/to-ratio blaze.elm.literal/to-ratio elm/to-string blaze.elm.literal/to-string - elm/calculate-age-at blaze.elm.literal/calculate-age-at} + elm/calculate-age-at blaze.elm.literal/calculate-age-at + ctu/optimizeable blaze.elm.compiler.test-util/optimizeable + ctu/optimize-to blaze.elm.compiler.test-util/optimize-to}