jmayaalv
3/1/2019 - 10:22 PM

test.clj

(def cofx-now
  "injects current time to context"
  {:enter (fn [ctx]
            (assoc-in ctx [:request :now] (java.util.Date.)))})

;; interceptor, in enter update value in `[:request :x]` with `inc`
(def inc-x-interceptor
  {:enter (fn [ctx]
            (update-in ctx [:request :x] inc))})

;; this is the business logic. There could be a macro that would generate this. something like
;; (defhandler somebusines-logic {:interceptors [inc-x-interceptor cofx-now]}
;;    {:y (inc (:x request))
;;     :now (:now request)}))
(def some-business-logic (with-meta
                           (fn [request]
                             {:y (inc (:x request))
                              :now (:now request)})
                           {:interceptors [inc-x-interceptor cofx-now]}))

;; This is internal code, programmer wouldn't see. But what it does is to extract the interceptors from the metadata and inject as cofx
(defn execute-handler [handler args]
  (let [interceptors (into [] (:interceptors (meta handler)))]
    (sieppari/execute (conj interceptors handler) args)))

(comment
  (execute-handler some-business-logic {:x 40})
  )

(defonce co-effects (atom {}))

(defn register-cofx [name f]
  (swap! co-effects assoc name f))

(register-cofx :now (fn [ctx]
                      (assoc-in ctx [:request :now] (java.util.Date.))))


(defn defn-from [name mdata args cofx & body]
  `(defn ~(symbol name) ~mdata ~args
     (sieppari.core/execute (conj ~cofx (fn ~args ~@body))
                            ~@args)))


(defmacro defhandler
  "Simplifies the creation of functions that declare coeffects.
  ```
  Example:
  (defhandler some-business-logic [request] 
    [:now]
    {:time (:now request)})
  ```
  "
  [name _ cofxs & body]

  (defn-from name {:coeffects cofxs} '[request] (mapv #(hash-map :enter (get @co-effects %)) cofxs)
    (cons 'do body)))



(defhandler test2 [request]
  [:now]
  (println request)
  {:changed true
   :db (:now request)})



(comment
  (test2 {:now :ok}))