gqlgen icon indicating copy to clipboard operation
gqlgen copied to clipboard

Extract result from parent resolver in the downstream resolver chains

Open tushar-rishav opened this issue 1 year ago • 3 comments

What happened?

With following graphql schema:

type Base64Gif {
    encoding: String!
}

type Content {
    video_url: String!
    gif: Base64Gif
}

type Metadata {
    content: Content
    start_time_sec: String!
}
type Query {
    search(query: String!): [Metadata!]!
}

The resolvers are as below:

// Search is the resolver for the search field.
func (r *queryResolver) Search(ctx context.Context, query string) ([]*model.Metadata, error) {
	...
}
// Content is the resolver for the content field.
func (r *metadataResolver) Content(ctx context.Context, obj *model.Metadata) (*model.Content, error) {
       ...
}
// Gif is the resolver for the gif field.
func (r *contentResolver) Gif(ctx context.Context, obj *model.Content) (*model.Base64Gif, error) {
      // How do I access `start_time_sec` field which is present in the grandparent chain ?
}

versions

  • go run github.com/99designs/gqlgen version? v0.17.36
  • go version? go1.21.0 linux/amd64

tushar-rishav avatar Aug 24 '23 20:08 tushar-rishav

It's tricky, but possible. Try this in your resolver Gif:

func (r *contentResolver) Gif(ctx context.Context, obj *model.Content) (*model.Base64Gif, error) {
	opCtx := graphql.GetFieldContext(ctx)
	var indent int
	for parent := opCtx.Parent; parent != nil; parent = parent.Parent {
		fmt.Printf("%sparent %v\n", strings.Repeat("  ", indent), parent.Result)
		indent += 1
	}
}

You'll see what you need to do.

geertjanvdk avatar Sep 12 '23 11:09 geertjanvdk

@geertjanvdk Is there a chance that parent.Result returns all results not just from its immediate ancestor in the parent chain but also that ancestor’s siblings?

Since there is 1-1 relationship between Metadata and Content, I was trying to figure out how to get the corresponding start_time_sec (Metadata) for which the Content chain node was created subsequently in resolver chain. An implementation I came up with was similar to what you’ve proposed, however it didn’t work for me because of aforementioned combined results issue.

tushar-rishav avatar Sep 12 '23 16:09 tushar-rishav

(moderators: this turns in a discussion; might be good to move this)

I am not sure I am grasping your need; maybe you need redo the schema? I can only give you tip on getting the parent(s) :)

I my case, I need to generate an id for things that don't have one, based on the parent's ID. I do this like this:

	var hg *MyThing
	var ok bool

	for p := graphql.GetFieldContext(ctx).Parent; ; p = p.Parent {
		hg, ok = p.Result.(*MyThing)
		if ok {
			break
		}
	}

	if hg == nil {
		return "", fmt.Errorf("failing to get parent")
	}

	return hg.ID + ":" + string(obj.SomethingUnique), nil

geertjanvdk avatar Sep 12 '23 18:09 geertjanvdk