jacobobryant / biff

A Clojure web framework for solo developers.
https://biffweb.com
MIT License
824 stars 39 forks source link

Cannot read my write via submit-tx #218

Closed marcrodgers closed 1 month ago

marcrodgers commented 1 month ago

First off, thank you all for this incredible project! I've been meaning to learn Clojure web dev for a long while. Thanks to biff, everything's finally clicking - including using htmx. Really appreciated!

I'm writing a basic "to-do" web app. I have a controller that toggles the status of the task using this call:

(biff/submit-tx ctx
   [{:db/op :update
    :db/doc-type :task
    :xt/id (:xt/id task)
    :task/completed toggle-to}])

Immediately after this call, I try to pull the new value of the task via xt/entity and return it via htmx. But somehow the returned HTML still has the old status. The new status is correctly displayed after I refresh the page. To test this out, I added the pprint statement, as follows, right after the submit-tx call:

(biff/pprint (str "post-update, value: " (xt/entity db (parse-uuid (:id path-params)))))

This call also returns the old status. I tried manually calling await-tx, that doesn't work either. Am I missing something?

jacobobryant commented 1 month ago

Hey, glad Biff's been helpful!

This a common pitfall/feature of how things work with XTDB. db is an immutable snapshot of the database, similar to clojure's regular immutable data structures. Biff passes in a new db value automatically, so each request handler gets a snapshot of whatever data was indexed when the handler started.

To get a new snapshot that contains data you've just written, you can get a new db like this:

(defn my-handler [{:keys [biff.xtdb/node] :as ctx}]
  (biff/submit-tx ctx
    [{:db/op :update
      :db/doc-type :task
      :xt/id (:xt/id task)
      :task/completed toggle-to}])
  (let [db (xt/db node)]
    ...))

Alternatively, Biff also has a merge-context helper function that'll get a new db value and merge it into the ctx value for you (convenient if you need to pass ctx around with the new db value):

(let [{:keys [biff/db] :as ctx} (biff/merge-context ctx)]
  ...)
marcrodgers commented 1 month ago

Thank you! That did it. I really appreciate the detailed answer!