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

Support conversion of data from one schema to another #241

Open
timclemons opened this issue Aug 5, 2020 · 1 comment
Open

Support conversion of data from one schema to another #241

timclemons opened this issue Aug 5, 2020 · 1 comment

Comments

@timclemons
Copy link

First off, thank for providing these tools. They've been instrumental in my current work.

I'd like to propose a feature request whereby type-based conversion with encode and decode can accommodate two specs: the spec for the original schema ("before") and another for the schema being targeted by the transform ("after"). As it stands, it looks like conform is getting called after each transform fn is called. That's fine provided the transform doesn't violate the spec, but there are cases of the transform ends up returning :invalid.

Example:

Say we get data for a jdbc connection as a map and would like to translate it to a string url.

(s/def :db/hostname string?)
(s/def :db/port pos-int?)
(s/def :db/database string?)
(s/def ::jdbc-connection
  (st/spec {:spec (s/keys :req-un [:db/hostname :db/port :db/database])
                 :type :dbconn}))

(defn dbconn->url
  [_ {:keys [hostname port database]}]
  (format "jdbc:postgres://%s:%s/%s" hostname port database))

(def jdbc-transformer
  (st/type-transformer
    {:name :jdbc
     :encoders {:dbconn dbconn->url}
     :default-encoder stt/any->any}))

(st/encode 
  ::jdbc-connection
  {:hostname "127.0.0.1" :port 5432 :database "postgres"}
  jdbc-transformer)

The current workaround for this is the use of multi-specs to encapsulate both before and after structures:

(defmulti jdbc-type class)
(defmethod jdbc-type :default
  [_]
  (st/spec {:spec (s/keys :req-un [:db/hostname :db/port :db/database])
                 :type :dbconn}))
(defmethod jdbc-type String
  [_]
  (s/spec string?))
(s/def ::jdbc-connection
  (s/multi-spec jdbc-type :tag))

However, this can be an awkward use case for multi-specs, particularly when translating a map or vector to a base type like a string. It also forces the spec to incorporate knowledge of all possible transforms, which breaks encapsulation.

All that said, I'm relatively new to this library and it could be I'm missing already established functionality. Appreciate any insights.

@wandersoncferreira
Copy link
Contributor

wandersoncferreira commented Nov 14, 2020

Hello again @timclemons ! I submitted a PR to accomplish this feature request. There are some odd bits that I noticed while coding it, when you run your first example wihtout the multispec, do you get a ::s/invalid key back or a ClassCastException? I got the exception back and seems like I cannot fix it without introducing breaking changes. The problem is not related to this feature request but with current behavior. There are more details in the PR page.

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

2 participants