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"}]