Hello everyone! Is it a good idea to have a resolver that outputs an EQL and then another resolver that takes this EQL as input and runs pathom process on it? The idea of running a pathom process while inside of pathom process gave me pause. So I wanted to check if it's might be something absolutely bad. Example: Resolver1 returns:
:app/title "Potato"
:app/query <some-eql-here>
Resolver 2 is resolving:
app/query -> app/dataA pattern I've used for somewhat dynamic queries like this is to use joins as conditional branches. e.g. I have these two resolvers which return if the user is signed in or not, respectively:
(defresolver session-user [{:keys [session]} _]
#::pco{:output [{:session/user [:xt/id]}]}
(when (:uid session)
{:session/user {:xt/id (:uid session)}}))
(defresolver session-anon [{:keys [session]} _]
#::pco{:output [{:session/anon []}]}
(when-not (:uid session)
{:session/anon {}}))
Then I can run a query like this:
[{(? :session/user)
[:user/foo
...]}
{(? :session/anon)
[:user/bar
...]}]
And only one branch of the query will execute.
idk if that's dynamic enough to handle your use case. if not, and you can't find some other way to put it all in one query, I imagine it's not the end of the world to have a nested process call? We have a bunch of them at work 🙈. The main disadvantage I've observed is that writing unit tests for them is really annoying. Whereas if your resolvers take all their input via ::pco/input, then they're just regular pure functions which are easy to test. I also imagine that nested process calls limit the degree to which the query planner can optimize things.Thanks for sharing. Pretty cool pattern 👍 Yeah, my case is more dynamic, because the first resolver needs to fetch some data first and then generate the EQL based on that data. I can do this outside pathom of course and then only call the processing with the result EQL, but I kinda want to do everything in pathom cause then the data fetched by this EQL fits nicely into the resulting graph. I'll try to run it with nested process and see how it goes. The fact that you guys have it in production gives me some peace of mind 😄
That's cool. I wrote a few resolvers that want to run more resolvers. I dissoc'd a bunch of keys off the env and used that as the env in the sub-query.
I do use some dynamic EQL in my project duck-repled. I tried to do it all in a single pass, by doing something similar as @foo, but unfortunately it got too complicated and quite slow too, so I decided to just add my "query" function to the Pathom's env, and then query it again.
Basically, I included a key :q here: https://gitlab.com/clj-editors/duck-repled/-/blob/master/src/duck_repled/core.cljc#L75
And then I'm using it here: https://gitlab.com/clj-editors/duck-repled/-/blob/master/src/duck_repled/definition_resolvers.cljc#L180-181
oh, interesting approach 🤔 didn't think of just adding a function to the env
Reporting back:
Nested processing works nicely. The only caveat, I needed to have a fresh env, cause using the already mutated env caused weird issues I couldn't make sense of.
Workaround: I've wrote a small plugin that add the initial env to the environment, so that if a resolver with nested processing needs it it's easy to get.
(pathom-plugin/defplugin add-fresh-env
{::pcr/wrap-root-run-graph!
(fn [root-run-graph]
(fn [env ast-or-graph entity-tree]
(let [env+fresh-env (assoc env :fresh-env env)]
(root-run-graph env+fresh-env ast-or-graph entity-tree))))})