I'm using Pathom 2 and wondering if you have plans for 'natively' handling complex queries.
There are a couple of reasons why this might make sense:
- Writing code to strip a 'dumb' query result of unwanted values reifies the structure of the data outside of the query. This can introduce a future disconnect between the shape of the data as requested and the shape as needed by the post-processing functions.
- Having a standard dialect for filtering results could allow for resolvers to take advantage of the requested filters to reduce the scope of the query, when supported by the backend. An example of this is illustrated below.
Let's say I have the following query:
[{:users/list [:user/email :user/employeeType :user/groups]}]
; yields:
{:users/list
[#:user{:email "jdoe@domain"
:employeeType "staff"
:groups [{:group/email "a-group@domain"}
{:group/email "b-group@domain"}]}
#:user{:email "jpublic@domain"
:employeeType "faculty"
:groups [{:group/email "a-group@domain"}]}]}
Well, now I'd like to formulate a query to find users who are either faculty or staff, and are members of "a-group@domain". I can solve part of this problem with parameterization on :users/list
:
[{(:users/list {:filter "(|(employeeType=staff)(employeeType=faculty))"}) .....
And, once I've implemented the logic to pick that up, that's all well and good. However, the part where I restrict to users who are members of "a-group@domain" is trickier. I created a transformer to filter results based on parameters (not the same as the logic catching the above parameterization), and then I can do something like this:
[{(:users/list {:filter "(|(employeeType=staff)(employeeType=faculty))"})
[:user/email (:user/groups {:group/email "b-group@domain"})]}]
And have the resolver for :user/groups
return :no-match
rather than a value when the filter is not satisfied. I then modified the Pathom parser to short-circuit when :no-match
is discovered as a value for a child and immediately return the same, and also to strip vector results of that keyword. This works: the above query will then produce
{:users/list
[#:user{:email "jdoe@domain"
:groups [{:group/email "b-group@domain"}]}]}
However, there is no easy way to invert this query that I can think of; i.e., it is nontrivial to ask "what users that are either faculty or staff are not members of b-group@domain" - not without going and implementing very specific logic to answer parts of the question, although all of the predicates involved are general. Moreover, I'm already up to two different approaches for filtering, as each one is ad-hoc. The only real difference is that the resolver providing :users/list
is capable of restricting its queries ahead of time, whereas the groups resolver does not know how to do that. However, these shouldn't ultimately be a difference in terms of interface, imo. In an ideal world, I would be able to define behavior for handling filters on a given resolver if possible given the particular backend, otherwise letting the results be resolved and filtered post-facto by Pathom.
Interested in any thoughts on how this could be approached. Of course, if I've totally missed something and there's already a better way to do this, I'd love to know.