Created
July 30, 2017 16:27
-
-
Save danielneal/22d420823efe7a02e27ac50c7c92b7c0 to your computer and use it in GitHub Desktop.
A micro structure for your data
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) | |
(def ^:private meta-index-defs | |
[{:id :id | |
:index-fn :id | |
:unique? true} | |
{:id :unique? | |
:index-fn :unique? | |
:unique? false}]) | |
(defn ^:private molecule [coll index-defs] | |
(let [initial-molecule [[] {}] | |
[molecule _] (reduce (fn [acc x] | |
(let [[molecule j] acc | |
[xs m] molecule] | |
[[(conj xs x) | |
(reduce (fn [m index-def] | |
(let [{:keys [index-fn unique? id]} index-def | |
k (index-fn x)] | |
(cond (and (some? k) unique?) | |
(let [existing (get-in m [id k])] | |
(if existing | |
(throw (ex-info "Duplicate key " {:x x | |
:k k})) | |
(assoc-in m [id k] j))) | |
(and (some? k) (not unique?)) | |
(update-in m [id k] (fnil conj #{}) j) | |
:else m))) | |
m index-defs)] | |
(inc j)])) | |
[initial-molecule 0] | |
coll)] | |
molecule)) | |
(defn ^:private molecule-get-positions [molecule k v] | |
(let [[_ m] molecule] | |
(get-in m [k v]))) | |
(def ^:private molecule-get-position molecule-get-positions) | |
(defn ^:private molecule-get-element [molecule j] | |
(let [[xs _] molecule] | |
(get xs j))) | |
(defn ^:private molecule-get-elements [molecule js] | |
(let [[xs _] molecule] | |
(into #{} (map #(get xs %)) js))) | |
(defn ^:private molecule-get-single [molecule k v] | |
(->> (molecule-get-position molecule k v) | |
(molecule-get-element molecule))) | |
(defn ^:private molecule-get-many [molecule k v] | |
(->> (molecule-get-positions molecule k v) | |
(molecule-get-elements molecule))) | |
(defn compound [coll index-defs] | |
[(molecule coll index-defs) | |
(molecule index-defs meta-index-defs)]) | |
(defn compound-get [compound k v] | |
(let [[molecule metacule] compound | |
index (molecule-get-single metacule :id k)] | |
(if (nil? index) | |
(throw (ex-info (str "No index on " k " present") {:k k, :v v :compound compound})) | |
(if (:unique? index) | |
(molecule-get-single molecule k v) | |
(molecule-get-many molecule k v))))) | |
(defn ^:private compound-update-single [compound k v f & args] | |
(let [[molecule metacule] compound | |
index (molecule-get-single metacule :id k) | |
{:keys [index-fn]} index | |
j (molecule-get-position molecule k v) | |
existing-value (molecule-get-element molecule j) | |
new-value (apply f existing-value args) | |
[indexes _] metacule | |
[xs m] molecule | |
new-molecule (reduce (fn [molecule index] | |
(let [[xs m] molecule | |
{:keys [unique? index-fn id]} index | |
old-v (if (= id k) v (index-fn existing-value)) | |
new-v (index-fn new-value)] | |
[xs (cond | |
(and (not= old-v new-v) (nil? new-v) unique?) (update m k dissoc old-v) | |
(and (not= old-v new-v) (not (nil? new-v)) unique?) (if-let [existing-value (get-in m [id new-v])] | |
(throw (ex-info "Duplicate key" {:id id :v new-v})) | |
(-> m (update id dissoc old-v) (update id assoc new-v j))) | |
(and (not= old-v new-v) (nil? new-v) (not unique?)) (-> m (update-in [id old-v] disj j)) | |
(and (not= old-v new-v) (not (nil? new-v)) (not unique?)) (-> m (update-in [id old-v] disj j) (update-in [id new-v] (fnil conj #{}) j)) | |
:else m)])) | |
[(assoc xs j new-value) m] indexes)] | |
[new-molecule | |
metacule])) | |
#_(defn ^:private compound-update-many [compound k v f & args] | |
(let [[molecule metacule] compound | |
index (molecule-get-single metacule :id k) | |
[indexes _] metacule | |
existing-values (molecule-get-many k v) | |
new-values (into #{} (apply f existing-values args)) | |
initial-molecule (reduce (fn [molecule index]) | |
molecule ) | |
new-molecule (reduce (fn [molecule index] | |
(let [[xs m] molecule | |
{:keys [unique? index-fn id]} index | |
old-v (if (= id k) v (index-fn existing-value)) | |
new-v (index-fn new-value)] | |
[xs (cond | |
(and (not= old-v new-v) (nil? new-v) unique?) (update m k dissoc old-v) | |
(and (not= old-v new-v) (not (nil? new-v)) unique?) (if-let [existing-value (get-in m [id new-v])] | |
(throw (ex-info "Duplicate key" {:id id :v new-v})) | |
(-> m (update id dissoc old-v) (update id assoc new-v j))) | |
(and (not= old-v new-v) (nil? new-v) (not unique?)) (-> m (update-in [id old-v] disj j)) | |
(and (not= old-v new-v) (not (nil? new-v)) (not unique?)) (-> m (update-in [id old-v] disj j) (update-in [id new-v] (fnil conj #{}) j)) | |
:else m)])) | |
molecule indexes)] | |
[new-molecule | |
metacule])) | |
;; initial-molecule [(assoc molecule j new-value) | |
;; (cond-> m | |
;; (not= v new-v) (update k dissoc v) | |
;; (not (nil? new-v)) (update k assoc new-v j)) metacule] | |
(defn compound-update [compound k v f & args] | |
(let [[molecule metacule] compound | |
index (molecule-get-single metacule :id k)] | |
(if (:unique? index) | |
(apply compound-update-single compound k v f args) | |
(apply compound-update-many compound k v f args)))) | |
(clojure.pprint/pprint (compound-update-single c [:a :b] [1 1] assoc :a 2 :b 2)) | |
(def c (compound #{{:a 1 :b 2 :c 3} | |
{:a 1 :b 1 :c 4}} | |
#{{:index-fn :a | |
:id :a | |
:unique? false} | |
{:index-fn :b | |
:id :b | |
:unique? false} | |
{:index-fn (juxt :a :b) | |
:id [:a :b] | |
:unique? true}})) | |
(compound-get c [:a :b] [1 1]) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment