diff --git a/CHANGELOG.md b/CHANGELOG.md index c913540d7..dde33f72d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,17 @@ # Changelog +## v0.17.10 + +### Bugfixes + +* Fix Reference Resolution on Extended Primitive References + +### Other Improvements ([#758](https://github.com/samply/blaze/issues/758)) + +* Implement CQL ConvertsToTime ([#759](https://github.com/samply/blaze/pull/759)) + +The full changelog can be found [here](https://github.com/samply/blaze/milestone/48?closed=1). + ## v0.17.9 ### Other Improvements diff --git a/README.md b/README.md index 89d428c5f..a80017f79 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ The goal of this project is to provide a FHIR® Store with an internal CQL Evalu Blaze passes all [Touchstone FHIR 4.0.1 Basic Tests][12] and almost all [CQL Tests][3]. Please refer to the [Conformance](docs/conformance.md) section and report any issues you encounter during evaluation. -Latest release: [v0.17.9][5] +Latest release: [v0.17.10][5] ## Quick Start @@ -72,7 +72,7 @@ Unless required by applicable law or agreed to in writing, software distributed [3]: [4]: -[5]: +[5]: [6]: [7]: [8]: diff --git a/deps.edn b/deps.edn index 0b9533a40..9ad80e070 100644 --- a/deps.edn +++ b/deps.edn @@ -80,7 +80,7 @@ :outdated {:replace-deps {com.github.liquidz/antq - {:mvn/version "1.7.804"} + {:mvn/version "1.8.847"} org.slf4j/slf4j-nop {:mvn/version "1.7.36"}} diff --git a/docs/conformance/cql.md b/docs/conformance/cql.md index f3a43a47c..6d1b24564 100644 --- a/docs/conformance/cql.md +++ b/docs/conformance/cql.md @@ -322,38 +322,38 @@ The section numbers refer to the documentation of the [ELM Specification](https: ### 22. Type Operators | Num | Group | Expression | State | Notes | -|--------|--------------------|------------|---------------|-------| -| 22.1. | As | ! | no strictness | | -| 22.2. | CanConvert | ✗ | | | -| 22.3. | CanConvertQuantity | ✓ | | | -| 22.4. | Children | ✓ | | | -| 22.5. | Convert | ✗ | | | -| 22.6. | ConvertQuantity | ✓ | | | -| 22.7. | ConvertsToBoolean | ✗ | | | -| 22.8. | ConvertsToDate | ✗ | | | -| 22.9. | ConvertsToDateTime | ✗ | | | -| 22.10. | ConvertsToDecimal | ✗ | | | -| 22.11. | ConvertsToLong | ✗ | | | -| 22.12. | ConvertsToInteger | ✗ | | | -| 22.13. | ConvertsToQuantity | ✗ | | | -| 22.14. | ConvertsToRatio | ✗ | | | -| 22.15. | ConvertsToString | ✗ | | | -| 22.16. | ConvertsToTime | ✗ | | | -| 22.17. | Descendents | ✓ | | | -| 22.18. | Is | ✗ | | | -| 22.19. | ToBoolean | ✗ | | | -| 22.20. | ToChars | ✗ | | | -| 22.21. | ToConcept | ✗ | | | -| 22.22. | ToDate | ✓ | | | -| 22.23. | ToDateTime | ✓ | | | -| 22.24. | ToDecimal | ✓ | | | -| 22.25. | ToInteger | ✓ | | | -| 22.26. | ToList | ✓ | | | -| 22.27. | ToLong | ✓ | | | -| 22.28. | ToQuantity | ✓ | | | -| 22.29. | ToRatio | ✗ | | | -| 22.30. | ToString | ✓ | | | -| 22.31. | ToTime | ✗ | | | +|--------|--------------------|-----------|---------------|-------| +| 22.1. | As | ! | no strictness | | +| 22.2. | CanConvert | ✗ | | | +| 22.3. | CanConvertQuantity | ✓ | | | +| 22.4. | Children | ✓ | | | +| 22.5. | Convert | ✗ | | | +| 22.6. | ConvertQuantity | ✓ | | | +| 22.7. | ConvertsToBoolean | ✓ | | | +| 22.8. | ConvertsToDate | ✓ | | | +| 22.9. | ConvertsToDateTime | ✓ | | | +| 22.10. | ConvertsToDecimal | ✓ | | | +| 22.11. | ConvertsToLong | ✓ | | | +| 22.12. | ConvertsToInteger | ✓ | | | +| 22.13. | ConvertsToQuantity | ✓ | | | +| 22.14. | ConvertsToRatio | ✗ | | | +| 22.15. | ConvertsToString | ✓ | | | +| 22.16. | ConvertsToTime | ✓ | | | +| 22.17. | Descendents | ✓ | | | +| 22.18. | Is | ✗ | | | +| 22.19. | ToBoolean | ✓ | | | +| 22.20. | ToChars | ✓ | | | +| 22.21. | ToConcept | ✗ | | | +| 22.22. | ToDate | ✓ | | | +| 22.23. | ToDateTime | ✓ | | | +| 22.24. | ToDecimal | ✓ | | | +| 22.25. | ToInteger | ✓ | | | +| 22.26. | ToList | ✓ | | | +| 22.27. | ToLong | ✓ | | | +| 22.28. | ToQuantity | ✓ | | | +| 22.29. | ToRatio | ✗ | | | +| 22.30. | ToString | ✓ | | | +| 22.31. | ToTime | ✓ | | | ### 23. Clinical Operators diff --git a/docs/deployment/docker-deployment.md b/docs/deployment/docker-deployment.md index b68d04a1b..dd67cdc78 100644 --- a/docs/deployment/docker-deployment.md +++ b/docs/deployment/docker-deployment.md @@ -27,7 +27,7 @@ Blaze should log something like this: 2021-06-27T11:02:37.834Z ee086ef908c1 main INFO [blaze.core:64] - JVM version: 16.0.2 2021-06-27T11:02:37.834Z ee086ef908c1 main INFO [blaze.core:65] - Maximum available memory: 1738 MiB 2021-06-27T11:02:37.835Z ee086ef908c1 main INFO [blaze.core:66] - Number of available processors: 8 -2021-06-27T11:02:37.836Z ee086ef908c1 main INFO [blaze.core:67] - Successfully started Blaze version 0.17.9 in 8.2 seconds +2021-06-27T11:02:37.836Z ee086ef908c1 main INFO [blaze.core:67] - Successfully started Blaze version 0.17.10 in 8.2 seconds ``` In order to test connectivity, query the health endpoint: @@ -47,7 +47,7 @@ that should return: ```json { "name": "Blaze", - "version": "0.17.9" + "version": "0.17.10" } ``` diff --git a/docs/deployment/manual-deployment.md b/docs/deployment/manual-deployment.md index edc4ac528..ee5595e1e 100644 --- a/docs/deployment/manual-deployment.md +++ b/docs/deployment/manual-deployment.md @@ -2,12 +2,12 @@ The installation works under Windows, Linux and macOS. The only dependency is an installed OpenJDK 11. Blaze is tested with [AdoptOpenJDK][1]. -Blaze runs on the JVM and comes as single JAR file. Download the most recent version [here](https://github.com/samply/blaze/releases/tag/v0.17.9). Look for `blaze-0.17.9-standalone.jar`. +Blaze runs on the JVM and comes as single JAR file. Download the most recent version [here](https://github.com/samply/blaze/releases/tag/v0.17.10). Look for `blaze-0.17.10-standalone.jar`. After the download, you can start blaze with the following command (Linux, macOS): ```sh -java -jar blaze-0.17.9-standalone.jar -m blaze.core +java -jar blaze-0.17.10-standalone.jar -m blaze.core ``` Blaze will run with an in-memory, volatile database for testing and demo purposes. @@ -17,14 +17,14 @@ Blaze can be run with durable storage by setting the environment variables `STOR Under Linux/macOS: ```sh -STORAGE=standalone java -jar blaze-0.17.9-standalone.jar -m blaze.core +STORAGE=standalone java -jar blaze-0.17.10-standalone.jar -m blaze.core ``` Under Windows, you need to set the Environment variables in the PowerShell before starting Blaze: ```powershell $Env:STORAGE="standalone" -java -jar blaze-0.17.9-standalone.jar -m blaze.core +java -jar blaze-0.17.10-standalone.jar -m blaze.core ``` This will create three directories called `index`, `transaction` and `resource` inside the current working directory, one for each database part used. @@ -42,7 +42,7 @@ The output should look like this: 2021-06-27T11:02:37.834Z ee086ef908c1 main INFO [blaze.core:64] - JVM version: 16.0.2 2021-06-27T11:02:37.834Z ee086ef908c1 main INFO [blaze.core:65] - Maximum available memory: 1738 MiB 2021-06-27T11:02:37.835Z ee086ef908c1 main INFO [blaze.core:66] - Number of available processors: 8 -2021-06-27T11:02:37.836Z ee086ef908c1 main INFO [blaze.core:67] - Successfully started Blaze version 0.17.9 in 8.2 seconds +2021-06-27T11:02:37.836Z ee086ef908c1 main INFO [blaze.core:67] - Successfully started Blaze version 0.17.10 in 8.2 seconds ``` In order to test connectivity, query the health endpoint: @@ -62,7 +62,7 @@ that should return: ```json { "name": "Blaze", - "version": "0.17.9" + "version": "0.17.10" } ``` diff --git a/modules/cql/src/blaze/elm/compiler/type_operators.clj b/modules/cql/src/blaze/elm/compiler/type_operators.clj index 98110464f..3f078a70e 100644 --- a/modules/cql/src/blaze/elm/compiler/type_operators.clj +++ b/modules/cql/src/blaze/elm/compiler/type_operators.clj @@ -130,9 +130,41 @@ (some? (p/to-boolean operand)))) -;; TODO 22.8. ConvertsToDate +;; 22.8. ConvertsToDate +(defrecord ConvertsToDateOperatorExpression [operand] + core/Expression + (-eval [_ {:keys [now] :as context} resource scope] + (when-let [operand (core/-eval operand context resource scope)] + (when (some? operand) + (some? (p/to-date operand now))))) + (-form [_] + (list 'converts-to-date (core/-form operand)))) + + +(defmethod core/compile* :elm.compiler.type/converts-to-date + [context {:keys [operand]}] + (when-let [operand (core/compile* context operand)] + (->ConvertsToDateOperatorExpression operand))) + + +;; 22.9. ConvertsToDateTime +(defrecord ConvertsToDateTimeOperatorExpression [operand] + core/Expression + (-eval [_ {:keys [now] :as context} resource scope] + (when-let [operand (core/-eval operand context resource scope)] + (when (some? operand) + (some? (p/to-date-time operand now))))) + (-form [_] + (list 'converts-to-date-time (core/-form operand)))) + + +(defmethod core/compile* :elm.compiler.type/converts-to-date-time + [context {:keys [operand]}] + (when-let [operand (core/compile* context operand)] + (if (system/date? operand) + (some? (p/to-date-time operand nil)) + (->ConvertsToDateTimeOperatorExpression operand)))) -;; TODO 22.9. ConvertsToDateTime ;; 22.10. ConvertsToDecimal (defunop converts-to-decimal [operand] @@ -166,7 +198,22 @@ (some? (p/to-string operand)))) -;; TODO 22.16. ConvertsToTime +;; 22.16. ConvertsToTime +(defrecord ConvertsToTimeOperatorExpression [operand] + core/Expression + (-eval [_ {:keys [now] :as context} resource scope] + (when-let [operand (core/-eval operand context resource scope)] + (when (some? operand) + (some? (p/to-time operand now))))) + (-form [_] + (list 'converts-to-time (core/-form operand)))) + + +(defmethod core/compile* :elm.compiler.type/converts-to-time + [context {:keys [operand]}] + (when-let [operand (core/compile* context operand)] + (->ConvertsToTimeOperatorExpression operand))) + ;; 22.17. Descendents (defrecord DescendentsOperatorExpression [source] 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 9474397d8..2d646c4a8 100644 --- a/modules/cql/test/blaze/elm/compiler/type_operators_test.clj +++ b/modules/cql/test/blaze/elm/compiler/type_operators_test.clj @@ -380,7 +380,7 @@ expr (c/compile compile-ctx elm)] (is (= '(converts-to-boolean (param-ref "x")) (core/-form expr)))))) -;; TODO 22.8. ConvertsToDate +;; 22.8. ConvertsToDate ;; ;; The ConvertsToDate operator returns true if the value of its argument is or ;; can be converted to a Date value. @@ -404,8 +404,38 @@ ;; As with date literals, date values may be specified to any precision. ;; ;; If the argument is null, the result is null. +(deftest compile-converts-to-date-test + (let [eval #(core/-eval % {:now tu/now} nil nil)] + (testing "String" + (are [x] (true? (eval (tu/compile-unop elm/converts-to-date elm/string x))) + "2019" + "2019-01" + "2019-01-01") + + (are [x] (false? (eval (tu/compile-unop elm/converts-to-date elm/string x))) + "aaaa" + "2019-13" + "2019-02-29")) + + (testing "Date" + (are [x] (true? (eval (tu/compile-unop elm/converts-to-date elm/date x))) + "2019" + "2019-01" + "2019-01-01")) + + (testing "DateTime" + (are [x] (true? (eval (tu/compile-unop elm/converts-to-date elm/date-time x))) + "2019" + "2019-01" + "2019-01-01" + "2019-01-01T12:13"))) + + (tu/testing-unary-null elm/converts-to-date) -;; TODO 22.9. ConvertsToDateTime + (tu/testing-unary-form elm/converts-to-date)) + + +;; 22.9. ConvertsToDateTime ;; ;; The ConvertsToDateTime operator returns true if the value of its argument is ;; or can be converted to a DateTime value. @@ -428,6 +458,33 @@ ;; evaluation request timestamp is assumed. ;; ;; If the argument is null, the result is null. +(deftest compile-converts-to-date-time-test + (let [eval #(core/-eval % {:now tu/now} nil nil)] + (testing "String" + (are [x] (true? (eval (tu/compile-unop elm/converts-to-date-time elm/string x))) + "2020-03-08T12:54:00+01:00") + + (are [x] (false? (eval (tu/compile-unop elm/converts-to-date-time elm/string x))) + "2019-13" + "2019-02-29")) + + (testing "Date" + (testing "Static" + (are [x] (true? (tu/compile-unop elm/converts-to-date-time elm/date x)) + "2020" + "2020-03" + "2020-03-08"))) + + (testing "DateTime" + (are [x] (true? (eval (tu/compile-unop elm/converts-to-date-time elm/date-time x))) + "2020" + "2020-03" + "2020-03-08" + "2020-03-08T12:13" ))) + + (tu/testing-unary-null elm/converts-to-date-time) + + (tu/testing-unary-form elm/converts-to-date-time)) ;; 22.10. ConvertsToDecimal @@ -772,7 +829,7 @@ expr (c/compile compile-ctx elm)] (is (= '(converts-to-string (param-ref "x")) (core/-form expr)))))) -;; TODO 22.16. ConvertsToTime +;; 22.16. ConvertsToTime ;; ;; The ConvertsToTime operator returns true if the value of its argument is or ;; can be converted to a Time value. @@ -795,6 +852,40 @@ ;; evaluation request timestamp is assumed. ;; ;; If the argument is null, the result is null. +(deftest compile-converts-to-time-test + (let [eval #(core/-eval % {:now tu/now} nil nil)] + (testing "String" + (are [x] (true? (eval (tu/compile-unop elm/converts-to-time elm/string x))) + "12:54:30" + "12:54:30.010") + + (are [x] (false? (eval (tu/compile-unop elm/converts-to-time elm/string x))) + "aaaa" + "12:54" + "24:54:00" + "23:60:00" + "14-30-00.0")) + + (testing "Time" + (are [x] (true? (eval (tu/compile-unop elm/converts-to-time elm/time x))) + "12:54" + "12:54:00" + "12:54:30.010")) + + (testing "DateTime" + (are [x] (true? (eval (tu/compile-unop elm/converts-to-time elm/date-time x))) + "2020-03-08T12:54:00" + "2020-03-08T12:54:30.010")) + + (testing "dynamic" + (are [x] (true? (tu/dynamic-compile-eval (elm/converts-to-time x))) + #elm/parameter-ref "12:54:00" + #elm/parameter-ref "2020-01-02T03:04:05.006Z"))) + + (tu/testing-unary-null elm/converts-to-time) + + (tu/testing-unary-form elm/converts-to-time)) + ;; 22.17. Descendents ;; diff --git a/modules/cql/test/blaze/elm/literal.clj b/modules/cql/test/blaze/elm/literal.clj index d0efde792..04f3f769e 100644 --- a/modules/cql/test/blaze/elm/literal.clj +++ b/modules/cql/test/blaze/elm/literal.clj @@ -809,6 +809,16 @@ {:type "ConvertsToBoolean" :operand operand}) +;; 22.8. ConvertsToDate +(defn converts-to-date [operand] + {:type "ConvertsToDate" :operand operand}) + + +;; 22.9. ConvertsToDateTime +(defn converts-to-date-time [operand] + {:type "ConvertsToDateTime" :operand operand}) + + ;; 22.10. ConvertsToDecimal (defn converts-to-decimal [operand] {:type "ConvertsToDecimal" :operand operand}) @@ -834,6 +844,11 @@ {:type "ConvertsToString" :operand operand}) +;; 22.16. ConvertsToTime +(defn converts-to-time [operand] + {:type "ConvertsToTime" :operand operand}) + + ;; 22.17. Descendents (defn descendents [source] {:type "Descendents" :source source}) diff --git a/modules/cql/test/data_readers.clj b/modules/cql/test/data_readers.clj index d501bc3b4..750db50ac 100644 --- a/modules/cql/test/data_readers.clj +++ b/modules/cql/test/data_readers.clj @@ -71,11 +71,14 @@ elm/can-convert-quantity blaze.elm.literal/can-convert-quantity elm/convert-quantity blaze.elm.literal/convert-quantity elm/converts-to-boolean blaze.elm.literal/converts-to-boolean + elm/converts-to-date blaze.elm.literal/converts-to-date + elm/converts-to-date-time blaze.elm.literal/converts-to-date-time elm/converts-to-decimal blaze.elm.literal/converts-to-decimal elm/converts-to-long blaze.elm.literal/converts-to-long elm/converts-to-integer blaze.elm.literal/converts-to-integer elm/converts-to-quantity blaze.elm.literal/converts-to-quantity elm/converts-to-string blaze.elm.literal/converts-to-string + elm/converts-to-time blaze.elm.literal/converts-to-time elm/children blaze.elm.literal/children elm/descendents blaze.elm.literal/descendents elm/to-boolean blaze.elm.literal/to-boolean diff --git a/modules/db/test/blaze/db/node/transaction_test.clj b/modules/db/test/blaze/db/node/transaction_test.clj index bf4eff3f3..4ef5d6f85 100644 --- a/modules/db/test/blaze/db/node/transaction_test.clj +++ b/modules/db/test/blaze/db/node/transaction_test.clj @@ -35,7 +35,7 @@ (given (tx/prepare-ops context [[:create {:fhir/type :fhir/Observation :id "0" - :subject #fhir/Reference{:reference "Patient/0"}}]]) + :subject #fhir/Reference{:reference #fhir/string"Patient/0"}}]]) [0 0 :op] := "create" [0 0 :type] := "Observation" [0 0 :id] := "0" @@ -43,13 +43,34 @@ [0 0 :refs] := [["Patient" "0"]] [1 0 0] := #blaze/hash"7B3980C2BFCF43A8CDD61662E1AABDA9CA6431964820BC8D52958AEC9A270378" [1 0 1] := {:fhir/type :fhir/Observation :id "0" - :subject #fhir/Reference{:reference "Patient/0"}}) + :subject #fhir/Reference{:reference #fhir/string"Patient/0"}}) + + (testing "with extended reference.reference" + (given (tx/prepare-ops + context + [[:create + {:fhir/type :fhir/Observation :id "0" + :subject #fhir/Reference + {:reference #fhir/string + {:extension [#fhir/Extension{:url "foo"}] + :value "Patient/190740"}}}]]) + [0 0 :refs] := [["Patient" "190740"]]) + + (testing "without value" + (given (tx/prepare-ops + context + [[:create + {:fhir/type :fhir/Observation :id "0" + :subject #fhir/Reference + {:reference #fhir/string + {:extension [#fhir/Extension{:url "foo"}]}}}]]) + [0 0 :refs] :? empty?))) (testing "with disabled referential integrity check" (given (tx/prepare-ops {:blaze.db/enforce-referential-integrity false} [[:create {:fhir/type :fhir/Observation :id "0" - :subject #fhir/Reference{:reference "Patient/0"}}]]) + :subject #fhir/Reference{:reference #fhir/string"Patient/0"}}]]) [0 0 :refs] :? empty?))) (testing "conditional" @@ -75,7 +96,7 @@ (given (tx/prepare-ops context [[:put {:fhir/type :fhir/Observation :id "0" - :subject #fhir/Reference{:reference "Patient/0"}}]]) + :subject #fhir/Reference{:reference #fhir/string"Patient/0"}}]]) [0 0 :op] := "put" [0 0 :type] := "Observation" [0 0 :id] := "0" @@ -83,12 +104,12 @@ [0 0 :refs] := [["Patient" "0"]] [1 0 0] := #blaze/hash"7B3980C2BFCF43A8CDD61662E1AABDA9CA6431964820BC8D52958AEC9A270378" [1 0 1] := {:fhir/type :fhir/Observation :id "0" - :subject #fhir/Reference{:reference "Patient/0"}}) + :subject #fhir/Reference{:reference #fhir/string"Patient/0"}}) (testing "with disabled referential integrity check" (given (tx/prepare-ops {:blaze.db/enforce-referential-integrity false} [[:put {:fhir/type :fhir/Observation :id "0" - :subject #fhir/Reference{:reference "Patient/0"}}]]) + :subject #fhir/Reference{:reference #fhir/string"Patient/0"}}]]) [0 0 :refs] :? empty?))) (testing "with matches" diff --git a/modules/fhir-structure/src/blaze/fhir/spec/type.clj b/modules/fhir-structure/src/blaze/fhir/spec/type.clj index a292f4f99..96a1736b6 100644 --- a/modules/fhir-structure/src/blaze/fhir/spec/type.clj +++ b/modules/fhir-structure/src/blaze/fhir/spec/type.clj @@ -36,7 +36,7 @@ (xml-name/alias-uri 'f "http://hl7.org/fhir") -;;(set! *warn-on-reflection* true) +(set! *warn-on-reflection* true) (set! *unchecked-math* :warn-on-boxed) @@ -1209,7 +1209,7 @@ ^:primitive-string display] :hash-num 43 :references - (-> (transient (or (some-> reference reference-reference) [])) + (-> (transient (or (some-> reference value reference-reference) [])) (macros/into! (p/-references extension)) (macros/into! (p/-references type)) (macros/into! (p/-references identifier)) diff --git a/modules/fhir-structure/test/blaze/fhir/spec/type_test.clj b/modules/fhir-structure/test/blaze/fhir/spec/type_test.clj index df43c1e3a..433dc0b1e 100644 --- a/modules/fhir-structure/test/blaze/fhir/spec/type_test.clj +++ b/modules/fhir-structure/test/blaze/fhir/spec/type_test.clj @@ -22,7 +22,8 @@ [com.fasterxml.jackson.databind ObjectMapper] [com.google.common.hash Hashing] [java.nio.charset StandardCharsets] - [java.time Instant LocalTime OffsetDateTime ZoneOffset])) + [java.time Instant LocalTime OffsetDateTime ZoneOffset] + [com.fasterxml.jackson.core SerializableString])) (xml-name/alias-uri 'f "http://hl7.org/fhir") @@ -489,27 +490,27 @@ (testing "getValue" (satisfies-prop 10 (prop/for-all [value fg/uri-value] - (= value (.getValue (type/uri value)))))) + (= value (.getValue ^SerializableString (type/uri value)))))) (testing "appendQuotedUTF8" (satisfies-prop 100 (prop/for-all [value fg/uri-value] (let [expected-buffer (.quoteAsUTF8 (JsonStringEncoder/getInstance) value) buffer (byte-array (count expected-buffer))] - (.appendQuotedUTF8 (type/uri value) buffer 0) + (.appendQuotedUTF8 ^SerializableString (type/uri value) buffer 0) (= (bb/wrap expected-buffer) (bb/wrap buffer)))))) (testing "asUnquotedUTF8" (satisfies-prop 100 (prop/for-all [value fg/uri-value] (= (bb/wrap (.encodeAsUTF8 (JsonStringEncoder/getInstance) ^String value)) - (bb/wrap (.asUnquotedUTF8 (type/uri value))))))) + (bb/wrap (.asUnquotedUTF8 ^SerializableString (type/uri value))))))) (testing "asQuotedUTF8" (satisfies-prop 100 (prop/for-all [value fg/uri-value] (= (bb/wrap (.quoteAsUTF8 (JsonStringEncoder/getInstance) value)) - (bb/wrap (.asQuotedUTF8 (type/uri value))))))))) + (bb/wrap (.asQuotedUTF8 ^SerializableString (type/uri value))))))))) (deftest url-test @@ -666,27 +667,27 @@ (testing "getValue" (satisfies-prop 10 (prop/for-all [value fg/canonical-value] - (= value (.getValue (type/canonical value)))))) + (= value (.getValue ^SerializableString (type/canonical value)))))) (testing "appendQuotedUTF8" (satisfies-prop 100 (prop/for-all [value fg/canonical-value] (let [expected-buffer (.quoteAsUTF8 (JsonStringEncoder/getInstance) value) buffer (byte-array (count expected-buffer))] - (.appendQuotedUTF8 (type/canonical value) buffer 0) + (.appendQuotedUTF8 ^SerializableString (type/canonical value) buffer 0) (= (bb/wrap expected-buffer) (bb/wrap buffer)))))) (testing "asUnquotedUTF8" (satisfies-prop 100 (prop/for-all [value fg/canonical-value] (= (bb/wrap (.encodeAsUTF8 (JsonStringEncoder/getInstance) ^String value)) - (bb/wrap (.asUnquotedUTF8 (type/canonical value))))))) + (bb/wrap (.asUnquotedUTF8 ^SerializableString (type/canonical value))))))) (testing "asQuotedUTF8" (satisfies-prop 100 (prop/for-all [value fg/canonical-value] (= (bb/wrap (.quoteAsUTF8 (JsonStringEncoder/getInstance) value)) - (bb/wrap (.asQuotedUTF8 (type/canonical value))))))))) + (bb/wrap (.asQuotedUTF8 ^SerializableString (type/canonical value))))))))) (deftest base64Binary-test @@ -1004,7 +1005,7 @@ (testing "equals" (satisfies-prop 100 (prop/for-all [date (s/gen :system/date)] - (.equals date date))) + (.equals ^Object date date))) (is (not (.equals #fhir/date"2020-01-01" #fhir/date"2020-01-02"))) (is (not (.equals #fhir/date"2020-01-01" "2020-01-01")))) @@ -1421,7 +1422,7 @@ (is (= extended-date-time-element (type/to-xml extended-date-time)))) (testing "equals" - (is (.equals (type/dateTime {:extension [string-extension] :value "2020"}) extended-date-time))) + (is (.equals ^Object (type/dateTime {:extension [string-extension] :value "2020"}) extended-date-time))) (testing "hash-into" (are [x hex] (= hex (murmur3 x)) @@ -1577,27 +1578,27 @@ (testing "getValue" (satisfies-prop 10 (prop/for-all [value fg/code-value] - (= value (.getValue (type/code value)))))) + (= value (.getValue ^SerializableString (type/code value)))))) (testing "appendQuotedUTF8" (satisfies-prop 100 (prop/for-all [value fg/code-value] (let [expected-buffer (.quoteAsUTF8 (JsonStringEncoder/getInstance) value) buffer (byte-array (count expected-buffer))] - (.appendQuotedUTF8 (type/code value) buffer 0) + (.appendQuotedUTF8 ^SerializableString (type/code value) buffer 0) (= (bb/wrap expected-buffer) (bb/wrap buffer)))))) (testing "asUnquotedUTF8" (satisfies-prop 100 (prop/for-all [value fg/code-value] (= (bb/wrap (.encodeAsUTF8 (JsonStringEncoder/getInstance) ^String value)) - (bb/wrap (.asUnquotedUTF8 (type/code value))))))) + (bb/wrap (.asUnquotedUTF8 ^SerializableString (type/code value))))))) (testing "asQuotedUTF8" (satisfies-prop 100 (prop/for-all [value fg/code-value] (= (bb/wrap (.quoteAsUTF8 (JsonStringEncoder/getInstance) value)) - (bb/wrap (.asQuotedUTF8 (type/code value))))))))) + (bb/wrap (.asQuotedUTF8 ^SerializableString (type/code value))))))))) (deftest oid-test @@ -2588,7 +2589,7 @@ #fhir/Reference{:extension [#fhir/Extension{}]} "210e3eb7" - #fhir/Reference{:reference "Patient/0"} + #fhir/Reference{:reference #fhir/string"Patient/0"} "cd80b8ac" #fhir/Reference{:type #fhir/uri"type-161222"} @@ -2597,7 +2598,7 @@ #fhir/Reference{:identifier #fhir/Identifier{}} "eb066d27" - #fhir/Reference{:display "display-161314"} + #fhir/Reference{:display #fhir/string"display-161314"} "543cf75f")) (testing "references" @@ -2610,23 +2611,36 @@ #fhir/Reference {:extension - [#fhir/Extension{:value #fhir/Reference{:reference "Patient/1"}}]} + [#fhir/Extension + {:value #fhir/Reference + {:reference #fhir/string"Patient/1"}}]} [["Patient" "1"]] - #fhir/Reference{:reference "Patient/0"} + #fhir/Reference{:reference #fhir/string"Patient/0"} [["Patient" "0"]] - #fhir/Reference{:reference "Patient"} + #fhir/Reference{:reference #fhir/string"Patient"} [] - #fhir/Reference{:reference ""} + #fhir/Reference{:reference #fhir/string""} [] #fhir/Reference {:extension - [#fhir/Extension{:value #fhir/Reference{:reference "Patient/1"}}] - :reference "Patient/0"} - [["Patient" "0"] ["Patient" "1"]])) + [#fhir/Extension + {:value #fhir/Reference + {:reference #fhir/string"Patient/1"}}] + :reference #fhir/string"Patient/0"} + [["Patient" "0"] ["Patient" "1"]] + + #fhir/Reference + {:reference #fhir/string{:extension [#fhir/Extension{:url "foo"}]}} + [] + + #fhir/Reference + {:reference #fhir/string{:extension [#fhir/Extension{:url "foo"}] + :value "Patient/0"}} + [["Patient" "0"]])) (testing "print" (are [v s] (= s (pr-str v)) diff --git a/modules/jepsen/deps.edn b/modules/jepsen/deps.edn index 5ca789b91..1fb7ec0d0 100644 --- a/modules/jepsen/deps.edn +++ b/modules/jepsen/deps.edn @@ -3,7 +3,7 @@ {:local/root "../fhir-client"} jepsen/jepsen - {:mvn/version "0.2.6"}} + {:mvn/version "0.2.7"}} :aliases {:test diff --git a/modules/operation-measure-evaluate-measure/test/blaze/fhir/operation/evaluate_measure/measure_test.clj b/modules/operation-measure-evaluate-measure/test/blaze/fhir/operation/evaluate_measure/measure_test.clj index a2d1a5aed..9fb133734 100644 --- a/modules/operation-measure-evaluate-measure/test/blaze/fhir/operation/evaluate_measure/measure_test.clj +++ b/modules/operation-measure-evaluate-measure/test/blaze/fhir/operation/evaluate_measure/measure_test.clj @@ -343,7 +343,8 @@ "q35-literal-library-ref" 1 "q36-parameter" 1 "q37-overlaps" 3 - "q38-di-surv" 2) + "q38-di-surv" 2 + "q39-social-sec-num" 1) (let [result (evaluate "q1" "subject-list")] (testing "MeasureReport is valid" @@ -497,5 +498,5 @@ (comment (log/set-level! :debug) (evaluate "q38-di-surv") - + (evaluate "q39-social-sec-num") ) diff --git a/modules/operation-measure-evaluate-measure/test/blaze/fhir/operation/evaluate_measure/q39-social-sec-num-data.json b/modules/operation-measure-evaluate-measure/test/blaze/fhir/operation/evaluate_measure/q39-social-sec-num-data.json new file mode 100644 index 000000000..1ab5fe0f2 --- /dev/null +++ b/modules/operation-measure-evaluate-measure/test/blaze/fhir/operation/evaluate_measure/q39-social-sec-num-data.json @@ -0,0 +1,145 @@ +{ + "resourceType": "Bundle", + "type": "transaction", + "entry": [ + { + "resource": { + "resourceType": "Patient", + "id": "0", + "identifier": [ + { + "system": "https://github.com/synthetichealth/synthea", + "value": "1363ed76-25b9-dc4f-6de7-6ee133d82db3" + }, + { + "type": { + "coding": [ + { + "system": "http://terminology.hl7.org/CodeSystem/v2-0203", + "code": "MR", + "display": "Medical Record Number" + } + ], + "text": "Medical Record Number" + }, + "system": "http://hospital.smarthealthit.org", + "value": "1363ed76-25b9-dc4f-6de7-6ee133d82db3" + }, + { + "type": { + "coding": [ + { + "system": "http://terminology.hl7.org/CodeSystem/v2-0203", + "code": "SS", + "display": "Social Security Number" + } + ], + "text": "Social Security Number" + }, + "system": "http://hl7.org/fhir/sid/us-ssn", + "value": "9A99-97-1459" + } + ] + }, + "request": { + "method": "PUT", + "url": "Patient/0" + } + }, + { + "resource": { + "resourceType": "Patient", + "id": "1", + "identifier": [ + { + "system": "https://github.com/synthetichealth/synthea", + "value": "19625ee6-1a94-1a6a-ca95-40c4efbbdfc7" + }, + { + "type": { + "coding": [ + { + "system": "http://terminology.hl7.org/CodeSystem/v2-0203", + "code": "MR", + "display": "Medical Record Number" + } + ], + "text": "Medical Record Number" + }, + "system": "http://hospital.smarthealthit.org", + "value": "19625ee6-1a94-1a6a-ca95-40c4efbbdfc7" + }, + { + "type": { + "coding": [ + { + "system": "http://terminology.hl7.org/CodeSystem/v2-0203", + "code": "SS", + "display": "Social Security Number" + } + ], + "text": "Social Security Number" + }, + "system": "http://hl7.org/fhir/sid/us-ssn", + "value": "999-38-6812" + } + ] + }, + "request": { + "method": "PUT", + "url": "Patient/1" + } + }, + { + "resource": { + "resourceType": "Measure", + "id": "0", + "url": "0", + "status": "active", + "subjectCodeableConcept": { + "coding": [ + { + "system": "http://hl7.org/fhir/resource-types", + "code": "Patient" + } + ] + }, + "library": [ + "0" + ], + "scoring": { + "coding": [ + { + "system": "http://terminology.hl7.org/CodeSystem/measure-scoring", + "code": "cohort" + } + ] + }, + "group": [ + { + "population": [ + { + "code": { + "coding": [ + { + "system": "http://terminology.hl7.org/CodeSystem/measure-population", + "code": "initial-population" + } + ] + }, + "criteria": { + "language": "text/cql", + "expression": "InInitialPopulation" + } + } + ] + } + ] + }, + "request": { + "method": "PUT", + "url": "Measure/0" + } + } + ] +} diff --git a/modules/operation-measure-evaluate-measure/test/blaze/fhir/operation/evaluate_measure/q39-social-sec-num-query.cql b/modules/operation-measure-evaluate-measure/test/blaze/fhir/operation/evaluate_measure/q39-social-sec-num-query.cql new file mode 100644 index 000000000..c06674931 --- /dev/null +++ b/modules/operation-measure-evaluate-measure/test/blaze/fhir/operation/evaluate_measure/q39-social-sec-num-query.cql @@ -0,0 +1,15 @@ +library Retrieve +using FHIR version '4.0.0' +include FHIRHelpers version '4.0.0' + +context Patient + +define SocialSecurityNumber: + First(Patient.identifier.where(system = 'http://hl7.org/fhir/sid/us-ssn').value) + +define IntegerParts: + from (Split(SocialSecurityNumber, '-')) S + where ConvertsToInteger(S) + +define InInitialPopulation: + Count(IntegerParts) = 3 diff --git a/modules/rest-api/src/blaze/rest_api/capabilities.clj b/modules/rest-api/src/blaze/rest_api/capabilities.clj index 0f6974d2d..c7b5d142b 100644 --- a/modules/rest-api/src/blaze/rest_api/capabilities.clj +++ b/modules/rest-api/src/blaze/rest_api/capabilities.clj @@ -117,7 +117,7 @@ :copyright #fhir/markdown"Copyright 2019 - 2022 The Samply Community\n\nLicensed under the Apache License, Version 2.0 (the \"License\"); you may not use this file except in compliance with the License. You may obtain a copy of the License at\n\nhttp://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License." :kind #fhir/code"instance" - :date #fhir/dateTime"2022-06-30" + :date #fhir/dateTime"2022-07-04" :software {:name "Blaze" :version version} diff --git a/perf-test/gatling/pom.xml b/perf-test/gatling/pom.xml index 766e2c7f0..7249eeee8 100644 --- a/perf-test/gatling/pom.xml +++ b/perf-test/gatling/pom.xml @@ -5,7 +5,7 @@ samply.blaze gatling - 0.17.9 + 0.17.10 1.8 diff --git a/pom.xml b/pom.xml index b61e43b73..93c70a15a 100644 --- a/pom.xml +++ b/pom.xml @@ -3,7 +3,7 @@ 4.0.0 samply blaze - 0.17.9 + 0.17.10 blaze A FHIR Store with internal, fast CQL Evaluation Engine diff --git a/src/blaze/system.clj b/src/blaze/system.clj index 18f72cf9a..01f5c3177 100644 --- a/src/blaze/system.clj +++ b/src/blaze/system.clj @@ -85,7 +85,7 @@ (def ^:private root-config - {:blaze/version "0.17.9" + {:blaze/version "0.17.10" :blaze/clock {}