Hey I asked in the om-next channel but maybe there are better leads in here... Are there any good sources on going from my basic app-state atom to full-blown datomic integration? As far as I can tell I just need to create a database connection and create a read function that queries the db.... is true?
@sova depends on the level of integration. Om-next queries are the same basic syntax as datomic queries, so it is possible to run some of them directly against that database. I believe we have something on that documented or sampled out.
Yeah, our todomvc uses Datomic
you're still going to want the basic app state atom as a map. IMHO, using a map as your app state atom is the right thing for the UI. I do not recommend complecting a datomic database into a UI in general.
If you were going to transfer the entire database from the server to the client, then it might make sense (because then you could do all database ops on the client, like complex queries); otherwise you're just adding a bunch of network and CPU overhead for no good effect.
Datascript, for example, gives you Datomic-like abilities on the client; however, using that as database to drive a UI is not so great an idea: queries against a datomic-like database are way more powerful than you need to fill out a UI, and waaay slower as a result. You'll end up with a sluggish UI, and since you won't want to download all of the complex data to the client, no real benefit. If you happen to have a use-case where it isn't just the "cool factor" on the client, then perhaps it is ok...but even then, I'd recommend: Datomic-like database PLUS simple UI database. Run your queries (once) against the heavy database, and use that to populate the light-weight UI database.
People see features of things like Meteor and think "I've gotta have that! A database mirrored on the client". Look more closely: what they have is a subscription API. You subscribe to a query, and it tries to keep you up to date. It happens to have an API similar to Mongo, but only because mongo is kinda feature poor. If what you want is interactive apps that keep state up to date between client and server, then Om + Untangled + Websockets + Datomic does make that relatively painless.
Thank you Tony. That's essentially what I'm aiming for. I have an app I was working on that has datomic as a back-end... I like building things from scratch to get a good handle on how they work. My application needs are pretty simple: users connect and get an instantaneous display of a tiny subset of info (9 elements from the database) ... then I want om.next and sockets to kick in on the cljs side so that there's interactivity and real-time updating.
yeah, we've done something like that as a prototype
it only took a couple of days
Ah that's nice news. So in short: a read function and a mutate function for every transaction I want to make to/from the datomic database, and just kinda flesh them out myself.
how well do you understand Om/Untangled?
well, you need read functions to get the initial data
and mutations to accomplish the subscriptions
e.g. (transact! this [(app/subscribe {:entity-id 3})])
That transaction will come in on the websocket of a client (and you'll know which client it is)
That's your signal to add them to your server-side list of clients that have interest in changes
then use the Datomic tx logging to watch for changes to that ID (the set of IDs subscribed)
when you see one, send it to the client(s) that want to know
you can get even more fancy and subscribe to a query
in that case, walk the graph of the response you send and set it up so you re-run the query any time any of those IDs change
(and of course re-record the IDs of the entities of interest)
the websockets support will let you run client-side functions in response to the server pushes, which you can use to integrate the changes into the app state atom
Ah! So it's all about integrating UI updates into the client-side atom (?)
If you're subscribing to a query, just use that query to merge the data to the Om app state atom (normalization is built in)
the client-side atom is just a simple graph db. If you have a UI query + the response, it is trivial
merge!
and then om.next will do all the ui updating, presumably?
on a merge against reconciler, yes
there's nearly nothing to write with respect to the UI 🙂
you just need to merge the data tree using a proper query that is co-located on that part of the UI
Om adds metadata to the query to support the normalization
(assuming you composed it with om/get-query on the UI components)
you can also use defui
to just make queries that are composed...no render function needed
(defui Thing static om/IQuery (query [this] [:x {:y (om/get-query Y)]]))
I'd suggest you play at the REPL with merge!
that will teach you what the general vibe will be like
Ah that's a good idea.
Thanks. More learning to do.
then it'll be much simpler to understand what to do from the server websocket layer
Sure thing. Always pays to do the simplest things first
Om makes it pretty dreamy, actually. I think you'll find that what you're trying to do is about 3x simpler than you think it is
performance scaling is the harder problem....1000's of clients. That sort of thing
Yeah I have a feeling it is so! haha! I am just trying to let all the jigsaw pieces settle into place.
you did do the untangled devguide, right?
and the websockets cookbook recipe
it's been a minute since I've looked in it again, but I'm really glad it exists.
I'm oscillating between learning and applying
OK. The big tip is that everything evolves around the Om queries and normalization. Given a structured Om query, and tree of response data. The normal pipeline is to send the query, then merge the tree response. This is built into the plumbing in Untangled (but it uses Om Next primitives).
At the networking response, Om gives you a lambda to use with the tree of data...it is essentially merge!
with the query pre-applied (e.g. via partial)
actually, the latest API has you give it the query too
anyway....`merge!` is the central thing
outside of a mutation, it is how you change the app database.
Gotcha. So Om queries are kinda the fundamental unit of the whole framework, and then smashing the om-question-tree with the server-response-tree is how it all works?
yep
Ah excellent. Thanks a lot for making yourself available for all my (incessant) questions 😄
the query knows where the idents are defined, so it knows how to normalize
It seems like a hidden aspect of om-next to have to create a response tree, though.
?
not following. The query asks for a tree
the Om parser (and Datomic) can both generate a tree of response for you
so unless you're using SQL on the back-end, you should not need to manually create the tree of response
Oh, okay! I did not know that. Datomic can just make a response tree of all the things I want?
Anyway, thanks a lot for your help so far. I'ma go through the dev guide some more and see if I can make sense of how I can add Datomic querying to my om-next app that I have so far.
@sova if you want some basic datomic mutation primitives (shameless plug) I’ve got some working code/ideas here https://github.com/synfnetic/flux/blob/master/src/flux/datomic.clj