biff 2024-03-15

I've also noticed lookup-info is getting called on doc-id. How is this supposed to work? It looks like it's expecting the transaction document judging by it calling special-val? on it, so won't this always return nil since we're not ever passing in the document itself?

This code is a bit convoluted and could do with some refactoring (part of my upcoming xtdb work)... anyway, reading the code again, lookup-info is taking the document ID--or more precisely, whatever the value of :xt/id is in the transaction document. The call to special-val? is used to see if the document ID has the form [:db/lookup ]. This is related to a https://biffweb.com/docs/reference/transactions/#%3Ccode%3E:db/lookup%3C/code%3E that has since been made unnecessary by Biff's upsert operation. Also in general, special-val? doesn't take the entire transaction document; it just takes in a value of one of the transaction document's keys.

Ah that's what confused me. They all looked like special-vals for operations, I didn't notice the :db/loopup. Thank you

👌 1

I am working on some concurrent update code. I want to update what I call a bundle by decrementing its field called counter, but I don't want the counter to go below zero. My reading of the docs is that I want to read the existing counter value (let's say its value is 1), then :update the bundle using {:counter [:db/add -1]} and add an extra txn like: [xtdb.api/match counter 1]. Then if counter is not 1 I would get an exception, and would then need to read the new counter value, and try again. Am I on the right track? Any example code?

Or maybe there is no exception, but only a false result from (tx-committed? txn)

It's probably easiest to not bother with :db/add and do it a bit more manually. biff/submit-tx lets you pass in a function as the second parameter, in which case it should take in a single argument--the ctx map, which will include an up-to-date :biff/db value--and return the transaction (I.e. the thing you would normally pass to biff/submit-tx. you can have the function query for the existing document and then do your own logic for updating the counter. e.g. if the counter is already at 0, you could either have the function return nil or throw an exception; up to you. I should type up an example of that. I don't think there is one currently.

actually there is an example in the docs:

(biff/submit-tx ctx
  (fn [{:keys [biff/db]}]
    [{:db/doc-type :user
      :db/op :merge
      :xt/id (or (biff/lookup-id db :user/email email)
                 (java.util.UUID/randomUUID))
      :user/email email}
     [::xt/fn :biff/ensure-unique {:user/email email}]]))
it's a few paragraphs down: https://biffweb.com/docs/reference/transactions/