Fork me on GitHub
#schema
<
2024-01-02
>
RAJKUMAR23:01:06

Hi, I'm trying to simulate oneOf which is in JsonSchema in plumatic/Schema

RAJKUMAR23:01:47

example code here

RAJKUMAR23:01:52

(s/defschema Dog
  {
   :food s/Str
   :activities s/Str
   })

(s/defschema Cat
  {
   :name s/Str
   })

(s/defschema Animal { s/enum [Dog Cat]}) 

RAJKUMAR23:01:09

then (s/check Animal {:food "biscuits" :activities "running"}) gives error

RAJKUMAR23:01:24

> Execution error at schema.core/parse-sequence-schema (core.cljc:940). > [{:food java.lang.String, :activities java.lang.String} {:name 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.

RAJKUMAR23:01:49

Any idea what is that I'm doing wrong here?

imre11:01:12

s/enum is applied incorrectly in the example, its correct application would be (s/defschema Animal (s/enum Dog Cat))

imre11:01:04

However that won't help in this case - checking enum's docstring:

schema.core/enum [& vs]  A value that must be = to some element of vs.

imre11:01:12

You'd need to use s/conditional:

(s/defschema Animal (s/conditional (every-pred map? #(contains? % :name)) Cat :else Dog))

(s/check Animal {:food "biscuits" :activities "running"})
=> nil
(s/check Animal {:name "Misty"})
=> nil

imre12:01:59

(there are also a few other similar options: s/cond-pre could be used if the type of the datums were different (but here both Dog and Cat are maps). There's also s/either but that's deprecated due to it not working good with coercion, so s/conditional is suggested in its docstring