Fork me on GitHub
#pathom
<
2022-05-30
>
Björn Ebbinghaus14:05:58

How do I update the env with pathom3 in a mutation? In pathom2 you just returned ::p/env

Björn Ebbinghaus14:05:20

Hmm… I used that functionality to update the :db key in my env to :db-after from the transaction report. https://clojurians.slack.com/archives/C87NB2CFN/p1626499102252200?thread_ts=1626471981.239700&amp;cid=C87NB2CFN

Björn Ebbinghaus15:05:49

@U066U8JQJ What would be the right place to put things like the current database value or user session or something…? Currently, I am satisfied with something like this:

(defresolver resolve-user-preferences [{:keys [current-user] :as env} _]
  {::pco/inputs []
   ::pco/output [:user/preferences]}
  {:user/preferences (get-preferences env current-user)}) 

(defmutation register-user [env user]
  {::pco/output [:user/id]}
  (let [id (register-user! env user)]
    {::p/env (assoc env :current-user user)
     :user/id id}))

wilkerlucio21:05:21

I removed that env feature because it was accidently leaking stuff sometimes, currently I think an option is to have some atom at env that you can modify, if path matters this atom could be something like {[:path] :some-value}, this way when reading from the env you use the current path to differenciate branches, makes sense? I'm also open to suggestions, just didn't put much though on this problem at Pathom 3 yet

Björn Ebbinghaus10:05:12

Do mean leaking outside the subgraph? In which situation does this occur? In this case, the atom would leak as well, so you gained nothing over adding the value with the path to the env.

wilkerlucio17:05:42

I mean the whole env leaking out in the output data

prepor16:05:07

Hi. I'm trying to figure out how pathom works with nested data and "contexts". I think it would be easier to just show example/reproducer:

(pco/defresolver situations [{:keys [module/id]}]
    {::pco/output
     [{:module/situations [:situation/id]}]}
    {:module/situations [{:situation/id :s1}
                         {:situation/id :s2}
                         {:situation/id :s3}]})

  (pco/defresolver situation-done [{:keys [situation/id]}]
    {::pco/output
     [:situation/done]}
    {:situation/done true})

  (def env
    (pci/register [situations
                   situation-done]))

  (comment
    (p.eql/process
     env
     {:module/id :m1}
     [{:module/situations [:situation/done]}])
    )
=> #:module{:situations [#:situation{:done true} #:situation{:done true} #:situation{:done true}]}
It works as expected. Now I want to add an input to situation-done resolver, something completely disconnected from situation/id. And I provide it as initial data.
(pco/defresolver situation-done [{:keys [situation/id user/id]}]
  {::pco/output
   [:situation/done]}
  {:situation/done true})

(p.eql/process
   env
   {:module/id :m1
    :user/id 1}
   [{:module/situations [:situation/done]}])
It stops working and says that
Graph execution failed: Pathom can't find a path for the following elements
   in the query: [:situation/done] at path [:module/situations 0]
Why? Isn't user/id resolvable in any "context"? Thank you!

Björn Ebbinghaus17:05:14

:user/id is only visible at the "root node" The situations are a node down from the root. Your Graph effectively looks like this:

{:module/id :m1
 :user/id 1
 :module/situations [{:situation/id :s1}]}
Having the :user/id on every level would break things Imagine following situation:
(defresolver resolve-friends [{:keys [user/id]}]
  {::pco/output [{:user/friends [:user/id]}]})

(defresolver resolve-user-name [{:keys [user/id]}]
  {::pco/output [:user/name]})

(process env {:user/id 42} [{:user/friends [:user/id]}])

Björn Ebbinghaus17:05:42

If you want something available everywhere use env

prepor18:05:56

Thank you. So, I made wrong assumptions about what pathom (it's funny I made it, but it's out of topic :) ) Could you suggest how to solve situations when I want to keep some context about required data and use it in resolvers? For example, imagine this data structure:

{:room/id :room1
 :room/users [{:user/id :user1
               :user/name-in-room "User name"}]}
To resolve :user/name-in-room I need two things: room/id and user/id. The only way that I see now it's providing it together with :room/users list, but it reduces composability and, possibly, performance. Not every query could want to get :user/name-in-room but it requires additional requests to get this data.

Björn Ebbinghaus20:05:32

Maybe:

{:room/id :room1
 :room/users [#:room+user{:name "User name"
                          :user {:user/id :user1}
                          :room {:room/id :room1}}]}
?
(defresolver resolve-room->room+user [{:keys [room/id]}]
  {::pco/output [{:room/users [:room+user/user :room+user/room]}]})

(defresolver resolve-user->room+user [{:keys [room/id]}]
  {::pco/output [{:user/rooms [:room+user/user :room+user/room]}]})

(defresolver resolve-room+user-name [{:room+user/keys [user room]}]
  {::pco/output [:room+user/name]})

wilkerlucio21:05:48

I have used this pattern many times, where you forward some data down, so you have the full context you need, something like:

{:room/id :room1
 :room/users [{:user/name "User name"
                          :user/id :user1
                          :room/id :room1}]}

Linus Ericsson07:05:02

You cannot destruct both user/id and subscription/id because both of them goes to the symbol id

prepor08:05:51

@UQY3M3F6D you are right, but the problem not in destructuring

👍 1
prepor08:05:56

@U066U8JQJ yes, I came up to the similar principle. But in my case it's not so natural. I have this nested structure for syllabus:

(pco/resolver
 `dashboard-self-studies-completed
 {::pco/input [:syllabus.situation/id :user/id]
  ::pco/output [:dashboard.self-studies/completed]})

(pco/resolver
 `syllabus-situations
 {::pco/input [:syllabus.module/id
               (pco/? :user/id)]
  ::pco/output [{:syllabus/situations [:syllabus.situation/id
                                       :user/id]}]})

(pco/resolver
 `syllabus-level
 {::pco/input [:syllabus/level
               (pco/? :user/id)]
  ::pco/output [{:syllabus/modules [:syllabus.module/id
                                    :user/id]}]})
syllabus is completely unrelated to the user and I want to keep resolvers this way. But in some queries I want to have data specific to some part of the syllabus AND some user (like :dashboard.self-studies/completed) So I'm adding an optional input user/id to every resolver in upper levels and forward to the downstream. It's working, but it's a hack.

Hukka12:05:26

I don't think I quite understand, but if you have syllabus entities that are independent from users, and user entities, and somehow users "own" or "have" some relationship to the syllabus but with extra (meta)information added, then this relationship is it's own entity that you could model

Hukka12:05:57

So that you could query somehow like {:user [{:syllabus-relationship [:extra-information {:syllabus [:common-data-for-syllabus]}]}]}

Björn Ebbinghaus12:05:03

That is what I did with :room+user/name above.

Hukka12:05:52

Yeah, akin how many-to-many relationships would be modelled in a relational DB