Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Upserting with unique tuple refs fails #378

Open
ash14 opened this issue Dec 17, 2020 · 3 comments
Open

Upserting with unique tuple refs fails #378

ash14 opened this issue Dec 17, 2020 · 3 comments

Comments

@ash14
Copy link
Contributor

ash14 commented Dec 17, 2020

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}
@ash14
Copy link
Contributor Author

ash14 commented Jan 14, 2021

Closing this, Datomic doesn't exhibit the behaviour I was expecting either.

@ash14 ash14 closed this as completed Jan 14, 2021
@tonsky
Copy link
Owner

tonsky commented Jan 14, 2021

Even if Datomic doesn’t support this, it seems like a reasonable thing to do? Let’s keep it open

@tonsky tonsky reopened this Jan 14, 2021
@caleb
Copy link

caleb commented Jul 7, 2021

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants