Fork me on GitHub
#pathom
<
2020-08-14
>
lilactown01:08:36

have a pathom/eql question: is it possible to have a disjoint union in a query? E.g. I have a folder tree where you can either have files, or more folders.

{::folder/id "x"
 ::folder/name "downloads"
 ::folder/children [{::file/id "y"} {::folder/id "z"}]}
what I’d like to do is have a query like:
[{::folder/all [::folder/id
                ::folder/name
                {::folder/children [::folder/node
                                    ::file/node]}]}]

lilactown01:08:01

where ::folder/node & ::file/node are resolvers that will look up the file / folder by ID

lilactown01:08:02

the above works, but I get lots of :com.wsscode.pathom.core/not-found values which aren’t very useful. hence the desire for a disjoint union, which would return either one or the other

souenzzo01:08:35

@lilactown you can use p/elide-special-outputs-plugin to remove ::p/not-found Also you can use unions

(let [register [(pc/constantly-resolver
                  :folder/all
                  [{:folder/id       1
                    :folder/name     "a"
                    :folder/children [{:folder/node "folder"}
                                      {:file/node "file"}]}])]

      parser (p/parser {::p/plugins [(pc/connect-plugin {::pc/register register})]})
      env {::p/reader               [p/map-reader
                                     pc/reader2
                                     pc/open-ident-reader
                                     p/env-placeholder-reader]
           ::p/placeholder-prefixes #{">"}}]
  (parser env [{:folder/all [:folder/id
                             :folder/name
                             {:folder/children {:folder/node [:folder/node]
                                                :file/node [:file/node]}}]}]))
Personally, i don't like unions.

wilkerlucio01:08:36

@lilactown using the elide to remove the output is probably the best in your case, unions add more value when the queries are very distinct (depending on some "type" notion that the union will use to select the branch), this way the union can avoid a lot of unescessary processing by running the query for only that type, but for smaller cases you can just ask all and use what is returned (looks more like your case)

lilactown03:08:08

Thanks, I’ll try that tomorrow

lilactown03:08:41

I suppose the other way of handling it would be to have separate keys where I keep folder refs and file refs?

uwo14:08:23

Remind me, is it considered an anti-pattern to create a resolver that just takes the ident and eql and passes it to datomic.api/pull? I can't remember where I thought I saw Wilker say that it was better to do each attribute individually.

wilkerlucio15:08:50

not a problem, but you may ask datomic to process more things than it knows about, I would check if that affects performance in any way, also remember that idents, params and unions are not valid syntax on datomic pull, so sending those there might break things

wilkerlucio15:08:02

ideally you should “trim” the query to send only what datomic can respond, which is what pathom-datomic does, but thar uses apis from pathom that are not recommended for general usage yet (reader3)

souenzzo15:08:52

I do that I use https://github.com/souenzzo/eql-datomic/ But there is some wired behaviors due cache like this:

(let [register (pc/resolver
                 `a+b
                 {::pc/output [:a :b]}
                 (fn [{:keys [ast]} _]
                   (d/pull db (eql.d/ast->query ast) eid)))]
  (parser env [{:>/a [:a]}
               {:>/b [:b]}]))
parser will enter :>/a, it need [:a] call a+b it will return just {:a 42} Then parser will enter :>/b, it need [:b]. It already called a+b, so it will take the result from cache and you will not get :b This is the behavior of reader2 reader3 has another behavior, it may not happen.

jeroenvandijk14:08:04

@uwo I’m guessing using datomic.api/entity directly is more efficient, because datomic.api/pull returns a normal map whereas (:some-attribute (datomic.api/entity db id)) potentially returns another entity that can used in subqueries. But just guessing here