pathom

Eric Dvorsak 2024-11-14T20:49:08.026619Z

In the plugin:

(defn sample-resolver-error-wrapper [resolver-error]
  (fn [env ast error]
    (let [e (resolver-error env ast error)]
      ; you may modify the error here
      e)))
what does resolver-error do as oppose to using error directly?

wilkerlucio 2024-11-14T22:22:01.858819Z

does the error markings on state, and fail-fast (on strict mode): https://github.com/wilkerlucio/pathom3/blob/4093b90f2afef9bb22123a1748e6442d5be2cdb4/src/main/com/wsscode/pathom3/connect/runner.cljc#L327-L337

JAtkins 2024-11-14T06:25:01.742119Z

Should it be possible to have a resolver that depends on graphql inputs? I seem to be seeing an error in the gql planner for something like this:

(resolver :input [:gql/a :gql/b] :output [:something])

[:gql/a
 :gql/b
 :something]
The planner seems to put the resolving of all of these at the same level, instead of marking :something as a dep of :gql/a and :gql/b , and thus isn't able to resolve :something

wilkerlucio 2024-11-23T21:54:16.317599Z

yeah, depending on how you organize the query Pathom may need to split it in pieces (getting your slow case), it should be able to forward in one go when that matches a possible GraphQL query on the other end. please let me know if you see it behaving wrongly

👍 1
JAtkins 2024-11-22T21:10:50.358139Z

For the future curious, we have a connection/edge simplifier for our codebase, since strawberry (python gql) likes to force connections and edges in for no reason. I ended up modifying our driver for that to be inside the gql interface logic, instead of in pathom middleware.

JAtkins 2024-11-14T20:24:38.287399Z

This particularly seems to be an issue with nested inputs. E.g.

(lib.pco/defresolver resolver-ancillary-markets
  [{:ops.Asset/keys [ancillaryMarkets]}]
  {:ops.Asset/ancillary-markets (mapv keyword ancillaryMarkets)})


(lib.pco/defresolver resolver-clr-resource
  [env
   {{clr :ops.QSEMetadata/clrResourceCode} :ops.Asset/qseMetadata}]
  {::pco/inputs [{:ops.Asset/qseMetadata [:ops.QSEMetadata/clrResourceCode]}]}
  {:ops.Asset/clr-resource-code clr})
[{[:ops.Asset/id 1]
  [:ops.Asset/id
   :ops.Asset/name
   :ops.Asset/ancillary-markets
   #_:ops.Asset/clr-resource-code]}]
=> 
{[:ops.Asset/id 1]
 {:ops.Asset/id 1,
  :ops.Asset/ancillary-markets [:reserves :reg_down :reg_up],
  :ops.Asset/name "example_battery_central_tz_subhourly"}}
[{[:ops.Asset/id 1]
  [:ops.Asset/id
   :ops.Asset/name
   :ops.Asset/ancillary-markets
   :ops.Asset/clr-resource-code]}]
=> 
{[:ops.Asset/id 1]
 {:ops.Asset/id 1,
  :ops.Asset/ancillary-markets :com.wsscode.pathom.core/not-found,
  :ops.Asset/clr-resource-code :com.wsscode.pathom.core/not-found,
  :ops.Asset/name :com.wsscode.pathom.core/not-found}}

JAtkins 2024-11-14T20:40:47.167009Z

The dynamic resolver for GQL doesn't seem to want to resolve the nested Asset requirements. Here's the finalized node plan for that:

{:com.wsscode.pathom3.connect.operation/op-name
 ops/pathom-entry-dynamic-resolver,
 :com.wsscode.pathom3.connect.planner/expects
 {:ops.Asset/ancillaryMarkets {},
  :ops.Asset/name {},
  :ops.Asset/qseMetadata {}},
 :com.wsscode.pathom3.connect.planner/foreign-ast
 {:children
  [{:dispatch-key :ops.Asset/name, :key :ops.Asset/name, :type :prop}
   {:dispatch-key :ops.Asset/ancillaryMarkets,
    :key :ops.Asset/ancillaryMarkets,
    :type :prop}
   {:dispatch-key :ops.Asset/qseMetadata,
    :key :ops.Asset/qseMetadata,
    :type :prop}],
  :type :root},
 :com.wsscode.pathom3.connect.planner/input {:ops.types/Asset {}},
 :com.wsscode.pathom3.connect.planner/node-id 1,
 :com.wsscode.pathom3.connect.planner/node-parents #{2},
 :com.wsscode.pathom3.connect.planner/run-next 11}
Also, the finalized node for running the clr-resource-code seems to only contain qseMetadata as the final requirement, not mentioning at all its' nested requirements.
{:com.wsscode.pathom3.connect.operation/op-name
 com.tybaenergy.model.operations.asset/resolver-clr-resource,
 :com.wsscode.pathom3.connect.planner/expects
 {:ops.Asset/clr-resource-code {}},
 :com.wsscode.pathom3.connect.planner/input
 {:ops.Asset/qseMetadata {}},
 :com.wsscode.pathom3.connect.planner/node-id 6,
 :com.wsscode.pathom3.connect.planner/node-parents #{11}}

wilkerlucio 2024-11-14T22:23:16.320999Z

humm, it may be a bug, because it should be fine to have resolvers relying on dynamic inputs

wilkerlucio 2024-11-14T22:23:30.349569Z

is it possible to give me a repro of it?

JAtkins 2024-11-14T22:24:03.112589Z

I'll try and repro it with the pathom gql example. eta ~1h most likely 🙂

wilkerlucio 2024-11-14T22:24:12.838629Z

no worries, take your time, and thanks for it

JAtkins 2024-11-14T22:58:47.815119Z

I can't repro it apparently. Looks like there's some collision between our custom gql resolving and the pathom planner. This is what we have for that:

(p.plugin/defplugin wrap-process-for-gql
                    {::p.eql/wrap-process-ast
                     (fn [process]
                       (fn [{:keys [query-params] :as env} ast]
                         (let [modified-ast (-> ast
                                                (eql/ast->query)
                                                (modify-gql-query env query-params)
                                                (eql/query->ast))
                               resp         (modify-gql-response (process env modified-ast) env)]
                           resp)))})
This removes the need to describe connections and edges in our frontend queries to simplify the fulcro components. Could this be stomping on our planner? I'm not really sure where to start to fix this 😂

JAtkins 2024-11-14T22:59:17.839239Z

🤔... Maybe I have an idea

JAtkins 2024-11-14T23:36:18.386799Z

ok, I've got an idea that sorta works. Here's my problem - I end up with tons of little sub gql queries being spammed out. e.g. if I want to do something like this:

(pco/defresolver films-sorted-by-director
  [input]
  {::pco/input [{:swapi.Person/filmConnection
                 [{:swapi.PersonFilmsConnection/films
                   [:swapi.Film/id
                    :swapi.Film/director]}]}]}
  {::films-sorted-by-director (sort-by :swapi.Film/director
                                       (get-in input
                                               [:swapi.Person/filmConnection :swapi.PersonFilmsConnection/films]))})

; lets create the environment
(def env
  (-> {}
      ; this helper will pull the schema and register it in the environment
      (p.gql/connect-graphql
       {::p.gql/namespace "swapi"}
       request-swapi-graphql)
      (pci/register [films-sorted-by-director])))

(comment
  ; request all people and the title of the films they participate
  (p.eql/process
   env
   [{:swapi.Root/allPeople
     [{:swapi.PeopleConnection/people
       [:swapi.Person/name
        {::films-sorted-by-director [:swapi.Film/director
                                     :swapi.Film/producers]}]}]}]))
this is very slow, because it has to go back and reach out for every Film to get the producer again. However, if I change the resolver to
(pco/defresolver films-sorted-by-director
  [input]
  {::pco/input [{:swapi.Person/filmConnection
                 [{:swapi.PersonFilmsConnection/films
                   [:swapi.Film/id
                    :swapi.Film/director
                    :swapi.Film/producers]}]}]}
  {::films-sorted-by-director (sort-by :swapi.Film/director
                                       (get-in input
                                               [:swapi.Person/filmConnection :swapi.PersonFilmsConnection/films]))})
I get back a result very quickly, because pathom pre-cached the producer list.

JAtkins 2024-11-14T06:26:36.264109Z

screenshot of the planner