datomic

mkvlr 2025-06-13T09:52:35.127599Z

according to my tests :db/cas resolves lookup refs in the entity id position and the new value position but not for the current value in the case of updating a :db.type/ref. Is that correct & intentional? Makes using it a bit more clunky than it needs to be imo.

mkvlr 2025-06-13T10:02:48.927469Z

(require '[datomic.api :as d])

(def conn
  (let [db-uri (doto (str "datomic:mem://" (d/squuid))
                 d/create-database)]
    (d/connect db-uri)))

(d/transact conn [{:db/ident :my/uuid
                   :db/valueType :db.type/uuid
                   :db/cardinality :db.cardinality/one
                   :db/unique :db.unique/identity}
                  {:db/ident :my/ref
                   :db/valueType :db.type/ref
                   :db/cardinality :db.cardinality/one}])

(def uuid
  (random-uuid))

(def ref-uuid
  (random-uuid))

(d/transact conn [{:my/uuid uuid
                   :my/ref {:my/uuid ref-uuid}}])

;; db id for current & new value works
(d/with (d/db conn)
        [[:db/cas
          [:my/uuid uuid]
          :my/ref
          (d/entid (d/db conn) [:my/uuid ref-uuid])
          (d/entid (d/db conn) [:my/uuid ref-uuid])]])


;; db id for current value & lookup ref for new value works
(d/with (d/db conn)
        [[:db/cas
          [:my/uuid uuid]
          :my/ref
          (d/entid (d/db conn) [:my/uuid ref-uuid])
          [:my/uuid ref-uuid]]])

;; lookup ref for new value fails
(d/with (d/db conn)
        [[:db/cas
          [:my/uuid uuid]
          :my/ref
          [:my/uuid ref-uuid]
          [:my/uuid ref-uuid]]])
;; throws ":db.error/cas-failed Compare failed: [:my/uuid #uuid \"c4ebabe2-4328-4995-9d60-6acfedeaf0a3\"] 17592186045422"

mkvlr 2025-06-13T10:25:51.326659Z

in case someone else feels similarly, here’s a db fn which resolves lookup refs for the current value

(defn cas
  "Ductile version of `:db/cas` with support for lookup refs for the current value."
  [db db-id attr current-value new-value]
  [[:db/cas
    db-id
    attr
    (if (and (= :db.type/ref (:db/valueType (d/entity db attr)))
             (vector? current-value))
      (d/entid db current-value)
      current-value)
    new-value]])

πŸ‘ 1
πŸ’œ 1
ghadi 2025-06-13T11:13:38.198119Z

Try to avoid relying on the resolution of the target eid. It gives the transactor work to do that is doable in the peer

☝️ 1
souenzzo 2025-06-13T12:29:57.687569Z

I remember reporting this bug back in ~2016 πŸ˜† the portal I reported no longer exists - and I'm pretty sure that at least one a year someone else reports it here in slack too.

πŸ‘ 1
mkvlr 2025-06-13T18:07:53.683779Z

transactor throughput is not an issue for us

πŸ‘πŸΌ 1
❀️ 1