Skip to content

Transaction / Indexing bug #376

Description

@den1k

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

Activity

den1k commented on Dec 15, 2020

@den1k
Author

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.

tonsky commented on Dec 15, 2020

@tonsky
Owner

Looks like a valid use-case, I’ll look into it, thank you!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions