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 generic object type extensions. #1297

Merged
merged 2 commits into from
Dec 16, 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
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