Skip to content

Commit

Permalink
Add skip/include directive implementation
Browse files Browse the repository at this point in the history
This is a snowflake implementation for skip/include directives based on
the graphql-js implementation.  Skip takes precedence here.
  • Loading branch information
Mathew Byrne committed Jul 23, 2018
1 parent ebfde10 commit ea0f821
Showing 1 changed file with 35 additions and 1 deletion.
36 changes: 35 additions & 1 deletion graphql/exec.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ func collectFields(reqCtx *RequestContext, selSet ast.SelectionSet, satisfies []
for _, sel := range selSet {
switch sel := sel.(type) {
case *ast.Field:
if !shouldIncludeNode(sel.Directives, reqCtx.Variables) {
continue
}
f := getOrCreateField(&groupedFields, sel.Alias, func() CollectedField {
f := CollectedField{
Alias: sel.Alias,
Expand All @@ -51,7 +54,7 @@ func collectFields(reqCtx *RequestContext, selSet ast.SelectionSet, satisfies []

f.Selections = append(f.Selections, sel.SelectionSet...)
case *ast.InlineFragment:
if !instanceOf(sel.TypeCondition, satisfies) {
if !shouldIncludeNode(sel.Directives, reqCtx.Variables) || !instanceOf(sel.TypeCondition, satisfies) {
continue
}
for _, childField := range collectFields(reqCtx, sel.SelectionSet, satisfies, visited) {
Expand All @@ -60,6 +63,9 @@ func collectFields(reqCtx *RequestContext, selSet ast.SelectionSet, satisfies []
}

case *ast.FragmentSpread:
if !shouldIncludeNode(sel.Directives, reqCtx.Variables) {
continue
}
fragmentName := sel.Name
if _, seen := visited[fragmentName]; seen {
continue
Expand Down Expand Up @@ -117,3 +123,31 @@ func getOrCreateField(c *[]CollectedField, name string, creator func() Collected
*c = append(*c, f)
return &(*c)[len(*c)-1]
}

func shouldIncludeNode(directives ast.DirectiveList, variables map[string]interface{}) bool {
if d := directives.ForName("skip"); d != nil {
return !resolveIfArgument(d, variables)
}

if d := directives.ForName("include"); d != nil {
return resolveIfArgument(d, variables)
}

return true
}

func resolveIfArgument(d *ast.Directive, variables map[string]interface{}) bool {
arg := d.Arguments.ForName("if")
if arg == nil {
panic(fmt.Sprintf("%s: argument 'if' not defined", d.Name))
}
value, err := arg.Value.Value(variables)
if err != nil {
panic(err)
}
ret, ok := value.(bool)
if !ok {
panic(fmt.Sprintf("%s: argument 'if' is not a boolean", d.Name))
}
return ret
}

0 comments on commit ea0f821

Please sign in to comment.