Fork me on GitHub
#biff
<
2023-02-23
>
floscr16:02:51

How would you handle biff/submit-tx when doing upsert with the db schema? For instance I just want to update the email for a user with this schema:

(def user
  {:user/id :uuid
   :user/email :string
   :user/joined-at inst?
   :user [:map {:closed true}
          [:xt/id :user/id]
          :user/email
          :user/joined-at]})
But when I do this
(biff/submit-tx sys [{:db/doc-type :user
                      :db/op :upsert
                      :xt/id #uuid "..."
                      :user/email ""}])
I get a schema error since joined-at is missing. Should I create separate schema for the transaction? Or lookup and merge the date (which defeats the purpose of :upsert or?)

2
floscr16:02:51

I also don't want to set joined-at as optional for the db, since I want to make sure it's always there in the db.

pavlosmelissinos16:02:22

I'd also like to know the answer to this > Or lookup and merge the date (which defeats :upsert or?) This is what I do now (didn't even know :upsert is a valid xtdb op) nevermind, I'm an idiot, I use :update

floscr16:02:42

I guess writing a separate schema for the transaction would make things safer in the long run, to avoid users overwriting arbitrary props

pavlosmelissinos16:02:19

Oh, https://biffweb.com/docs/reference/transactions/ and it's the same as merge if the document exists

floscr16:02:54

Interesting, but it still has to fit the db schema 😄

Jacob O'Bryant16:02:37

is this for a user that definitely is already in the database? if so you should use :update instead of :upsert.

pavlosmelissinos16:02:42

Right, that's what I was just thinking; because :update will fail if the user doesn't exist

floscr16:02:43

Update has the same issue though?

floscr16:02:36

In that I need to pass all the keys that are required in the db schema. But I want only to update user/email for example with an update

Jacob O'Bryant16:02:02

update (and merge) will look up the existing doc for you and use the current values

pavlosmelissinos16:02:52

:upsert doesn't do that?

Jacob O'Bryant16:02:42

it does that if the document exists, but if not it'll create a new doc, in which case you need to provide all the required keys

Jacob O'Bryant16:02:08

you can use the :db/default operation to set keys only if it's a new doc/if the keys aren't set yet

pavlosmelissinos16:02:31

According to OP, the document exists but xtdb still complains that the schema is wrong Under the transaction docs, there's this note: > Note: You must have installed the :biff/ensure-unique transaction function for this to work. See com.biffweb/tx-fns (installed by default in new projects). Is this a prerequisite in order to do a proper :update/:merge (seems relevant but maybe it's not)?

Jacob O'Bryant17:02:41

if the doc exists and it already has all the required keys, that error shouldn't be triggered by upsert. the upsert in the code snippet is also not in the right format--with upsert you never pass in the :xt/id, since the whole point of upsert is to create or update a document based on an arbitrary key-value pair(s). e.g. it's good for creating a user with a given email address so that if they hit the signup button twice in a row or something, you don't accidentally create two separate user docs. see the transaction docs (linked above) for an example of upsert (on my phone currently so a little hard to type it out :) )

Jacob O'Bryant17:02:29

the :biff/ensure-unique transaction fn is installed by biff automatically

Jacob O'Bryant17:02:55

it's needed for upsert but not update or merge

🙏 2
Jacob O'Bryant17:02:23

(aside, maybe I should deprecate the merge operation and just have upsert--they're quite different implementation wise but I guess semantically they're the same. difference is that merge only works for updating/creating documents based on :xt/id, while upsert works for arbitrary keys)

floscr17:02:41

Thank you, that makes more sense now 🙌

👌 2
floscr17:02:54

Here's my results/notes for getting started with unit testing biff/submit-tx https://gist.github.com/floscr/4af4fa5cb79d4538d558b0f685ffdf97

Jacob O'Bryant18:02:48

looks great 👍