Skip to content

Commit

Permalink
Added fluent API support for Relay IDs. (#2166)
Browse files Browse the repository at this point in the history
  • Loading branch information
michaelstaib committed Jul 26, 2020
1 parent 5b658df commit 97e3cf7
Show file tree
Hide file tree
Showing 9 changed files with 389 additions and 133 deletions.
166 changes: 166 additions & 0 deletions src/Core/Types.Tests/Types/Relay/IdDescriptorTests.cs
@@ -0,0 +1,166 @@
using System;
using System.Threading.Tasks;
using HotChocolate.Execution;
using Snapshooter.Xunit;
using Xunit;

namespace HotChocolate.Types.Relay
{
public class IdDescriptorTests
{
[Fact]
public async Task Id_On_Arguments()
{
// arrange
var idSerializer = new IdSerializer();
string intId = idSerializer.Serialize("Query", 1);
string stringId = idSerializer.Serialize("Query", "abc");
string guidId = idSerializer.Serialize("Query", Guid.Empty);

// act
IExecutionResult result =
await SchemaBuilder.New()
.AddQueryType<QueryType>()
.AddType<FooPayloadType>()
.Create()
.MakeExecutable()
.ExecuteAsync(
QueryRequestBuilder.New()
.SetQuery(
@"query foo ($intId: ID! $stringId: ID! $guidId: ID!) {
intId(id: $intId)
stringId(id: $stringId)
guidId(id: $guidId)
}")
.SetVariableValue("intId", intId)
.SetVariableValue("stringId", stringId)
.SetVariableValue("guidId", guidId)
.Create());

// assert
result.ToJson().MatchSnapshot();
}

[Fact]
public async Task Id_On_Objects()
{
// arrange
var idSerializer = new IdSerializer();
string someId = idSerializer.Serialize("Some", 1);

// act
IExecutionResult result =
await SchemaBuilder.New()
.AddQueryType<QueryType>()
.AddType<FooPayloadType>()
.Create()
.MakeExecutable()
.ExecuteAsync(
QueryRequestBuilder.New()
.SetQuery(
@"query foo ($someId: ID!) {
foo(input: { someId: $someId }) {
someId
}
}")
.SetVariableValue("someId", someId)
.Create());

// assert
new
{
result = result.ToJson(),
someId
}.MatchSnapshot();
}

[Fact]
public void Id_Type_Is_Correctly_Inferred()
{
SchemaBuilder.New()
.AddQueryType<QueryType>()
.AddType<FooPayloadType>()
.Create()
.ToString()
.MatchSnapshot();
}

public class QueryType : ObjectType<Query>
{
protected override void Configure(IObjectTypeDescriptor<Query> descriptor)
{
descriptor
.Field(t => t.IntId(default))
.Argument("id", a => a.ID());

descriptor
.Field(t => t.StringId(default))
.Argument("id", a => a.ID());

descriptor
.Field(t => t.GuidId(default))
.Argument("id", a => a.ID());

descriptor
.Field(t => t.Foo(default))
.Argument("input", a => a.Type<FooInputType>())
.Type<FooPayloadInterfaceType>();
}
}

public class FooInputType : InputObjectType<FooInput>
{
protected override void Configure(IInputObjectTypeDescriptor<FooInput> descriptor)
{
descriptor
.Field(t => t.SomeId)
.ID("Some");
}
}

public class FooPayloadType : ObjectType<FooPayload>
{
protected override void Configure(IObjectTypeDescriptor<FooPayload> descriptor)
{
descriptor.Implements<FooPayloadInterfaceType>();

descriptor
.Field(t => t.SomeId)
.ID("Bar");
}
}

public class FooPayloadInterfaceType : InterfaceType<IFooPayload>
{
protected override void Configure(IInterfaceTypeDescriptor<IFooPayload> descriptor)
{
descriptor
.Field(t => t.SomeId)
.ID();
}
}

public class Query
{
public string IntId(int id) => id.ToString();
public string StringId(string id) => id.ToString();
public string GuidId(Guid id) => id.ToString();
public IFooPayload Foo(FooInput input) => new FooPayload { SomeId = input.SomeId };
}

public class FooInput
{
public string SomeId { get; set; }
}

public class FooPayload : IFooPayload
{
public string SomeId { get; set; }
}

public interface IFooPayload
{
string SomeId { get; set; }
}
}
}
1 change: 1 addition & 0 deletions src/Core/Types.Tests/Types/Relay/NodeResolverTests.cs
@@ -1,6 +1,7 @@
using System.Threading.Tasks;
using HotChocolate.Execution;
using HotChocolate.Language;
using HotChocolate.Types.Relay;
using Snapshooter.Xunit;
using Xunit;

Expand Down
@@ -0,0 +1 @@
{"data":{"intId":"1","stringId":"abc","guidId":"00000000-0000-0000-0000-000000000000"}}
@@ -0,0 +1,4 @@
{
"result": "{\"data\":{\"foo\":{\"someId\":\"QmFyCmQx\"}}}",
"someId": "U29tZQppMQ=="
}
@@ -0,0 +1,28 @@
schema {
query: Query
}

interface IFooPayload {
someId: ID
}

type FooPayload implements IFooPayload {
someId: ID
}

type Query {
foo(input: FooInput): IFooPayload
guidId(id: ID!): String
intId(id: ID!): String
stringId(id: ID): String
}

input FooInput {
someId: ID
}

"The `ID` scalar type represents a unique identifier, often used to refetch an object or as key for a cache. The ID type appears in a JSON response as a String; however, it is not intended to be human-readable. When expected as an input type, any string (such as `\"4\"`) or integer (such as `4`) input value will be accepted as an ID."
scalar ID

"The `String` scalar type represents textual data, represented as UTF-8 character sequences. The String type is most often used by GraphQL to represent free-form human-readable text."
scalar String
@@ -1,13 +1,7 @@
using System;
using System.Reflection;
using System.Threading.Tasks;
using HotChocolate.Resolvers;
using HotChocolate.Types;
using HotChocolate.Types.Relay;
using HotChocolate.Types.Relay.Descriptors;
using HotChocolate.Utilities;

namespace HotChocolate
namespace HotChocolate.Types.Relay
{
public static class NodeObjectTypeExtensions
{
Expand Down

0 comments on commit 97e3cf7

Please sign in to comment.