Skip to content

Commit

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

type Fragment struct {
On string
OnLoc *errors.Location
SelSet *SelectionSet
Directives map[string]common.ArgumentList
}
Expand Down Expand Up @@ -124,6 +125,7 @@ func resolveSelection(doc *Document, sel Selection) (Selection, *errors.QueryErr
}
return &Fragment{
On: frag.On,
OnLoc: frag.OnLoc,
SelSet: frag.SelSet,
Directives: sel.Directives,
}, nil
Expand Down Expand Up @@ -188,6 +190,7 @@ func parseFragment(l *lexer.Lexer) *NamedFragment {
f := &NamedFragment{}
f.Name = l.ConsumeIdent()
l.ConsumeKeyword("on")
f.OnLoc = l.Location()
f.On = l.ConsumeIdent()
f.SelSet = parseSelectionSet(l)
return f
Expand Down Expand Up @@ -245,6 +248,7 @@ func parseSpread(l *lexer.Lexer) Selection {
fs.Directives = common.ParseDirectives(l)
return fs
}
f.OnLoc = l.Location()
f.On = l.ConsumeIdent()
}
f.Directives = common.ParseDirectives(l)
Expand Down
1 change: 1 addition & 0 deletions internal/tests/testdata/export.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ Module._load = function(request, parent, isMain) {
require('./src/validation/__tests__/ArgumentsOfCorrectType-test.js');
require('./src/validation/__tests__/DefaultValuesOfCorrectType-test.js');
require('./src/validation/__tests__/FieldsOnCorrectType-test.js');
require('./src/validation/__tests__/FragmentsOnCompositeTypes-test.js');

let output = JSON.stringify(tests, null, 2)
output = output.replace('{stringListField: [\\"one\\", 2], requiredField: true}', '{requiredField: true, stringListField: [\\"one\\", 2]}');
Expand Down
85 changes: 85 additions & 0 deletions internal/tests/testdata/tests.json
Original file line number Diff line number Diff line change
Expand Up @@ -1053,5 +1053,90 @@
"name": "Validate: Fields on correct type/valid field in inline fragment",
"query": "\n fragment objectFieldSelection on Pet {\n ... on Dog {\n name\n }\n ... {\n name\n }\n }\n ",
"errors": []
},
{
"name": "Validate: Fragments on composite types/object is valid fragment type",
"query": "\n fragment validFragment on Dog {\n barks\n }\n ",
"errors": []
},
{
"name": "Validate: Fragments on composite types/interface is valid fragment type",
"query": "\n fragment validFragment on Pet {\n name\n }\n ",
"errors": []
},
{
"name": "Validate: Fragments on composite types/object is valid inline fragment type",
"query": "\n fragment validFragment on Pet {\n ... on Dog {\n barks\n }\n }\n ",
"errors": []
},
{
"name": "Validate: Fragments on composite types/inline fragment without type is valid",
"query": "\n fragment validFragment on Pet {\n ... {\n name\n }\n }\n ",
"errors": []
},
{
"name": "Validate: Fragments on composite types/union is valid fragment type",
"query": "\n fragment validFragment on CatOrDog {\n __typename\n }\n ",
"errors": []
},
{
"name": "Validate: Fragments on composite types/scalar is invalid fragment type",
"query": "\n fragment scalarFragment on Boolean {\n bad\n }\n ",
"errors": [
{
"message": "Fragment \"scalarFragment\" cannot condition on non composite type \"Boolean\".",
"locations": [
{
"line": 2,
"column": 34
}
]
}
]
},
{
"name": "Validate: Fragments on composite types/enum is invalid fragment type",
"query": "\n fragment scalarFragment on FurColor {\n bad\n }\n ",
"errors": [
{
"message": "Fragment \"scalarFragment\" cannot condition on non composite type \"FurColor\".",
"locations": [
{
"line": 2,
"column": 34
}
]
}
]
},
{
"name": "Validate: Fragments on composite types/input object is invalid fragment type",
"query": "\n fragment inputFragment on ComplexInput {\n stringField\n }\n ",
"errors": [
{
"message": "Fragment \"inputFragment\" cannot condition on non composite type \"ComplexInput\".",
"locations": [
{
"line": 2,
"column": 33
}
]
}
]
},
{
"name": "Validate: Fragments on composite types/scalar is invalid inline fragment type",
"query": "\n fragment invalidFragment on Pet {\n ... on String {\n barks\n }\n }\n ",
"errors": [
{
"message": "Fragment cannot condition on non composite type \"String\".",
"locations": [
{
"line": 3,
"column": 16
}
]
}
]
}
]
29 changes: 22 additions & 7 deletions internal/validation/validation.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,22 +48,26 @@ func Validate(s *schema.Schema, q *query.Document) (errs []*errors.QueryError) {
}

for _, frag := range q.Fragments {
errs = append(errs, validateDirectives(s, frag.Directives)...)
t, ok := s.Types[frag.On]
if !ok {
continue
}
if !canBeFragment(t) {
errs = append(errs, errors.ErrorfWithLoc(frag.OnLoc, "Fragment %q cannot condition on non composite type %q.", frag.Name, t))
continue
}
errs = append(errs, validateSelectionSet(s, frag.SelSet, t)...)
}

return
}

func validateSelectionSet(s *schema.Schema, selSet *query.SelectionSet, t common.Type) []*errors.QueryError {
var errs []*errors.QueryError
func validateSelectionSet(s *schema.Schema, selSet *query.SelectionSet, t common.Type) (errs []*errors.QueryError) {
for _, sel := range selSet.Selections {
errs = append(errs, validateSelection(s, sel, t)...)
}
return errs
return
}

func validateSelection(s *schema.Schema, sel query.Selection, t common.Type) (errs []*errors.QueryError) {
Expand Down Expand Up @@ -100,10 +104,14 @@ func validateSelection(s *schema.Schema, sel query.Selection, t common.Type) (er
}

case *query.Fragment:
errs = append(errs, validateDirectives(s, sel.Directives)...)
if sel.On != "" {
t = s.Types[sel.On]
}
errs = append(errs, validateDirectives(s, sel.Directives)...)
if !canBeFragment(t) {
errs = append(errs, errors.ErrorfWithLoc(sel.OnLoc, "Fragment cannot condition on non composite type %q.", t))
return
}
errs = append(errs, validateSelectionSet(s, sel.SelSet, t)...)

default:
Expand All @@ -118,10 +126,8 @@ func fields(t common.Type) schema.FieldList {
return t.Fields
case *schema.Interface:
return t.Fields
case *schema.Union, nil:
return nil
default:
panic("unreachable")
return nil
}
}

Expand Down Expand Up @@ -258,6 +264,15 @@ func validateLiteral(v *lexer.Literal, t common.Type) bool {
return false
}

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

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

0 comments on commit 254afa8

Please sign in to comment.