datascript
datascript copied to clipboard
Upserting with unique tuple refs fails
Attempting an upsert to an entity using its unique tuple attribute does not work as expected.
Hope this example is clear:
(let [conn (d/create-conn {:player {:db/unique :db.unique/identity}
:home {:db/valueType :db.type/ref}
:away {:db/valueType :db.type/ref}
:players {:db/unique :db.unique/identity
:db/tupleAttrs [:home :away]}})]
(d/transact! conn [[:db/add -1 :player "Nadal"]
[:db/add -2 :player "Federer"]
{:home -1
:away -2}])
(d/transact! conn [{:db/id "p1"
:player "Nadal"}
{:db/id "p2"
:player "Federer"}
{:db/id "match"
:players ["p1" "p2"]
:game 3}]))
Execution error (ClassCastException) at datascript.db/value-compare (db.cljc:339).
java.lang.String cannot be cast to java.lang.Number
Expecting a result like (= 3 (:game (d/entity @conn 3)))
I don't think this is related to #364?
Thanks. I'll try to open a PR for this if it's straightforward enough.
Edit: for what it's worth, here's the same example on Datomic 1.0.6202
@(d/transact conn [{:db/ident :player
:db/valueType :db.type/string
:db/unique :db.unique/identity
:db/cardinality :db.cardinality/one}
{:db/ident :home
:db/valueType :db.type/string
:db/cardinality :db.cardinality/one}
{:db/ident :away
:db/valueType :db.type/string
:db/cardinality :db.cardinality/one}
{:db/ident :players
:db/unique :db.unique/identity
:db/valueType :db.type/tuple
:db/tupleAttrs [:home :away]
:db/cardinality :db.cardinality/one}
{:db/ident :game
:db/valueType :db.type/long
:db/cardinality :db.cardinality/one}])
@(d/transact conn [[:db/add "p1" :player "Nadal"]
[:db/add "p2" :player "Federer"]
{:home "p1"
:away "p2"}])
@(d/transact conn [{:db/id "p1" :player "Nadal"}
{:db/id "p2" :player "Federer"}
{:db/id "match"
:players ["p1" "p2"]
:game 3}])
(d/pull (d/db conn) '[*] (:e (last (d/datoms (d/db conn) :eavt))))
; => {:db/id 17592186045420, :home "p1", :away "p2", :players ["p1" "p2"], :game 3}
Closing this, Datomic doesn't exhibit the behaviour I was expecting either.
Even if Datomic doesn’t support this, it seems like a reasonable thing to do? Let’s keep it open
EDIT: I noticed that this is specific to refs. I've been playing with this issue for a while and got my wires crossed on this issue. Do you think I should open a separate issue about this? I don't have access to Datomic so I can't test over there.
I don't know if this is the same issue but I'm getting a different error message when trying to upsert with a unique composite tuple:
;;
;; Upsert by Unique Composite Tuple
;;
(let [schema {:one+two {:db/tupleAttrs [:one :two]
:db/unique :db.unique/identity}}
conn (ds/create-conn schema)]
(ds/transact! conn [{:db/id "tmpid"
:some-field "first upsert"
:one "one"
:two "two"}
{:db/id "tmpid"
:other-field "first upsert"
:one "one"
:two "two"}])
(ds/transact! conn [{:db/id "tmpid"
:some-field "second upsert"
:one "one"
:two "two"}
{:db/id "tmpid"
:other-field "second upsert"
:one "one"
:two "two"}])
(ds/q '[:find [(pull ?e [*]) ...]
:where
[?e :one _]]
@conn))
I get this error:
Execution error (ExceptionInfo) at datascript.db/validate-datom (db.cljc:967).
Cannot add #datascript/Datom [2 :one+two ["one" "two"] 536870914 true] because of unique constraint: (#datascript/Datom [1 :one+two ["one" "two"] 536870913 true])
Of course, when I try the same type of upsert with a non-tuple unique attribute everything works
;;
;; Upsert by non-tuple unique attribute
;;
(let [schema {:email {:db/unique :db.unique/identity}}
conn (ds/create-conn schema)]
(ds/transact! conn [{:db/id "tmpid"
:some-field "first upsert"
:email "[email protected]"}
{:db/id "tmpid"
:other-field "first upsert"
:email "[email protected]"}])
(ds/transact! conn [{:db/id "tmpid"
:some-field "second upsert"
:email "[email protected]"}
{:db/id "tmpid"
:other-field "second upsert"
:email "[email protected]"}])
(ds/q '[:find [(pull ?e [*]) ...]
:where
[?e :email _]]
@conn))
Result:
[{:db/id 1,
:email "[email protected]",
:other-field "second upsert",
:some-field "second upsert"}]