Khan / genqlient

a truly type-safe Go GraphQL client
MIT License
1.09k stars 113 forks source link

Support for pagination when using relay pattern #357

Open netixx opened 1 month ago

netixx commented 1 month ago

Describe the solution you'd like i would like the generated file to expose a function such as:

func queryPaged(
    ctx context.Context,
    client graphql.Client,
    pageSize int,
    pf func(T) error,
) error {
    var cursor *string
    resp, err := query(ctx, client, pageSize, cursor)
    if err != nil {
        return nil
    }

    for _, edge := range resp.X.Edges {
        if err := pf(edge.GetNode()); err != nil {
            return err
        }
    }
    return nil
}

The issue I have is that this needs to be generated as the "X" is the query endpoint so it's not fixed. One possibility is to add a generic method to the root query that returns the node inside "data", Then we can write a generic pager with interfaces and generics.

Describe alternatives you've considered Writing a pager function for every query, but that sort of defeats the purpose of the generator.

Additional context The relay connection paging pattern is described here: https://relay.dev/graphql/connections.htm and here: https://graphql.org/learn/pagination/.

benjaminjkraft commented 1 month ago

Definitely agree this would be useful, I think the question is just what exactly to add! Would love to hear a bit more from you and any other interested users a description of what you're trying to do so we can try to optimize for it.

netixx commented 1 month ago

I would like the generator to make some code that enables me to transparently use API where a pager is available.

Right now I need to write an additional bit of code for every request I write, to handle the paging mecanism (iterating through all the pages until the end), it looks a little bit like the function in the description, and it mostly the same for each query (only the X differs), so it seems like an good opportunity to have it generated.

The query looks like that:

query Endpoint($pageSize: Int!, $cursor: Cursor) {
  endpoint(first: $pageSize, after: $cursor) {
    pageInfo {
      hasNextPage
      endCursor
    }
    edges {
      node {
        id
        name
...
      }
    }
  }
}

I have thought some more about that, and I am not sure how/if the following points can be handled: