Created
July 27, 2017 15:54
-
-
Save danielneal/cde96234f55fff2d1392e109bf383586 to your computer and use it in GitHub Desktop.
compound
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
(ns compound.core | |
(:refer-clojure :exclude [get-in update-in assoc-in])) | |
(def ^:private index-permutations | |
(memoize | |
(fn permutations [coll] | |
(if (= 1 (count coll)) | |
(list coll) | |
(for [head coll | |
tail (permutations (disj (set coll) head))] | |
(cons head tail)))))) | |
(defn compound [coll compound-index] | |
(let [indexes (index-permutations compound-index) | |
updates (for [index indexes | |
item coll] | |
[(mapv (fn [k] | |
(if-let [idx (get item k)] | |
{k idx} | |
(throw (ex-info "key-fn returns nil" {:key k | |
:item item | |
:index index})))) index) item])] | |
{:indexes (set indexes) | |
:index-length (count compound-index) | |
:data (reduce (fn [m [k v]] | |
(let [existing-value (clojure.core/get-in m k)] | |
(if existing-value | |
(throw (ex-info "Duplicate key" {:key k | |
:new-value v | |
:existing-value existing-value})) | |
(clojure.core/assoc-in m k v)))) {} updates)})) | |
(def c (compound #{{:product-id 1 :date "today" :customer-id 1} | |
{:product-id 2 :date "tomorrow" :customer-id 2} | |
{:product-id 1 :date "tomorrow" :customer-id 3} | |
{:product-id 1 :date "tomorrow" :customer-id 4}} | |
[:product-id :date :customer-id])) | |
(defn get-in [compound ks] | |
(let [{:keys [indexes index-length data]} compound | |
freedom (- index-length (count ks)) | |
root (clojure.core/get-in data ks)] | |
(if (= freedom 0) | |
root | |
(nth (iterate #(mapcat vals %) (vals root)) (dec freedom))))) | |
(get-in c [{:date "tomorrow"} {:product-id 1}]) | |
(defn update-in [compound ks f & args] | |
(let [{:keys [indexes index-length data]} compound | |
freedom (- index-length (count ks)) | |
root (clojure.core/get-in data ks)] | |
(if (= freedom 0) | |
root | |
(nth (iterate #(mapcat vals %) (vals root)) (dec freedom))))) | |
(defn update-all-indexes [compound ks f] | |
(let [new-value (f (get-in compound ks)) | |
compound (assoc-in compound ks new-value) | |
other-indexes (disj (set (index-permutations ks)) ks)] | |
(reduce (fn [compound index] (assoc-in compound index new-value)) compound other-indexes))) | |
(defn update-in [compound ks f & args] | |
(update-all-indexes update-in)) | |
(update-all-indexes c [{:date "tomorrow"} {:product-id 2}] (fn [v] (clojure.core/update v :date str "a"))) | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment