shurcooL / githubv4

Package githubv4 is a client library for accessing GitHub GraphQL API v4 (https://docs.github.com/en/graphql).

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

How can i make omit empty in grpahql query struct

parithiban opened this issue · comments

I have the following struct in which the Topics in the field tag can be optional so I made it as a pointer. Now while try calling the graphql it is resulting in error

type Topic struct {
	Name githubv4.String
}
type TopicsNode struct {
	Topic Topic
}

type RepositoryTopics struct {
	Nodes []TopicsNode
}

type Repository struct {
	Name        githubv4.String
	Description githubv4.String
	Topics      *RepositoryTopics `graphql:"repositoryTopics(first: 20)"`
}

type Execute struct {
	Repository *Repository `graphql:"repository(owner:$orgName,name: $repositoryName)"`
}

I tried calling the graphql


	repos := Repository{
		Name: "MY_REPO",
	}

	query := Execute{
		Repository: &repos,
	}

	variables := map[string]interface{}{
		"repositoryName": githubv4.String(RepoName),
		"orgName":        githubv4.String(GithubOrg),
	}

	err := GraphQL.Query(context.Background(), &query, variables)

I am getting the topics field always. How can i make it as optional

I tried two ways

Topics      *RepositoryTopics `graphql:"repositoryTopics(first: 20)" json:",omitempty"`
Topics      *RepositoryTopics `graphql:"repositoryTopics(first: 20) omitempty"`

Now while try calling the graphql it is resulting in error

What error do you get? Can you paste it here?

I am getting the topics field always. How can i make it as optional

You'll need to use GraphQL syntax for this, not JSON. GraphQL has a directive called "include":

https://graphql.github.io/graphql-spec/June2018/#sec--include

So you can do something like:

Topics *RepositoryTopics `graphql:"repositoryTopics(first: 20) @include(if: $includeTopics)"`

Then set the includeTopics variable to true or false:

variables := map[string]interface{}{
	"repositoryName": githubv4.String(RepoName),
	"orgName":        githubv4.String(GithubOrg),
	"includeTopics":  githubv4.Boolean(false),
}

Is that what you're looking to do?

@dmitshur

Thanks for the reply this is what exactly I needed. One query reg @include tag will this include GraphQL resource limitations i.e will it include the node limit & rate limit.

What error do you get? Can you paste it here?

If I change the structure as below. That is changing

  • RepositoryTopics
  • TopicsNode
  • Topic

struct to pointer

type Topic struct {
	Name *githubv4.String
}
type TopicsNode struct {
	Topic *Topic
}

type RepositoryTopics struct {
	Nodes *[]TopicsNode
}

type Repository struct {
	Name        githubv4.String
	Description githubv4.String
	Topics      *RepositoryTopics `graphql:"repositoryTopics(first: 20)"`
}

type Execute struct {
	Repository *Repository `graphql:"repository(owner:$orgName,name: $repositoryName)"`
}

And then calling the graphql as above i get the below error

slice doesn't exist in any of 1 places to unmarshal

I have one more scenario where I need to find the codeowner existence in a repo. According to Github the codeowners can be found in three different locations.. Is there a way can I combine a struct group and assign it to the repository struct


type Blob struct {
	Text string
}

type CodeOwnerLocation struct {
	Blob Blob `graphql:"... on Blob"`
}

type GithubCodeOwner struct {
	Blob Blob `graphql:"... on Blob"`
}

type DocsCodeOwner struct {
	Blob Blob `graphql:"... on Blob"`
}

type GetCodeOwners struct {
	CodeOwner       CodeOwnerLocation `graphql:"codeowner:object(expression: \"HEAD:CODEOWNERS\")"`
	GithubCodeOwner GithubCodeOwner   `graphql:"object(expression: \"HEAD:.github/CODEOWNERS\")"` 
	DocsCodeOwner   DocsCodeOwner     `graphql:"object(expression: \"HEAD:docs/CODEOWNERS\")"` 
}

type Repository struct {
	Name        githubv4.String
	Description githubv4.String
	CodeOwners  *GetCodeOwners // This doesn't work
        GithubCodeOwner GithubCodeOwner `graphql:"object(expression: \"HEAD:.github/CODEOWNERS\")"` // This works fine
}

And then calling the graphql as above i get the below error

slice doesn't exist in any of 1 places to unmarshal

Thanks. I'll need a complete runnable snippet that can reproduce this problem to investigate further. Do you mind putting one together?


Is there a way can I combine a struct group and assign it to the repository struct

Yes. Instead of doing:

Name        githubv4.String
Description githubv4.String
CodeOwners  *GetCodeOwners // This doesn't work

You need to do something like:

Name           githubv4.String
Description    githubv4.String
*GetCodeOwners // Embed this struct.

Or:

Name            githubv4.String
Description     githubv4.String
CodeOwner       CodeOwnerLocation `graphql:"object(expression: \"HEAD:CODEOWNERS\")"`
GithubCodeOwner CodeOwnerLocation `graphql:"object(expression: \"HEAD:.github/CODEOWNERS\")"` 
DocsCodeOwner   CodeOwnerLocation `graphql:"object(expression: \"HEAD:docs/CODEOWNERS\")"` 

When you do CodeOwners *GetCodeOwners instead of embedding GetCodeOwners, the generated GraphQL query looks like:

{
	codeOwners {
		docsCodeOwner: object(expression: "HEAD:docs/CODEOWNERS" {
			... on Blob {
				text
			}
		}
		githubCodeOwner: object(expression: "HEAD:.github/CODEOWNERS" {
			// ...
		}
		// ...
	}
}

Which isn't valid, because of "codeOwners". Embedding that struct means its contents are directly inserted, which is what you want.

In general, I suggest coming up with the GraphQL query that does what you want first, testing it via GitHub GraphQL API Explorer at https://developer.github.com/v4/explorer/, and then converting it to Go code that executes the GraphQL query.

@dmitshur

Is it possible to pass a dynamic variable to a struct tag? In the below struct, I want to pass the TopicsCount variable inside the tag

const TopicsCount = 30

type Repository struct {
	Name        string
	Description string
	IsPrivate   bool
	Topics      RepositoryTopics `graphql:"repositoryTopics(first: 30)"`
}
Topics      RepositoryTopics `graphql:"repositoryTopics(first: TopicsCount)"

The problem here is that I have the topicsCount variable in the config and need to fetch it from there.

Could you assist me with this?

I got it. This is mentioned in the documentation of passing the variable.

https://github.com/shurcooL/githubv4#arguments-and-variables

@dmitshur

Is there a way we can concatenate the graphql tag in the above repository struct

type Repository struct {
	Name        string
	Description string
	IsPrivate   bool
	Readme      GetFileContent   `graphql:"readme:object(expression: \"HEAD:README.md\")"`
        CodeOwner   CodeOwnerLocation `graphql:"object(expression: \"HEAD:CODEOWNERS\")"`
        
}

Here in some cases expression has a head but in some cases, it has some other head sha

Can this be made in a dynamic way

Readme      GetFileContent   `graphql:"readme:object(expression: \"$SHA:README.md\")"`

I can do it by

Readme      GetFileContent   `graphql:"readme:object(expression: $headRef)"`

Where my headRef should be "e4005132asad123b7107bcc7dc5cd213123:README.md"

I am thinking a way of using it as common so it can be used for CodeOwner field also