Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added support for schema description and directives. #699

Merged
merged 5 commits into from
Apr 28, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

- Added new SchemaBuilder. [#369](https://github.com/ChilliCream/hotchocolate/issues/369)
- Added code-first type extensions. [#683](https://github.com/ChilliCream/hotchocolate/issues/683)
- Added code-first support for schema description. [spec](https://github.com/graphql/graphql-spec/pull/466)
- Added support for schema description. [spec](https://github.com/graphql/graphql-spec/pull/466)
- Added resolver overloads to schema builder.
- Added new UTF-8 parser
- Added support for schema directives. [spec](https://graphql.github.io/graphql-spec/June2018/#sec-Schema)

## [0.8.2] - 2019-04-10

Expand Down
14 changes: 7 additions & 7 deletions ROADMAP.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,8 @@ This document shall give and outlook of what we have planned for the next releas
- [x] FragmentDefinition
- [x] FragmentSpread
- [x] InlineFragment
- [ ] Schema (in development - 0.9.0)
- [ ] Scalar (in development - 0.9.0)
- [x] Schema
- [ ] Scalar (in development - 9.0.0)
- [x] Object
- [x] FieldDefinition
- [ ] ArgumentDefinition
Expand Down Expand Up @@ -87,8 +87,8 @@ We are currently working on the following features that are proposed for the nex

- [x] [Limit directive uniqueness to explicitly marked directives](https://github.com/facebook/graphql/pull/472)
- [x] ["Directive order is significant" section](https://github.com/facebook/graphql/pull/470)
- [ ] [Add rules for how circular references in Input Objects are handled](https://github.com/facebook/graphql/pull/445) (in development - 0.9.0)
- [ ] [Add description to Schema](https://github.com/facebook/graphql/pull/466) (in development - 0.9.0)
- [ ] [Add rules for how circular references in Input Objects are handled](https://github.com/facebook/graphql/pull/445) (in development - 9.1.0)
- [x] [Add description to Schema](https://github.com/facebook/graphql/pull/466)

## Experimental Features

Expand All @@ -108,7 +108,7 @@ We are currently working on the following features that are proposed for the nex
## Additional Directives

- [x] Schema Stitching
- [ ] HTTP Directives (in development - 0.9.0)
- [ ] HTTP Directives (in development - 9.0.0)
- [x] Custom Schema Directives
- [x] Custom Query Directives

Expand All @@ -121,15 +121,15 @@ We are currently working on the following features that are proposed for the nex

- [x] Schema-First approach
- [x] Code-First approach
- [ ] Schema Builder (in development - 0.9.0)
- [ ] Schema Builder (in development - 9.0.0)

## Supported Frameworks

- [x] ASP.NET Classic

- [x] Get
- [x] Post
- [ ] _WebSockets_ (in development - 0.10.0)
- [ ] _WebSockets_ (in development - 12.0.0)
- [x] .net Framework 4.7
- [x] .net Framework 4.6.1

Expand Down
147 changes: 101 additions & 46 deletions src/Core/Language.Tests/Parser/SchemaParserTests.cs
Original file line number Diff line number Diff line change
@@ -1,75 +1,130 @@
using Xunit;
using Snapshooter.Xunit;
using Xunit;

namespace HotChocolate.Language
{
public class SchemaParserTests
{
[Fact]
[Fact]
public void ParserSimpleObjectType()
{
// arrange
string sourceText = "type a { b: String c: Int }";
string sourceText = "type a @foo(a: \"123\") " +
"{ b: String @foo(a: \"123\") " +
"c(d: F = ENUMVALUE @foo(a: \"123\")): Int }";
var parser = new Parser();

// act
DocumentNode document = parser.Parse(sourceText);

// assert
SchemaSyntaxSerializer.Serialize(document).MatchSnapshot();
}

[Fact]
public void ParserInputObjectType()
{
// arrange
string sourceText = "input a @foo(a: \"123\") " +
"{ b: String @foo(a: \"123\") c: Int = 123 }";
var parser = new Parser();

// act
DocumentNode document = parser.Parse(sourceText);

// assert
Assert.Collection(document.Definitions,
t =>
{
Assert.IsType<ObjectTypeDefinitionNode>(t);
var objectTypeDefinition = (ObjectTypeDefinitionNode)t;
Assert.Equal(NodeKind.ObjectTypeDefinition, objectTypeDefinition.Kind);
Assert.Equal("a", objectTypeDefinition.Name.Value);
Assert.Collection(objectTypeDefinition.Fields,
f =>
{
Assert.Equal("b", f.Name.Value);
Assert.IsType<NamedTypeNode>(f.Type);
Assert.Equal("String", ((NamedTypeNode)f.Type).Name.Value);
},
f =>
{
Assert.Equal("c", f.Name.Value);
Assert.IsType<NamedTypeNode>(f.Type);
Assert.Equal("Int", ((NamedTypeNode)f.Type).Name.Value);
});
});
SchemaSyntaxSerializer.Serialize(document).MatchSnapshot();
}

[Fact]
public void ParserScalarType()
{
// arrange
string sourceText = "scalar FOO @foo(a: \"123\")";
var parser = new Parser();

// act
DocumentNode document = parser.Parse(sourceText);

// assert
SchemaSyntaxSerializer.Serialize(document).MatchSnapshot();
}

[Fact]
public void ParserSimpleInterfaceType()
{
// arrange
string sourceText = "interface a { b: String c: Int }";
string sourceText = "interface a @foo(a: \"123\") " +
"{ b: String @foo(a: \"123\") " +
"c(d: F = ENUMVALUE @foo(a: \"123\")): Int }";
var parser = new Parser();

// act
DocumentNode document = parser.Parse(sourceText);

// assert
SchemaSyntaxSerializer.Serialize(document).MatchSnapshot();
}

[Fact]
public void ParseEnum()
{
// arrange
string sourceText = "enum Foo @foo(a: \"123\") "
+ "{ BAR @foo(a: 123) , BAZ }";
var parser = new Parser();

// act
DocumentNode document = parser.Parse(sourceText);

// assert
SchemaSyntaxSerializer.Serialize(document).MatchSnapshot();
}

[Fact]
public void ParseUnion()
{
// arrange
string sourceText = "union Foo @foo(a: \"123\") = "
+ "BAR | BAZ ";
var parser = new Parser();

// act
DocumentNode document = parser.Parse(sourceText);

// assert
SchemaSyntaxSerializer.Serialize(document).MatchSnapshot();
}

[Fact]
public void ParseUnion_LeadingPipe()
{
// arrange
string sourceText = "union Foo @foo(a: \"123\") = "
+ "| BAR | BAZ ";
var parser = new Parser();

// act
DocumentNode document = parser.Parse(sourceText);

// assert
SchemaSyntaxSerializer.Serialize(document).MatchSnapshot();
}

[Fact]
public void ParseSchemaDefinition()
{
// arrange
string sourceText = "\"\"\"\nDescription\n\"\"\"" +
"schema @foo(a: \"123\") " +
"{ query: Foo mutation: Bar subscription: Baz }";
var parser = new Parser();

// act
DocumentNode document = parser.Parse(sourceText);

// assert
Assert.Collection(document.Definitions,
t =>
{
Assert.IsType<InterfaceTypeDefinitionNode>(t);
var objectTypeDefinition = (InterfaceTypeDefinitionNode)t;
Assert.Equal(NodeKind.InterfaceTypeDefinition, objectTypeDefinition.Kind);
Assert.Equal("a", objectTypeDefinition.Name.Value);
Assert.Collection(objectTypeDefinition.Fields,
f =>
{
Assert.Equal("b", f.Name.Value);
Assert.IsType<NamedTypeNode>(f.Type);
Assert.Equal("String", ((NamedTypeNode)f.Type).Name.Value);
},
f =>
{
Assert.Equal("c", f.Name.Value);
Assert.IsType<NamedTypeNode>(f.Type);
Assert.Equal("Int", ((NamedTypeNode)f.Type).Name.Value);
});
});
SchemaSyntaxSerializer.Serialize(document).MatchSnapshot();
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
enum Foo @foo(a: "123") {
BAR @foo(a: 123)
BAZ
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
"""
Description
"""
schema @foo(a: "123") {
query: Foo
mutation: Bar
subscription: Baz
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
union Foo @foo(a: "123") = BAR | BAZ
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
union Foo @foo(a: "123") = BAR | BAZ
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
input a @foo(a: "123") {
b: String @foo(a: "123")
c: Int = 123
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
scalar FOO @foo(a: "123")
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
interface a @foo(a: "123") {
b: String @foo(a: "123")
c(d: F = ENUMVALUE @foo(a: "123")): Int
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
type a @foo(a: "123") {
b: String @foo(a: "123")
c(d: F = ENUMVALUE @foo(a: "123")): Int
}
17 changes: 17 additions & 0 deletions src/Core/Language.Tests/Utf8/Utf8SchemaParserTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -118,5 +118,22 @@ public void ParseUnion_LeadingPipe()
// assert
SchemaSyntaxSerializer.Serialize(document).MatchSnapshot();
}

[Fact]
public void ParseSchemaDefinition()
{
// arrange
string sourceText = "\"\"\"\nDescription\n\"\"\"" +
"schema @foo(a: \"123\") " +
"{ query: Foo mutation: Bar subscription: Baz }";
var parser = new Utf8GraphQLParser(
Encoding.UTF8.GetBytes(sourceText));

// act
DocumentNode document = parser.Parse();

// assert
SchemaSyntaxSerializer.Serialize(document).MatchSnapshot();
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
"""
Description
"""
schema @foo(a: "123") {
query: Foo
mutation: Bar
subscription: Baz
}
3 changes: 1 addition & 2 deletions src/Core/Language/Visitors/SchemaSyntaxSerializer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,7 @@ protected override void VisitSchemaDefinition(
SchemaDefinitionNode node,
DocumentWriter writer)
{
// TODO : Add schema description support to parser
// WriteDescription(node.Description, writer);
WriteDescription(node.Description, writer);

writer.Write(Keywords.Schema);
WriteDirectives(node.Directives, writer);
Expand Down
24 changes: 24 additions & 0 deletions src/Core/Types.Tests/SchemaFirstTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,5 +30,29 @@ public async Task DescriptionsAreCorrectlyRead()
IExecutionResult result = await executor.ExecuteAsync(query);
result.MatchSnapshot();
}

[Fact]
public async Task SchemaDescription()
{
// arrange
string sourceText = "\"\"\"\nMy Schema Description\n\"\"\"" +
"schema" +
"{ query: Foo }" +
"type Foo { bar: String }";

// act
ISchema schema = Schema.Create(
sourceText,
c =>
{
c.Use(next => context => next(context));
});

// assert
IQueryExecutor executor = schema.MakeExecutable();
IExecutionResult result =
await executor.ExecuteAsync("{ __schema { description } }");
result.MatchSnapshot();
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"Data": {
"__schema": {
"description": "My Schema Description"
}
},
"Extensions": {},
"Errors": []
}
17 changes: 17 additions & 0 deletions src/Core/Types/SchemaBuilder.Create.cs
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,23 @@ private IEnumerable<ITypeReference> ParseDocuments(
visitor.MutationTypeName);
RegisterOperationName(OperationType.Subscription,
visitor.SubscriptionTypeName);

IReadOnlyCollection<DirectiveNode> directives =
visitor.Directives ?? Array.Empty<DirectiveNode>();

if (_schema == null
&& (directives.Count > 0
|| visitor.Description != null))
{
SetSchema(new Schema(d =>
{
d.Description(visitor.Description);
foreach (DirectiveNode directive in directives)
{
d.Directive(directive);
}
}));
}
}

return types;
Expand Down
6 changes: 5 additions & 1 deletion src/Core/Types/SchemaSerializer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -133,11 +133,15 @@ private static SchemaDefinitionNode SerializeSchemaTypeDefinition(
referenced));
}

var directives = schema.Directives
.Select(t => t.ToNode())
.ToList();

return new SchemaDefinitionNode
(
null,
SerializeDescription(schema.Description),
Array.Empty<DirectiveNode>(),
directives,
operations
);
}
Expand Down
Loading