Created
June 4, 2024 15:17
-
-
Save escherize/58d09deb1fde49805052b56cc65de27c to your computer and use it in GitHub Desktop.
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
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | |
;; Execution requires a set of operations, a starting state, and a script. | |
;; | |
;; Each operation from the script is applied to the state, and returns a map where the keys are effects (fxs), and the values are the single args to the fx handlers. | |
;; the state is updated by the :value fx handle. Also, each operation's result is added to the output. | |
#_:clj-kondo/ignore | |
(defn step [op-factory operations [op & args :as operation]] | |
(if-let [op-fn (get operations op)] | |
(try | |
(apply op-fn @(:*state op-factory) args) | |
(catch Exception e | |
(throw (ex-info (str "Error executing operation: " op) | |
{:operation operation | |
:state @(:*state op-factory) | |
:args args | |
:error e})))) | |
(throw (ex-info (str "Unknown operation: " op) {:operation operation})))) | |
#_:clj-kondo/ignore | |
(defn execute [{:keys [verbs verbs-schema fx-handlers] :as op-factory} script] | |
(loop [[operation & next] script] | |
(if (nil? operation) | |
(-> op-factory :out (update-vals deref)) | |
(let [[op & args] operation | |
fxs (step op-factory verbs operation)] | |
(doseq [[fx-key fx-value] fxs] | |
(let [handler (get fx-handlers fx-key)] | |
(if handler | |
(handler fx-value) | |
(throw (ex-info (str "Unknown fx: " fx-key) {:fx-key fx-key}))))) | |
(recur next))))) | |
(execute | |
(let [*state (atom {}) | |
*recording (atom [])] | |
{:out {:state *state | |
:recording *recording} | |
:*state *state | |
:fx-handlers {:value (fn [new-state] (reset! *state new-state)) | |
:record (fn [datum] (swap! *recording conj datum))} | |
:verbs {:o/set (fn o-set [m k v] {:value (assoc m k v)}) | |
:o/save (fn o-print | |
([m] {:value m :record m}) | |
([m k] {:value m :record (get m k)})) | |
:o/update (fn o-update [m k f] {:value (update m k f)}) | |
:o/delete (fn o-delete [m k] {:value (dissoc m k)})}}) | |
[[:o/set :user/one {:id 1 :name "bryan" :age 30}] | |
[:o/set :user/two {:id 2 :name "joe" :age 40}] | |
[:o/save] | |
[:o/update :user/one #(assoc % :name-age (str (:name %) "-" (:age %)))] | |
[:o/delete :user/two] | |
[:o/save] | |
[:o/transaction | |
[:o/set :user/three {:id 3 :name "jane" :age 50}] | |
[:o/save]]]) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment