Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Child sequence resolvers do not use parent entity data #171

Closed
rschmukler opened this issue Nov 17, 2022 · 2 comments
Closed

Child sequence resolvers do not use parent entity data #171

rschmukler opened this issue Nov 17, 2022 · 2 comments

Comments

@rschmukler
Copy link

rschmukler commented Nov 17, 2022

Hello! Thank you for all of your work on Pathom.

I am unsure if this is a bug or if intentional, but it would be nice if child resolvers could arbitrarily insert data from parent resolvers. This is a somewhat contrived example, but consider the following:

(ns tmp
  (:require
   [com.wsscode.pathom3.connect.operation :as pco :refer [defresolver]]
    [com.wsscode.pathom3.connect.indexes :as pci]
    [com.wsscode.pathom3.interface.eql :as p.eql]))

(defresolver users-resolver
  []
  {::pco/output [{:users [:id :age]}]}
  {:users [{:id 1 :age 20} {:id 2 :age 30}]})

(defresolver age-times-multiple-resolver
  [{:keys [age multiple]}]
  {:age-times-multiple (* age multiple)})

(defresolver multiple-resolver
  [{:keys [seed]}]
  {:multiple (dec seed)})

(def env
  (pci/register [users-resolver
                 age-times-multiple-resolver
                 multiple-resolver]))

(p.eql/process env {:seed 5} [{:users [:id :age-times-multiple]}])
;; Error: Pathom can't find a path for the following elements in the query: [:age-times-multiple] at path [:users 0]

I was able to get the behavior I wanted by changing the following in the runner.clj (and async / parallel variants) but I am unsure if this is the right way to solve this.

(defn process-sequence-subquery
  [env ast s]
  (if (pco/final-value? s)
    s
    (into
      (empty s)
      (keep-indexed #(p.plugin/run-with-plugins env
                       ::wrap-process-sequence-item
                       process-map-subquery
                       (p.path/append-path env %) ast
                       (merge (some-> env ::p.ent/entity-tree* deref) %2))) ;; <- This line is what is different
      (cond-> s
        (coll/coll-append-at-head? s)
        reverse))))

My specific use case is that a root level config is mapped into a database query. That query is then used to populate child records, and then those child resolvers have the ability to compute statistics on themselves by referencing the parent query.

@wilkerlucio
Copy link
Owner

Hello, this behavior is by design. Semantically for Pathom each map is an entity, when you join, the meaning is like navigating to another node, this is the mental model, and no data is shared between the entities. That said, there are ways to incorporate such behavior as the child takes into account some data from the parent.

The way I mostly do it is by explicitly forwarding the data down from the parent to the child. To apply this strategy to your example, we can modify the users-resolver:

(defresolver users-resolver
  [{:keys [seed]}]
  {::pco/output [{:users [:id :age]}]}
  {:users (mapv #(assoc % :seed seed) [{:id 1 :age 20} {:id 2 :age 30}])})

This way, you have fine control, and can affect the child from the parent.

If you like to play with that more generically, we can make a plugin to do it:

(defn merge-into-val [m v]
  (cond
    (map? v)
    ; note the order matters, using m v we prioritize the child
    ; value
    (merge m v)

    ; for this example I'll only handle vectors
    (vector? v)
    (mapv #(merge m %) v)

    :else
    v))

(p.plugin/defplugin forward-data-down
  {:com.wsscode.pathom3.connect.runner/wrap-merge-attribute
   (fn [merge-attribute]
     (fn [env out k v]
       (merge-attribute env out k (merge-into-val out v))))})

(def env
  (-> (pci/register [users-resolver
                     age-times-multiple-resolver
                     multiple-resolver])
      (p.plugin/register forward-data-down)))

Now if you revert the user-resolver to the original, it will still work.

Hope that can helps, closing it for now, but please re-open if you think there is more to discuss about it.

@rschmukler
Copy link
Author

rschmukler commented Nov 18, 2022

Thanks a ton for the detailed response. I really appreciate you taking the time to explain everything and show case the plugin. Cheers!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants