Fork me on GitHub

Anyone aware of a Pathom resolver that allows to walk the file system or a git repo?


I've heard of none, but what's the use case? Putting a pathom interface in front of things may or may not add any value


It’s a very specific one 🙂


I want to be able to browse files in my new web framework haha


I want to do this without leaking implementation details in my view (the whole reason of using Pathom I believe)


So i was thinking of starting with something simple like a file browser


Maybe someone else was crazy enough to do this as well


I guess not 🙈


Any feedback on this? I want it to work recursively, but I’m still trying to get that to work


@jeroenvandijk hello, first I like to suggest you to use the simple parser instead of parallel, will be faster for this case. And I guess looking at the code that you can do recursive calls already, you can try this query:

 (async/<!! (parser {::p/entity {:file/path "."}}
                      {:dir/files ...})))


thank you! It’s not resolving the :dir/files recursively. I think I should add some join functionality somewhere. Reading that documentation now, but it didn’t click yet for me


This is the output. I would expect/hope ./src and ./git to be expanded

{:file/path ".",
 ... nil,
 :file/type :dir,
 [#:file{:path "./project.clj"}
  #:file{:path "./.gitignore"}
  #:file{:path "./.nrepl-history"}
  #:file{:path "./.git"}
  #:file{:path "./src"}]}


@jeroenvandijk I wrote my version of it, this works:

(pc/defresolver file-resolver [env {:file/keys [path]}]
  {::pc/input  #{:file/path}
   ::pc/output [:file/type]}
  (let [f    ( path)
        dir? (.isDirectory f)]
    {:file/type (if dir? :dir :file)
     :file/dir? dir?}))

(pc/defresolver directory-files-resolver [env {:file/keys [path dir?]}]
  {::pc/input  #{:file/path :file/dir?}
   ::pc/output [{:dir/files [:file/path]}]}
  (if dir?
     (mapv (fn [^File f0] {:file/path (.getPath f0)})
       (.listFiles ( path)))}))

(def my-resolvers [file-resolver directory-files-resolver])

(def parser
    {::p/env     {::p/reader               [p/map-reader
                  ::p/placeholder-prefixes #{">"}}
     ::p/mutate  pc/mutate
     ::p/plugins [(pc/connect-plugin {::pc/register my-resolvers})

  (parser {} [{[:file/path "src"]
                {:dir/files '...}]}]))

👍 4

So I guess my version didn’t trigger the recursion because :dir/files was already in the returning map, right?


I don't think that's the issue, your code seems like it should work


but your initial query example was off


was missing the map on the join for :dir/files


:dir/files [* {:dir/files [*]}]


☝️ missing {} around


Ah thank you. Good to understand this 🙂


you are right, my query was wrong. The resolver was working


I guess it is in general a best practise to make your resolvers as small as possible. For reusability and maybe also for performance?


From the docs:

Pathom will scan through the defined resolvers in order to try to satisfy all of the properties in a query. So, technically you can split up your queries as much as makes sense into separate resolvers, and as long as the inputs are in the context Pathom will assemble things back together.
I guess my resolver was indeed not lazy enough


Thanks @wilkerlucio. You have created an amazing library. Looking forward to use it more


Is it possible to have context dependent resolvers? E.g. when I want to browse a git tree {:dir/files …} would need to trigger a different resolver than when I browse a normal file system. I could also use a different key for that, but it would require more knowledge of the user


I think I have an idea 🙂


I think this will work when I implemented

(pc/defresolver file-resolver [{:keys [:resolvers.file/root-dir] :as env} {:file/keys [path]}]
  {::pc/input  #{:file/path}
   ::pc/output [:file/type]}
  (let [f    ( (str root-dir) path)
        dir? (.isDirectory f)]
    {:file/type (if dir? :dir :file)
     :file/dir? dir?
     :filesystem/type :normal}))

(pc/defresolver directory-files-resolver [{:keys [:resolvers.file/root-dir] :as env} {:file/keys [path dir?] filesystem-type :filesystem/type}]
  {::pc/input  #{:file/path :file/dir? :filesystem/type}
   ::pc/output [:dir/files]}
  (let [relativy (if root-dir
                   (let [idx (count root-dir)]
                     (fn [path]
                       (subs path idx)))
    (if (= filesystem-type :normal)
       (when dir?
         (mapv (fn [^ f0] {:file/path (relativy (.getPath f0))})
               (.listFiles ( root-dir path))))}
      (throw (ex-info "not implemented yet" {}))
When I write a different resolver for a git filesystem the user doesn’t have to know it’s querying something different 🙂


@jeroenvandijk you can just make multiple resolvers for the same key as well, and in the case out of context you return nil on the resolver, so pathom will try the other one

Reily Siegel15:05:08

Hello, is there an acceptable way to access the parser from within a mutation? I have two use cases for this: 1. Resolve unknown information that a mutation needs to function, that the caller of the mutation does not know. 2. Have a mutation submit several other "sub-mutations" to make smaller, reusable mutations For context, my problem domain is interfacing with the Discord API. So for example, for a higher level feature, I might need to make several "sub-mutations" (create post, add a reaction, etc). I also dont want to burden callers of the mutation with knowing details. For example, instead of requiring the "create post" mutation to accept a parameter, it would be more convenient to accept a and resolve the id based on an existing resolver. Am I thinking about this completely wrong?


@reilysiegel there's :parser key in env already

Reily Siegel15:05:00

Thank you! So in that case the solution to 2 is obvious, and for 1 I could pass the parameter map as the context to the resolver, and the desired parameters as a query.

Reily Siegel15:05:46

In fact, I could probably write a transform that automatically does that based on ::pc/params


a note to consider sub-mutations vs one composite mutation if you're using fulcro: each individual mutation may receive some data from server so your client db is updated - all the updates may be hard to denoted with a composite mutation


also, sub-mutations can "co-ordinate" by using tempids


anyway, both ways are valid, just evaluate the tradeoffs


I was going to try out the latest pathom release 2.3.0-alpha9. Upon updating to that release from 2.2.30, I receive an exception trying to load a ns that uses pathom:

Syntax error (ClassNotFoundException) compiling at (com/fulcrologic/guardrails/config.cljc:17:1).
From the changelog I saw 2.3.0-alpha4 bumped the dep that appears to be causing this issue - guardrails. I tried running with 2.3.0-alpha4 instead and received the same issue. I went all the way back to 2.3.0-alpha1 and still get the exception.


@kenny just a generic workaround: have you tried :exclusions in your dependencies?


Wasn’t worth the time to try it out. That’s probably the solution though. One of pathom’s deps updated and now conflicts with something else.


@kenny I wonder if has something to do with cljs versions itself, are you running on a recent one?


This isn't on a cljs app. It's a dep on a Clojure backend service.


I suppose cljs could be brought in accidentally.


maybe, what makes me think around that is because the error seems go be around some missing google closure thing


and from the deps jump you did, guardrails is a new dep


The line of code the exception is pointing to also has this comment:

;; This isn't particularly pretty, but it's how we avoid
;; having ClojureScript as a required dependency on Clojure