A very basic event sourcing library.
Add the following to your :dependencies
:
[kilgore "0.2.1"]
Setup a store and a stream; a store is responsible for keeping your events safe and a stream aggregates events closely related to each other.
(require '[kilgore.store :as store])
(require '[kilgore.stream :as stream])
(def store (store/acquire {:store-atom (atom nil)}))
(def stream (stream/acquire store "Slate Rock and Gravel Company"))
Next we’ll define some events. Please notice the use of past tense; we will be recording events which have already happened.
(require '[kilgore.event :refer [defevent]])
(defevent employee-hired [id name])
(defevent employee-promoted [id])
(defevent employee-demoted [id])
(defevent employee-left [id])
Now we can record events.
(require '[kilgore.stream :refer [record-event!]])
(record-event! stream (->EmployeeHired "fred" "Fred Flintstone"))
(record-event! stream (->EmployeeHired "barney" "Barney Rubble"))
(record-event! stream (->EmployeePromoted "fred"))
(record-event! stream (->EmployeeLeft "barney"))
To access our our current data set, we’ll write an event handler. In this case we’re interested in making a map of employees, record their employment level and count how many times employees where hired.
(require '[kilgore.stream :refer [event-reducer]])
(defmulti handle-event (fn [_ event] (type event)))
(defmethod handle-event :default [state _] state)
(defmethod handle-event employee-hired
[state {:keys [id name]}]
(-> state
(assoc-in [:employees id] {:name name})
(update-in [:total-hires] (fnil inc 0))))
(defmethod handle-event employee-promoted
[state {:keys [id]}]
(update-in state [:employees id :level] (fnil inc 0)))
(defmethod handle-event employee-demoted
[state {:keys [id]}]
(update-in state [:employees id :level] (fnil dec 0)))
(defmethod handle-event employee-left
[state {:keys [id]}]
(update-in state [:employees] dissoc id))
(def current (event-reducer handle-event))
Let’s see what the current state of our company is given the events we recorded earlier.
(current stream)
;; => {:employees {"fred" {:name "Fred Flintstone", :level 1}}, :total-hires 2}
That’s it!
This library does not provide a locking mechanism to ensure a consistent data set for things like uniqueness constraints.
Copyright © 2015 R.W. van ‘t Veer
Distributed under the Eclipse Public License either version 1.0 or (at your option) any later version.