Last active
August 10, 2018 09:37
-
-
Save Hendekagon/2fc00cbf4eeddab8f834c84f6eb66262 to your computer and use it in GitHub Desktop.
Unique upsert in Datomic
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
; create attributes p and q, where p is unique identity | |
(d/transact edb1 {:tx-data [{:db/ident :p :db/cardinality :db.cardinality/one :db/valueType :db.type/keyword :db/unique :db.unique/identity}]}) | |
=> | |
(d/transact edb1 {:tx-data [{:db/ident :q :db/cardinality :db.cardinality/one :db/valueType :db.type/keyword}]}) | |
=> | |
; now add a datum | |
(d/transact edb1 {:tx-data [{:p :a1 :q :x}]}) | |
=> | |
; and another with a different :p | |
(d/transact edb1 {:tx-data [{:p :a2 :q :x}]}) | |
=> | |
; let's have a look: | |
(d/q '{:find [(pull ?e [*])] :where [[?e :p]]} (d/db edb1)) | |
=> | |
[[{:db/id 37216269576962135, :p :a1, :q :x}] | |
[{:db/id 5286451906347096, :p :a2, :q :x}]] | |
; there they are | |
; now let's transact a different :q for the same value of :p | |
(d/transact edb1 {:tx-data [{:p :a1 :q :y}]}) | |
=> | |
; (all is well) | |
(d/q '{:find [(pull ?e [*])] :where [[?e :p]]} (d/db edb1)) | |
=> | |
[[{:db/id 37216269576962135, :p :a1, :q :y}] | |
[{:db/id 5286451906347096, :p :a2, :q :x}]] | |
; that same entity 37216269576962135 now has a :q of :y not :x | |
; let's upsert again: | |
(d/transact edb1 {:tx-data [{:p :a1 :q :z}]}) | |
=> | |
(d/q '{:find [(pull ?e [*])] :where [[?e :p]]} (d/db edb1)) | |
=> | |
[[{:db/id 37216269576962135, :p :a1, :q :z}] | |
[{:db/id 5286451906347096, :p :a2, :q :x}]] | |
; again it updates | |
; now let's try to upsert the same entity with two conflicting assertions: | |
(d/transact edb1 {:tx-data [{:p :a1 :q :z} {:p :a1 :q :w}]}) | |
ExceptionInfo Two datoms in the same transaction conflict: {:d1 #datom[37216269576962135 79 :z 13194139533352 true], :d2 #datom[37216269576962135 79 :w 13194139533352 true]} clojure.core/ex-info (core.clj:4739) | |
; because those two datums had conflicting values in the same transaction - split that into 2 separate transactions if that's what you want | |
; next let's look at :db.unique/value | |
; add an attibute :r which is unique by value | |
(d/transact edb1 {:tx-data [{:db/ident :r :db/cardinality :db.cardinality/one :db/valueType :db.type/keyword :db/unique :db.unique/value}]}) | |
=> | |
; and assert that there's an the :r of entity with :p :a2 is :x | |
(d/transact edb1 {:tx-data [{:p :a2 :r :x}]}) | |
=> | |
; let's try the same thing with the entity with :p :a1 | |
(d/transact edb1 {:tx-data [{:p :a1 :r :x}]}) | |
ExceptionInfo Unique conflict: :r, value: :x already held by: 5286451906347096 asserted for: 37216269576962135 clojure.core/ex-info (core.clj:4739) | |
; no - there can be only one with :r :x | |
; now let's see what happens without unique identity | |
; we'll add an attribute :s which doesn't have :db/unique :db.unique/identity | |
(d/transact edb1 {:tx-data [{:db/ident :s :db/cardinality :db.cardinality/one :db/valueType :db.type/keyword}]}) | |
=> | |
; now assert something with a :s on it | |
(d/transact edb1 {:tx-data [{:s :x :q :x}]}) | |
=> | |
; let's have a look what we've got: | |
(d/q '{:find [(pull ?e [*])] :where [[?e :q]]} (d/db edb1)) | |
=> | |
[[{:db/id 37216269576962135, :p :a1, :q :z}] | |
[{:db/id 5286451906347096, :p :a2, :q :x, :r :x}] | |
[{:db/id 54298282226090073, :q :x, :s :x}]] | |
; there it is, 54298282226090073, along with the previous things | |
; what happens when we assert that again ? | |
(d/transact edb1 {:tx-data [{:s :x :q :x}]}) | |
=> | |
(d/q '{:find [(pull ?e [*])] :where [[?e :q]]} (d/db edb1)) | |
=> | |
[[{:db/id 37216269576962135, :p :a1, :q :z}] | |
[{:db/id 5286451906347096, :p :a2, :q :x, :r :x}] | |
[{:db/id 54298282226090073, :q :x, :s :x}] | |
[{:db/id 54047593574957146, :q :x, :s :x}]] | |
; because :s isn't unique identity, there's no upsert so we get multiple datums | |
; let's have another: | |
(d/transact edb1 {:tx-data [{:s :x :q :y}]}) | |
=> | |
(d/q '{:find [(pull ?e [*])] :where [[?e :q]]} (d/db edb1)) | |
=> | |
[[{:db/id 12208977114824795, :q :y, :s :x}] | |
[{:db/id 37216269576962135, :p :a1, :q :z}] | |
[{:db/id 5286451906347096, :p :a2, :q :x, :r :x}] | |
[{:db/id 54298282226090073, :q :x, :s :x}] | |
[{:db/id 54047593574957146, :q :x, :s :x}]] | |
; and so on - we can have as many as we like | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment