spec-tools icon indicating copy to clipboard operation
spec-tools copied to clipboard

Support for s/cat and regex ops (s/*, s/?, s/+) in data specs, with decoding

Open alza-bitz opened this issue 6 years ago • 0 comments

Hi there,

I am seeing some interesting results when I try and perform decoding on data specs with s/cat and regex ops.

For example, given the following example data specs:

(def sub-widget-a-spec
  (std/spec
   {:name ::sub-widget-a
    :spec {:a-prop pos-int?}}))

(def sub-widget-b-spec
  (std/spec
   {:name ::sub-widget-b
    :spec {:b-prop pos-int?}}))

(def sub-widget-c-spec
  (std/spec
   {:name ::sub-widget-c
    :spec {:c-prop pos-int?}}))

(def widget-spec
  (std/spec
   {:name ::widget-spec
    :spec {:the-sub-widget (s/cat
                            :sub-widget-a (std/spec {:name ::sub-widget-a
                                                     :spec sub-widget-a-spec})
                            :sub-widget-b (s/? (std/spec {:name ::sub-widget-b
                                                          :spec sub-widget-b-spec}))
                            :sub-widget-c (s/* (std/spec {:name ::sub-widget-c
                                                          :spec sub-widget-c-spec})))}}))

If I try and generate some sample data using the data spec, all is good and I see the regex op rules and ordering being adhered to for the sequence:

(gen/generate (s/gen widget-spec))
{:the-sub-widget ({:a-prop 22} {:c-prop 19} {:c-prop 1} {:c-prop 7436}

However, if I then try to perform decoding either with st/coerce or st/decode, for example decoding on already-encoded data, the data is left as-is (as in, it remains string encoded):

(def widget-encoded (st/encode widget-spec (gen/generate (s/gen widget-spec)) st/string-transformer))
widget-encoded
{:the-sub-widget ({:a-prop "285981"} {:b-prop "24438"} {:c-prop "844"} {:c-prop "102400766"} {:c-prop "1395"})}

With st/coerce:

(st/coerce widget-spec widget-encoded st/string-transformer)
{:the-sub-widget ({:a-prop "285981"} {:b-prop "24438"} {:c-prop "844"} {:c-prop "102400766"} {:c-prop "1395"})}

With st/decode:

(st/decode widget-spec widget-encoded st/string-transformer)
{:the-sub-widget ({:a-prop "285981"} {:b-prop "24438"} {:c-prop "844"} {:c-prop "102400766"} {:c-prop "1395"})}

Since st/decode uses st/coerce, it seems reasonable to assume that the issue lies inside the latter.

It's worth noting that st/conform followed by s/unform, instead of st/decode or st/coerce seems to work as expected:

(s/unform widget-spec (st/conform widget-spec widget-encoded st/string-transformer))
{:the-sub-widget ({:a-prop 285981} {:b-prop 24438} {:c-prop 844} {:c-prop 102400766} {:c-prop 1395})}

alza-bitz avatar Nov 22 '18 00:11 alza-bitz