Last active
April 23, 2020 09:57
-
-
Save mszajna/94708c97d6f2d33238ce35cd421d0771 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
(require '[datomic.api :as d]) | |
; Datomic transaction are ACID which is achieved processing only one at a time. | |
; For certain workloads it's a good enough model. The built in transaction functions | |
; offer enforcing uniqueness and a compare-and-swap operation. They work great but | |
; are often too little for expressing more complex business rules. | |
; For those, datomic offers transaction functions, that you can install storing the | |
; source code in the DB. | |
(def conn (let [url "datomic:mem:call"] (d/create-database url) (d/connect url))) | |
(def tx-println | |
(d/function | |
'{:lang "clojure" | |
:params [db s] | |
:code (println s)})) ; this one returns nil - empty transaction. NB. side effects in tx are to be avoided! | |
(d/transact conn [{:db/ident :tx-println :db/fn tx-println}]) | |
(d/transact conn [[:tx-println "look ma, I'm in a tx!"]]) | |
; This is pretty cool, although maintaining the parity between the source code | |
; of this function and the value stored in Datomic is often painful. Datomic also | |
; advocates acretion, so ideally a function wouldn't change once transacted. This | |
; gets in the way of fast-paced development. | |
; Introducing 'call' - the last transaction function you ever have to install. | |
; It allows running a transaction function without installing it, compiling the | |
; code the first time it's run. | |
(def call | |
(d/function | |
'{:lang "clojure" | |
:params [db f & args] | |
:code (do (when-not (resolve 'user/datomic-function-mem) | |
(intern 'user 'datomic-function-mem (memoize datomic.api/function))) | |
(apply (user/datomic-function-mem f) db args))})) | |
(d/transact conn [{:db/ident :call :db/fn call}]) ; install the function | |
(d/transact conn [[:call tx-println "look ma, I'm in a tx!"]]) ; run another, referring its source, not :db/ident | |
(d/transact conn [[:call '{:language "clojure" :params [db] :code (pringln "risky bussiness")}]]) | |
; Transaction functions tend to be small and caching forever shouldn't be too much strain | |
; on the memory, as long as you avoid generating source code at runtime, which could also | |
; be dangerous - think eval. The call below empties the cache. | |
(d/transact conn [[:call '{:language "clojure" :params [db] :code (ns-unmap 'user 'datomic-function-mem)}]]) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment