# om

This page is not created by, affiliated with, or supported by Slack Technologies, Inc.

tobiash 18:46:29

i finally figured out what my problem with process-roots was: it only seems to work on join queries, not even on a flat [:prop] query. is there a reason for that or is it just missing functionality?

jfntn 19:05:45

I'm integrating compassus in our app, my approach was to use an App wrapper component, with a query for global state, and read methods for our routes that'd just recurse with the parser like:

(defmethod client-read :route/home [{:keys [parser query] :as env} _ _] {:value (parser env query)})

I was hoping this would let us have compassus' routing sit on top of our current component/parsing structure, but the above doesn't work.

While the queries on App work as expected, our Home component -- which has a link query like [{[:current-user '_] [:db/id :foo]}] -- is now parsed into these props {[:current-user '_] {:db/id 123 :foo "bar"}}, when it used to be {:current-user {:db/id 123 :foo "bar"}}

anmonteiro 19:30:03

@jfntn you’ll only get [:current-user _] in props if you don’t use db->tree

anmonteiro 19:30:13

links are supposed to be used with normalization

jfntn 19:48:53

I’m using it, :current-user falls back to our :default reader which is:
(defmethod client-read :default [{:keys [state query] :as env} k _] (let [st @state] {:value (om/db->tree query (get st k) st)}))

anmonteiro 19:58:58

@jfntn can you put a minimal repro together then? could be a compassus bug

anmonteiro 19:59:10

should be easy to create one

arohner 20:40:25

I’d really appreciate more docs on remotes and :send. What is a remote mutate allowed to return? Just {:value {:keys []}} ? I assume it ignores :action?

arohner 20:40:49

Is there a way to send back “error” data with a remote mutate, e..g “you aren’t allowed to do that”?

arohner 20:50:27

I could list an extra key to be read, but then I’d need to store it on the server until the next time the user reads, which seems annoying and anti-scalable

anmonteiro 20:53:55

@arohner IIRC there’s a :result key that’s returned in the mutation response

anmonteiro 20:54:52

anyway, a remote mutation’s response is a map, you can add whatever you’d like to it

anmonteiro 20:55:39

it’ll get thrown away when merging back to the local app state, but you can change that behavior

arohner 20:56:07

the docs hint at :result, but don’t actually specify it

arohner 20:58:14

@anmonteiro by replacing :merge in the reconciler?

anmonteiro 20:59:24

@arohner also note that you don’t necessarilly need to reimplement merge when overriding it, what I commonly do is call and do my custom stuff

anmonteiro 20:59:36

the default-* functions are public vars for a reason

jfntn 22:49:59

@anmonteiro wrote this gist to illustrate the problem:

arohner 22:57:48

@anmonteiro not sure if this is a good idea, but I made my merge recognize transacts in :keys, and just call om/transact on everything returned

arohner 23:01:16

so now on the server, I just return {:value {:keys [(foo/error :text “an error”)]}} from a mutation

anmonteiro 23:04:06

@arohner right. one thing I forgot to mention is that whatever you return from the :action thunk will be assoced to the returning response under :result

anmonteiro 23:04:30

maybe I should have started there, apologies :slightly_smiling_face:

arohner 23:04:32

but :result is ignored?

arohner 23:04:46

and this is in remote sends, so I don’t think I could use :action anyways, right?

anmonteiro 23:05:16

wait, I mean the mutation that’s executed on the server

anmonteiro 23:05:37

I suppose that’s what we’re talking about

arohner 23:05:57

I still don’t see what :result is connected to

arohner 23:06:43

my original goal was, given the client does a transaction that goes to the server, change client state in a different key, to signal errors, etc

anmonteiro 23:06:48

^ here’s a server mutation example for a talk I gave at a meetup

anmonteiro 23:07:48

so if the server knows it’s an error, return that from the :action thunk, say {:error :nuke/wrong-code}

anmonteiro 23:08:12

and the server will return that to the client

anmonteiro 23:08:46

so your merge will receive something like {‘launch/missiles {:result {:error ::nuke/wrong-code}}}

arohner 23:09:18

right, and then does vanilla om do anything with that :result?

anmonteiro 23:09:25

nop it just throws it away

anmonteiro 23:09:30

which is why you need to override :merge

arohner 23:09:40

right, ok we’re on the same page so far

arohner 23:10:09

so then I modified my merge to walk {:value {:keys []}, and om/transact on the client anything that looks like a transaction

anmonteiro 23:11:03

right, but remember that those transactions could in theory send to the server again an enter a loop

anmonteiro 23:11:07

it’s up to you to prevent that ofc

arohner 23:11:09

yep. don’t do that :slightly_smiling_face:

anmonteiro 23:11:47

@arohner so what you could do is just swap! to the state directly, or only support a predefined set of mutations that are guaranteed to run locally

anmonteiro 23:12:50

@jfntn thanks, I’ll have a look soon!

arohner 23:12:54

I’m not too worried about loops

jfntn 23:13:16

@anmonteiro thank you, added a bit of context in the ns docstring!