Liking cljdoc? Tell your friends :D

the commit function which is used for transactions has been implemented using defmulti, allowing you to easily implement your own transactions. a transaction must be a vector, where the first element is used to dispatch the transaction to the corresponding defmethod.

the five basic transaction types are :dx/put :dx/delete :dx/merge, :dx/update and :dx/match

commit accepts either a single transaction and a collection of transactions

dx/put


;; (dx/commit {} [:dx/put {?table-id ?entity-id k v}])
(dx/commit {} [:dx/put {:db/id 1 :name "Ivan" :age 18}])
;; => {[:db/id 1] {:db/id 1, :name "Ivan", :age 18}}

;; (dx/commit {} [:dx/put [{?table-id ?entity-id k v} ...]])
(dx/commit {} [:dx/put [{:db/id 1 :name "Ivan" :age 18} {:db/id 2 :name "Petr" :age 33}]])
;; => {[:db/id 1] {:db/id 1, :name "Ivan", :age 18}, [:db/id 2] {:db/id 2, :name "Petr", :age 33}}

;; (dx/commit {} [:dx/put [?table-id ?entity-id] {k v}])
(dx/commit {} [:dx/put [:db/id 1] {:name "Ivan" :age 18}])
;; => {[:db/id 1] {:name "Ivan", :age 18, :db/id 1}}

;; (dx/commit {} [:dx/put [?table-id ?entity-id] k v])
(dx/commit {} [:dx/put [:db/id 1] :name "Ivan"])
;; => {[:db/id 1] {:db/id 1, :name "Ivan"}}

;; (dx/commit {} [:dx/put [?table-id ?entity-id] k v & kvs])
(dx/commit {} [:dx/put [:db/id 1] :name "Ivan" :age 18])
;; => {[:db/id 1] {:db/id 1, :name "Ivan", :age 18}}

dx/put acts as assoc and always replaces values


(dx/commit {[:db/id 1] {:db/id 1 :name "Ivan"}} [:dx/put [:db/id 1] {:name "Petr"}])
;; => {[:db/id 1] {:name "Petr", :db/id 1}}

(dx/commit {[:db/id 1] {:db/id 1 :name "Ivan"}} [:dx/put [:db/id 1] :name "Petr"])
;; => {[:db/id 1] {:db/id 1, :name "Petr"}}

(dx/commit {[:db/id 1] {:db/id 1 :name "Ivan" :aka ["Devil"]}} [:dx/put [:db/id 1] :aka ["Tupen"]])
;; => {[:db/id 1] {:db/id 1, :name "Ivan", :aka ["Tupen"]}}

references are created automatically and data is normalised


(dx/commit {} [:dx/put {:db/id 1 :name "Ivan" :friend {:db/id 2 :name "Petr"}}])
; => {[:db/id 2] {:_friend [:db/id 1], :db/id 2, :name "Petr"}, [:db/id 1] {:db/id 1, :name "Ivan", :friend [:db/id 2]}}

(dx/commit {} [:dx/put {:db/id 1 :name "Ivan" :friend [{:db/id 2 :name "Petr"} {:db/id 3 :name "Lucy"}]}])
;; => {[:db/id 2] {:_friend [:db/id 1], :db/id 2, :name "Petr"},
;;     [:db/id 3] {:_friend [:db/id 1], :db/id 3, :name "Lucy"},
;;     [:db/id 1] {:db/id 1, :name "Ivan", :friend #ordered/set #{[:db/id 2] [:db/id 3]}}}

for improved performance, back references are kept explicitly in the map.

dx/delete


(dx/commit {[:db/id 1] {:db/id 1 :name "Ivan" :aka ["Devil"]}}
           [:dx/delete [:db/id 1]])
;; => {}

(dx/commit {[:db/id 1] {:db/id 1 :name "Ivan" :aka ["Devil"]}}
           [:dx/delete {:db/id 1}])
;; => {}

(dx/commit {[:db/id 1] {:db/id 1 :name "Ivan" :aka ["Devil"]}}
           [:dx/delete [:db/id 1] :name])
;; => {[:db/id 1] {:db/id 1, :aka ["Devil"]}}

(dx/commit {[:db/id 1] {:db/id 1 :name "Ivan" :aka ["Devil"]}}
           [:dx/delete [:db/id 1] [:name :aka]])
;; => {}

dx/delete allows you to delete an item from the collection


(dx/commit {[:db/id 1] {:db/id 1 :name "Ivan" :aka ["Devil" "Tupen"]}}
           [:dx/delete [:db/id 1] :aka "Devil"])
;; => {[:db/id 1] {:db/id 1, :name "Ivan", :aka ["Tupen"]}}

dx/delete keeps data compact


(dx/commit {[:db/id 1] {:db/id 1 :name "Ivan"}}
           [:dx/delete [:db/id 1] :name])
;; => {}

deleting entire entities also deletes all references to them


(def db (dx/commit {} [:dx/put {:db/id 1 :name "Ivan" :friend [{:db/id 2 :name "Petr"} {:db/id 3 :name "Lucy"}]}]))
db
;; => {[:db/id 2] {:_friend [:db/id 1], :db/id 2, :name "Petr"},
;;     [:db/id 3] {:_friend [:db/id 1], :db/id 3, :name "Lucy"},
;;     [:db/id 1] {:db/id 1, :name "Ivan", :friend #ordered/set #{[:db/id 2] [:db/id 3]}}}

(dx/commit db [:dx/delete [:db/id 2]])
;; => {[:db/id 3] {:_friend [:db/id 1], :db/id 3, :name "Lucy"},
;;     [:db/id 1] {:db/id 1, :name "Ivan", :friend #ordered/set #{[:db/id 3]}}}

(dx/commit db [:dx/delete [:db/id 1]])
;; => {[:db/id 2] {:db/id 2, :name "Petr"},
;;     [:db/id 3] {:db/id 3, :name "Lucy"}}

dx/merge

dx/merge always tries to merge data instead of replacing it, which is especially important for collections


(dx/commit {[:db/id 1] {:db/id 1 :name "Ivan" :aka ["Devil"]}}
           [:dx/merge [:db/id 1] :name "Petr"])
;; => {[:db/id 1] {:db/id 1, :name "Petr", :aka ["Devil"]}}

(dx/commit {[:db/id 1] {:db/id 1 :name "Ivan" :aka ["Devil"]}}
           [:dx/merge [:db/id 1] {:aka "Tupen"}])
;; => {[:db/id 1] {:db/id 1, :name "Ivan", :aka ["Devil" "Tupen"]}}

(dx/commit {[:db/id 1] {:db/id 1 :name "Ivan" :aka ["Devil"]}}
           [:dx/merge [:db/id 1] {:aka ["Tupen"]}])
;; => {[:db/id 1] {:db/id 1, :name "Ivan", :aka ["Devil" "Tupen"]}}

dx/update

dx/update works identically to update and update-in, depending on the number of arguments. however, it should be used with extreme caution, because the correctness of the data is not verified in any way, so it is possible, for example, to add a reference to the collection without automatically adding a back reference

if the third argument to a transaction is a function and fourth is a key, then the value on which function is called will be the entire document


(dx/commit {[:db/id 1] {:db/id 1 :name "ivan" :aka ["devil"]}}
           [:dx/update [:db/id 1] assoc :aka "tupen"])
;; => {[:db/id 1] {:db/id 1, :name "ivan", :aka "tupen"}}

if the third argument to a transaction is a key and the fourth argument is a function, then the value on which the function is called will be the value under the key


(dx/commit {[:db/id 1] {:db/id 1 :name "ivan" :aka ["devil"]}}
           [:dx/update [:db/id 1] :aka conj "tupen"])
;; => {[:db/id 1] {:db/id 1, :name "ivan", :aka ["devil" "tupen"]}}

dx/match

dx/match allows for conditional execution of transactions. the transaction itself returns a db if the condition is met, in a transaction chain this leads to transactions being executed until either nil is reached or another condition is met.


(def db (dx/commit {} [:dx/put {:db/id 1 :name "Ivan" :age 18}]))
db
;; => {[:db/id 1] {:db/id 1, :name "Ivan", :age 18}}

;; condition may be kv
(dx/commit db [:dx/match [:db/id 1] :name "Ivan"])
;; => {[:db/id 1] {:db/id 1, :name "Ivan", :age 18}}

;; or map, where all the individual kv are checked, rather than the identical to doc
(dx/commit db [[:dx/match [:db/id 1] {:name "Ivan"}]
               [:dx/update [:db/id 1] :age inc]])
;; => {[:db/id 1] {:db/id 1, :name "Ivan", :age 19}}

;; the reference can be either a vector or a map
(dx/commit db [[:dx/match {:db/id 1 :name "Ivan"}]
               [:dx/update [:db/id 1] :age inc]])
;; => {[:db/id 1] {:db/id 1, :name "Ivan", :age 19}}


(dx/commit db [[:dx/match [:db/id 1] :name "Ivan"]
               [:dx/update [:db/id 1] :age inc]])
;; => {[:db/id 1] {:db/id 1, :name "Ivan", :age 19}}

(dx/commit db [[:dx/match [:db/id 1] :name "Petr"]
               [:dx/update [:db/id 1] :age inc]
               [:dx/match [:db/id 1] :name "Ivan"]
               [:dx/update [:db/id 1] :age dec]])
;; => {[:db/id 1] {:db/id 1, :name "Ivan", :age 17}}

;; condition may be also fn?, then the function is called with the doc
(dx/commit db [[:dx/match [:db/id 1] (fn [m] (= 3 (count m)))]
               [:dx/update [:db/id 1] :age inc]])
;; => {[:db/id 1] {:db/id 1, :name "Ivan", :age 19}}

;; condition may be k fn?, then the function is called with the value under key k
(dx/commit db [[:dx/match [:db/id 1] :age #(>= % 18)]
               [:dx/put [:db/id 1] :adult? true]])
;; => {[:db/id 1] {:db/id 1, :name "Ivan", :age 18, :adult? true}}

Can you improve this documentation?Edit on GitHub

cljdoc is a website building & hosting documentation for Clojure/Script libraries

× close