【问题标题】:Using clj-schema to validate that a sequence of maps has unique values for a given key使用 clj-schema 验证一系列映射对于给定键是否具有唯一值
【发布时间】:2014-04-30 06:02:49
【问题描述】:

我有一个包含一系列地图的请求对象。我想验证这些映射中的给定键没有重复值。

例如,这是有效的:

[
  { :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 来表达这种唯一性约束?

【问题讨论】:

    标签: validation clojure clj-schema


    【解决方案1】:

    clj-schema 提供了一个函数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
    

    (以下是我对 Prismatic 模式的原始答案。)

    我认为标准架构分发中没有现成的架构,但始终可以实现新架构 - 请参阅架构 wiki 中的 Defining New Schema Types 页面。

    这是一个草图:

    (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

    【讨论】:

    • 谢谢,但您的代码使用 Prismatic 模式,而不是 clj-schema :) 不过我可以看看它,因为它似乎更积极地开发。
    • 哎呀,对不起,不敢相信我错过了!猜猜我最近看到太多棱柱模式了。 :-) 这是一个很棒的图书馆,值得一看。无论如何,我将编辑我的答案,在一秒钟内添加一个适用于 clj-schema 1.0.0 的解决方案。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-12-02
    • 1970-01-01
    • 2015-06-22
    • 2023-03-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多