Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

At least one optional key present in clojure's Schema

Say I have the following Schema for some input I'm receiving from the outside world:

(def my-schema
  {(s/optional-key :foo) Bool
   (s/optional-key :baz) Bool
   (s/optional-key :bar) Bool})

With the above, all or none of the keys can be present or missing in the map I'm validating, makes sense. However, what if I want to make sure that at least one of them is present?

I can certainly perform an additional separate check after Schema has validated the above and make sure that the key count >= 1, but I'm curious if there's a way of enforcing that in Schema definitions themselves.

Thoughts?

like image 200
Alexandr Kurilin Avatar asked Aug 16 '14 23:08

Alexandr Kurilin


2 Answers

You can specify whatever predicate you want in your schemas:

(def my-schema
  (s/both
     (s/pred (complement empty) 'not-empty)
     {(s/optional-key :foo) Bool
      (s/optional-key :baz) Bool
      (s/optional-key :bar) Bool}))

If you are asking how to validate the map using just the built-in predicates you could write:

(def my-schema
  (s/both
     {(s/optional-key :foo) Bool
      (s/optional-key :baz) Bool
      (s/optional-key :bar) Bool}
     (s/either
      {:foo Bool s/Any s/Any}
      {:baz Bool s/Any s/Any}
      {:bar Bool s/Any s/Any})))

which is pretty ugly and a lot more verbose than the pred example

like image 151
DanLebrero Avatar answered Sep 20 '22 19:09

DanLebrero


Another way to do this (probably better) is to use constrained:

(def my-schema
  (s/constrained
    {(s/optional-key :foo) Bool
     (s/optional-key :baz) Bool
     (s/optional-key :bar) Bool}
    (fn [{:keys foo baz bar}]
      (or foo bar bar))
     "At least one of the keys is required")))
like image 34
baself Avatar answered Sep 20 '22 19:09

baself