Skip to content
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

Improve Field Collection API #533

Closed
mathewbyrne opened this issue Feb 6, 2019 · 2 comments
Closed

Improve Field Collection API #533

mathewbyrne opened this issue Feb 6, 2019 · 2 comments
Labels

Comments

@mathewbyrne
Copy link
Contributor

We get a number of support requests around users wanting to know which fields were selected in a query. This is possible via the CollectFieldsCtx helper method, but it's a little unintuitive, not well documented, and could be simplified a bit.

Field collection is the process of resolving a selection set down to the fields that are relevant for the resolved object. In generated code, field collection is run after the resolver, because we need to know what the GraphQL Type of the resolved value will be so that we can ensure we only relevant collect fields.

The common use-case that is encountered is a resolver that fetches from a data source, and the user wants to prevent over-fetching by limiting their query to only the set of requested fields. This is possible with CollectFieldsCtx, but requires a value for satisfies []string, which is not documented.

The other use-case that should be supported is to get the collected fields that satisfy the resolved value. This is also possible with CollectFieldsCtx, however the resolver needs to know all of the possible implementors for a type, which is a problem codegen should be able to solve.

I'm proposing to add two methods to solve these use-cases:

func CollectFields(ctx context.Context) []CollectedField

This would return a set of all fields, ignoring fragment Type Conditions. This would be the common use-case for simple sets of fields a user wants to query.

func CollectFieldsFor(ctx context.Context, obj interface{}) []CollectedField

This would return a set of fields, with respect to the resolved type. Internally gqlgen would resolve the set of Implementors for a given type and pass it through to graphql.CollectFields as satisfies []string.

I'm not sure the best way to do the resolving of the type yet, perhaps a method GetImplementors(obj interface{}) could be generated to support this? Open to suggestions.

Along with these changes would come some documentation explaining field collection and how users can access this in resolvers.

@vektah
Copy link
Collaborator

vektah commented Feb 6, 2019

I think the first use case (overfetching) shouldnt expose collected fields at all, its just a []string of the graphql field names. CollectedField exposes child selection sets too which is rarely what you want.

This would return a set of fields, with respect to the resolved type.

what does this actually look like?

row := db.Query("SELECT id, type FROM common")

var fields []string
switch row.Type {
   case "left":
      var leftEvent Left
      db.Query("SELECT ${graphql.CollectedFieldsFor(ctx, leftEvent)} FROM left_events", &leftEvent)\
      return leftEvent
   case "joined":
      var joinedEvent Joined
      db.Query("SELECT ${graphql.CollectedFieldsFor(ctx, joinedEvent)} FROM joined_events", &joinedEvent)
      return joinedEvent
}

@mathewbyrne
Copy link
Contributor Author

I think the first use case (overfetching) shouldnt expose collected fields at all, its just a []string of the graphql field names.

Yep, I think that's a nice refinement. Maybe both use-cases could return []string — anything more complex; we wait for a common use-case and recommend using the internal method for now.

what does this actually look like?

Yeah that's more or less what I was envisioning. How does that feel to you?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants