untangled

NEW CHANNEL: #fulcro
sova-soars-the-sora 2017-01-09T21:29:27.001918Z

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?

tony.kay 2017-01-09T21:31:18.001919Z

@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.

tony.kay 2017-01-09T21:33:01.001920Z

Yeah, our todomvc uses Datomic

tony.kay 2017-01-09T21:34:44.001921Z

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.

tony.kay 2017-01-09T21:35:52.001922Z

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.

tony.kay 2017-01-09T21:38:43.001923Z

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.

tony.kay 2017-01-09T21:41:10.001924Z

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.

sova-soars-the-sora 2017-01-09T21:44:04.001925Z

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.

tony.kay 2017-01-09T21:44:45.001926Z

yeah, we've done something like that as a prototype

tony.kay 2017-01-09T21:44:51.001927Z

it only took a couple of days

sova-soars-the-sora 2017-01-09T21:45:03.001928Z

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.

tony.kay 2017-01-09T21:45:03.001929Z

how well do you understand Om/Untangled?

tony.kay 2017-01-09T21:45:19.001930Z

well, you need read functions to get the initial data

tony.kay 2017-01-09T21:45:29.001931Z

and mutations to accomplish the subscriptions

tony.kay 2017-01-09T21:45:50.001932Z

e.g. (transact! this [(app/subscribe {:entity-id 3})])

tony.kay 2017-01-09T21:46:11.001933Z

That transaction will come in on the websocket of a client (and you'll know which client it is)

tony.kay 2017-01-09T21:46:29.001934Z

That's your signal to add them to your server-side list of clients that have interest in changes

tony.kay 2017-01-09T21:46:49.001935Z

then use the Datomic tx logging to watch for changes to that ID (the set of IDs subscribed)

tony.kay 2017-01-09T21:47:03.001936Z

when you see one, send it to the client(s) that want to know

tony.kay 2017-01-09T21:47:19.001937Z

you can get even more fancy and subscribe to a query

tony.kay 2017-01-09T21:47:51.001938Z

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

tony.kay 2017-01-09T21:48:01.001939Z

(and of course re-record the IDs of the entities of interest)

tony.kay 2017-01-09T21:48:44.001940Z

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

sova-soars-the-sora 2017-01-09T21:49:12.001941Z

Ah! So it's all about integrating UI updates into the client-side atom (?)

tony.kay 2017-01-09T21:49:18.001942Z

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)

tony.kay 2017-01-09T21:49:37.001943Z

the client-side atom is just a simple graph db. If you have a UI query + the response, it is trivial

tony.kay 2017-01-09T21:49:47.001944Z

merge!

sova-soars-the-sora 2017-01-09T21:50:02.001945Z

and then om.next will do all the ui updating, presumably?

tony.kay 2017-01-09T21:50:14.001946Z

on a merge against reconciler, yes

tony.kay 2017-01-09T21:50:30.001947Z

there's nearly nothing to write with respect to the UI 🙂

tony.kay 2017-01-09T21:50:49.001948Z

you just need to merge the data tree using a proper query that is co-located on that part of the UI

tony.kay 2017-01-09T21:51:07.001949Z

Om adds metadata to the query to support the normalization

tony.kay 2017-01-09T21:51:21.001950Z

(assuming you composed it with om/get-query on the UI components)

tony.kay 2017-01-09T21:51:37.001951Z

you can also use defui to just make queries that are composed...no render function needed

tony.kay 2017-01-09T21:52:06.001952Z

(defui Thing static om/IQuery (query [this] [:x {:y (om/get-query Y)]]))

tony.kay 2017-01-09T21:56:11.001954Z

I'd suggest you play at the REPL with merge!

tony.kay 2017-01-09T21:56:25.001955Z

that will teach you what the general vibe will be like

sova-soars-the-sora 2017-01-09T21:56:28.001956Z

Ah that's a good idea.

sova-soars-the-sora 2017-01-09T21:56:37.001957Z

Thanks. More learning to do.

tony.kay 2017-01-09T21:56:47.001958Z

then it'll be much simpler to understand what to do from the server websocket layer

tony.kay 2017-01-09T21:57:01.001959Z

Sure thing. Always pays to do the simplest things first

tony.kay 2017-01-09T21:57:33.001960Z

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

tony.kay 2017-01-09T21:58:03.001961Z

performance scaling is the harder problem....1000's of clients. That sort of thing

sova-soars-the-sora 2017-01-09T21:58:14.001962Z

Yeah I have a feeling it is so! haha! I am just trying to let all the jigsaw pieces settle into place.

tony.kay 2017-01-09T21:58:32.001963Z

you did do the untangled devguide, right?

tony.kay 2017-01-09T21:58:47.001964Z

and the websockets cookbook recipe

sova-soars-the-sora 2017-01-09T21:59:10.001966Z

it's been a minute since I've looked in it again, but I'm really glad it exists.

sova-soars-the-sora 2017-01-09T21:59:26.001967Z

I'm oscillating between learning and applying

tony.kay 2017-01-09T22:00:55.001968Z

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).

tony.kay 2017-01-09T22:01:27.001969Z

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)

tony.kay 2017-01-09T22:01:40.001970Z

actually, the latest API has you give it the query too

tony.kay 2017-01-09T22:01:58.001971Z

anyway....`merge!` is the central thing

tony.kay 2017-01-09T22:02:13.001972Z

outside of a mutation, it is how you change the app database.

sova-soars-the-sora 2017-01-09T22:02:16.001973Z

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?

tony.kay 2017-01-09T22:02:35.001974Z

yep

sova-soars-the-sora 2017-01-09T22:02:51.001975Z

Ah excellent. Thanks a lot for making yourself available for all my (incessant) questions 😄

tony.kay 2017-01-09T22:02:58.001976Z

the query knows where the idents are defined, so it knows how to normalize

sova-soars-the-sora 2017-01-09T22:03:32.001977Z

It seems like a hidden aspect of om-next to have to create a response tree, though.

tony.kay 2017-01-09T22:05:06.001978Z

?

tony.kay 2017-01-09T22:05:13.001979Z

not following. The query asks for a tree

tony.kay 2017-01-09T22:05:31.001980Z

the Om parser (and Datomic) can both generate a tree of response for you

tony.kay 2017-01-09T22:05:53.001981Z

so unless you're using SQL on the back-end, you should not need to manually create the tree of response

sova-soars-the-sora 2017-01-09T22:16:51.001982Z

Oh, okay! I did not know that. Datomic can just make a response tree of all the things I want?

sova-soars-the-sora 2017-01-09T22:26:59.001983Z

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.

adambros 2017-01-09T22:52:39.001984Z

@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