Search code examples
clojurepreconditionsplumatic-schema

Is it possible to use Prismatic schema.core/maybe in a Clojure function precondition?


I'm trying to use Prismatic schema.core/maybe in a precondition for a function taking an optional argument opts, but it seems to always throw an AssertionError when I call the function with no opts:

(require '[schema.core :as schema])

(defn foo [& modules]
  {:pre [(schema/validate (schema/maybe [(schema/enum :foo :bar)]) opts)]}
  :yay)

(foo :foo)
;=> :yay

(foo :foo :bar)
;=> :yay

(foo)
;=> AssertionError Assert failed: (schema/validate (schema/maybe [(schema/enum :foo :bar)]) modules)  user/foo (form-init3808809389777994177.clj:1)

The interesting thing is that this works as expected:

(schema/validate (schema/maybe [(schema/enum :foo :bar)]) nil)
;=> nil

I've used macroexpand on the defn, but nothing looks out of the ordinary there.

I can of course work around this with a precondition like


Solution

  • A function precondition must evaluate as truthy for the assertion to pass, but schema/validate returns the expression being tested if validation passes, and throws an exception if it fails. You'll need to alter your precondition to always return true if the validation passes:

    (defn foo [& opts]
      {:pre [(or (schema/validate (schema/maybe [(schema/enum :foo :bar)]) opts) true)]}
      :yay)
    
    (foo :foo) ;=> :yay
    (foo :foo :bar) ;=> :yay
    (foo) ;=> :yay
    (foo :baz) ;=> ExceptionInfo Value does not match schema: [(not (#{:foo :bar} :baz))]