Transaction / Indexing bug
In a transaction where a map has refs and reverse-ref attributes, the ref attributes are thrown away.
This works:
(require '[datascript.core :as d])
(def db
(d/empty-db
{:foo/id {:db/unique :db.unique/identity}
:foo/relations {:db/valueType :db.type/ref
:db/cardinality :db.cardinality/many}}))
(def db-with-foo
(d/db-with
db
[{:foo/id "foo1"
:foo/relations [{:foo/id "foo2"}
{:foo/id "foo3"}]}]))
(comment
(d/touch (d/entity db-with-foo [:foo/id "foo3"]))
; works!
; => {:foo/id "foo3", :db/id 3}
)
This fails for :foo/relations [{:foo/id "foo3"}] but works for the reverse :foo/_relations:
(def db-with-foo-backwards
(d/db-with
db
[{:foo/id "foo2"
:foo/_relations [{:foo/id "foo1" :foo/relations [{:foo/id "foo3"}]}]}]))
(comment
(d/touch (d/entity db-with-foo-backwards [:foo/id "foo3"]))
; errors!
; => #object[Error Error: Assert failed: (entity? e)]
; relation between "foo1" and "foo2" exists
(d/touch (d/entity db-with-foo-backwards [:foo/id "foo1"]))
; => {:foo/id "foo1", :foo/relations #{#:db{:id 1}}, :db/id 2}
)
Looking at the indexes of either DB we see that the relations and datoms are missing in db-with-foo-backwards:
(comment
(:aevt db-with-foo)
; =>
;#{#datascript/Datom[1 :foo/id "foo1" 536870913 true]
; #datascript/Datom[2 :foo/id "foo2" 536870913 true]
; #datascript/Datom[3 :foo/id "foo3" 536870913 true] ; <-- foo3 exists!
; #datascript/Datom[1 :foo/relations 2 536870913 true]
; #datascript/Datom[1 :foo/relations 3 536870913 true]}
)
(comment
(:aevt db-with-foo-backwards)
; =>
;#{#datascript/Datom[1 :foo/id "foo2" 536870913 true]
; #datascript/Datom[2 :foo/id "foo1" 536870913 true] ; <-- foo3 and relations missing!
; #datascript/Datom[2 :foo/relations 1 536870913 true]}
)
The common use case where this matters anytime one wants to run a pull query on one database and transact the result into another. In my case I have a backend and frontend DataScript DB. Based on the route the backend runs d/pull and sends the result to the frontend to be transacted. Since the pull result contains both forward and backward refs, this fails.
Looks like a valid use-case, I’ll look into it, thank you!