Skip to content

Instantly share code, notes, and snippets.

@escherize
Created June 4, 2024 15:17
Show Gist options
  • Save escherize/58d09deb1fde49805052b56cc65de27c to your computer and use it in GitHub Desktop.
Save escherize/58d09deb1fde49805052b56cc65de27c to your computer and use it in GitHub Desktop.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; 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