Skip to content

Commit

Permalink
RFC: Directive location: schema definition (#382)
Browse files Browse the repository at this point in the history
This allows directives to be defined on schema definitions.

Commit:
0aa78f61a2dc150b5ea9ee4f50b68a736796f068 [0aa78f6]
Parents:
1b6824bc5d
Author:
Lee Byron <[email protected]>
Date:
7 May 2016 at 7:05:27 AM SGT
Labels:
HEAD
  • Loading branch information
sogko authored and chris-ramon committed Mar 15, 2017
1 parent e7fdfd1 commit 3a56b94
Show file tree
Hide file tree
Showing 9 changed files with 53 additions and 9 deletions.
1 change: 1 addition & 0 deletions directives.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ const (
DirectiveLocationInlineFragment = "INLINE_FRAGMENT"

// Schema Definitions
DirectiveLocationSchema = "SCHEMA"
DirectiveLocationScalar = "SCALAR"
DirectiveLocationObject = "OBJECT"
DirectiveLocationFieldDefinition = "FIELD_DEFINITION"
Expand Down
4 changes: 4 additions & 0 deletions introspection.go
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,10 @@ func init() {
Value: DirectiveLocationInlineFragment,
Description: "Location adjacent to an inline fragment.",
},
"SCHEMA": &EnumValueConfig{
Value: DirectiveLocationSchema,
Description: "Location adjacent to a schema definition.",
},
"SCALAR": &EnumValueConfig{
Value: DirectiveLocationScalar,
Description: "Location adjacent to a scalar definition.",
Expand Down
2 changes: 2 additions & 0 deletions language/ast/type_definitions.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ var _ TypeSystemDefinition = (*DirectiveDefinition)(nil)
type SchemaDefinition struct {
Kind string
Loc *Location
Directives []*Directive
OperationTypes []*OperationTypeDefinition
}

Expand All @@ -46,6 +47,7 @@ func NewSchemaDefinition(def *SchemaDefinition) *SchemaDefinition {
return &SchemaDefinition{
Kind: kinds.SchemaDefinition,
Loc: def.Loc,
Directives: def.Directives,
OperationTypes: def.OperationTypes,
}
}
Expand Down
12 changes: 8 additions & 4 deletions language/parser/parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -877,7 +877,7 @@ func parseNamed(parser *Parser) (*ast.Named, error) {
/* Implements the parsing rules in the Type Definition section. */

/**
* SchemaDefinition : schema { OperationTypeDefinition+ }
* SchemaDefinition : schema Directives? { OperationTypeDefinition+ }
*
* OperationTypeDefinition : OperationType : NamedType
*/
Expand All @@ -887,6 +887,10 @@ func parseSchemaDefinition(parser *Parser) (*ast.SchemaDefinition, error) {
if err != nil {
return nil, err
}
directives, err := parseDirectives(parser)
if err != nil {
return nil, err
}
operationTypesI, err := many(
parser,
lexer.TokenKind[lexer.BRACE_L],
Expand All @@ -902,11 +906,11 @@ func parseSchemaDefinition(parser *Parser) (*ast.SchemaDefinition, error) {
operationTypes = append(operationTypes, op)
}
}
def := ast.NewSchemaDefinition(&ast.SchemaDefinition{
return ast.NewSchemaDefinition(&ast.SchemaDefinition{
OperationTypes: operationTypes,
Directives: directives,
Loc: loc(parser, start),
})
return def, nil
}), nil
}

func parseOperationTypeDefinition(parser *Parser) (interface{}, error) {
Expand Down
22 changes: 18 additions & 4 deletions language/printer/printer.go
Original file line number Diff line number Diff line change
Expand Up @@ -455,13 +455,27 @@ var printDocASTReducer = map[string]visitor.VisitFunc{
"SchemaDefinition": func(p visitor.VisitFuncParams) (string, interface{}) {
switch node := p.Node.(type) {
case *ast.SchemaDefinition:
operationTypesBlock := block(node.OperationTypes)
str := fmt.Sprintf("schema %v", operationTypesBlock)
directives := []string{}
for _, directive := range node.Directives {
directives = append(directives, fmt.Sprintf("%v", directive.Name))
}
str := join([]string{
"schema",
join(directives, " "),
block(node.OperationTypes),
}, " ")
return visitor.ActionUpdate, str
case map[string]interface{}:
operationTypes := toSliceString(getMapValue(node, "OperationTypes"))
operationTypesBlock := block(operationTypes)
str := fmt.Sprintf("schema %v", operationTypesBlock)
directives := []string{}
for _, directive := range getMapSliceValue(node, "Directives") {
directives = append(directives, fmt.Sprintf("%v", directive))
}
str := join([]string{
"schema",
join(directives, " "),
block(operationTypes),
}, " ")
return visitor.ActionUpdate, str
}
return visitor.ActionNoChange, nil
Expand Down
5 changes: 4 additions & 1 deletion language/visitor/visitor.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,10 @@ var QueryDocumentKeys = KeyMap{
"List": []string{"Type"},
"NonNull": []string{"Type"},

"SchemaDefinition": []string{"OperationTypes"},
"SchemaDefinition": []string{
"Directives",
"OperationTypes",
},
"OperationTypeDefinition": []string{"Type"},

"ScalarDefinition": []string{
Expand Down
3 changes: 3 additions & 0 deletions rules.go
Original file line number Diff line number Diff line change
Expand Up @@ -617,6 +617,9 @@ func getDirectiveLocationForASTPath(ancestors []ast.Node) string {
if kind == kinds.FragmentDefinition {
return DirectiveLocationFragmentDefinition
}
if kind == kinds.SchemaDefinition {
return DirectiveLocationSchema
}
if kind == kinds.ScalarDefinition {
return DirectiveLocationScalar
}
Expand Down
9 changes: 9 additions & 0 deletions rules_known_directives_rule_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,10 @@ func TestValidate_KnownDirectives_WithinSchemaLanguage_WithWellPlacedDirectives(
input MyInput @onInputObject {
myField: Int @onInputFieldDefinition
}
schema @onSchema {
query: MyQuery
}
`)
}

Expand All @@ -139,6 +143,10 @@ func TestValidate_KnownDirectives_WithinSchemaLanguage_WithMisplacedDirectives(t
input MyInput @onEnum {
myField: Int @onArgumentDefinition
}
schema @onObject {
query: MyQuery
}
`, []gqlerrors.FormattedError{
testutil.RuleError(`Directive "onInterface" may not be used on OBJECT.`, 2, 43),
testutil.RuleError(`Directive "onInputFieldDefinition" may not be used on ARGUMENT_DEFINITION.`, 3, 30),
Expand All @@ -152,5 +160,6 @@ func TestValidate_KnownDirectives_WithinSchemaLanguage_WithMisplacedDirectives(t
testutil.RuleError(`Directive "onUnion" may not be used on ENUM_VALUE.`, 15, 20),
testutil.RuleError(`Directive "onEnum" may not be used on INPUT_OBJECT.`, 18, 23),
testutil.RuleError(`Directive "onArgumentDefinition" may not be used on INPUT_FIELD_DEFINITION.`, 19, 24),
testutil.RuleError(`Directive "onObject" may not be used on SCHEMA.`, 22, 16),
})
}
4 changes: 4 additions & 0 deletions testutil/rules_test_harness.go
Original file line number Diff line number Diff line change
Expand Up @@ -485,6 +485,10 @@ func init() {
Name: "onInlineFragment",
Locations: []string{graphql.DirectiveLocationInlineFragment},
}),
graphql.NewDirective(graphql.DirectiveConfig{
Name: "onSchema",
Locations: []string{graphql.DirectiveLocationSchema},
}),
graphql.NewDirective(graphql.DirectiveConfig{
Name: "onScalar",
Locations: []string{graphql.DirectiveLocationScalar},
Expand Down

0 comments on commit 3a56b94

Please sign in to comment.