Skip to content

Commit

Permalink
Validate: Unique variable names
Browse files Browse the repository at this point in the history
Commit:
089caad3628e69003d79675558fe38023af02d31 [089caad]
Parents:
9234c6da0e
Author:
Jan Jergus <[email protected]>
Date:
18 February 2016 at 7:00:39 AM SGT
Commit Date:
18 February 2016 at 8:47:14 AM SGT
  • Loading branch information
sogko committed Apr 6, 2016
1 parent 4323bff commit 507dfd2
Show file tree
Hide file tree
Showing 2 changed files with 77 additions and 0 deletions.
49 changes: 49 additions & 0 deletions rules.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ var SpecifiedRules = []ValidationRuleFn{
UniqueFragmentNamesRule,
UniqueInputFieldNamesRule,
UniqueOperationNamesRule,
UniqueVariableNamesRule,
VariablesAreInputTypesRule,
VariablesInAllowedPositionRule,
}
Expand Down Expand Up @@ -1735,6 +1736,54 @@ func UniqueOperationNamesRule(context *ValidationContext) *ValidationRuleInstanc
}
}

/**
* Unique variable names
*
* A GraphQL operation is only valid if all its variables are uniquely named.
*/
func UniqueVariableNamesRule(context *ValidationContext) *ValidationRuleInstance {
knownVariableNames := map[string]*ast.Name{}

visitorOpts := &visitor.VisitorOptions{
KindFuncMap: map[string]visitor.NamedVisitFuncs{
kinds.OperationDefinition: visitor.NamedVisitFuncs{
Kind: func(p visitor.VisitFuncParams) (string, interface{}) {
if node, ok := p.Node.(*ast.OperationDefinition); ok && node != nil {
knownVariableNames = map[string]*ast.Name{}
}
return visitor.ActionNoChange, nil
},
},
kinds.VariableDefinition: visitor.NamedVisitFuncs{
Kind: func(p visitor.VisitFuncParams) (string, interface{}) {
if node, ok := p.Node.(*ast.VariableDefinition); ok && node != nil {
variableName := ""
var variableNameAST *ast.Name
if node.Variable != nil && node.Variable.Name != nil {
variableNameAST = node.Variable.Name
variableName = node.Variable.Name.Value
}
if nameAST, ok := knownVariableNames[variableName]; ok {
return reportError(
context,
fmt.Sprintf(`There can only be one variable named "%v".`, variableName),
[]ast.Node{nameAST, variableNameAST},
)
}
if variableNameAST != nil {
knownVariableNames[variableName] = variableNameAST
}
}
return visitor.ActionNoChange, nil
},
},
},
}
return &ValidationRuleInstance{
VisitorOpts: visitorOpts,
}
}

/**
* VariablesAreInputTypesRule
* Variables are input types
Expand Down
28 changes: 28 additions & 0 deletions rules_unique_variable_names_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package graphql_test

import (
"testing"

"github.com/graphql-go/graphql"
"github.com/graphql-go/graphql/gqlerrors"
"github.com/graphql-go/graphql/testutil"
)

func TestValidate_UniqueVariableNames_UniqueVariableNames(t *testing.T) {
testutil.ExpectPassesRule(t, graphql.UniqueVariableNamesRule, `
query A($x: Int, $y: String) { __typename }
query B($x: String, $y: Int) { __typename }
`)
}
func TestValidate_UniqueVariableNames_DuplicateVariableNames(t *testing.T) {
testutil.ExpectFailsRule(t, graphql.UniqueVariableNamesRule, `
query A($x: Int, $x: Int, $x: String) { __typename }
query B($x: String, $x: Int) { __typename }
query C($x: Int, $x: Int) { __typename }
`, []gqlerrors.FormattedError{
testutil.RuleError(`There can only be one variable named "x".`, 2, 16, 2, 25),
testutil.RuleError(`There can only be one variable named "x".`, 2, 16, 2, 34),
testutil.RuleError(`There can only be one variable named "x".`, 3, 16, 3, 28),
testutil.RuleError(`There can only be one variable named "x".`, 4, 16, 4, 25),
})
}

0 comments on commit 507dfd2

Please sign in to comment.