Monday, April 1, 2019

Clojure spec: key required depending on another key value

;; status > 0 => msgid required
(defmulti sendmt-rsp-mm (fn [rsp] (-> rsp :status (clojure.string/starts-with? "-")))) ; Actually means: status < 0
(defmethod sendmt-rsp-mm false [_] (s/keys :req-un [::status
                                                    ::msgid]))
(defmethod sendmt-rsp-mm true  [_] (s/keys :req-un [::status
                                                    ::text]))
(s/def ::sendmt-rsp (s/multi-spec sendmt-rsp-mm (fn [gen-v _] gen-v)))
or
(s/def ::sendmt-rsp (s/and (s/keys :req-un [::status])
                            #(if (clojure.string/starts-with? (:status %) "-")
                               (contains? % :text)
                               (contains? % :msgid))))
user> (s/valid? ::sendmt-rsp {:status "2" :text "caca"})
false
user> (s/valid? ::sendmt-rsp {:status "2" :msgid "caca"})
true
user> (s/valid? ::sendmt-rsp {:status "-2" :text "caca"})
true
user> (s/valid? ::sendmt-rsp {:status "-2" :msgid "caca"})
false