tonsky / datascript

Immutable database and Datalog query engine for Clojure, ClojureScript and JS
Eclipse Public License 1.0
5.45k stars 304 forks source link

Lookup ref in composite tuple during upsert #452

Closed telekid closed 2 months ago

telekid commented 1 year ago

Back with another weird one. In the following example, I'd like to upsert an entity via composite tuple. One element of the composite tuple is a ref. At insertion time, I only know the natural identity (:db/uuid) of said referent, not its datascript :db/id.

It occurred to me that I may be able to supply a lookup ref as an element within a composite tuple that is being used for upsert, but it appears that is not the case.

Does this seem like a useful feature? Any suggested workarounds for its absence (that don't require multiple transactions?)

(ns core
  (:require [datascript.core :as d]))

(def schema
  {:db/uuid {:db/unique    :db.unique/identity}
   :user/db {:db/valueType :db.type/ref}
   :user/dbid {}
   :user/db+dbid {:db/valueType :db.type/tuple
                  :db/unique :db.unique/identity
                  :db/tupleAttrs [:user/db :user/dbid]}})

(def db (d/create-conn schema))

(d/transact!
 db
 [{:db/uuid "A"}
  {:user/db [:db/uuid "A"]
   :user/dbid 1}])

;; This transaction will fail
(d/transact!
 db            ;; |    BELOW   |
 [{:user/db+dbid [[:db/uuid "A"] 1] ;; This will work if you change `[:db/uuid "A"]` to `1`
   :user/name "jake"}])

;; Execution error (ClassCastException) at datascript.db/value-compare (db.cljc:387).
;; class clojure.lang.PersistentVector cannot be cast to class java.lang.Number
tonsky commented 1 year ago

Yes, seems useful

handerpeder commented 3 months ago

Ran into this as well. Would fixing this require changing just validate-datom or is this more involved?