Optional element in sequence
I am trying to match the following sequences using Prismatic / Schema:
[{:n "some text"}] ; => valid
and
[{:k "some text"} {:n "some text"}] ; => valid
What I 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 do not understand how to write a scheme that allows you to omit the first element of the specified vector. What is the correct way to combine both vectors from above?
The problem with your first attempt is that starting with does not necessarily mean that he expects {: ks / Str} or nothing, and he sees
{:n s/Str}, so that is clearly not correct.
. Maybe
nil, .
.
s/one* s/optional*,
s/optional s/one.
, , , , .
:
(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)