Skip to content

Instantly share code, notes, and snippets.

@danielneal
Last active June 30, 2019 18:48
Show Gist options
  • Save danielneal/6e543eafda4289389a75283ef22b948c to your computer and use it in GitHub Desktop.
Save danielneal/6e543eafda4289389a75283ef22b948c to your computer and use it in GitHub Desktop.
compound2
(ns compound2.core3)
(defprotocol Index
:extend-via-metadata true
(before [this o])
(after [this o])
(kfn [this o x])
(vfn [this o x])
(lookup [this o k] [this o k not-found])
(index [this o k v])
(unindex [this o k]))
(defn transact
[c k & args]
(case k
:add-items
(let [[o xs] args]
(after c
(reduce (fn [o x]
(index c o (kfn c o x) (vfn c o x)))
(before c o)
xs)))
:remove-items
(let [[o xs] args]
(after c
(reduce (fn [o x]
(unindex c o (kfn c o x)))
(before c o)
xs)))
:remove-keys
(let [[o ks] args]
(after c
(reduce (fn [o k]
(unindex c o k))
(before c o)
ks)))))
(def transactor
(reify clojure.lang.ILookup
(valAt [this k] (partial transact this k))))
(defn with-impl
[index m]
(vary-meta index merge m))
(defn with-hash-map [index]
(with-impl index {`before (fn [c m] (or m {}))
`after (fn [c m] m)
`lookup (fn [c & args] (apply get args))
`index (fn [c m k x] (assoc m k x))
`unindex (fn [c m k] (dissoc m k))}))
(defn with-transient-map [index]
(with-impl index {`before (fn [c m] (transient (or m {})))
`after (fn [c m] (persistent! m))
`lookup (fn [c & args] (apply get args))
`index (fn [c m k x] (assoc! m k x))
`unindex (fn [c m k] (dissoc! m k))}))
(defn with-multiple-entries [index]
(with-impl index {`vfn (fn [c o x] (conj (lookup index o (kfn index o x) #{}) (vfn index o x)))}))
(defn basic-index [opts]
(let [{:keys [kfn]} opts]
(-> transactor
(with-impl {`kfn (fn [c m x] (kfn x))
`vfn (fn [c m x] x)})
(with-hash-map))))
(let [{:keys [add-items remove-keys]} (basic-index {:kfn :id})]
(def add-products add-items)
(def remove-products remove-keys))
(add-products {} [{:id 1, :sku "Asdfs"}
{:id 2, :sku "Asdfasd"}])
;; => {1 {:id 1, :sku "Asdfs"},
;; 2 {:id 2, :sku "Asdfasd"}}
(-> (add-products {} [{:id 1, :sku "Asdfs"}
{:id 2, :sku "Asdfasd"}])
(remove-products [1]))
;; => {2 {:id 2, :sku "Asdfasd"}}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment