Fork me on GitHub
#fulcro
<
2018-09-18
>
thheller07:09:53

how would I run a remote query using fulcro that is not tied to any components? meaning to fetch data used by background actions that'll eventually get turned into UI data but only after some processing?

thheller07:09:13

do I just skip fulcro and xhr it myself?

claudiu07:09:09

@thheller is it on the fulcro backend ?

claudiu07:09:17

Think df/load also works with nil as component. Or if you want to specify a query you can just create a component defs with only query that you just use for the load

thheller07:09:24

I'll just xhr it I think. easier to process directly.

thheller07:09:55

I can't specify a component since its code split and not available at that time

thheller08:09:22

don't want to add an empty component for that

claudiu08:09:29

So (df/load :server-key nil {:post-mutation etc..) works. If you juat want all the data and no component.

thheller08:09:13

but I want not just a key I want a full query

thheller08:09:12

basically right now I have a few df/load calls that I want to combine

thheller08:09:36

but maybe I'll scrap that entire approach. I guess I still haven't quite figured out how to integrate remote data into my app

thheller08:09:52

given that something is streaming in via websocket and something is loaded on demand

thheller08:09:16

its working alright just doesn't feel very natural yet

thheller08:09:24

@wilkerlucio I tried using the Query (OgE) in fulcro-inspect but I can't type a p 😛

wilkerlucio11:09:24

how so, can you please check the logs for the inspector and see if it's showing any errors?

thheller11:09:31

no errors no. just nothing happens when typing p

wilkerlucio11:09:26

I mean if you right click on the inspector page and ask to Inspect it (to show devtools from the devtools :P), nothing there?

thheller11:09:05

yes nothing there

thheller11:09:33

panel initialized .. Object is the only message from your extension

wilkerlucio11:09:13

the p is the only one that fails to type?

thheller11:09:13

just tested. t also doesn't work

wilkerlucio11:09:02

odd, can you check which version you are in, I released an update yesterday, I can't reproduce the issue, but I'm interested in figuring it out, not cool to have this broken

thheller11:09:39

2.2.2 for fulcro-inspect. 1.0.3 for the chrome ext

wilkerlucio11:09:00

1.0.4 is the new one, can you try upgrade the extension and see if the issue persists?

thheller11:09:37

now it complains about a missing deps.js and I still can't type tp

thheller11:09:51

2.2.3 + 1.0.4

wilkerlucio12:09:11

wtf... the rest of inspect works or deps.js broke everything?

wilkerlucio12:09:51

you use Windows right? I wonder if has something to do with the OS

wilkerlucio12:09:40

just released 1.0.5 using the externs fix, I just noticed when I changed the language in/out the output got much bigger, I set that back and add the externs and seems fine, but I guess you would return to the same issue as before, but without the deps.js complain

wilkerlucio12:09:38

if you on we can make some tests around it, the issue is probably related to parinfer, do you use some extension like Vimium that hooks on all keyboard?

thheller12:09:36

no other extensions no. I'm on Windows10 yes

wilkerlucio13:09:03

just ot confirm, same thing on 1.0.5, right?

claudiu08:09:53

Also to take into consideration that multiple loads get batched together in the same request

thheller08:09:11

yeah its probably good enough. I guess the issue is the websocket and its streaming nature

thheller08:09:28

its for the shadow-cljs UI which streams everything that is happening on the server to the UI

thheller08:09:15

although the UI may only display parts of it

thheller08:09:26

can't decide if I should just do everything over the websocket instead of trying to combine it with the normal remote

claudiu08:09:01

Sounds like a fun :)

claudiu08:09:27

You also have the option of adding a custom remote (like the restffull api example in the book) for more funky stuff over the network.

wilkerlucio11:09:19

@thheller about the load, the reason you need a component is to proper merge the data from the server, can be a bit annoying at first but makes merge easy when you have one, and you can create a simple component with just query and ident to merge the load you need

thheller11:09:13

yeah I think I was just fighting the issue due to not having the component class available

thheller11:09:32

I now delayed the load until later when loading the actual code-split module

thheller11:09:14

that solved that and the data from the websocket is just merged into the proper location

wilkerlucio11:09:32

there is a "hack" you can do to reuse so component that have a correct ident and update the query entirely, could do something like: (df/load this [:some/ident "value"] ComponentWithProperIdent {:update-query (fn [q] [:replaced :query :here])})

wilkerlucio11:09:51

still, pretty dirty, better have a new one 😛

maxt12:09:43

When I use load-field with params, I don't receive those params as params argument in defquery-entity. Rather, they seem to be included in the query. Is that by design? What am I missing here? With this definition in the server:

(defquery-entity :person/by-id
  (value [{:keys [query]} id params]
         (timbre/info :query query)
         (timbre/info :id id)
         (timbre/info :params params)
         {:db/id          1
          :person/name    "Jane"
          :person/numbers (vec (repeatedly 10 #(rand-int 100)))}))
Without params, #(df/load-field this :person/numbers)
:query [:person/numbers]
:id 1
:params nil
With params, #(df/load-field this :person/numbers {:params {:amount 4}})
:query [(:person/numbers {:amount 4})]
:id 1
:params nil

wilkerlucio12:09:28

@maxt not sure if was a design decision or accident, but yeah, that's how it works, what you can use to go around is use load with update-query, something like this: (df/load this (prim/get-ident this) (prim/react-type this) {:update-query (fn [q] '[(:person/numbers {:amount 4})])})

maxt12:09:28

@wilkerlucio Thank you for replying. Then I know I should try to work around it. Do you happen to know why load-field works that way? I.e. when is that behaviour useful?

wilkerlucio12:09:41

not sure, it may vary according to each case, I can think you wanting to set the param on the join, you could on the parser send it down, but really that is no right or wrong, just some cases will be more convenient on the join, others on the attr

maxt12:09:44

In this example, what I'm trying to achieve is to load a variable number of random numbers. With your suggestion, I was able to get the following to do that

#(df/load this (prim/get-ident this) (prim/react-type this)
                                  {:update-query (fn [q] '[:person/numbers])
                                   :params {:amount 4}})
I was kind of expecting load-field to do just that, but ok. I don't understand the difference between params on the join vs attr though

wilkerlucio12:09:52

this will just affect where they will be on the server, I guess there is no formal thing and its a feature not many people use, it probably can be better at pointing the right place, I had this though process sometimes already wanting the param to be in a place but it going somewhere else

maxt13:09:55

I tried to read the code and understand what puts it in the query, but I gave up.

maxt13:09:57

Seem I can use :focus to get a smaller work-around.

maxt13:09:04

Another thing: I'd like to transfer #inst between the client and the server. I guess that's something I need to tell transit how to do. Can I do that through fulcro somehow?

wilkerlucio13:09:42

@maxt insts are native to transit, so you don't need anything extra for it

maxt13:09:36

Hm. It complains here when I try, I'll try again.

maxt13:09:16

In a minimal testcase, it does indeed work, so my problem must be elsewhere, thanks!

maxt13:09:55

Ah, I had accidentally converted it to a cljs-time object.

tony.kay14:09:24

@maxt that actually sounds like a bug to me. I'll look at load-field.

tony.kay15:09:42

oh wait, no, that is how it is supposed to work.

tony.kay15:09:02

The queries that trigger an entity load look like this: [{[:table id] [:x :y]}]

tony.kay15:09:22

and that is what load-field generates...but you could issue a load-field for :x, and then one for :y, or you could issue a load for a manual ident join via load as (load [:table id] Component {:params ...}). The latter will put the params on the join, whereas the former will put them on the field. If you were manually parsing (or using pathom) then that is what actually makes the most sense.

tony.kay15:09:39

for example, if you were loading comments and wanted to send a pagination parameter, you'd want the parameter to appear on comments (say, from inside a Blog entry): (load-field this :comments {:params {:page 1}})

tony.kay15:09:52

so that when your parser reached the :comments field it would see the parameter.

tony.kay15:09:45

I guess it might make sense to have a third "hook" for top-level parsing called defquery-field that could handle it as you expect...

tony.kay15:09:38

defquery-entity is looking for params on the load of an ident case.

tony.kay15:09:49

because that is what it is a shortcut handler for

maxt20:09:18

@tony.kay Thank you for expanding on why I see the behavior I see. I don't quite get the params on field vs join part. Do the params get embedded in the query somehow? I'd expect #(df/load-field this :person/numbers {:params {:amount 4}}) to turn into a query like [{[:person/by-id 1] [:person/numbers]}]. Are the params also put in there somehow?

tony.kay20:09:02

so, params are part of the query element (prop, join, mutation)

tony.kay20:09:19

so [(:k {:param 1})] is a parameter on a prop

tony.kay20:09:49

[({:join [:subquery]} {;param 1})] is a parameter on a join

tony.kay20:09:54

and mutation is obvious

tony.kay20:09:04

in your case, :join is an ident

tony.kay20:09:54

load is meant to load a entire entity(ies), so the parameters go on the ident-based join if you use an ident, but they always go on the join

maxt20:09:00

ok, a list bundles together an element and parameter?

tony.kay20:09:03

load-field is mean to load a field, so the params go on the field

tony.kay20:09:19

if the list starts with a sym, then it;s a mutation

tony.kay20:09:26

if keyword, then prop

tony.kay20:09:29

if map, then join

maxt20:09:31

But you don't talk about list in queries in the book, because it's normally not something that's exposed?

tony.kay20:09:49

AH, that’s an oversight 🙂 Are you sure?

maxt20:09:18

Well, I've read it many times but maybe I wasn't just prepared for it 🙂

jaihindhreddy-duplicate20:09:24

@tony.kay Does fulcro minimize the number of queries to an SQL database when parsing queries (like join-monster or walkable)?

tony.kay20:09:50

@jaihindh.reddy Fulcro doesn’t say anything about how you get your data from SQL

tony.kay20:09:04

that’s why libs like walkable exist 🙂

tony.kay20:09:27

@maxt It is true that the book doesn’t tell you what query the various loads generate

tony.kay20:09:47

so, that could be improved upon

tony.kay20:09:22

@jaihindh.reddy Fulcro stops at the network layer…it tries to minimize the number of HTTP requests when you schedule multiple loads/mutations all at once

👍 4
maxt20:09:19

@maxt I'm sorry, it's there for sure, I just didn't think I was parsing queries, but obviously, the info was in that chapter. Then I do understand what happens, thanks!

tony.kay20:09:12

@maxt welcome. The defquery* macros are just there as a quick placeholder for not having to write a top-level parser for beginning apps. You almost certainly want to use something like pathom connect on the back-end to actually parse/satisfy the graph queries.

👍 4
tony.kay20:09:52

The server-parser is just a parser pre-hooked to the endpoints that those macros emit.

tony.kay20:09:02

you can easily make your own and use it instead

maxt20:09:09

@tony.kay I'm using datomic as a backend, would I still use pathom for parsing out things like params?

tony.kay20:09:43

So, even though Datomic shares pull syntax with Fulcro, in practice you’re going to have schema mis-matches all over the place from what you actually want in your UI.

tony.kay20:09:55

and Datomic knows nothing about your parameters syntactically in pull

maxt20:09:55

Ok, thanks. Then I should def study chapter 12 closer.

tony.kay20:09:19

I’ve been helping Wilker with his pathom docs…you might want to look at this branch/guide:

tony.kay20:09:54

It’s so much easier than dealing with Ch 12 🙂

tony.kay20:09:36

at about 23 mins in

tony.kay20:09:32

The Query tab of Fulcro Inspect can also use the indexes from connect to give you auto-complete…so you can play with your server from the inspect tool with query autocomplete…it’s really cool

maxt20:09:35

I was under the faulty assumtion that pathom was only for SQL or rest, so I haven't looked at it at all.

tony.kay20:09:52

Oh no…it is the server tool you almost always want

tony.kay20:09:09

I need to update the book to stress that

tony.kay20:09:21

I’ll do a bit of that right now…I keep forgetting

maxt20:09:12

Oh, I also hadn't seen the tabs in fulcro inspect!

maxt20:09:33

In the older version I think there was only the DB tab.

wilkerlucio20:09:13

@maxt are you using the extension or the in-browser? tabs have been there for quite a while 🙂

maxt20:09:42

@wilkerlucio I just recently switched to the extension. Apparently I didn't check it out enough.

tony.kay20:09:50

book updated

metal 4
👍 4
tony.kay20:09:47

Yeah, Wilker’s been working like a mad man on pathom and inspect…great stuff

maxt21:09:40

I read the patch and I think the updated book does make it clear that pathom would be useful even with datomic. 👍

wilkerlucio21:09:22

yeah, after a while you realize that datomic per see will not have all the information you need (you might need pull parts from external services/databases or even simple computed information), and patching on that by hand can be a lot of work, pathom tries to provide some abstractions so you can avoid most of the hard parts

currentoor22:09:26

I was reading about (fulcro.client/clear-pending-remote-requests! my-app) in the book

currentoor22:09:48

where exactly am I supposed to call that from? the fallback handler?

currentoor22:09:07

I don’t see the app in the mutation env

currentoor23:09:06

so I’ve got this situation and I’m not sure what the best strategy is

(prim/ptransact! this `[;; First update the vehicle
                        (a.mutations/update-vehicle {...})
                        ;; Then post payment, if unsuccessful handle failure
                        (a.m.mutations/post-payment {...})
                        (fulcro.client.data-fetch/fallback
                         {:action a.m.mutations/handle-failed-payment})

                        ;; These should only happen if post-payment didn't fail
                        (a.m.mutations/handle-successful-payment)
                        (a.mutations/add-to-queue {...})
                        (u.p.state-machine/set {...})
                        (r/route-to {...})])

currentoor23:09:10

i’ve got it working as desired, except i want the last block to only execute if there were no errors, i thought the fallback would have flushed the remaining mutations but they seem to still be executing

currentoor23:09:06

i suppose i could check app state to see if they payment was successful, in each of the mutations in the last block, but seems like there should be a way to flush mutation queue on error

tony.kay23:09:10

@currentoor Any API that requires the top-level app is one you’ll have to use by saving the app to a global atom on startup

tony.kay23:09:41

I can’t self reference something you create 🙂

tony.kay23:09:08

well, I guess I could, but it would be a global that I create, which would not work since you can put multiple apps on a page/VM

currentoor23:09:50

and does fulcro.client/clear-pending-remote-requests! also clear local mutations?

tony.kay23:09:54

If you need decision logic, you have to code that inside of a mutation