Created
April 16, 2014 22:34
-
-
Save SegFaultAX/10939429 to your computer and use it in GitHub Desktop.
Dotted path expansion in Clojure
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(defn deep-merge-with | |
"Like merge-with, but preserves shared key paths, recursively." | |
[f & maps] | |
(letfn [(merge-elem [m e] | |
(let [k (key e) v (val e) src (m k)] | |
(if src | |
(if (and (map? src) (map? v)) | |
(assoc m k (merge2 src v)) | |
(assoc m k (f src v))) | |
(assoc m k v)))) | |
(merge2 [d1 d2] | |
(reduce merge-elem (or d1 {}) (seq d2)))] | |
(reduce merge2 maps))) | |
(defn expand-key | |
"Converts a key/value pair from the form | |
[:a.b.c.d 1] | |
to a map with nested keys | |
{:a {:b {:c {:d 1}}}}" | |
[[k v]] | |
(let [parts (clojure.string/split (name k) #"\.") | |
path (mapv keyword parts)] | |
(assoc-in {} path v))) | |
(defn expand-keys | |
"Expands all keys in a given map using `expand-key`" | |
[d] | |
(apply deep-merge-with into (map expand-key d))) | |
(defn expand-paths | |
"Walks a recursive data structure, expanding all key paths using | |
`clojure.walk/prewalk` with `expand-keys`" | |
[d] | |
(clojure.walk/prewalk #(if (map? %) (expand-keys %) %) d)) | |
;; Example usage | |
(comment | |
(def q {:query.filtered.query.bool.should | |
[{:query_string.default_field "_all" | |
:query_string.query "keywords"} | |
{:multi_match.query 123 | |
:multi_match.type "most_fields" | |
:multi_match.fields "derp"}] | |
:query.filtered.query.filter []}) | |
(= | |
(expand-paths q) | |
{:query | |
{:filtered | |
{:query | |
{:bool | |
{:should | |
[{:query_string {:query "keywords", :default_field "_all"}} | |
{:multi_match | |
{:type "most_fields", :query 123, :fields "derp"}}]}, | |
:filter []}}}}) | |
) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment