shurcooL / githubv4

Package githubv4 is a client library for accessing GitHub GraphQL API v4 (https://docs.github.com/en/graphql).
MIT License
1.1k stars 89 forks source link

More of a question; need clarification #102

Closed naikrovek closed 2 years ago

naikrovek commented 2 years ago

Hello, thank you for this library. It will be extremely useful to me, if I can get through my small problem, here.

I have this GraphQL query which works fine if I run it in a tool like Insomnia:

{
    enterprise(slug: "asdf") {
        members(first: 100, after: "asdfasdfasdfasdf==") {
            nodes { ... on User { login suspendedAt } }
            pageInfo { hasNextPage endCursor }
        }
    }
}

but this query in your githubv4 library produces an error:

type user struct {
    Login       string
    SuspendedAt githubv4.DateTime
}

var q struct {
    Enterprise struct {
        Members struct {
            Nodes    []user
            PageInfo struct {
                HasNextPage bool
                EndCursor   githubv4.String
            }
        } `graphql:"members(first: 100, after: $cursor)"`
    } `graphql:"enterprise(slug: \"asdf\")"`
}

variables := map[string]any{
    "cursor": (*githubv4.String)(nil),
}

var allUsers []user
for {
    fmt.Print(".")
    err := client.Query(ctx, &q, variables)
    if err != nil {
        check(err)
    }
    allUsers = append(allUsers, q.Enterprise.Members.Nodes...)
    if !q.Enterprise.Members.PageInfo.HasNextPage {
        break
    }
    variables["cursor"] = githubv4.String(q.Enterprise.Members.PageInfo.EndCursor)
}

The error I get is this: Selections can't be made directly on unions (see selections on EnterpriseMember) which is a bit of a surprise to me, because this is effectively copied verbatim from your example on pagination, with relevant structs changed to match the working GraphQL query above.

I have a strong feeling that I am missing something very trivial that is obvious to you, so I'm asking if you see the problem, in the hopes that you can help.

Thank you again!

dmitshur commented 2 years ago

I suspect what's happening is that the type of Enterprise.Members a list of EnterpriseMember, which is a GraphQL union:

https://docs.github.com/en/graphql/reference/unions#enterprisemember

So its type can be EnterpriseUserAccount or User. You may not be able to directly access their fields.

In the GraphQL query you showed, you're using GraphQL inline fragments:

nodes {
    ... on User {
        login
        suspendedAt
    }
}

You should try the same in the Go code. See https://github.com/shurcooL/githubv4#inline-fragments for an example. It might look something like this:

var q struct {
    Enterprise struct {
        Members struct {
-           Nodes    []user
+           Nodes    []struct {
+               User user `graphql:"... on User"`
+           }
            PageInfo struct {
                HasNextPage bool
                EndCursor   githubv4.String
            }
        } `graphql:"members(first: 100, after: $cursor)"`
    } `graphql:"enterprise(slug: \"asdf\")"`
}
naikrovek commented 2 years ago

Thank you. I love you lol