Fork me on GitHub
#hyperfiddle
<
2023-06-08
>
J17:06:51

What is the strategy to not store an ui event into the database? Let’s say we have a button that show something on click. I would like to show on every client when a user click on the button. Should I use an atom state into the server for this use case?

Dustin Getz17:06:41

global state on the server is a good starting point

👍 2
Dustin Getz17:06:30

you are looking for something more streamy probably, we are working on a new primitive that should help with that

2
s-ol18:06:51

This is probably old news, but feeling pretty smug about this way of staging user modifications with datomic rn:

; go from {db/id {...}} to (list {:db/id id, ...})
(defn changes->tx [changes]
  (map (fn [[k v]] (merge v {:db/id k})) changes))

(defn with-changes [db changes]
 (let [tx (changes->tx changes)]
   (:db-after (d/with db tx))))

...

  (e/server
    (let [!changes (atom nil)           ; {db/id {...}} map of DB changes
          tx (d/pull (with-changes db (e/watch !changes)) ...] ; fetch data for view, modified in real time

      ...
      (ui/button (e/fn [] (e/server (d/transact !conn (changes->tx @changes))))
        (dom/text "save"))

👍 2
s-ol18:06:01

only deletions are hard to model using this, at that point you'd probably just want to operate directly on a datomic-transaction-shaped store

Dustin Getz00:06:04

we use this pattern a ton in our unreleased stuff, did you figure it out yourself? nice work

s-ol09:06:26

Yeah, I was about to add an atom clientside to hold the modified values copied from the DB results, but then I realized that merging sparse changes with the db-returned state was basically what datomic does internally and that tipped me off 🙂

s-ol09:06:27

I ended up putting !changes into a (e/def) too. Do you use the same change structure (map keyed by :db/id)? That seems slightly easier to update with clojure primitives, but not sure about deletion. Although now that I think about it, that could be represented as an [id nil] or [id :db/retractEntity] entry in the !changes map that can easily be transformed into datomic tx format by changes->tx

Dustin Getz10:06:54

our current design vision tracks both txn and local record representation for optimistic updates, so the client doesn’t have to wait for a round trip to refresh a record which it already knows the shape of

Dustin Getz10:06:35

also an edit can have additional transaction logic attached to it at any level (field, form, etc)

Dustin Getz10:06:19

and it needs to work for the “create new todo item” rapid data entry case too, where the newly inserted record is pending and optimistically rendered. Consider an app like iMessage where you can send N text messages rapidly (faster than network latency) and each message is optimistically rendered and individually progresses towards completion, i.e. the nth text can fail and render a “retry” button but the others complete

👍 2
Dustin Getz10:06:58

the code you have already is easily upgraded to track a stack of dbvals, giving you essentially layered modal forms