I'm trying to match following sequences using Prismatic/Schema:
[{:n "some text"}] ; => valid
and
[{:k "some text"} {:n "some text"}] ; => valid
What I have tried:
(s/def Elem3
{:k s/Str})
(s/def Elem2
{:n s/Str})
(s/def Elem
[(s/optional Elem2 "elem2") Elem3])
(s/validate Elem [{:k "huji"}])
;; =>
;; Value does not match schema: [(named {:n missing-required-key, :k
;; disallowed-key} "elem2")]
(s/def Elem
[(s/maybe Elem2) Elem3])
(s/validate Elem [{:k "huji"}])
;; =>
;; [(maybe {:n Str}) {:k java.lang.String}] is not a valid sequence
;; schema; a valid sequence schema consists of zero or more `one`
;; elements, followed by zero or more `optional` elements, followed by
;; an optional schema that will match the remaining elements.
(s/defrecord ElemOption1
[elem3 :- Elem3])
(s/defrecord ElemOption2
[elem2 :- Elem2
elem3 :- Elem3])
(s/def Elem
(s/conditional
#(= 2 (count %)) ElemOption2
:else ElemOption1))
(s/validate Elem [{:k "huji"}])
;; =>
;; Value does not match schema: (not (instance?
;; peg_dsl.standard_app.ElemOption1 [{:k "huji"}]))
The main problem is that I don't understand what is the way to write schema which allows to omit first element of specified vector. What is the correct way to match both the vectors from above?
The problem with your first attempt is that starting with an
optional means it expects {:k s/Str} or nothing, and it's seeing
{:n s/Str}
, so that's clearly not right.
Your second attempt has two problems. Maybe
can be the value
or nil
, but it needs to be present. You're also not writing the
sequence schema correctly. But the problem with a sequence schema
is the elements need to be in the order s/one* s/optional*
, and you
want s/optional s/one
.
Your third attempt is closer, using the conditional, but you're failing to match because you're not validating instances of the records, you're validating maps.
A solution looks like this:
(def ElemKNList [(s/one {:k s/Str} "k") (s/one {:n s/Str} "n")])
(def ElemNList [(s/one {:n s/Str} "n")])
(def Elem (s/conditional #(= 2 (count %)) ElemKNList
:else ElemNList))
(s/validate Elem [{:k "huji"} {:n "huji"}])
=> [{:k "huji"} {:n "huji"}]
(s/validate Elem [{:n "huji"}])
=> [{:n "huji"}]
(s/validate Elem [{:k "huji"}])
=> ExceptionInfo Value does not match schema: [(named {:n missing-required-key, :k disallowed-key} "n")] schema.core/validator/fn--18435 (core.clj:151)