我有一个请求对象,它包含一系列映射。我想验证在这些映射中,给定的键没有重复的值。
例如,这是有效的:
[
{ :id 1, :data "foo" }
{ :id 2, :data "bar" }
]这是无效的,因为它包含:id 1的副本。
[
{ :id 1, :data "foo" }
{ :id 2, :data "bar" }
{ :id 1, :data "baz" }
]目前,我有一些类似于:
(def-map-schema item-schema
[[:id] integer?
[:data] string?])
(def-map-schema request-schema
[[:items] (sequence-of item-schema)])如何使用clj-schema表示此唯一性约束?
发布于 2014-04-28 12:18:50
clj-架构提供了一个函数clj-schema.schema/simple-schema,可用于将任意谓词转换为架构.下面是如何使用它实现maps-with-unique-key?模式:
(defn maps-with-unique-key? [k]
(s/simple-schema [(s/sequence-of map?)
(fn [xs]
(= (count xs)
(count (distinct (map #(get % k) xs)))))]))在REPL会议上:
(v/valid? (maps-with-unique-key? :id)
[])
;= true
(v/valid? (maps-with-unique-key? :id)
[{:id 0 :foo "bar"} {:id 1 :foo "baz"} {:id 2 :foo "quux"}])
;= true
(v/valid? (maps-with-unique-key? :id)
[{:id 0 :foo "bar"} {:id 1 :foo "baz"} {:id 0 :foo "quux"}])
;= false
(v/valid? (maps-with-unique-key? :id)
[["not a map"] {:id 0 :foo "bar"} {:id 1 :foo "baz"} {:id 2 :foo "quux"}])
;= false(下面是我对棱镜模式的最初答案。)
我不认为在标准模式发行版中有现成的模式,但是总是可以实现一个新的模式--参见模式的wiki中的定义新模式类型页面。
这是一个草图:
(defrecord MapsWithUniqueKey [k]
s/Schema
(walker [this]
(fn [x]
(if (and (or (seq? x) (vector? x))
(every? map? x)
(every? #(contains? % k) x)
(== (count x)
(count (distinct (map #(get % k) x)))))
x
(schema.macros/validation-error
this x
(list 'maps-with-unique-key? k (schema.utils/value-name x))))))
(explain [this]
(list 'maps-with-unique-key? k)))示例验证:
(s/check (->MapsWithUniqueKey :id)
[{:id 1 :foo "bar"} {:id 2 :foo "baz"} {:id 3 :foo "quux"}])
;= nil
(s/check (->MapsWithUniqueKey :id)
[{:id 1 :foo "bar"} {:id 2 :foo "baz"} {:id 1 :foo "quux"}])
;= (not (maps-with-unique-key? :id a-clojure.lang.PersistentVector))从第一个调用返回的nil表示成功,而后者返回的值是一个schema.utils.ValidationError。
https://stackoverflow.com/questions/23339695
复制相似问题