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]}]}]
where ::folder/node
& ::file/node
are resolvers that will look up the file / folder by ID
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
@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.@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)
Thanks, I’ll try that tomorrow
I suppose the other way of handling it would be to have separate keys where I keep folder refs and file refs?
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.
@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
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
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)
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.