如何编写一个规范,其中映射具有基于另一个键的异构内容的键

Kri*_*ris 1 clojure clojure.spec

我很确定我需要一个有效的多规格。但是我不确定如何说作为向量的键值可以包含异构映射。

我是我要规范的源数据:

(def int-attr { :type "int" :validations [{ :min 0 } { :max 100 }] })
(def string-attr { :type "string" :validations [{ :presence true }] })
Run Code Online (Sandbox Code Playgroud)

这是validations我遇到问题的type钥匙,取决于钥匙,"int"或者"string",我想要validations钥匙中的不同规格。

我很确定我必须使用multi-spec. 这是我尝试过的:

(defmulti attribute-type :type)
(defmethod attribute-type "string" [a] ::string-validations)
(defmethod attribute-type "int" [a] ::int-validations)

;; how to say this is a vector of int-min-validation, or int-max-validation etc.
;; (s/+ ...) and (s/or ...) maybe?
(s/def ::int-validations (...) 
(s/def ::string-validations (...)

;; not sure how to incorporate these...    
(s/def ::int-min-validation (s/keys :req-un [::min]))
(s/def ::int-max-validation (s/keys :req-un [::max]))
(s/def ::string-presence-validation (s/keys :req-un [::presence])) 

(s/def ::attribute (s/multi-spec attribute-type ::type))

(s/explain ::attribute int-attr)
(s/explain ::attribute string-attr)
Run Code Online (Sandbox Code Playgroud)

Ton*_*ala 5

使用命名空间关键字来允许相同的键,但使用两个不同的规范指定值,即int/validationsstring/validations。要允许包含地图的向量,一个不错的选择是使用s/coll-of.

(def int-attr { :type "int" :validations [{ :min 0 } { :max 100 }] })
(def string-attr { :type "string" :validations [{ :presence true }] })

(defmulti attribute-type :type)
(defmethod attribute-type "string" [_]
  (s/keys :req-un [::type :string/validations]))
(defmethod attribute-type "int" [_]
  (s/keys :req-un [::type :int/validations]))

(s/def :int/validations (s/coll-of :int/validation))
(s/def :string/validations (s/coll-of :string/presence))

(s/def :int/validation (s/keys :opt-un [:int/min :int/max]))
(s/def :int/min number?)
(s/def :int/max number?)
(s/def :string/presence (s/keys :req-un [::presence]))

(s/def ::attribute (s/multi-spec attribute-type ::type))

(s/explain ::attribute int-attr)    ;; => Success!
(s/explain ::attribute string-attr) ;; => Success!
Run Code Online (Sandbox Code Playgroud)