Skip to content

Upserting by Unique Composite Tuple works in Datomic but not Datascript #400

@caleb

Description

@caleb

Upserting by unique composite tuple doesn't work in Datascript as it does in Datomic.

It was not immediately clear to me how to upsert by unique composite tuple in Datomic by the documentation, but I found this forum post about it:

https://forum.datomic.com/t/db-unique-identity-does-not-work-for-tuple-attributes/1072

The key part is the last post by jaret:

If you do want to identify an entity by a unique key, you must indeed specify that unique key (not its constituents).

Datascript:

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

;;
;; 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"
                       :one+two ["one" "two"]
                       :one "one"
                       :two "two"}
                      {:db/id "tmpid"
                       :one+two ["one" "two"]
                       :one "one"
                       :two "two"}])

  (ds/transact! conn [{:db/id "tmpid"
                       :one+two ["one" "two"]
                       :one "one"
                       :two "two"}
                      {:db/id "tmpid"
                       :one+two ["one" "two"]
                       :one "one"
                       :two "two"}])

  (ds/q '[:find [(pull ?e [*]) ...]
          :where
          [?e :one _]]
        @conn))

Gives this error:

Unhandled clojure.lang.ExceptionInfo
   Can’t modify tuple attrs directly: [:db/add 1 :one+two ["one" "two"]]
   {:error :transact/syntax, :tx-data [:db/add 1 :one+two ["one" "two"]]}

But in Datomic, this works:

(ns ds.datomic
  (:require [datomic.client.api :as d]))

(let [client (d/client {:server-type :dev-local :system "dev"})]
  (d/delete-database client {:db-name "tuples"})
  (d/create-database client {:db-name "tuples"})

  (let [conn (d/connect client {:db-name "tuples"})
        schema [{:db/ident :one
                 :db/valueType :db.type/string
                 :db/cardinality :db.cardinality/one}
                {:db/ident :two
                 :db/valueType :db.type/string
                 :db/cardinality :db.cardinality/one}
                {:db/ident :one+two
                 :db/valueType :db.type/tuple
                 :db/tupleAttrs [:one :two]
                 :db/cardinality :db.cardinality/one
                 :db/unique :db.unique/identity}]]
    (d/transact conn {:tx-data schema})

    (d/transact conn {:tx-data [{:db/id "tmpid"
                                 :one "one"
                                 :two "two"
                                 :one+two ["one" "two"]}
                                {:db/id "tmpid"
                                 :one "one"
                                 :two "two"
                                 :one+two ["one" "two"]}]})

    (d/transact conn {:tx-data [{:db/id "tmpid"
                                 :one "one"
                                 :two "two"
                                 :one+two ["one" "two"]}
                                {:db/id "tmpid"
                                 :one "one"
                                 :two "two"
                                 :one+two ["one" "two"]}]})
    (d/q '[:find (pull ?e [*])
           :where
           [?e :one _]]
         (d/db conn))))

Yields:

[[{:db/id 79164837199948,
   :one "one",
   :two "two",
   :one+two ["one" "two"]}]]

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