Earlier quoted context omitted.
This is an interesting way to tackle it, but in my scenario, the company id is data from the users table. So without fetching the user first, you don't know what their company ID is. If we don't have the users data, we can't pass the company id with the user ID. This is not a problem if you are doing an explicit query because you can fetch user + company data at the same time. But if you're using the three resolvers…
It doesn't seem petty at all. These are the fundamental primitives of how you want to decouple and organize code. You have to look at them through small examples. In the first case, the situation looks largely the same. I mean you can either uses the same nested inputs strategy but have a special key that triggers the fat-query resolver. Something like :employed-user-id. The other alternative is using nested outputs.…
When I say cached result I misspoke, I mean Pathom, rather than running the one resolver that gets everything, will first see the resolver that gets only the user and grab that. Then it will consider :user/email satisfied and look for other resolvers. It seems to not look for the resolver that solves all the requested data, and instead goes first come first serve.
> In the first case, the situation looks largely the same. I mean you can either uses the same nested inputs strategy but have a special key that triggers the fat-query resolver. Something like :employed-user-id.
> The other alternative is using nested outputs. You have the resolver returned a keyed bundle. Something like {:fat-request [:users/email :company/phone_number]}. The downstream resolver then consumers a :fat-request and unpacks it using nested inputs.
> You can make resolverZZ output some dummy key :zz-was-run. If you request :zz-was-run then I think it should also take the branch? (or maybe it runs both branches)
I think that these tricks can work sometimes, but you might be surprised what odd behavior can come up if you rely on this. In your pathom query, the order of your requested data matters.
(pco/defresolver get-user [{:users/keys [id]}]
{::pco/output [:users/id :users/email :users/customer_id :users/budget]}
(println "get-user triggered")
(-> (jdbc/execute-one! ds ["SELECT * FROM users WHERE id = ?" id])))
(pco/defresolver get-customer [{:customers/keys [id]}]
{::pco/output [:customers/id :customers/billing_number :customers/phone_number]}
(println "get-customer triggered")
(-> (jdbc/execute-one! ds ["SELECT * FROM customers WHERE id = ?" id])))
(pco/defresolver get-user-with-customer [{:users/keys [id]}]
{::pco/output [:users/id :users/email :users/customer_id :fat-key
:customers/id :customers/billing_number :customers/phone_number]}
(println "get-user-with-customer triggered")
(let [user (jdbc/execute-one! ds ["SELECT * FROM users WHERE id = ?" id])
customer (jdbc/execute-one! ds ["SELECT * FROM customers WHERE id = ?" (:users/customer_id user)])]
(merge user {:customers/id (:customers/id customer)
:customers/billing_number (:customers/billing_number customer)
:customers/phone_number (:customers/phone_number customer)
:fat-key true})))
(def user-customer-bridge
(pbir/alias-resolver :users/customer_id :customers/id))
;; ---- test1
(p.eql/process env
{:users/id 1000}
[:fat-key
:customers/phone_number
:users/email])
;; ---- get-user-with-customer triggered
;; ---- test2
(p.eql/process env
{:users/id 1000}
[:customers/phone_number
:fat-key
:users/email])
;; ---- get-user triggered,
;; ---- get-user-with-customer triggered
I couldn't tell you why it shakes out this way. Something about the bridge and requesting `:customers/phone_number` first must be coercing Pathom to take the longer path to :customers/phone_number, even though the other resolver can get everything in one shot. This is the kind of subtle behavior that is unintuitive and could blow up production if you trigger the wrong resolver in the wrong hot path. So I don't see a reasonable argument for using Pathom in an application that needs reliability unless you make the resolved paths part of the test suite. Although, I still think it could be a powerful combination with something like Sqlite or Datalevin where many reads don't matter as much.