Skip to content

Add support for constraint schemas: This, that, or both keys in map  #474

@brettrowberry

Description

@brettrowberry

I'm just getting started with Malli, and I really like it!

There is something I can't figure out.

Consider this schema:

(def Schema
  [:map
   [:x boolean?]
   [:y {:optional true} int?]
   [:z {:optional true} string?]])

(m/validate Schema {:x true}) => true

Now imagine I want to require :y, :z, or both such that:

(m/validate Schema {:x true})              => false
(m/validate Schema {:x true :y 1})         => true
(m/validate Schema {:x true :z "hi"})      => true
(m/validate Schema {:x true :y 1 :z "hi"}) => true

Attempt 1

(def Schema
  [:map
   [:x boolean?]
   [:or
    [:y {:optional true} int?]
    [:z {:optional true} string?]]])

(m/validate Schema {:x true})

; Execution error (ExceptionInfo) at malli.impl.util/-fail! (util.cljc:17).
; :malli.core/invalid-schema {:schema :z}

Attempt 2

(def Schema
  [:or
   [:map
    [:x boolean?
     :y int?]]
   [:map
    [:x boolean?
     :z string?]]
   [:map
    [:x boolean?
     :y int?
     :z string?]]])

(m/validate Schema {:x true}) => true

That's not good!

Attempt 3

(def Schema
  [:and
   [:map [:x boolean?]]
   [:or
    [:map [:y int?]]
    [:map [:z string?]]
    [:map [:y int? :z string?]]]])

(m/validate Schema {:x true})              => false
(m/validate Schema {:x true :y 1})         => true
(m/validate Schema {:x true :z "hi"})      => true
(m/validate Schema {:x true :y 1 :z "hi"}) => true

This seems to work, but there's a bit of repetition.

The errors are pretty good, but perhaps they could be better if I did this the right way:

(me/humanize (m/explain Schema {:x true}))

=>
{:y
 ["missing required key"
  "missing required key"],
 :z ["missing required key"]}

(me/humanize (m/explain Schema {:x true :y "hi"}))

=> 
{:y
 ["should be an int"
  "should be an int"]
 :z ["missing required key"]}

What's the best way to do this?

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    Status

    ⌛Waiting

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions