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

How can i make omit empty in grpahql query struct #49

Open
parithiban opened this issue Nov 1, 2019 · 7 comments
Open

How can i make omit empty in grpahql query struct #49

parithiban opened this issue Nov 1, 2019 · 7 comments
Labels

Comments

@parithiban
Copy link

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"`
@dmitshur
Copy link
Member

dmitshur commented Nov 2, 2019

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?

@parithiban
Copy link
Author

@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

@parithiban
Copy link
Author

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
}

@dmitshur
Copy link
Member

dmitshur commented Nov 4, 2019

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.

@parithiban
Copy link
Author

@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?

@parithiban
Copy link
Author

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

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

@parithiban
Copy link
Author

@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

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

No branches or pull requests

2 participants