    {:name \"Bar Widget\" :price 200}]"
   ; Create rows by transforming  issue objects as follows:
   ; (A) only contain keys from cols map;
-  ; (B) values are all strings
-  ; (C) entries are in same order as cols entries
-  (let [transform-issue (comp
-                          #(into (sorted-map-by (partial map-key-comparator cols)) %)
+  ; (B) resolves nested values for path keys (e.g. replaces milestone object with title if key is [:milestone :title])
+  ; (C) values are all strings
+  ; (D) entries are in same order as cols entries
+  (let [topkeys (cols->topkeys cols)
+        transform-issue (comp
+                          #(into (sorted-map-by (partial idx-comparator topkeys)) %)
                           ;#(into (sorted-map) %)
                           #(fmap str %)
-                          #(select-keys % (keys cols)))
+                          #(map (partial resolve-nested-val cols) %)
+                          #(select-keys % topkeys))
         rows (map transform-issue issues)]
     (println "---------------")
     (clojure.pprint/pprint rows)

(ns labradoodle.excel
  (:use [dk.ative.docjure.spreadsheet]))

; http://stackoverflow.com/questions/1676891/mapping-a-function-on-the-values-of-a-map-in-clojure
(defn fmap [f m]
  (into {} (for [[k v] m] [k (f v)])))

(defn map-key-comparator [m a b]
  "Sort order is based on order of keys in map m"
  (let [idxa (.indexOf (keys m) a)
        idxb (.indexOf (keys m) b)]
    ;(println (str "A: " a "->" idxa))
    ;(println (str "B: " b "->" idxb))
    (compare idxa idxb)))

(defn issues->rows [cols issues]
  "Produces rows array, with shape like this:


(defn issues->wb [proj issues]
  "Creates a spreadsheet containing data from issues"
  (let [sheet-name (str (:name proj) " Issues")
        celldata (issues->celldata issues)
        wb (create-workbook sheet-name celldata)
