Fork me on GitHub
#fulcro
<
2020-02-08
>
dansudol00:02:10

how is the best way to denormalize a tree of data on state from an ident and a query ? I am doing this

dansudol00:02:24

(prim/db->tree (prim/get-query InvoiceQuery) state-map {:invoice/id "i1"}))

cjmurphy01:02:57

You need the state map to be the last arg.

cjmurphy01:02:39

Here's example code from my code-base.

cjmurphy01:02:24

Although mine is F3 and yours F2 it seems.

codonnell01:02:07

@ Can you provide an example with all of the data explicit where db->tree isn't behaving as you expect?

dansudol01:02:00

It's not that it is not behaving as expected. I just don't know how to work that function. What I am trying to do is simple. I have an ident , let's say [:invoice/id "i1"] and that ident is normalized as usual in the state-map . I just want to do a db->tree to expand that ident and all its children based on a query from component InvoiceQuery

dansudol01:02:32

though let me try that Chris

dansudol01:02:03

wait, yes you got it @ .. that was it .. thanks man.. I owe you one.. That is a really important function for me in many ways. Very nice

cjmurphy01:02:59

Great. I'll give the full function then. There's sometimes :ui/ keys that are not wanted when expanding out to a tree:

(apply dissoc (fdn/db->tree (comp/get-query component) (get-in st ident) st) not-wanted)
Although that only removes them from the top level component. Could be recursive...

dansudol03:02:52

Ok .. good point. I have my own treewalk function that gets rid of the ui related fields .. your idea here is different and interesting .. nice

dansudol00:02:49

which is not quite right. I have looked at that db->tree method a while and can't quite get it

codonnell01:02:35

I am writing a little app with a fulcro frontend that's shipping EQL to a server running pathom, and I'm thinking about how to handle errors in the backend and communicate them to the frontend. I took a look at the fulcro template for inspiration. It looks like fulcro.server.api-middleware/handle-api-request identifies errors by trying to catch exceptions thrown on the parsing context, but the pathom parser is using the p/error-handler-plugin, which catches exceptions and adds a string description of them to the parser result. It seems like this is not configured correctly unless I'm missing something. I'm curious how folks with a similar setup have decided to handle this. Anyone willing to share? My current inclination is to throw an exception with an info-map from the parser, catch it in my middleware, and pass that info-map along to the client in the reponse body with an http error status. I'm not sure how this would interact with mutation joins in the client, though. I'd love any feedback on this approach or ideas on what a better solution looks like. Thanks!

codonnell01:02:35

I am writing a little app with a fulcro frontend that's shipping EQL to a server running pathom, and I'm thinking about how to handle errors in the backend and communicate them to the frontend. I took a look at the fulcro template for inspiration. It looks like fulcro.server.api-middleware/handle-api-request identifies errors by trying to catch exceptions thrown on the parsing context, but the pathom parser is using the p/error-handler-plugin, which catches exceptions and adds a string description of them to the parser result. It seems like this is not configured correctly unless I'm missing something. I'm curious how folks with a similar setup have decided to handle this. Anyone willing to share? My current inclination is to throw an exception with an info-map from the parser, catch it in my middleware, and pass that info-map along to the client in the reponse body with an http error status. I'm not sure how this would interact with mutation joins in the client, though. I'd love any feedback on this approach or ideas on what a better solution looks like. Thanks!

currentoor01:02:08

so status code is the default

currentoor01:02:57

in addition to that we also have this function under the :remote-error? in the call to app/fulcro-app

currentoor01:02:00

(defn error? [{:keys [body] :as result}]
  (when (map? body)
    (let [value (or
                  (app/default-remote-error? result)
                  (contains? (second-level-keys body) :ucv/mutation-errors))]
      (when value (log/warn "API error" body))
      value)))

currentoor01:02:56

that way we can put a meaningful error purposefully under :ucv/mutation-errors rather than throwing exceptions

currentoor01:02:19

and by default we catch all exceptions and put the message under that key anyway

currentoor01:02:38

this will trigger error-action parts of the mutation

codonnell01:02:39

Yes, I'm aware of how to control dispatch between ok-action and error-action in the client. I guess that answers my question about mutation joins; I imagine the results wouldn't be merged in the event of an error response.

codonnell01:02:44

If you're using pathom in the backend, what are you doing to capture errors in your mutations and get them into the response body under the :ucv/mutation-errors key? That's the piece that I'm missing right now.

codonnell01:02:02

Thank you for your help, by the way.

currentoor19:02:27

we have macros that wrap defresolver and defmutation

currentoor19:02:40

they do authorization permissions and try/catch

currentoor19:02:20

and happy to help! simple_smile

currentoor20:02:13

also some of our mutations manually put a value under :ucv/mutation-errors

currentoor20:02:23

let me know if anything doesn’t make sense

currentoor19:02:10

@ here are our macros

codonnell17:02:25

Thank you @!

thosmos20:02:17

I keep getting these kinds of errors when attempting to build a form for a fairly complex map with nested maps: ERROR [com.fulcrologic.fulcro.algorithms.form-state:518] - FORM NOT NORMALIZED: [:org.riverdb.db.sitevisit/gid "17592186255331"] is it allowable to have child maps that aren’t part of the form state directly?

holyjak21:02:19

Question: Given a Root with initial-state for a list of Person components, why I end up not with :person/id {0 ..., 1 ...} + :people [[:person/id 0] [:person/id 1]] in the DB but just with :people [{:person/name ...}] , i.e. why isn't the initial state normalized? Code here - https://gist.github.com/holyjak/c0f2cbf515b2e10191aee516e2553922 (I have a very similar example from the Book with PersonList and there the data is normalized?!)

holyjak21:02:19

Question: Given a Root with initial-state for a list of Person components, why I end up not with :person/id {0 ..., 1 ...} + :people [[:person/id 0] [:person/id 1]] in the DB but just with :people [{:person/name ...}] , i.e. why isn't the initial state normalized? Code here - https://gist.github.com/holyjak/c0f2cbf515b2e10191aee516e2553922 (I have a very similar example from the Book with PersonList and there the data is normalized?!)

thosmos21:02:36

you’re mixing the lambda and template forms of the :initial-state in Root. I think it should be in a lambda if you’re calling get-initial-state, or if you want to keep it as a simple map, there’s a different way to write the Person maps. Also your query in Root is missing the {:people (comp/get-query Person)} join which is required for auto-normalization.

thosmos21:02:21

try this:

(defsc Root [this {people :people}]
  {:query         [{:people (comp/get-query Person)}]
   :initial-state {:people [{:id 0 :name "Sally" :city "Nowhere" :state "GA"}
                            {:id 1 :name "Tom" :city "There" :state "OH"}]}})

holyjak21:02:45

OMG, thanks a lot!

holyjak09:02:21

Hi @, thanks a lot for your help! I have "fixed" the code but I still don't see the data being normalized: https://gist.github.com/holyjak/eeb4341f85e824c040ee2b3a7af44705 Could you be so very kind and tell me what am I still doing wrong? (BTW When I switched from the lambda to a template - see L15 - then it did not work, the Person's initial-state was not invoked and I ended up with the data as-is in the Root, i.e. :id instead of :person/idetc. Is my connection between Root and Person still broken somehow?! 🙏

thosmos10:02:52

The query is malformed:

:query         [:people [(comp/get-query Person)]]
try:
:query         [{:people (comp/get-query Person)}]
the curly brackets define a join. The query could either be [:some :keys] (which would not be normalized because there’s no ident) or can be a get-query reference which will be normalized In other words, the above query is the same as
:query [{:people [:ui/modified? :person/id :person/name :address/city :address/state]}]
except that because it calls (get-query Person) it has the ident (:person/id) and metadata it needs to normalize

thosmos10:02:55

to have the map form of initial-state work, you might need to use the namespaced keys of the joined entity like:

:initial-state {:people [{:person/id 0 :person/name "Sally" :person/city "Nowhere" :person/state "GA"}
                            {:person/id 1 :person/name "Tom" :person/city "There" :person/state "OH"}]}
I haven’t tested that, but it seems to match the docs

holyjak11:02:48

Oh, thank you so much! I am really good at finding ways of doing it wrong 🙂 Finally it works. The template initial state now actually works. I find the docs for http://book.fulcrologic.com/#_template_mode confusing (@) because they use namespaced keywords: :initial-state {:person/job {:job/name "Welder"}} which means you cannot use the template for for the child's (Job) init state as templates only work with simple keywords so that :param/name etc can work.

tony.kay21:02:01

I just announced RAD on #announcements if anyone wants to read more.

tony.kay21:02:18

For existing Fulcro users: RAD does not require you to change almost anything about an existing app in order to use it (assuming you’re using Pathom on the back-end, or are willing to make your back-end respond correctly). Forms are stand-alone Fulcro components with their own route, state machine, etc….you just route to them and they do the rest, assuming your server can respond to their query for data, and their save (which is just a fs/dirty-fields delta)

tony.kay21:02:34

reports will be the same

tony.kay21:02:42

just saves you from writing lots of boilerplate

thosmos23:02:22

cool, I just got a simple RAD table and form working in my app!