update dependencies and some little cleanups
This commit is contained in:
parent
8684899bfa
commit
4ed1dff618
16
project.clj
16
project.clj
|
@ -3,8 +3,16 @@
|
||||||
:url "https://github.com/gered/clj-hl7-fhir"
|
:url "https://github.com/gered/clj-hl7-fhir"
|
||||||
:license {:name "Apache License, Version 2.0"
|
:license {:name "Apache License, Version 2.0"
|
||||||
:url "http://www.apache.org/licenses/LICENSE-2.0"}
|
:url "http://www.apache.org/licenses/LICENSE-2.0"}
|
||||||
:dependencies [[org.clojure/clojure "1.6.0"]
|
|
||||||
[cheshire "5.3.1"]
|
:dependencies [[cheshire "5.7.0"]
|
||||||
[clj-http "0.9.2"]
|
[clj-http "2.3.0"]
|
||||||
[com.cemerick/url "0.1.1"]
|
[com.cemerick/url "0.1.1"]
|
||||||
[camel-snake-kebab "0.1.5"]])
|
[camel-snake-kebab "0.4.0"]]
|
||||||
|
|
||||||
|
:profiles {:provided
|
||||||
|
{:dependencies [[org.clojure/clojure "1.8.0"]]}
|
||||||
|
|
||||||
|
:test
|
||||||
|
{:dependencies [[pjstadig/humane-test-output "0.8.1"]]
|
||||||
|
:injections [(require 'pjstadig.humane-test-output)
|
||||||
|
(pjstadig.humane-test-output/activate!)]}})
|
||||||
|
|
|
@ -1,11 +1,14 @@
|
||||||
(ns clj-hl7-fhir.core
|
(ns clj-hl7-fhir.core
|
||||||
(:import (java.util Date)
|
(:refer-clojure :exclude [update])
|
||||||
(clojure.lang ExceptionInfo))
|
(:require
|
||||||
(:require [clojure.string :as str]
|
[camel-snake-kebab.core :as csk]
|
||||||
[cemerick.url :refer [url]]
|
[cemerick.url :refer [url]]
|
||||||
[cheshire.core :as json])
|
[cheshire.core :as json]
|
||||||
(:use [camel-snake-kebab]
|
[clojure.string :as string]
|
||||||
[clj-hl7-fhir.util]))
|
[clj-hl7-fhir.util :as util])
|
||||||
|
(:import
|
||||||
|
(java.util Date)
|
||||||
|
(clojure.lang ExceptionInfo)))
|
||||||
|
|
||||||
; HACK: using this dynamic/"with"-wrapping type of API design is arguably a "lazy" design.
|
; HACK: using this dynamic/"with"-wrapping type of API design is arguably a "lazy" design.
|
||||||
; in the future I intend to explore reworking the API so as to not require this if
|
; in the future I intend to explore reworking the API so as to not require this if
|
||||||
|
@ -49,30 +52,30 @@
|
||||||
(if (map? (:headers *options*)) {:headers (:headers *options*)})))
|
(if (map? (:headers *options*)) {:headers (:headers *options*)})))
|
||||||
|
|
||||||
(defn- ->fhir-resource-name [x]
|
(defn- ->fhir-resource-name [x]
|
||||||
(name (->CamelCase x)))
|
(name (csk/->PascalCase x)))
|
||||||
|
|
||||||
(defn- fhir-response? [response]
|
(defn- fhir-response? [response]
|
||||||
(and (map? response)
|
(and (map? response)
|
||||||
(.contains (get-in response [:headers "Content-Type"]) "application/json+fhir")))
|
(.contains (get-in response [:headers "Content-Type"]) "application/json+fhir")))
|
||||||
|
|
||||||
(defn- fhir-request [type base-url resource-url & {:keys [params body params-as-body? follow-location?]}]
|
(defn- fhir-request [type base-url resource-url & {:keys [params body params-as-body? follow-location?]}]
|
||||||
(let [query (map->query-string params)
|
(let [query (util/map->query-string params)
|
||||||
url (build-url base-url resource-url (if-not params-as-body? query))
|
url (util/build-url base-url resource-url (if-not params-as-body? query))
|
||||||
body (if params-as-body? query body)
|
body (if params-as-body? query body)
|
||||||
follow-location? (if (nil? follow-location?) true follow-location?)
|
follow-location? (if (nil? follow-location?) true follow-location?)
|
||||||
http-req-params (get-base-http-req-params)]
|
http-req-params (get-base-http-req-params)]
|
||||||
(try
|
(try
|
||||||
(let [response (case type
|
(let [response (case type
|
||||||
:get (http-get-json url http-req-params)
|
:get (util/http-get-json url http-req-params)
|
||||||
:form-post (http-post-form url http-req-params body)
|
:form-post (util/http-post-form url http-req-params body)
|
||||||
:post (http-post-json url http-req-params body)
|
:post (util/http-post-json url http-req-params body)
|
||||||
:put (http-put-json url http-req-params body)
|
:put (util/http-put-json url http-req-params body)
|
||||||
:delete (http-delete-json url http-req-params body))
|
:delete (util/http-delete-json url http-req-params body))
|
||||||
response-body (:body response)
|
response-body (:body response)
|
||||||
location (get-in response [:headers "Location"])]
|
location (get-in response [:headers "Location"])]
|
||||||
(if location
|
(if location
|
||||||
(if follow-location?
|
(if follow-location?
|
||||||
(-> (http-get-json location http-req-params)
|
(-> (util/http-get-json location http-req-params)
|
||||||
:body
|
:body
|
||||||
(json/parse-string true))
|
(json/parse-string true))
|
||||||
(if (fhir-response? response)
|
(if (fhir-response? response)
|
||||||
|
@ -98,7 +101,7 @@
|
||||||
(if (vector? parameter)
|
(if (vector? parameter)
|
||||||
(->> parameter
|
(->> parameter
|
||||||
(map name)
|
(map name)
|
||||||
(str/join ".")
|
(string/join ".")
|
||||||
)
|
)
|
||||||
(name parameter))
|
(name parameter))
|
||||||
(if modifier
|
(if modifier
|
||||||
|
@ -130,13 +133,13 @@
|
||||||
(sequential? value)
|
(sequential? value)
|
||||||
(->> value
|
(->> value
|
||||||
(map format-search-value)
|
(map format-search-value)
|
||||||
(str/join ","))
|
(string/join ","))
|
||||||
|
|
||||||
(map? value)
|
(map? value)
|
||||||
(str (:namespace value) "|" (format-search-value (:value value)))
|
(str (:namespace value) "|" (format-search-value (:value value)))
|
||||||
|
|
||||||
(instance? Date value)
|
(instance? Date value)
|
||||||
(->timestamp value)
|
(util/->timestamp value)
|
||||||
|
|
||||||
:else
|
:else
|
||||||
(-> value str escape-parameter)))
|
(-> value str escape-parameter)))
|
||||||
|
@ -210,7 +213,7 @@
|
||||||
|
|
||||||
(defn- format-resource-url-type [url-path-parts keywordize?]
|
(defn- format-resource-url-type [url-path-parts keywordize?]
|
||||||
(if keywordize?
|
(if keywordize?
|
||||||
(-> url-path-parts first ->kebab-case keyword)
|
(-> url-path-parts first csk/->kebab-case keyword)
|
||||||
(-> url-path-parts first ->fhir-resource-name)))
|
(-> url-path-parts first ->fhir-resource-name)))
|
||||||
|
|
||||||
(defn parse-relative-url
|
(defn parse-relative-url
|
||||||
|
@ -221,7 +224,7 @@
|
||||||
the URL cannot be parsed, returns nil"
|
the URL cannot be parsed, returns nil"
|
||||||
[relative-url & [keywordize?]]
|
[relative-url & [keywordize?]]
|
||||||
(let [parts (-> (strip-query-params relative-url)
|
(let [parts (-> (strip-query-params relative-url)
|
||||||
(str/split #"/"))]
|
(string/split #"/"))]
|
||||||
(cond
|
(cond
|
||||||
(= 2 (count parts))
|
(= 2 (count parts))
|
||||||
{:type (format-resource-url-type parts keywordize?)
|
{:type (format-resource-url-type parts keywordize?)
|
||||||
|
@ -241,11 +244,11 @@
|
||||||
the URL cannot be parsed, returns nil."
|
the URL cannot be parsed, returns nil."
|
||||||
[absolute-url & [keywordize?]]
|
[absolute-url & [keywordize?]]
|
||||||
(let [{:keys [path]} (url absolute-url)
|
(let [{:keys [path]} (url absolute-url)
|
||||||
parts (str/split path #"/")
|
parts (string/split path #"/")
|
||||||
has-version? (= "_history" (second (reverse parts)))]
|
has-version? (= "_history" (second (reverse parts)))]
|
||||||
(cond
|
(cond
|
||||||
(and (> (count parts) 4)
|
(and (> (count parts) 4)
|
||||||
(= "_history" (second-last parts))
|
(= "_history" (util/second-last parts))
|
||||||
has-version?)
|
has-version?)
|
||||||
(let [versioned-url-parts (take-last 4 parts)]
|
(let [versioned-url-parts (take-last 4 parts)]
|
||||||
{:type (format-resource-url-type versioned-url-parts keywordize?)
|
{:type (format-resource-url-type versioned-url-parts keywordize?)
|
||||||
|
@ -263,7 +266,7 @@
|
||||||
passed in is not a string (or an empty string) an exception is thrown."
|
passed in is not a string (or an empty string) an exception is thrown."
|
||||||
[^String resource-url]
|
[^String resource-url]
|
||||||
(if (and (string? resource-url)
|
(if (and (string? resource-url)
|
||||||
(not (str/blank? resource-url)))
|
(not (string/blank? resource-url)))
|
||||||
(boolean
|
(boolean
|
||||||
(try
|
(try
|
||||||
(url resource-url)
|
(url resource-url)
|
||||||
|
@ -297,8 +300,8 @@
|
||||||
"combines a base URL to a FHIR server and a relative FHIR resource URL into an
|
"combines a base URL to a FHIR server and a relative FHIR resource URL into an
|
||||||
absolute resource URL."
|
absolute resource URL."
|
||||||
[base-url relative-url]
|
[base-url relative-url]
|
||||||
(if-not (or (str/blank? base-url)
|
(if-not (or (string/blank? base-url)
|
||||||
(str/blank? relative-url))
|
(string/blank? relative-url))
|
||||||
(-> (url base-url relative-url)
|
(-> (url base-url relative-url)
|
||||||
(.toString))))
|
(.toString))))
|
||||||
|
|
||||||
|
@ -350,7 +353,7 @@
|
||||||
[bundle]
|
[bundle]
|
||||||
(if-let [next-url (get-bundle-next-page-url bundle)]
|
(if-let [next-url (get-bundle-next-page-url bundle)]
|
||||||
(let [http-req-params (get-base-http-req-params)]
|
(let [http-req-params (get-base-http-req-params)]
|
||||||
(http-get-json next-url http-req-params))))
|
(util/http-get-json next-url http-req-params))))
|
||||||
|
|
||||||
(defn- concat-bundle-entries [bundle other-bundle]
|
(defn- concat-bundle-entries [bundle other-bundle]
|
||||||
(if (nil? bundle)
|
(if (nil? bundle)
|
||||||
|
@ -400,7 +403,7 @@
|
||||||
reference:
|
reference:
|
||||||
contained resources: http://www.hl7.org/implement/standards/fhir/references.html#contained"
|
contained resources: http://www.hl7.org/implement/standards/fhir/references.html#contained"
|
||||||
[containing-resource ref-id]
|
[containing-resource ref-id]
|
||||||
(if-not (str/blank? ref-id)
|
(if-not (string/blank? ref-id)
|
||||||
(if-let [parsed-id (if (.startsWith ref-id "#") (subs ref-id 1))]
|
(if-let [parsed-id (if (.startsWith ref-id "#") (subs ref-id 1))]
|
||||||
(->> (:contained containing-resource)
|
(->> (:contained containing-resource)
|
||||||
(filter #(= parsed-id (:id %)))
|
(filter #(= parsed-id (:id %)))
|
||||||
|
@ -453,7 +456,7 @@
|
||||||
url-components (if version
|
url-components (if version
|
||||||
["/" resource-name id "_history" version]
|
["/" resource-name id "_history" version]
|
||||||
["/" resource-name id])]
|
["/" resource-name id])]
|
||||||
(get-resource base-url (apply join-paths url-components)))))
|
(get-resource base-url (apply util/join-paths url-components)))))
|
||||||
|
|
||||||
(defn get-relative-resource
|
(defn get-relative-resource
|
||||||
"gets a single resource from a FHIR server. the server to be queried will be taken from the
|
"gets a single resource from a FHIR server. the server to be queried will be taken from the
|
||||||
|
@ -479,10 +482,10 @@
|
||||||
url-components ["/" resource-name]]
|
url-components ["/" resource-name]]
|
||||||
(fhir-request :get
|
(fhir-request :get
|
||||||
base-url
|
base-url
|
||||||
(apply join-paths url-components)
|
(apply util/join-paths url-components)
|
||||||
:params (merge
|
:params (merge
|
||||||
{:_id id}
|
{:_id id}
|
||||||
(build-params-map params)))))
|
(util/build-params-map params)))))
|
||||||
|
|
||||||
(defn history
|
(defn history
|
||||||
"returns a bundle containing the history of a single FHIR resource. note that this history can
|
"returns a bundle containing the history of a single FHIR resource. note that this history can
|
||||||
|
@ -501,8 +504,8 @@
|
||||||
url-components ["/" resource-name id "_history"]]
|
url-components ["/" resource-name id "_history"]]
|
||||||
(fhir-request :get
|
(fhir-request :get
|
||||||
base-url
|
base-url
|
||||||
(apply join-paths url-components)
|
(apply util/join-paths url-components)
|
||||||
:params (build-params-map params))))
|
:params (util/build-params-map params))))
|
||||||
|
|
||||||
(defn search
|
(defn search
|
||||||
"searches for resources on a FHIR server. multiple parameters are ANDed together. use of the search
|
"searches for resources on a FHIR server. multiple parameters are ANDed together. use of the search
|
||||||
|
@ -521,11 +524,11 @@
|
||||||
url-components ["/" resource-name "/_search"]]
|
url-components ["/" resource-name "/_search"]]
|
||||||
(fhir-request :form-post
|
(fhir-request :form-post
|
||||||
base-url
|
base-url
|
||||||
(apply join-paths url-components)
|
(apply util/join-paths url-components)
|
||||||
:params-as-body? true
|
:params-as-body? true
|
||||||
:params (merge
|
:params (merge
|
||||||
(search-params->query-map where)
|
(search-params->query-map where)
|
||||||
(build-params-map params)))))
|
(util/build-params-map params)))))
|
||||||
|
|
||||||
(defn search-and-fetch
|
(defn search-and-fetch
|
||||||
"same as search, but automatically fetches all pages of resources returning a single bundle
|
"same as search, but automatically fetches all pages of resources returning a single bundle
|
||||||
|
@ -551,7 +554,7 @@
|
||||||
return-resource? (if (nil? return-resource?) true return-resource?)]
|
return-resource? (if (nil? return-resource?) true return-resource?)]
|
||||||
(fhir-request :post
|
(fhir-request :post
|
||||||
base-url
|
base-url
|
||||||
(apply join-paths uri-components)
|
(apply util/join-paths uri-components)
|
||||||
:body resource
|
:body resource
|
||||||
:follow-location? return-resource?)))
|
:follow-location? return-resource?)))
|
||||||
|
|
||||||
|
@ -574,7 +577,7 @@
|
||||||
return-resource? (if (nil? return-resource?) true return-resource?)]
|
return-resource? (if (nil? return-resource?) true return-resource?)]
|
||||||
(fhir-request :put
|
(fhir-request :put
|
||||||
base-url
|
base-url
|
||||||
(apply join-paths uri-components)
|
(apply util/join-paths uri-components)
|
||||||
:body resource
|
:body resource
|
||||||
:follow-location? return-resource?)))
|
:follow-location? return-resource?)))
|
||||||
|
|
||||||
|
@ -589,7 +592,7 @@
|
||||||
uri-components ["/" resource-name id]]
|
uri-components ["/" resource-name id]]
|
||||||
(fhir-request :delete
|
(fhir-request :delete
|
||||||
base-url
|
base-url
|
||||||
(apply join-paths uri-components))))
|
(apply util/join-paths uri-components))))
|
||||||
|
|
||||||
(defn deleted?
|
(defn deleted?
|
||||||
"checks if a resource has been deleted or not. this is based on FHIR servers returning
|
"checks if a resource has been deleted or not. this is based on FHIR servers returning
|
||||||
|
@ -597,7 +600,7 @@
|
||||||
[base-url type id]
|
[base-url type id]
|
||||||
(let [resource-name (->fhir-resource-name type)
|
(let [resource-name (->fhir-resource-name type)
|
||||||
url-components ["/" resource-name id]
|
url-components ["/" resource-name id]
|
||||||
relative-url (apply join-paths url-components)]
|
relative-url (apply util/join-paths url-components)]
|
||||||
(try
|
(try
|
||||||
(fhir-request :get
|
(fhir-request :get
|
||||||
base-url
|
base-url
|
||||||
|
@ -651,13 +654,13 @@
|
||||||
(:valueDecimal extension))
|
(:valueDecimal extension))
|
||||||
|
|
||||||
(defmethod get-extension-value :valueDateTime [extension]
|
(defmethod get-extension-value :valueDateTime [extension]
|
||||||
(parse-timestamp (:valueDateTime extension)))
|
(util/parse-timestamp (:valueDateTime extension)))
|
||||||
|
|
||||||
(defmethod get-extension-value :valueDate [extension]
|
(defmethod get-extension-value :valueDate [extension]
|
||||||
(parse-date (:valueDate extension)))
|
(util/parse-date (:valueDate extension)))
|
||||||
|
|
||||||
(defmethod get-extension-value :valueInstant [extension]
|
(defmethod get-extension-value :valueInstant [extension]
|
||||||
(parse-timestamp (:valueInstant extension)))
|
(util/parse-timestamp (:valueInstant extension)))
|
||||||
|
|
||||||
(defmethod get-extension-value :valueString [extension]
|
(defmethod get-extension-value :valueString [extension]
|
||||||
(:valueString extension))
|
(:valueString extension))
|
||||||
|
|
|
@ -1,10 +1,12 @@
|
||||||
(ns clj-hl7-fhir.util
|
(ns clj-hl7-fhir.util
|
||||||
(:import (java.util TimeZone Date)
|
(:require
|
||||||
(java.text SimpleDateFormat))
|
|
||||||
(:require [clojure.string :as str]
|
|
||||||
[clj-http.client :as http]
|
|
||||||
[cemerick.url :refer [url url-encode]]
|
[cemerick.url :refer [url url-encode]]
|
||||||
[cheshire.core :as json]))
|
[cheshire.core :as json]
|
||||||
|
[clj-http.client :as http]
|
||||||
|
[clojure.string :as string])
|
||||||
|
(:import
|
||||||
|
(java.util TimeZone Date)
|
||||||
|
(java.text SimpleDateFormat)))
|
||||||
|
|
||||||
(def tz (TimeZone/getDefault))
|
(def tz (TimeZone/getDefault))
|
||||||
(def iso8601-timestamp "yyyy-MM-dd'T'HH:mm:ssXXX")
|
(def iso8601-timestamp "yyyy-MM-dd'T'HH:mm:ssXXX")
|
||||||
|
@ -35,7 +37,7 @@
|
||||||
(format-date date iso8601-date))
|
(format-date date iso8601-date))
|
||||||
|
|
||||||
(defn parse-formatted-timestamp [^String timestamp ^String format]
|
(defn parse-formatted-timestamp [^String timestamp ^String format]
|
||||||
(if-not (str/blank? timestamp)
|
(if-not (string/blank? timestamp)
|
||||||
(let [df (SimpleDateFormat. format)]
|
(let [df (SimpleDateFormat. format)]
|
||||||
(.setTimeZone df tz)
|
(.setTimeZone df tz)
|
||||||
(.parse df timestamp))))
|
(.parse df timestamp))))
|
||||||
|
@ -84,8 +86,8 @@
|
||||||
(defn join-paths [& paths]
|
(defn join-paths [& paths]
|
||||||
(as-> paths x
|
(as-> paths x
|
||||||
(remove nil? x)
|
(remove nil? x)
|
||||||
(str/join "/" x)
|
(string/join "/" x)
|
||||||
(str/replace x #"(/+)" "/")))
|
(string/replace x #"(/+)" "/")))
|
||||||
|
|
||||||
(defn build-url [base-url path & [params]]
|
(defn build-url [base-url path & [params]]
|
||||||
(-> (url base-url)
|
(-> (url base-url)
|
||||||
|
|
Reference in a new issue