-
Notifications
You must be signed in to change notification settings - Fork 1.2k
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
Added support for @include/@skip directives. #130
Conversation
Neat! I think I'm happy to add a hacky solution temporarily until the new parser lands. Once thats in we will need a more generic user pluggable way to define directives, and there will need to be a bit of planning around that to support various use cases (authentication, api fetch resolvers, caching). |
graphql/exec.go
Outdated
fieldAllowed := true | ||
switch arg.(type) { | ||
case *common.Variable: | ||
{ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm surprised none of the linters fire on this, you don't need curlies here.
graphql/exec.go
Outdated
} | ||
default: | ||
// Custom directives are not supported yet | ||
return fieldAllowed |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
probably should return true
. Do nothing rather then do something unexpected. Or error.
graphql/exec.go
Outdated
func collectFields(doc *query.Document, selSet []query.Selection, satisfies []string, variables map[string]interface{}, visited map[string]bool) []CollectedField { | ||
var groupedFields []CollectedField | ||
|
||
oop, err := doc.GetOperation("") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
😟
Maybe these methods should be refactored to take the request context instead of document so they can get the correct operation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This comment sill applies, everywhere that calls CollectFields is grabbing the doc out of the RequestContext embedded in execution context, they could pretty easily be updated to do
fields := graphql.CollectFields(ec.RequestContext, sel, implementors)
instead of
fields := graphql.CollectFields(ec.Doc, sel, implementors, ec.Variables)
and then you have access to the right operation instead of assuming it was an anonymous operation.
if variables == nil { | ||
variables = make(map[string]interface{}) | ||
} | ||
for _, variable := range operation.Vars { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This seems like a lot of work to do on every fieldset, I think this goes away if we pass context in?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If there will be one specific place which will have both variables and their default values, this will be super good!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can do this check inline, the one place you need the value from a variable, this function shouldn't exist.
And it really shouldn't mutate variables
, they should be static after the initial validation pass.
Thanks for addressing some comments. I will try to update PR ASAP. |
@vektah could you please do review once again? Thanks in advance :} |
fieldAllowed := true | ||
switch arg.(type) { | ||
case *common.Variable: | ||
value := arg.Value(variables) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why can't you pass the operation in here and do the variable lookup only when its actually referenced, instead of every resolver?
populateVariables
is a big smell to me, its going to run on every resolver regardless of if there is even a directive.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will fix ASAP!
graphql/exec.go
Outdated
func collectFields(doc *query.Document, selSet []query.Selection, satisfies []string, variables map[string]interface{}, visited map[string]bool) []CollectedField { | ||
var groupedFields []CollectedField | ||
|
||
oop, err := doc.GetOperation("") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This comment sill applies, everywhere that calls CollectFields is grabbing the doc out of the RequestContext embedded in execution context, they could pretty easily be updated to do
fields := graphql.CollectFields(ec.RequestContext, sel, implementors)
instead of
fields := graphql.CollectFields(ec.Doc, sel, implementors, ec.Variables)
and then you have access to the right operation instead of assuming it was an anonymous operation.
@vektah thanks for comments! Will try to fix ASAP! |
@vektah |
Yeah, the template changes are going to be required. A graphql query can have a few forms:
The only thing this works for is the first one, in order to get the operation name (you are using "", but thats 100% a bug). All this resolution has already been done though, when the validation happened, and it was put in context so the rest of the runtime knows whats going on. |
Actually, as I understood, we are only taking one operation. And doesn't matter if it was named or not according to this code: if operationName == "" {
if len(d.Operations) > 1 {
return nil, fmt.Errorf("more than one operation in query document and no operation name given")
}
for _, op := range d.Operations {
return op, nil // return the one and only operation
}
} |
Thats only |
@vektah |
- prevents possible collision with an object type named `Short`
* Update generated.gotpl * Update models.gotpl * Update data.go * update go generate * revert code changes
The new parser is nearly done now, full directive support should only be a few weeks away. |
Great. I'll close second one then. Thanks |
Overview
Resolves #126
Added support for builtin
@skip
/@include
directives. They only work with$if
argument (!).This supports syntax with inline variables and default ones.
It is very-very-very WIP PR. I'm really looking into ways of improving this code to actually bring in support for directives!
Default variables case
Query:
Result:
{ "data": {} }
As expected.
Inline variables case
Query:
Result:
{ "data": {} }
As expected.
Passed variables with default values
Query:
Variables:
Result:
As expected.