Fork me on GitHub

Does anyone know of a React library that comes close to Fulcro's form state handling? Or more broadly, a React state management library that has the same normalized db + component query functionality? I'm reviewing another team's React codebase and it's infuriating seeing ad hoc "dirty" checking in each of their forms.


I have not looked extensively at current evolutions. Apollo was trying. Not quite the same, but they are at least trying to adopt the normalization mechanisms.


You can take a look at mobx-state-tree (, but its documentation barely exists and it was a pain to work with tbh. But they also have the concept of normalizing state, or at least, provide you the means to do so. You have to write a ton of boilerplate code. As you see, I'm not exactly a fan. I tried mobx-state-tree after finishing another project with plain MobX, which was nice enough. How you use it is entirely up to you. Before that, I've always written my own state management based on RxJS which kept things reasonably simple. Anway, long story short: You can give mobx or mobx-state-tree a shot, but in reality fulcro is lightyears ahead to every other solution I've tried over the years

Jakub Holý (HolyJak)10:12:11

Also Relay has a normalized cache for its GQL queries just like Apollo


Great, thanks folks!

Thomas Moerman09:12:58

@tony.kay a small question about the future/commercial guardrails library you mentioned on a podcast: will it depend on clojure.spec or will the "spec'ing" library be pluggable perhaps? I was wondering about this, given the known flaw in the current spec version regarding "selection" context of specs (as discussed in the Maybe Not talk by Rich). What's your current perspective?


The version we’re working on “comes with” spec support at the moment, but we’ve put all of that behind a protocol. Hoping to support Spec 1, Spec 2, Mali, and whatever comes next in that arena. I’m aware of the problems, and that no single thing perfectly covers the bases at the moment.


If you want to have a “paid alpha” program or something like that, count me in! 🙂 :thumbsup:


I’m hoping to have an early access program in the next month or two. There are a lot of little kinks to work out, and the CLJS support will probably be a few more months out from there (assuming ppl buy it, and I can afford to keep working on it).


Thx to all for the help running queries inside of Fulcro RAD, @holyjak @randumbo. Okay, now I’m having a problem with the session/get-all-sessions resolver not being able to connect to the correct database (a Datomic Cloud instance, in addition to the in-memory db in the example.) In my defaults.edn file, here’s the databases I have configured.

                                    {:main {:datomic/schema :production
                                            :datomic/database "example"
                                            :datomic/client {:server-type :dev-local
                                                             :system "fulcro-rad-demo"}
                                            :datomic/prevent-changes? true}

                                     :video {:datomic/schema :production2
                                             :datomic/client  {:server-type   :ion
                                                               :region        "us-west-2"                       
                                                               :system        "datomic-2"
                                                               :creds-profile "default"
                                                               :endpoint      ""
                                                               :proxy-port    8182}
                                             :datomic/database "videolibrary"
                                             :datomic/prevent-changes? true}}
And here is my database query in com.example.components.database-queries
(defn get-all-sessions
  [env query-params]
  (if-let [db (some-> (get-in env [do/databases :production2]) deref)]
    (let [ids (d/q '[:find ?s
                     [?s :session/title _]] db)]
      (->> ids
           (mapv (fn [id] {:session/session id}))))
    (log/error "No database atom for production schema!")))
I’m pretty sure I must have something wrong either in the schema name, or name of the datomic entry? Hoping someone can show me what I”m doing wrong. Thx!!!


Your config looks correct on first glance. Maybe you just forgot to open the ssh tunnel to your cloud system?


Alas, manual queries work, so tunnel is working. Is it okay for both :main and :video dbs to share :production schema? How does resolver know to look in video db? (Manually examining the get-all-sessions env, it looks like it’s looking in :main db, not :video db… Thx!

Jakub Holý (HolyJak)10:12:39

I guess ""No database atom for production schema!"" is the result you are getting? Are you sure do/databases should not be ::do/databases , assuming (require '[com.fulcrologic.rad.database-adapters.datomic :as do]) ?


Sorry, @holyjak, I forgot to mention!! I’m getting as a return value: [] That is when I have db entry set to production (not production2), and code in db query set to the same: (if-let [db (some-> (get-in env [do/databases :production]) deref)]

Jakub Holý (HolyJak)10:12:09

OK, so your query runs but returns no data so you suspect it uses the wrong db.


Yes. (and all the other queries that work use do/databases… I just copied/pasted. 🙂

👍 3
Jakub Holý (HolyJak)10:12:00

I don't really know as I use SQL. There I need to explicitely tell it which DB to use:

data-source    (get-in env [::sql/connection-pools :video])


Ooh…. looking…


Wow! Trying that now, and assuming I can have one for :main and one for :video. (crossing fingers!)

Jakub Holý (HolyJak)10:12:26

It seems you have not so I would expect (some-> (get-in env [do/databases :production2]) to return nil What does it return?


(Can I have both :main and :video dbs share :production schema? I’m hoping so, otherwise, I have to handle the attributes differently in


(Now it’s returning #:session{:all-sessions []}. I think I’m getting closer? Still not sure if I need two schemas or not…. hmm…



#:session{:all-sessions [#:session{:session 43518670227374203}
                         #:session{:session 54109166226112675}


Okay, so it works when I replace out the datomic/pathom-plugin entry in parser. Is there a way to have two datomic databases, and if so, how? Thx again, @holyjak!

(defstate parser
     (form/pathom-plugin save/middleware delete/middleware)
     ;(datomic/pathom-plugin (fn [env] {:production (:main datomic-connections)}))
     (datomic/pathom-plugin (fn [env] {:production (:video datomic-connections)}))
     (blob/pathom-plugin bs/temporary-blob-store {:files         bs/file-blob-store
                                                  :avatar-images bs/image-blob-

Jakub Holý (HolyJak)11:12:09

Perhaps this:

(datomic/pathom-plugin (fn [env] {
:main (:main datomic-connections)
:video (:video datomic-connections)}))
and in the code change to (if-let [db (some-> (get-in env [do/databases :main #_:video]) deref)]

Jakub Holý (HolyJak)11:12:11

the key in the datomic/databases map and in the env are completely arbitrary and do not need to relate to the DB schema, I believe


A schema should have a 1-to-1 correspondence with a data store. You supply a function that figures out, for a request, which connection(s) should be associated with which schema. This allows you to shard easily, and even spread attributes among database types (Datomic could supply data for schema A, kv store for B, etc.)


I just happened to have this page open from the pathom docs, maybe that helps too:


E.g. large strings are bad for Datomic, but you could set up a different db/connection/schema for those attributes and RAD can then save/load them to different stores. There’s a bit more work for you to do around that to make such a thing “atomic” to whatever degree you find satisfactory….RAD has no strong opinion on implementing two-phase commit for you.

Jakub Holý (HolyJak)17:12:38

Is the RAD concept of Schema identical to the underlying relational / Datomic DB schéma or is it a separate thing? Regarding > You supply a function that figures out, for a request, which connection(s) should be associated with which schema. Where, how? Is that what the datomic parser plugin does? The way I understand it, the datomic plugin inserts 1+ DBS into the env, each with a unique key, and I get-in env [.. the-key] to get the one my queey/resolver wants. Do I misunderstand? (I was thinking in terms of manual resolvers just as the one Gene was showing. I guess for the auto-generated ones it is indeed crucial that the Schema and DB key under env are the same so that they know what DB to use.)


@holyjak The RAD concept of schema on attributes is just a way to group the attributes together for some logical reason. From there the provided DB plugins use that to decide if the attribute belongs in their database. So, when the Datomic plugin generates resolvers and form handlers it only pays attn to attributes on the schema of interest. So then then pathom db ENV plugin for the db adapters needs to know, for a given request, what connection to use with every schema that that database supports. So, say you have a :prod schema and you want to store that in SQL, and you have an :accounting schema you want to store in Datomic. On the SQL side you decide to shard based on user, so some users go to db cluster A, and other users go to cluster B. You find that accounting data only needs a single database C. When a request comes in for some user that uses SQL A and accounting (C), you’d set the :prod connection to talk to A and the :accounting connection to C. Etc.

👍 6

It’s all really lightweight code (the plugins), so you can easily define it however you want, and invent whatever custom attribute options you desire to do it however you want.


I’ve got a project where RAD is integrated top to bottom and does many of the screens, and another where RAD is just doing a report or two and has no RAD back-end (just using plain Pathom resolvers).


Thx, all! This was all so helpful today — I’ll post an update tomorrow. Feeling great, but I’ve got to turn in a little early, after a super late night last night. 🙂 I’m so grateful for all this help!

Jakub Holý (HolyJak)10:12:41

thanks a lot for the explanation, Tony!