This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
Is there a way to assign a tempid to an existing id in a transaction function, so that when tempid is used in a later transaction, it resolves to the existing id?
Given this schema:
(def schema {:partial/f+e+forward? {:db/valueType :db.type/tuple
:db/tupleAttrs [:partial/f
:partial/e
:partial/forward?]
:db/unique :db.unique/identity}
:partial/f {:db/valueType :db.type/ref}
:partial/e {:db/valueType :db.type/ref}
:partial/forward? {:db/valueType :db.type/boolean}})
I have this transaction function:
(d/transact!
conn
[{:db/ident :add-partial
:db/fn (di/inter-fn [db tempid f-id e-id forward?]
[{:db/id tempid
:partial/f f-id
:partial/e e-id
:partial/forward? forward?}])}])
The issue is that this transaction function is not valid when f+e+forward? is already bound, as upsertion on composite tuples is not supported. I want to change this transaction function so that it checks whether f+e+forward? exists and only run that transaction when it doesn't exist. But in that case, tempid is not bound, so later if I want to write something like
(d/transact! conn [[:add-partial -1 f-id e-id forward?] [:do-something-with-partial -1]])
it wouldn't work, making the transaction not composable.My understanding is that composite tuples are completely system managed. User doesn’t need to do anything with it. If f, e, forward? exist, the composite tuple is created. There’s no point trying to test it.
Right, but with unique composite tuples, the operation in the transaction above is not allowed. I don't need to test it, but I want to create a transaction function that simulates an upsert. The existence test is only to facilitate the upsert operation.
If the composite tuple already exists, it will result in an error, which I am trying to avoid by testing.
I don’t quite understand what you mean by upserting a composite tuple. composite tuples are entirely depending on its parts, it doesn’t have its own storage at all.
if one of its attribute is changed, the tuple is updated, become another tuple, automatically
unlike hetero and hmo tuples, which are actually stored, composite tuples are fake, there’s no storage backing it up, so there’s no point talking about upserting a composite tuple.
If composite tuple is declared unique, then two successive txns with same f, e, forward? will fail, as per https://forum.datomic.com/t/upsert-behavior-with-composite-tuple-key/1075
because the combination is unique. If you want “upsert”, meaning changing one of the attribute values, then it’s a different tuple, it shouldn’t fail
I see. Either way, I am looking for a solution to the composability of transactions, as outlined above.
you can get an existing entity id and use it later on, there’s no problem, it doesn’t have to be tempid
Right, that's not an issue. But the advantage of [:add-partial tempid ...] is that you can use tempid for later transactions, and have :add-partial be composable.
For instance, with this:
(d/transact! new-conn
[{:db/ident :add-node
:db/doc "Add node."
:db/fn (di/inter-fn [db tempid s]
[{:db/id tempid :node/value s}])}])
I can use the tempid later, like you would with default db transaction functions:
(->
(d/transact! conn [[:add-node -1 node-val]
[:add-pinned-node -2 -1 workspace-id card-opts]])
:tempids
(get -2))
I couldn't figure out how to do this with :add-partial.i don’t normally worry too much about elegance. Elegance comes out naturally if the problem is well understood and nothing unrelated is tagged on. So it is not a goal in itself.
yeah, composite tuple attributes are not real attributes, so there are some differences, it is not supposed to be used as a regular attribute. Not everything works the same.