-
Notifications
You must be signed in to change notification settings - Fork 490
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
POC: allow users to get requested fields from context #70
base: master
Are you sure you want to change the base?
Conversation
@jargv We've discussed something like this before, what do you think of this implementation? |
internal/exec/exec.go
Outdated
@@ -25,6 +25,10 @@ const OpenTracingTagTrivial = "graphql.trivial" | |||
const OpenTracingTagArgsPrefix = "graphql.args." | |||
const OpenTracingTagError = "graphql.error" | |||
|
|||
type contextKey string | |||
|
|||
const GRAPHQL_FIELDS contextKey = "GRAPHQL_FIELD" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This identifier name does not follow Go style. See https://github.com/golang/go/wiki/CodeReviewComments#initialisms.
3daf4a8
to
1506699
Compare
This POC could solve graph-gophers#17
1506699
to
7a0c87b
Compare
One question I have is what should the type be of the list of fields. I started by making it a However, to get constant lookup times, I changes it to a recursive map. type FieldList map[string]FieldList Do you think that is the right approach? |
We already have something like this structure in the |
@tonyghita is there a specific part of the |
Hmm you're right, but the query does have to match the schema for it to be valid, right? I'll think about this a bit more and get back to you tomorrow. |
Is it worth it for me to refactor this PR to resolve conflicts or should I abandon it? @neelance if we got this right, would you merge? |
Sorry, but I'm not fully convinced about this yet. Please give me some more time, I haven't forgotten about this. |
@neelance @nicksrandall I would really need this feature. It's quite essential for properly optimizing DB queries. |
Hey I agree @nicksrandall and @tj that the intent could solve this but I feel it's at the wrong level. We've been using neelance/graphql for the last 3 mo (thanks guys) to build our MVP. One element we did do is adapt Uncle Bob's clean architecture. The major change it made us do is split business logic away from the resolvers (resolvers are in the adapter layer but are mostly stubs that relay the call to the business logic functions). The aggregation of multiple results is already taken care by graphql package, adding custom logic there to get types and sub-types recursively (IMHO) to avoid complex joins seems counter-intuitive. An alternate approach to #17 n+1 issue I'm looking currently into is looking into channels to act as js promises and aggregate calls to the same type into a single DB query vs multiple (aka debounce the query calls or Facebooks' dataloader). |
The problem right now is that some queries are basically impossible with this package as-is, you can't possibly fetch/process all the data, in all ways, just to filter on it later. You have to construct a query based on what the user asks for. That said it's not like it has to go into this package, easy enough to fork of course :D, just a different use-case than the typical fetch/filter. |
I think this is a problem that dataloader can solve. Have you tried adapting https://github.com/nicksrandall/dataloader for your usecase? |
@tonyghita I'll check that out, I already hacked the field stuff into a fork. If it's not something the maintainers would use or want that's no biggie, just mentioning the context. |
@nicksrandall what do you think of #169 compared to these changes? I know it's been a while unfortunately. |
I think that we can do better than my implementation here. As I recall, this was a quick and dirty proof of concept. The JavaScript implementation of Graphql has a "context" argument that gets passed to every resolver. One of the fields in that context is an AST of the current query which can be introspected to get a list of all the requested fields. I think the idiomatic go way to provide a list of the currently selected fields would be to leverage the context variable that we already have. That way we're not adding yet another argument for every feature we'd like to provide the resolvers. It would be nice if the implementation we come up with could lazily evaluate the requested fields so that resolvers that don't ask for it don't have to pay the price. Once evaluated, we could store the result in the context so that downstream resolvers have less work to do. Then again, calculating the requested fields might be so trivial that such optimizations would be unnecessary. |
This POC could solve #17
This PR gives resolvers access to get the list of field names that have been requested for the resolver of that type and any sub-types recursively.
Example
Assume a user executes the following query
The resolver (optionally) has access to the fields requested like so:
The field information is useful because now I can potentially optimize my data fetching mechanism based on what was requested in the query (like avoiding an expensive SQL join).
@neelance Thoughts?
@tj would this solve your issue?