Fork me on GitHub
#fulcro
<
2020-05-07
>
Matthew00:05:03

If I send the same mutation locally and to a remote, and something happens that means the remote doesn’t execute properly, will this result in inconsistency between the local dB and the remote? Does fulcro have a graceful way of dealing with this?

tony.kay01:05:27

Of course it will result in an inconsistency. Fulcro is not magic 🙂 The problems of distributed systems still apply, and the solutions are those of normal CS: things like idempotent mutations, looking for errors and retrying, etc. The optimism of Fulcro lets you give a fast user experience in the (common) case that your network is solid…but you still have to write unhappy path code that deals with problems when they happen. See error-action, result-action, global-error-handler, etc.

Matthew01:05:43

Haha, thanks. I don’t expect PFM. I was just wondering if it had defaults for down networks or something. However, sometimes when I’m dealing with a new macro I feel like magic is guaranteed!

tony.kay04:05:20

no, the primary mechanisms Fulcro is concerned with are getting data in and out with normalization. The websocket support has a bit more (really part of Sente, which has a status you can subscribe to). The http remote is nothing more than a wrapper around XhrIO with support for middleware.

Matthew04:05:34

In defmutation I’m just playing around with stuff and trying to send a specific mutation to the server. The remote inside defmutation looks like (remote [env] ‘(app.server/some-mutation). This naive attempt isn’t working. I can send this mutation in the query tools of fulcro inspect no problem however. What is the correct way to send a mutation to the remote that’s not just an exact duplicate of the client side mutation - IE (remote [env] true)? Answer: Good to know for anyone who may stumble upon this. Remote mutations need the query’s AST, that’s all there is to it. It’s pretty central to the way everything works. The above just needs to be changed to (remote [env] (eql/query->ast ‘[(a.server/some-mutation)]). Where eql is edn-query-language.core.

tony.kay05:05:03

see mutations/with-server-side-mutation I think it’s called

tony.kay05:05:57

and with-params….they can be threaded together…or you can directly modify the AST in env and return the updated env, which is all those fns do

murtaza5209:05:05

I had a modeling question, on which option below is a better fit for fulcro /pathom/rad. Lets assume a shop entity and sales entity. First Model :- the first way of modeling is where a shop contains a vector referencing sales -

{:shop/name "abc" :shop/sales [1, 2 , 3]}

{:sales/id 1}
{:sales/id 2}
{:sales/id 3}
I would be frequently performing CRUD on sales, which means every time I create sale I have to perform two operations on the server side - create a new sale, and associate that sale id with the shop. Second Model:- Another model is where the sales contains a reference to the shop -
{:shop/name "abc" :shop/id 1}

{:sales/id 1 :sales/shop 1}
{:sales/id 2 :sales/shop 1}
{:sales/id 3 :sales/shop 1}
The advantage of this model is that I dont need to update the shop whenever I add a new sales. However I am not sure how well this plays with fulcro. Any suggestions on which is a better model with respect to fulcro and pathom.

Jakub Holý (HolyJak)10:05:04

And I guess in the UI you want to show all sales for a shop? I would go with the latter and make a Pathom resolver that adds the mapping, ie, in pseudocode:

(pc/defresolver [..]
{::pc/inputs: #{:shop/id}
 ::pc/outputs [{:shop/sales [:sales/id]}]}
{:shop/sales (all-sales-for-shop db shop-id)})
where all-sales-for-shop effectively does (get (->> sales (group-by :sales/shop)) <shop id>)

murtaza5212:05:36

@holyjak in the outputs, is there a significance of having :shops/sales as the join key instead of just :sales -

{::pc/inputs: #{:shop/id}
 ::pc/outputs [{:sales [:sales/id]}]}

tony.kay14:05:05

I would recommend namspacing everything…you don’t want unexpected aliasing to bite you later.

Jakub Holý (HolyJak)16:05:25

@tony.kay I have a strange problem with one particular report (ChargeList), where it fetches its data (I can see them in the DB) but does not render them, staying empty. When I get to it by clicking around in the app, it works, but when I hard-reload the page when displaying this report, it sometimes shows the rows, sometimes not. What could be causing it? How can I troubleshoot it? In the DB at :com.fulcrologic.rad.report/id .../ChargeList :ui/current-rows I see the data. "Force app re-render" in the fulcro inspect has no effect (no change in UI, no log in the Console). In the Console logs I see > Updating value for [:com.fulcrologic.rad.report/id .../ChargeList] alias :current-rows ... > ... > DEBUG [com.fulcrologic.fulcro.ui-state-machines:?] - Activating state :state/gathering-parameters on [:com.fulcrologic.rad.report/id .../ChargeList] > ... > DEBUG [com.fulcrologic.fulcro.algorithms.tx-processing:?] - Scheduling a render A difference I see that in the empty case there is logged Indexing component [:com.fulcrologic.rad.report/id .../ChargeList] but none of these, logged when it is not empty: Indexing component [:charge/synt-id "681109:4798765432:0"] (where the charge list is obviously expected to display the charges)

tony.kay16:05:01

@holyjak you mean when using HTML5 routing to put you on the page to start? Sounds like some kind of sequence problem in the startup logic. I assume the report works if you run it via changes to the report parameters or a report/reload! once it’s on screen

4
Jakub Holý (HolyJak)17:05:45

Yes, just as you said. What can I do to pinpoint the cause? I don't know where to look. The data is in the DB and there is a render scheduled after it was loaded. Does Fulcro fail to see that the data is for the component in question and that it should re-render it?

tony.kay18:05:00

The report runs as the result of a state machine event, which is triggered from the router’s will-enter (I think). You could add debug statmements throughout the code and watch what happens.

Jakub Holý (HolyJak)20:05:00

Yes, but what should I look for? It seems from the log there is a render after the data is loaded => how can I make sure that the scheduled render happened and how can I see which components were rendered and what data/why was sent to them? My hypothesis is that either the render happens before the data arrives (unlikely) or that somehow Fulcro doesn't realize that the report needs re-rendering.

Jakub Holý (HolyJak)07:05:12

FYI I have switched to keyframe-render2 and the problem went away. I would still be happy to fix it so that it works with the multi-root renderer but I would need some help to know where to look / what for.

tony.kay20:05:04

hm. I would not expect that, since MRR is just KR2 with multi-root support. I’m not convinced that this really fixed anything…could have just changed the timing.

tony.kay20:05:19

and with MRR, RAD will not work properly, as it uses it for some features

tony.kay16:05:17

ignore indexing…those happen when components mount

janezj20:05:00

janezj  [10:21 PM] I have a global resolver: [:mytime] returns {:mytime "21:55"} I would like to use it in many places, can't even load it into component. it can be loaded into X, but then don't know how to bring X to components. I admit that I don't know how query works, it is always targeting just ident table in state-atom, or can fetch something outside state-atom?

(defsc EditTime [this {:keys [:mytime] :as props}]
  {:query         [:mytime]
   :ident         (fn [] [:component/id ::edit-time])
   :initial-state {:mytime "na"}}
  (div mytime))

(comment
(df/load! SPA :mytime nil {:target [:X]}) ; OK, loads time into X
(df/load! SPA :mytime root/EditTime)      ; nothing
(df/load! SPA :mytime nil {:target [:mytime]}) ;nothing
)

Jakub Holý (HolyJak)21:05:45

Is EditTime the root of your app? Is it set on the app and mounted correctly? I believe that's important.

janezj21:05:28

i started with mentioned chapter, it is ordinary component initialized form the root

janezj21:05:01

my example is simplified, reduced to the problem.

janezj21:05:20

this is actual resolver, in the first exampe i just truncated query response

(pc/defresolver server-time [env _]
  {::pc/output [:mytime]}
  {:mytime (java.util.Date.)})

Jakub Holý (HolyJak)09:05:19

how does the full frontend code look like? Perhaps make a gist?

janezj09:05:19

I will try to doit, i have to remove some code, which is confidential, nothing special, just a bunch of phone numbers and urls hard coded in several files.