Main | My top n tips for python coding in Optimisation »
Tuesday
Mar172015

Caching in transit-cljs

So I've been doing alot of coding in clojurescript lately and I had to do some work with transit-cljs.

One of the things I had to test was if I could do comprehensive caching and de-duping of objects serialized with transit-cljs. I based my tests on transit-js-caching but this article has an example in javascript and not clojurescript. So I needed to convert it. Here is how I did it but you will need to read the previous article for the motivation of each step.

1) include the transit-cljs library in your code

 (ns main.transit
    (:require [cognitect.transit :as t]))

2) define an Object in clojurescript

 (defrecord Point [x y])

you can also use deftype but defrecord provides more helper functions like equality etc

3) define a custom write handler with transit-cljs and a function that uses it

 (def PointHandler 
   (t/write-handler (fn [v, h] "point") (fn [v, h] [v.x v.y])))

 (def writer (t/writer "json" {:handlers {Point PointHandler}}))

 (defn write [x]
   (t/write writer x))

3) use this writing function

 (def p (Point. 1 2))

 (print (write p))
 (print (write [p p p p]))

gives

 "[\"~#point\",[1,2]]"
 "[[\"~#point\",[1,2]],[\"^0\",[1,2]],
  [\"^0\",[1,2]],[\"^0\",[1,2]]]"

see by default transit-cljs caches the keys in the JSON

4) create a custom reader

 (defn read [x]
    (t/read (t/reader "json" 
                      {:handlers {"point" 
                                 (fn [v] 
                                     (Point. (aget v 0) 
                                             (aget v 1)))}})
            x))

5) now we can do a roundtrip!

 (print (= p (read (write p))))
 (print (= [p p p p] (read (write [p p p p]))))

 true
 true

6) How do we write a caching writer

 (defn caching-point-handler
   ([] (caching-point-handler (atom {})))
   ([cache]
    (t/write-handler 
      (fn [v, h] (if (get @cache v) 
                   "cache" 
                   "point")) 
      (fn [v, h] (let [id (get @cache v)] 
                   (if (nil? id)
                     (do 
                       (swap! cache 
                              #(assoc % v (count %)))
                       [v.x v.y])
                     id))))))

 (defn c-writer 
   []
   (t/writer "json" {:handlers {Point (caching-point-handler)}}))

 (defn c-write [x]
   (t/write (c-writer) x))

7) what does this produce

 (print (c-write p))
 (print (c-write [p p p p]))

 "[\"~#point\",[1,2]]"
 "[[\"~#point\",[1,2]],[\"~#cache\",0],
  [\"^1\",0],[\"^1\",0]]"

note that the second item is cached and the "cache" keyword is replaced by ^1 in the third item

8) what does the reader look like

 (defn c-read [x]
   (let [cache (atom {})] 
     (t/read (t/reader "json" 
                       {:handlers {"point" 
                                   (fn [v]
                                     (let [point (Point. 
                                                    (aget v 0) 
                                                    (aget v 1))]
                                       (swap! cache 
                                              #(assoc % 
                                                (count %) point))
                                       point))
                                   "cache"
                                   (fn [v]
                                     (get @cache v))}})
             x)))

9) now we can roundtrip

 (print (= p (c-read (c-write p))))
 (print (= [p p p p] (c-read (c-write [p p p p]))))))

 true
 true

PrintView Printer Friendly Version

EmailEmail Article to Friend

References (6)

References allow you to track sources for this article, as well as articles that were written in response to this article.

Reader Comments (1)

Hi

Does your site has RSS or Atom feed? I want to include Clojure-related parts into Planet Clojure.

Thanks

March 24, 2015 | Unregistered CommenterAlex Ott

PostPost a New Comment

Enter your information below to add a new comment.

My response is on my own website »
Author Email (optional):
Author URL (optional):
Post:
 
Some HTML allowed: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <code> <em> <i> <strike> <strong>