-
-
Save jcromartie/094b36e20132c970fbc0 to your computer and use it in GitHub Desktop.
CQRS/event-sourcing, because that's the cool thing to do right?
This file contains 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 ecc2.data | |
(:require [clojure.java.io :as io] | |
[clojure.tools.logging :as log])) | |
(defprotocol Event | |
(affect [this state] "Return new state from given state.")) | |
(defprotocol EventStore | |
(events [this] "Returns a seq of all events in the store.") | |
(store [this event] "Append an event to the store.")) | |
(extend-protocol Event | |
;; Implement Event protocol on sequential collections to allow | |
;; grouping of events in a single transation: | |
clojure.lang.Sequential | |
(affect [coll state] | |
(reduce #(affect %2 %1) state coll))) | |
;; Implement EventStore on nil to allow simple in-memory db: | |
(extend-protocol EventStore | |
nil | |
(events [_] nil) | |
(store [_ _] nil)) | |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | |
;; Data system functions. | |
;; The data system is just the read-model ref and event-store taken | |
;; together in a map with :read-model and :event-store keys. | |
;; A command fn is a function which takes the current state and | |
;; returns a seq of events to apply to the data model. | |
(defprotocol Command | |
(perform [this system] "Check validity, do side effects, and return events to apply to system.")) | |
(extend-protocol Command | |
clojure.lang.IPersistentVector | |
(perform [this system state] | |
(doall (map #(perform % system state) this)))) | |
(defn with-timestamp | |
[x] | |
(with-meta x {::timestamp (java.util.Date.)})) | |
(defn timestamp | |
[x] | |
(::timestamp (meta x))) | |
(defn do-command | |
"Apply a command to the system." | |
[{:keys [read-model event-store] :as system} command] | |
(let [raw-events (perform command system @read-model) | |
events (map with-timestamp raw-events)] | |
(dosync | |
(store event-store events) | |
(alter read-model (partial affect events))))) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment