clojureplumatic-schema

Prismatic schema coercion - renaming map key


I'm trying to coerce a map using prismatic-schema (1.0.4)

I'm trying to coerce

{:a 1}

to

{:b 1}

Using a custom matcher with the schema:

{:b s/Int}

But this code isn't working:

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

((coerce/coercer {:b s/Int}
                 (fn [s]
                   (when (= s s/Keyword)
                     (fn [x]
                       (if (= x :a)
                       :b
                       x))))) 
{:a 1})

Output:

 #schema.utils.ErrorContainer{:error {:b missing-required-key, :a disallowed-key}}

I tried debugging it by running the following code which matches everything in the schema and outputs the current value and schema being matched:

 ((coerce/coercer {:b s/Int}
             (fn [s]
               (when true
                 (fn [x]
                   (println s x)
                   x)))) 
  {:a 1})

Output:

 {:b Int} {:a 1}
 =>
 #schema.utils.ErrorContainer{:error {:b missing-required-key, :a disallowed-key}}

It looks as though the matcher bombs out as soon as it gets to the map?


Solution

  • Schema first breaks your map up into pieces that match up to the schema, then coerces each MapEntry to the corresponding MapEntry schema, and so on down. This breakdown fails in your case, so you never get to the key.

    To accomplish what you want, you'll have to attach the coercion to the map schema and use e.g. clojure.set/rename-keys in your coercion function:

    (def Foo {:b s/Int})
    ((coerce/coercer 
       Foo
       (fn [s]
         (when (= s Foo)
           #(clojure.set/rename-keys % {:a :b}))))
     {:a 1})