Skip to content

Commit

Permalink
validation: ScalarLeafs
Browse files Browse the repository at this point in the history
  • Loading branch information
neelance committed Mar 22, 2017
1 parent 4584498 commit 8632753
Show file tree
Hide file tree
Showing 4 changed files with 147 additions and 1 deletion.
2 changes: 2 additions & 0 deletions internal/query/query.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ type NamedFragment struct {

type SelectionSet struct {
Selections []Selection
Loc errors.Location
}

type Selection interface {
Expand Down Expand Up @@ -164,6 +165,7 @@ func parseFragment(l *lexer.Lexer) *NamedFragment {

func parseSelectionSet(l *lexer.Lexer) *SelectionSet {
sel := &SelectionSet{}
sel.Loc = l.Location()
l.ConsumeToken('{')
for l.Peek() != '}' {
sel.Selections = append(sel.Selections, parseSelection(l))
Expand Down
2 changes: 1 addition & 1 deletion internal/tests/testdata/export.js
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ require('./src/validation/__tests__/LoneAnonymousOperation-test');
// require('./src/validation/__tests__/OverlappingFieldsCanBeMerged-test');
// require('./src/validation/__tests__/PossibleFragmentSpreads-test');
require('./src/validation/__tests__/ProvidedNonNullArguments-test');
// require('./src/validation/__tests__/ScalarLeafs-test');
require('./src/validation/__tests__/ScalarLeafs-test');
require('./src/validation/__tests__/UniqueArgumentNames-test');
// require('./src/validation/__tests__/UniqueDirectivesPerLocation-test');
// require('./src/validation/__tests__/UniqueFragmentNames-test');
Expand Down
124 changes: 124 additions & 0 deletions internal/tests/testdata/tests.json
Original file line number Diff line number Diff line change
Expand Up @@ -1781,6 +1781,130 @@
}
]
},
{
"name": "Validate: Scalar leafs/valid scalar selection",
"rule": "ScalarLeafs",
"query": "\n fragment scalarSelection on Dog {\n barks\n }\n ",
"errors": []
},
{
"name": "Validate: Scalar leafs/object type missing selection",
"rule": "ScalarLeafs",
"query": "\n query directQueryOnObjectWithoutSubFields {\n human\n }\n ",
"errors": [
{
"message": "Field \"human\" of type \"Human\" must have a selection of subfields. Did you mean \"human { ... }\"?",
"locations": [
{
"line": 3,
"column": 9
}
]
}
]
},
{
"name": "Validate: Scalar leafs/interface type missing selection",
"rule": "ScalarLeafs",
"query": "\n {\n human { pets }\n }\n ",
"errors": [
{
"message": "Field \"pets\" of type \"[Pet]\" must have a selection of subfields. Did you mean \"pets { ... }\"?",
"locations": [
{
"line": 3,
"column": 17
}
]
}
]
},
{
"name": "Validate: Scalar leafs/valid scalar selection with args",
"rule": "ScalarLeafs",
"query": "\n fragment scalarSelectionWithArgs on Dog {\n doesKnowCommand(dogCommand: SIT)\n }\n ",
"errors": []
},
{
"name": "Validate: Scalar leafs/scalar selection not allowed on Boolean",
"rule": "ScalarLeafs",
"query": "\n fragment scalarSelectionsNotAllowedOnBoolean on Dog {\n barks { sinceWhen }\n }\n ",
"errors": [
{
"message": "Field \"barks\" must not have a selection since type \"Boolean\" has no subfields.",
"locations": [
{
"line": 3,
"column": 15
}
]
}
]
},
{
"name": "Validate: Scalar leafs/scalar selection not allowed on Enum",
"rule": "ScalarLeafs",
"query": "\n fragment scalarSelectionsNotAllowedOnEnum on Cat {\n furColor { inHexdec }\n }\n ",
"errors": [
{
"message": "Field \"furColor\" must not have a selection since type \"FurColor\" has no subfields.",
"locations": [
{
"line": 3,
"column": 18
}
]
}
]
},
{
"name": "Validate: Scalar leafs/scalar selection not allowed with args",
"rule": "ScalarLeafs",
"query": "\n fragment scalarSelectionsNotAllowedWithArgs on Dog {\n doesKnowCommand(dogCommand: SIT) { sinceWhen }\n }\n ",
"errors": [
{
"message": "Field \"doesKnowCommand\" must not have a selection since type \"Boolean\" has no subfields.",
"locations": [
{
"line": 3,
"column": 42
}
]
}
]
},
{
"name": "Validate: Scalar leafs/Scalar selection not allowed with directives",
"rule": "ScalarLeafs",
"query": "\n fragment scalarSelectionsNotAllowedWithDirectives on Dog {\n name @include(if: true) { isAlsoHumanName }\n }\n ",
"errors": [
{
"message": "Field \"name\" must not have a selection since type \"String\" has no subfields.",
"locations": [
{
"line": 3,
"column": 33
}
]
}
]
},
{
"name": "Validate: Scalar leafs/Scalar selection not allowed with directives and args",
"rule": "ScalarLeafs",
"query": "\n fragment scalarSelectionsNotAllowedWithDirectivesAndArgs on Dog {\n doesKnowCommand(dogCommand: SIT) @include(if: true) { sinceWhen }\n }\n ",
"errors": [
{
"message": "Field \"doesKnowCommand\" must not have a selection since type \"Boolean\" has no subfields.",
"locations": [
{
"line": 3,
"column": 61
}
]
}
]
},
{
"name": "Validate: Unique argument names/no arguments on field",
"rule": "UniqueArgumentNames",
Expand Down
20 changes: 20 additions & 0 deletions internal/validation/validation.go
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,13 @@ func (c *context) validateSelection(sel query.Selection, t common.Type) {
var ft common.Type
if f != nil {
ft = f.Type
sf := hasSubfields(ft)
if sf && sel.SelSet == nil {
c.addErr(sel.Loc, "ScalarLeafs", "Field %q of type %q must have a selection of subfields. Did you mean \"%s { ... }\"?", sel.Name, ft, sel.Name)
}
if !sf && sel.SelSet != nil {
c.addErr(sel.SelSet.Loc, "ScalarLeafs", "Field %q must not have a selection since type %q has no subfields.", sel.Name, ft)
}
}
if sel.SelSet != nil {
c.validateSelectionSet(sel.SelSet, ft)
Expand Down Expand Up @@ -370,6 +377,19 @@ func canBeInput(t common.Type) bool {
}
}

func hasSubfields(t common.Type) bool {
switch t := t.(type) {
case *schema.Object, *schema.Interface, *schema.Union:
return true
case *common.List:
return hasSubfields(t.OfType)
case *common.NonNull:
return hasSubfields(t.OfType)
default:
return false
}
}

func stringify(v interface{}) string {
switch v := v.(type) {
case *lexer.Literal:
Expand Down

0 comments on commit 8632753

Please sign in to comment.