This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2022-10-21
Channels
- # announcements (1)
- # aws (18)
- # babashka (5)
- # beginners (72)
- # biff (2)
- # calva (38)
- # cider (2)
- # clj-commons (6)
- # clj-yaml (2)
- # clojars (7)
- # clojure (41)
- # clojure-austin (5)
- # clojure-europe (78)
- # clojure-nl (1)
- # clojure-norway (18)
- # clojure-uk (3)
- # clojurescript (13)
- # component (9)
- # cursive (37)
- # datahike (3)
- # datomic (7)
- # fulcro (7)
- # graphql (3)
- # holy-lambda (2)
- # honeysql (8)
- # introduce-yourself (1)
- # jobs (1)
- # kaocha (1)
- # leiningen (19)
- # lsp (104)
- # malli (5)
- # nbb (8)
- # off-topic (60)
- # polylith (22)
- # portal (2)
- # reagent (24)
- # reveal (1)
- # shadow-cljs (126)
- # test-check (11)
- # tools-build (39)
- # vim (23)
- # xtdb (10)
Is it possible to upsert a entity with a composite db/tupleAttrs
:db.unique/identity
when the tupleAttrs are db.type/ref
keys? I can't figure out the proper way to transact the upsert without getting unique constraint violations.
Here is a self contained example:
(ns user
(:require [datahike.api :as d]))
(defn connect
[]
(d/delete-database) ;; deletes the 'default' db
(d/create-database {:schema-flexibility :write})
(d/connect))
(def conn2 (connect))
(d/transact conn2 [;; this will be one part of the composite
{:db/ident :gig/title
:db/valueType :db.type/string
:db/unique :db.unique/value
:db/cardinality :db.cardinality/one
:db/doc "The title of the gig"}
;; this will be the second part of the composite
{:db/ident :song/title
:db/valueType :db.type/string
:db/unique :db.unique/value
:db/cardinality :db.cardinality/one
:db/doc "The title of the song"}
;; here we establish the references
{:db/ident :played/song
:db/valueType :db.type/ref
:db/cardinality :db.cardinality/one
:db/index true
:db/doc "The song that was played"}
{:db/ident :played/gig
:db/valueType :db.type/ref
:db/cardinality :db.cardinality/one
:db/index true
:db/doc "The gig that the song was played at"}
;; here is a simple attribute we will want to upsert
{:db/ident :played/quality
:db/valueType :db.type/keyword
:db/cardinality :db.cardinality/one
:db/index true
:db/doc "Quality"}
;; finally our composite id
{:db/ident :played/gig+song
:db/valueType :db.type/tuple
:db/tupleAttrs [:played/gig :played/song]
:db/cardinality :db.cardinality/one
:db/unique :db.unique/identity}])
;; create the referenced entities
(d/transact conn2 [{:song/title "A"} {:gig/title "Z"}])
;; create our entity that we want to upsert
(d/transact conn2 [{:played/gig [:gig/title "Z"]
:played/song [:song/title "A"]
:played/quality :quality/good}])
(let [ent (->> (d/q '[:find [?e ...]
:where [?e :played/gig [:gig/title "Z"]]]
@conn2)
first
(d/entity @conn2)
(into {}))]
;; this simple upsert fails with
;; Cannot add #datahike/Datom [10 :played/gig+song [8 7] 536870916 true] because
;; of unique constraint: #datahike/Datom [9 :played/gig+song [8 7] 536870915
;; true]
;; (d/transact conn2 [{:played/gig (-> ent :played/gig :db/id)
;; :played/song (-> ent :played/song :db/id)
;; :played/quality :quality/bad}])
;; this works! but it is not an upsert
(d/transact conn2 [{:db/id [:played/gig+song (:played/gig+song ent)] :played/quality :quality/bad}]))
Hey Casey, I don't really know. Maybe @UB95JRKM3 or @UQVCR784A knows.