I’m trying to use Specter to convert some dates in string form to java.time.LocalDate objects in a deep map/vector hierarchy. I have a recursive path that correctly visits all the leaves of the tree:
(def TREE-VALS
(s/recursive-path [] p-vals
(s/cond-path vector? [s/ALL p-vals]
map? [s/MAP-VALS p-vals]
string? s/STAY)))
and I’m trying to do this:
(s/transform [TREE-VALS #"\d\d\d\d-\d\d-\d\d"] ld/parse my-data-structure)
where “ld” is the cljc.java-time.LocalDate library and ld/parse is effectively java.time.LocalDate/parse.
But I get this error:
Execution error (ClassCastException) at com.rpl.specter$fn$reify__16117/transform_STAR_ (specter.cljc:1136).
class java.time.LocalDate cannot be cast to class java.lang.String (java.time.LocalDate and java.lang.String are in module java.base of loader 'bootstrap')
It seems like once it navigates to a string, it doesn’t want to be able to transform that to a LocalDate. If my transformation function returns a string (e.g., #(str % "-blah")), it works as expected. So, what am I doing wrong? Specter can convert a visited object from one type to another, right?!?!using a regex implicitly uses regex-nav, which calls (clojure.string/replace structure re next-fn)
so using a regex navigates to the matches within that string
whereas you're expecting it to act like a predicate to filter
you should use something like (fn [s] (re-matches #"\d\d\d\d-\d\d-\d\d" s))
Ah, OK, gotcha. Makes sense. Use that function (or something like it) as a path predicate or do the match in the transformation function (e.g., if match, then parse the date, otherwise return the same string)?
I would do that in the path
if you do it in the transform function, then you need to return the value unchanged in the else case
fyi, this is the part of the Specter implementation which determines how a regex in a path is interpreted https://github.com/redplanetlabs/specter/blob/master/src/clj/com/rpl/specter.cljc#L1260
OK, thanks Nathan. Much appreciated!
Another qq: Is it a lot more efficient to perform multiple transformations in a single call to multi-transform than multiple calls to transform? I have a couple of different date types I need to convert (both local dates and zoned date-times). Doing it as multiple passes is fairly straight-forward, but that seems like it would be a lot slower since I’d have to visit every node in the tree twice.
a multi-transform would be faster