Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Encodes fails when using multi-spec #238

Open
felipegmarques opened this issue Jun 27, 2020 · 0 comments
Open

Encodes fails when using multi-spec #238

felipegmarques opened this issue Jun 27, 2020 · 0 comments

Comments

@felipegmarques
Copy link

Hello!

Problem

Version: 0.10.2

The following code fails:

(require '[clojure.spec.alpha :as s])
(require '[spec-tools.core :as st])

(def strict-json-transformer (st/type-transformer st/strip-extra-keys-transformer
                                                  st/json-transformer))

(def status-set #{:success :error})
(def reason-set #{:generic-error :some-other-error})

(s/def ::reason (st/spec {:spec reason-set :type :keyword}))
(s/def ::status (st/spec {:spec status-set :type :keyword}))

(defmulti inclusion-result :status)
(defmethod inclusion-result :success [_] (s/keys :req-un [::status]))
(defmethod inclusion-result :error [_] (s/keys :req-un [::status ::reason]))

(s/def ::inclusion-result (s/multi-spec inclusion-result :status))
(st/encode ::inclusion-result {:status :error, :reason :some-other-error} strict-json-transformer)

with the following exception:

1. Unhandled java.lang.IllegalStateException
   No method of: com.piposaude.spec-serialization.core-test/inclusion-result for
   dispatch value: error

                 alpha.clj:  964  clojure.spec.alpha/multi-spec-impl/reify
                 alpha.clj:  171  clojure.spec.alpha/unform
                 alpha.clj:  166  clojure.spec.alpha/unform
                 core.cljc:  417  spec_tools.core.Spec/unform_STAR_
                 alpha.clj:  171  clojure.spec.alpha/unform
                 alpha.clj:  166  clojure.spec.alpha/unform
                 core.cljc:  259  spec_tools.core$encode/invokeStatic
                 core.cljc:  250  spec_tools.core$encode/invoke
                 ....

I believe this relates to #119 .

Looking the code I saw that in the encode function there is an conform + unform pair, but the data
being passed to the unform is {:error "error" :status "some-other-error"}, therefore the multi-spec fails to perform the dispatch and find the right spec to do the unform.

Possible solution?

In the issue #119, you guys mention the possibility of:

if there is a way to ask from a multi-spec what spec it will dispatch for this given data, we could unform against that spec
directly, not for the multispec itself.

Which I imagine maps to these lines of code in the spec source-code (ref1 and ref2), wheremm is the multi-method.

(let [predx #(let [^clojure.lang.MultiFn mm @mmvar]
                    (c/and (.getMethod mm ((.dispatchFn mm) %))
                           (mm %)))]
; ....
(unform* [_ x] (if-let [pred (predx x)]
                         (unform pred x)
                         (throw (IllegalStateException. (str "No method of: " form " for dispatch value: " (dval x))))))

I believe it would be possible to modify the encode to get the right spec to use in the unform in the case of multi-spec.
But I'm not sure if this would be the right place to do so and how it would impact when we merge multi-spec with others specs. Maybe it would be better to wrap the multi-spec in a st/spec and modify the unform* there, but probably it would need access to the original data.

What do you think? Would be ok to add this as a condition in the encode function?
If you guys could give me direction on the best way to proceed, I could try to submit a patch.

Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant