Skip to content

Commit

Permalink
Added support for generic object type extensions. (#1297)
Browse files Browse the repository at this point in the history
  • Loading branch information
michaelstaib authored Dec 16, 2019
1 parent e6c189b commit 1252157
Show file tree
Hide file tree
Showing 16 changed files with 402 additions and 184 deletions.
30 changes: 30 additions & 0 deletions src/Core/Types.Tests/Types/EnumTypeTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -489,6 +489,16 @@ public void Deprecate_Fields_With_Deprecated_Attribute()
schema.ToString().MatchSnapshot();
}

[Fact]
public void EnumType_That_Is_Bound_To_String_Should_Not_Interfere_With_Scalar()
{
SchemaBuilder.New()
.AddQueryType<SomeQueryType>()
.Create()
.ToString()
.MatchSnapshot();
}

public enum Foo
{
Bar1,
Expand All @@ -511,5 +521,25 @@ public enum FooDeprecated
[GraphQLDeprecated("Baz.")]
Bar2
}

public class SomeQueryType : ObjectType
{
protected override void Configure(IObjectTypeDescriptor descriptor)
{
descriptor.Name("Query");
descriptor.Field("a").Type<SomeEnumType>().Resolver("DEF");
descriptor.Field("b").Type<StringType>().Resolver("StringResolver");
}
}

public class SomeEnumType
: EnumType<string>
{
protected override void Configure(IEnumTypeDescriptor<string> descriptor)
{
descriptor.Name("Some");
descriptor.Value("ABC").Name("DEF");
}
}
}
}
70 changes: 68 additions & 2 deletions src/Core/Types.Tests/Types/ObjectTypeExtensionTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,57 @@ public void ObjectTypeExtension_AddField()
Assert.True(type.Fields.ContainsField("test"));
}

[Fact]
public void ObjectTypeExtension_Infer_Field()
{
// arrange
// act
ISchema schema = SchemaBuilder.New()
.AddQueryType<FooType>()
.AddType<GenericFooTypeExtension>()
.Create();

// assert
ObjectType type = schema.GetType<ObjectType>("Foo");
Assert.True(type.Fields.ContainsField("test"));
}

[Fact]
public void ObjectTypeExtension_Declare_Field()
{
// arrange
// act
ISchema schema = SchemaBuilder.New()
.AddQueryType<FooType>()
.AddType(new ObjectTypeExtension<FooExtension>(d =>
{
d.Name("Foo");
d.Field(t => t.Test).Type<IntType>();
}))
.Create();

// assert
ObjectType type = schema.GetType<ObjectType>("Foo");
Assert.True(type.Fields.ContainsField("test"));
Assert.IsType<IntType>(type.Fields["test"].Type);
}

[Fact]
public async Task ObjectTypeExtension_Execute_Infer_Field()
{
// arrange
// act
IQueryExecutor executor = SchemaBuilder.New()
.AddQueryType<FooType>()
.AddType<GenericFooTypeExtension>()
.Create()
.MakeExecutable();

// assert
IExecutionResult result = await executor.ExecuteAsync("{ test }");
result.MatchSnapshot();
}

[Fact]
public void ObjectTypeExtension_OverrideResolver()
{
Expand Down Expand Up @@ -124,7 +175,7 @@ public void ObjectTypeExtension_DeprecateField_Obsolete()
}

[Fact]
public void ObjectTypeExtension_DepricateField_With_Reason()
public void ObjectTypeExtension_DeprecateField_With_Reason()
{
// arrange
FieldResolverDelegate resolver =
Expand All @@ -148,7 +199,7 @@ public void ObjectTypeExtension_DepricateField_With_Reason()
}

[Fact]
public void ObjectTypeExtension_DepricateField_Without_Reason()
public void ObjectTypeExtension_DeprecateField_Without_Reason()
{
// arrange
FieldResolverDelegate resolver =
Expand Down Expand Up @@ -484,6 +535,16 @@ protected override void Configure(
}
}

public class GenericFooTypeExtension
: ObjectTypeExtension<FooExtension>
{
protected override void Configure(
IObjectTypeDescriptor<FooExtension> descriptor)
{
descriptor.Name("Foo");
}
}

public class Foo
{
public string Description { get; } = "hello";
Expand All @@ -494,6 +555,11 @@ public string GetName(string a)
}
}

public class FooExtension
{
public string Test { get; set; } = "Test123";
}

public class FooResolver
{
public string GetName2()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
schema {
query: Query
}

type Query {
a: Some
b: String
}

enum Some {
DEF
}

"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

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"Data": {
"test": "Test123"
},
"Extensions": {},
"Errors": [],
"ContextData": {}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using System.Collections;
using System;
using System.Collections.Generic;
using HotChocolate.Language;

Expand All @@ -7,13 +7,23 @@ namespace HotChocolate.Types.Descriptors.Definitions
public class ObjectTypeDefinition
: TypeDefinitionBase<ObjectTypeDefinitionNode>
{
public override Type ClrType
{
get => base.ClrType;
set
{
base.ClrType = value;
FieldBindingType = value;
}
}

public Type FieldBindingType { get; set; }

public IsOfType IsOfType { get; set; }

public ICollection<ITypeReference> Interfaces { get; } =
new List<ITypeReference>();

public BindingBehavior FieldBindingBehavior { get; set; }

public IBindableList<ObjectFieldDefinition> Fields { get; } =
new BindableList<ObjectFieldDefinition>();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ protected TypeDefinitionBase() { }
/// <summary>
/// Gets or sets the .net type representation of this type.
/// </summary>
public Type ClrType
public virtual Type ClrType
{
get => _clrType;
set
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,28 @@ public static void AddImplicitFields<TDescriptor, TMember, TField>(
where TMember : MemberInfo
where TField : FieldDefinitionBase
{
if (descriptor.ClrType != typeof(object))
AddImplicitFields<TDescriptor, TMember, TField>(
descriptor,
descriptor.ClrType,
createdFieldDefinition,
fields,
handledMembers);
}

public static void AddImplicitFields<TDescriptor, TMember, TField>(
TDescriptor descriptor,
Type fieldBindingType,
Func<TMember, TField> createdFieldDefinition,
IDictionary<NameString, TField> fields,
ISet<TMember> handledMembers)
where TDescriptor : IHasDescriptorContext
where TMember : MemberInfo
where TField : FieldDefinitionBase
{
if (fieldBindingType != typeof(object))
{
foreach (TMember member in descriptor.Context.Inspector
.GetMembers(descriptor.ClrType)
.GetMembers(fieldBindingType)
.OfType<TMember>())
{
TField fieldDefinition = createdFieldDefinition(member);
Expand Down
6 changes: 2 additions & 4 deletions src/Core/Types/Types/Descriptors/InterfaceTypeDescriptor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,8 @@ protected InterfaceTypeDescriptor(
}

Definition.ClrType = clrType;
Definition.Name =
context.Naming.GetTypeName(clrType, TypeKind.Interface);
Definition.Description =
context.Naming.GetTypeDescription(clrType, TypeKind.Interface);
Definition.Name = context.Naming.GetTypeName(clrType, TypeKind.Interface);
Definition.Description = context.Naming.GetTypeDescription(clrType, TypeKind.Interface);
}

protected InterfaceTypeDescriptor(
Expand Down
4 changes: 4 additions & 0 deletions src/Core/Types/Types/Descriptors/ObjectTypeDescriptor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -309,6 +309,10 @@ public static ObjectTypeDescriptor<T> New<T>(
IDescriptorContext context) =>
new ObjectTypeDescriptor<T>(context);

public static ObjectTypeExtensionDescriptor<T> NewExtension<T>(
IDescriptorContext context) =>
new ObjectTypeExtensionDescriptor<T>(context);

public static ObjectTypeDescriptor FromSchemaType(
IDescriptorContext context,
Type schemaType)
Expand Down
Loading

0 comments on commit 1252157

Please sign in to comment.