Fork me on GitHub
#om
<
2016-10-07
>
rastandy10:10:02

hello everyone

rastandy10:10:19

I’m struggling with the om.next parser implementation

rastandy10:10:14

i have implemented the “read” method as a multimethod as shown in various tutorials

rastandy10:10:37

and when it comes to read queries with joins

rastandy10:10:58

I call the parser recursively

rastandy10:10:36

the problem is: how I can recover the possibility to ask for remote call when I use the parser recursively?

rastandy10:10:47

parser only return a value

rastandy10:10:04

and I need the :remote key from my read methods

rastandy11:10:52

I can make an example if someone would like to help me

wilkerlucio11:10:27

@rastandy are you using om/db->tree?

rastandy11:10:13

@wilkerlucio no, I have a custom database format

rastandy11:10:06

the problem for me is that if I call the parser recursively from “read”, I lose the possiblity to ask for remote call from my read methods

wilkerlucio11:10:55

umhum, I see the issue, I don't know how to solve that using a recursive parser

wilkerlucio11:10:16

are you doing it for the sake of learning or just trying to get something working?

rastandy11:10:28

trying to get something working

rastandy11:10:38

and learning

wilkerlucio11:10:14

had you tried the Untangled framework?

rastandy11:10:30

I’m trying to convince my colleagues to go for om.next in our projects

rastandy11:10:50

@wikkerlucio No, I can’t chose the backend

rastandy11:10:55

only frontend

rastandy11:10:00

and interface with a rest api

wilkerlucio11:10:01

you don't have to choose the backend

wilkerlucio11:10:09

I for example only use the untangled-client

rastandy11:10:14

interesting

wilkerlucio11:10:15

because it saves me all this work on the parser

wilkerlucio11:10:52

at least on the client-side, on the server-side I'm using cljs + node

rastandy11:10:33

I don’t know if I’ll have time to change the app

rastandy11:10:51

but it’s a good suggestion for the next app

wilkerlucio11:10:05

no worries, if you have some time take a read on their docs: http://untangled-web.github.io/untangled/reference/reference.html

rastandy11:10:22

@anmonteiro thank you, will take a look at that

rastandy11:10:59

btw, @anmonteiro thank you for your great talk “Clients in control”, I really enjoyed that, and also I started reading your blog

anmonteiro11:10:43

Thanks, always glad to be of help

petterik11:10:37

It's a bit hacky and I should probably look at the om-tutorial version. Just thought I'd provide another example

rastandy11:10:21

@petterik wow thank you very much, I’ll try to understand all this suggestion

rastandy11:10:00

@petterik I’m not able to understand your solution, maybe when I’ll go deeper in this problem

petterik12:10:29

@rastandy I didn't understand it either. Was a long time since I hacked it together. So I made it better: https://gist.github.com/petterik/abfae9d8383138b2daa83588e4c7a9fb

petterik12:10:59

which is now pretty much an inline version of the om-tutorial version, without the (decend ) code

tony.kay15:10:13

Thanks for letting people know that Untangled doesn't force you into a back-end @wilkerlucio. That seems to be a common misconception. It is really just a collection of libraries that, taken together, provide a full-stack solution. But just in case others are wondering: The client and server libraries don't have any opinion on back-end database. There is a Datomic integration library that adds some helpers for that, but you could easily use PostgreSQL, MySQL, etc etc etc. Even the testing library (untangled-spec) is a stand-alone library that you can use stand-alone. Basically, Untangled makes it easy to get going on an Om Next app (you don't have to write a parser, network plumbing, etc.). You do have to tolerate a few decisions (e.g. we pick the "default" database format, and provide more complete merge/migration implementations), but we've not had a single complaint about that. We also give a server interaction story that is pre-constructed, but it uses stock Om-Next primitives...it just does a lot of the work you'd have to do anyway. We're in the process of updating the docs (the tutorial is becoming a dev guide...feel free to check out the progress on the develop branch of https://github.com/untangled-web/untangled-tutorial/tree/develop

rastandy15:10:47

thanks @tony.kay for the explanation

peeja15:10:56

@rastandy Did you ever find an answer about calling the parser recursively?

peeja15:10:14

Oh, my Slack's scrolling poorly 😛

rastandy15:10:16

@tony.kay your tutorials are awesome and Untangled looks very cool!

peeja15:10:16

@rastandy This is where you're mistaken, but it's an easy mistake to make.

rastandy15:10:51

@peeja I’m still in the process of learning from @tony.kay’s om-tutorial

peeja15:10:54

The parser is actually called twice: once with target set to nil, and once with it set to your remote name (and then again for each additional remote you have)

peeja15:10:28

When target is nil, it'll return the value of the :value key. When target is a remote name, it'll return the query you return for that remote.

peeja15:10:09

so you actually do get the remote query when you're parsing recursively, you just have to make sure to call the parser with the target

rastandy15:10:22

@peeja interesting, are there some example of this? I’m not sure I understand the call graph 😞

peeja15:10:23

Also, the :remote key in the map you return from your read expects an AST (or true, to include everything), but the parser returns a query. You'll need to covert that query back to an AST to include it recursively in another read invocation.

peeja15:10:04

I don't have an example to point to, but you can see it happening here: https://github.com/omcljs/om/blob/master/src/main/om/next.cljc#L1267-L1273

peeja15:10:19

gather-sends calls the parser once for each remote

peeja15:10:01

And here (if I'm reading right) is where it calls it without a target: https://github.com/omcljs/om/blob/master/src/main/om/next.cljc#L2560

rastandy15:10:01

uhm thank you @peeja, looks like I have a lot to understand for this weekend

peeja15:10:10

The weird thing is that your read generally returns a map, but the parser is only ever paying attention to one of the keys in that map. Which key it cares about depends on whether it was invoked with a target (and if so, which one).

peeja15:10:44

You can also check the value of target in the env from your read and only calculate the :value or the :remote as appropriate, if you'd like.

peeja15:10:18

For instance, we're doing this:

(defn read [{:keys [target] :as env} key params]
  ;; Dispatch to either read-local or read-remote. Remember that, despite the
  ;; fact that a read function can return both a :value and a :remote entry in a
  ;; single map, the parser is actually only looking for one or the other during
  ;; a given call, and the presence or absence of target tells you which it is.
  (case target
    nil {:value (read-local env key params)}
    :remote {:remote (read-remote env key params)}))

peeja15:10:43

We found it wasn't useful to make read the multimethod; instead we've got a read-local multimethod and a read-remote one.

peeja15:10:02

Almost every key uses the default read-local, which is just db->tree

peeja15:10:15

but lots of keys have special implementations for read-remote

rastandy15:10:34

I’m trying to understand your suggestions, but I think I need to study the source first, because the process is still obscure to me

peeja15:10:22

Yeah, it's one of those things 🙂

peeja15:10:41

Keep slamming your head against the things that don't make sense until it all clicks. That's how I did it. 😛

rastandy15:10:42

@peeja hehe, it’s how I’m doing right now, but my problem is time

rastandy15:10:18

I need to make a working demo very fast or else people will think this is a too complex solution to use

rastandy15:10:39

but I will try hard, I feel like there is nice panorama after the tip of the mountain 😉

peeja16:10:18

If you can get away without calling the parser recursively, it'll probably help. It takes a bit of massaging to do it right. Even if that's ultimately the right thing for your app, it may not be worth the time for a prototype

tony.kay16:10:19

@rastandy Thanks. One of the main reasons we built and open-source it is I realized a number of things were a bit hard to reason about (like the stuff you're discussing right now with remotes). I saw a number of generalizations (e.g. when you want to remote: you end up marking things in state, running a parser to figure out how to do things...which just looks at something you invented in state, and then return the whole remote true/ast. I realized that you could build all of that in, so you didn't have to write all of that. The load story becomes explicit calls instead of these convoluted constructions of parser/state)

tony.kay16:10:29

and you get things like "loading markers", no need for process-roots, etc. The main trade-off is that you move away from a parser and towards explicit post-read data transforms.

tony.kay16:10:44

but I personally understand transforms more easily than parser logic

tony.kay16:10:32

The overall model is mostly preserved (which is awesome, because David designed something really cool here), but most of the pain evaporates.

rastandy16:10:02

I’m starting to convince myself that trying to use Untangled could save me time

rastandy16:10:30

@tony.kay If I can query a REST api without writing any server code, I think I can give it a try

tony.kay16:10:13

@rastandy The whole Om Next model is to avoid REST...can't help you there

therabidbanana16:10:17

We wrap an external REST api with our Untangled server, if that helps, it's a bit of indirection, but lets us be more flexible.

tony.kay16:10:36

well, actually, you could replace the networking component on client. That is supported

tony.kay16:10:47

Then you could do the transform to/from REST in the client

tony.kay16:10:57

now that I think about it. You lose a lot of cool things, but you could do it

tony.kay16:10:32

That's actually an interesting use-case for a plugin 🙂

rastandy16:10:26

hehe that would be nice .D

tony.kay16:10:33

just implement untangled.client.impl.network/UntangledNetwork (two functions, only one of consequence).

tony.kay16:10:48

then pass it as :networking when you make an untangled client

tony.kay16:10:26

you get the EDN, and would transform it to REST, then call the provided ok with a proper Om Next response transformed from the REST response

tony.kay16:10:02

Taking @therabidbanana 's approach is better, because then you get all the coolness of other bits as you add new functionality.

rastandy16:10:55

saving your messages for when they’ll make sense, after reading the Untangled tutorial

rastandy16:10:31

@tony.kay I think that having a good story for REST api’s is nice because it’s easier to convince people writing the frontend that om.next and clojurescript are awesome

rastandy16:10:05

than trying to convince to rewrite big REST services all at same time

tony.kay16:10:06

@rastandy If that's what you're doing, though, you're losing some of the best parts of the Om Next story.

rastandy16:10:41

@tony.kay I know, but I’m trying to find a breach for om.next in my corporation

rastandy16:10:12

If I win with the frontend guys, things will be easier on the backend

petterik16:10:48

@rastandy I hope you convince them! You and your corporation are very welcome to this community

rastandy16:10:04

having a responsive and helpful community like this is a very good start 🙂

tony.kay16:10:14

@rastandy If you'd like some tips on the transforms, I'd be glad to help

rastandy16:10:02

@petterik I hope it too! Frontend development is awesome with clojurescript and om.next!

rastandy16:10:19

@tony.kay thank you very much!

si1418:10:50

I'm sorry if it's already covered somewhere, but I suddenly realized that I don't understand why :foo/by-id is a common idiom in Om land. Why :foo is a namespace here? As far as I understand, we don't usually have :foo/by-id, :foo/by-bar, etc. Why not :by-id/foo?

wilkerlucio22:10:48

does anyone here knows if there is a way to access React private API's from the compiled version? I want to use the ReactMultiChild mixin (used by people on react-canvas), but I can't figure how to access it

alex-glv22:10:48

@si14: also curious about the origins of :stuff/more-stuff when they're not strictly namespaces. My bet it's coming from Datomic