metosin / malli

High-performance data-driven data specification library for Clojure/Script.
Eclipse Public License 2.0
1.44k stars 204 forks source link

Fn guard #1000

Closed ikitommi closed 5 months ago

ikitommi commented 5 months ago

Function Guards

:=> accepts optional third child, a guard schema that is used to validate a vector of function arguments and return value.

;; function schema of arg:int -> ret:int, where arg < ret
;; with generative function checking always enabled
(def input<output
  (m/schema
   [:=>
    [:cat :int]
    :int
    [:fn {:error/message "argument should be less than return"}
     (fn [[[arg] ret]] (< arg ret))]]
   {::m/function-checker mg/function-checker}))

(m/explain input<output (fn [x] (inc x)))
; nil

(m/explain input<output (fn [x] x))
;{:schema ...
; :value #object[user$eval19073$fn__19074],
; :errors ({:path [],
;           :in [],
;           :schema ...,
;           :value #object[user$eval19073$fn__19074],
;           :check {:total-nodes-visited 1,
;                   :result false,
;                   :result-data nil,
;                   :smallest [(0)],
;                   :time-shrinking-ms 0,
;                   :pass? false,
;                   :depth 0,
;                   :malli.core/result 0}},
;          {:path [2],
;           :in [],
;           :schema [:fn
;                    #:error{:message "argument should be less than return"}
;                    (fn [[[arg] ret]] (< arg ret))],
;           :value [(0) 0]})}

(me/humanize *1)
; ["invalid function" "argument should be less than return"]

Identical schema using the Schema AST syntax:

(m/from-ast
 {:type :=>
  :input {:type :cat
          :children [{:type :int}]}
  :output {:type :int}
  :guard {:type :fn
          :value (fn [[[arg] ret]] (< arg ret))
          :properties {:error/message "argument should be less than return"}}}
 {::m/function-checker mg/function-checker})
allentiak commented 5 months ago

Thank you so much for this, @ikitommi !