wilkerlucio / pathom3

Interface with complex data via graph mapping.
https://pathom3.wsscode.com
Eclipse Public License 2.0
376 stars 31 forks source link

Placeholder bug when using foreign environments #159

Closed mitchelkuijpers closed 2 years ago

mitchelkuijpers commented 2 years ago

I find it quite hard to explain but I managed to reproduce this bug in small repro:

(ns avisi-apps.pathom-bug
  (:require [com.wsscode.pathom3.connect.operation :as pco]
            [com.wsscode.pathom3.connect.indexes :as pci]
            [com.wsscode.pathom3.interface.async.eql :as p.a.eql]
            [com.wsscode.pathom3.connect.foreign :as pcf]))

(def todo-db
  {1 {:todo/id    1
      :todo/title "Write foreign docs"
      :todo/foo "bar1"
      :todo/done? true}
   2 {:todo/id    2
      :todo/title "Integrate the whole internet"
      :todo/foo "bar2"
      :todo/done? false}})

(pco/defresolver todo-items []
  {::pco/output
   [{:app/all-todos
     [:todo/id
      :todo/title
      :todo/foo
      :todo/done?]}]}
  ; If I keep this and only return the ID's and then let a other resolver handle this then it works.
  ; And ofcourse change the output to `[{:app/all-todos [:todo/id]}]`
  ;{:app/all-todos
  ; [{:todo/id 1}
  ;  {:todo/id 2}]}
  ; If I return the complete documents here it breaks
  {:app/all-todos
   [(get todo-db 1)
    (get todo-db 2)]})

;(pco/defresolver todo-by-id [{:todo/keys [id]}]
;  {::pco/output
;   [:todo/id
;    :todo/title
;    :todo/foo
;    :todo/done?]}
;  (get todo-db id))

(def foreign-env
  (pci/register
    {:com.wsscode.pathom3.connect.planner/plan-cache* (atom {})
     ::p.a.eql/parallel? true}
    [todo-items
     #_todo-by-id]))

(def foreign-request
  (p.a.eql/boundary-interface foreign-env))

(def canceled-todos
  #{2})

(pco/defresolver todo-canceled? [{:todo/keys [id]}]
  {:todo/cancelled? (contains? canceled-todos id)})

(def local-env
  (pci/register
    {:com.wsscode.pathom3.connect.planner/plan-cache* (atom {})
     :com.wsscode.pathom3.placeholder/placeholder-prefixes #{">"}
     ::p.a.eql/parallel? true}
    [; pull the remote instance
     @(pcf/foreign-register foreign-request)

     ; add our custom resolver on top
     todo-canceled?]))

(def local-request
  (p.a.eql/boundary-interface local-env))

(comment
  ;; This works
  @(foreign-request
     [(list {:app/all-todos
             [:todo/title
              :todo/id
              {:>/foo [:todo/done?
                       :todo/id
                       :todo/foo
                       :todo/title]}]} {:foo "bar"})])

  ;; Adding this foreign request to a local parser makes this fail
  @(local-request
     [(list {:app/all-todos
             [:todo/title
              :todo/id
              {:>/foo [:todo/done?
                       :todo/id
                       :todo/foo
                       :todo/title]}]} {:foo "bar"})])

  )
wilkerlucio commented 2 years ago

Thanks for the report, I'm investigating, I first reduced the example, this is minimal thing I could get to:

(ns com.wsscode.pathom3.demos.repro159-foreign-placeholders
  (:require
    [com.wsscode.pathom3.connect.foreign :as pcf]
    [com.wsscode.pathom3.connect.indexes :as pci]
    [com.wsscode.pathom3.connect.operation :as pco]
    [com.wsscode.pathom3.interface.eql :as p.eql]))

(pco/defresolver sample-todo []
  {:app/sample-todo
   {:todo/id    1
    :todo/title "Write foreign docs"}})

(def foreign-env (pci/register [sample-todo]))

(def foreign-request
  (p.eql/boundary-interface foreign-env))

(def local-env
  (pci/register
    [(pcf/foreign-register foreign-request)]))

(def local-request
  (p.eql/boundary-interface local-env))

(comment
  ;; This works
  (foreign-request
    [{:app/sample-todo
      [{:>/foo
        [:todo/id]}]}])

  ;; This fails
  (local-request
    [{:app/sample-todo
      [{:>/foo
        [:todo/id]}]}]))

Seems that the planner is not being aware of the possible values in the parent when it comes from a nested parent and the value isn't used in the parent of the placeholder.

mitchelkuijpers commented 2 years ago

Yeah it seeems that way it is fixed if I separate sample-todo in two resolvers.