pathom

:pathom: https://github.com/wilkerlucio/pathom/ & https://pathom3.wsscode.com & https://roamresearch.com/#/app/wsscode
lilactown 2020-08-14T01:10:36.003400Z

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]}]}]

lilactown 2020-08-14T01:11:01.003900Z

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

lilactown 2020-08-14T01:12:02.004700Z

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

souenzzo 2020-08-14T01:29:35.006200Z

@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.

souenzzo 2020-08-14T01:30:05.006400Z

https://github.com/edn-query-language/eql#unions

wilkerlucio 2020-08-14T01:36:36.008Z

@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)

lilactown 2020-08-14T03:00:08.008400Z

Thanks, I’ll try that tomorrow

lilactown 2020-08-14T03:00:41.009400Z

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

2020-08-14T14:28:23.011Z

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.

2020-08-14T14:43:04.014100Z

@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

👍 2
wilkerlucio 2020-08-14T15:05:50.016300Z

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

👍 1
wilkerlucio 2020-08-14T15:07:02.018200Z

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)

souenzzo 2020-08-14T15:13:52.018400Z

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.