Skip to content

Commit

Permalink
Fixed and issue that caused the implements of object type to not be m…
Browse files Browse the repository at this point in the history
…erged when interfaces where added to the object type extension V10 (#1544)
  • Loading branch information
michaelstaib authored Mar 11, 2020
1 parent 58b06a6 commit 66679d5
Show file tree
Hide file tree
Showing 16 changed files with 955 additions and 827 deletions.
2 changes: 1 addition & 1 deletion src/Core/Core/Execution/Utilities/FieldCollector.cs
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,7 @@ private static bool DoesTypeApply(
}
else if (typeCondition is InterfaceType it)
{
return current.Interfaces.ContainsKey(it.Name);
return current.IsAssignableFrom(it.Name);
}
else if (typeCondition is UnionType ut)
{
Expand Down
2 changes: 1 addition & 1 deletion src/Core/Types.Tests/Types/InterfaceTypeTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ public void InferSchemaInterfaceTypeFromClrInterface()

// assert
ObjectType type = schema.GetType<ObjectType>("FooImpl");
Assert.Collection(type.Interfaces.Values,
Assert.Collection(type.Interfaces,
t => Assert.Equal("IFoo", t.Name));
}

Expand Down
9 changes: 4 additions & 5 deletions src/Core/Types.Tests/Types/ObjectTypeTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ public void IntializeExplicitFieldWithImplicitResolver()
}

[Fact]
public void IntArgumentIsInferedAsNonNullType()
public void IntArgumentIsInferredAsNonNullType()
{
// arrange
// act
Expand Down Expand Up @@ -153,7 +153,7 @@ public async Task FieldMiddlewareIsIntegrated()

[Obsolete]
[Fact]
public void DeprecationReasion_Obsolete()
public void DeprecationReason_Obsolete()
{
// arrange
var resolverContext = new Mock<IMiddlewareContext>();
Expand Down Expand Up @@ -1185,8 +1185,7 @@ public void InferInterfaceImplementation()
b => b.AddType(new InterfaceType<IFoo>()));

// assert
Assert.IsType<InterfaceType<IFoo>>(
fooType.Interfaces.Values.First());
Assert.IsType<InterfaceType<IFoo>>(fooType.Interfaces[0]);
}

[Fact]
Expand Down Expand Up @@ -1301,7 +1300,7 @@ public void Support_Argument_Attributes()
}

[Fact]
public void Argument_Type_IsInfered_From_Parameter()
public void Argument_Type_IsInferred_From_Parameter()
{
// arrange
// act
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
schema {
query: QueryWithIntArg
}

type QueryWithIntArg {
bar(foo: Int!): String
}

"The `Int` scalar type represents non-fractional signed whole numeric values. Int can represent values between -(2^31) and 2^31 - 1."
scalar Int

"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

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions src/Core/Types/Configuration/TypeTrimmer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ private void VisitObject(ObjectType type)
{
VisitDirectives(type);

foreach (InterfaceType interfaceType in type.Interfaces.Values)
foreach (InterfaceType interfaceType in type.Interfaces)
{
VisitInterface(interfaceType, true);
}
Expand Down Expand Up @@ -129,7 +129,7 @@ private void VisitInterface(InterfaceType type, bool implements = false)
foreach (ObjectType objectType in
_discoveredTypes.Types.Select(t => t.Type).OfType<ObjectType>())
{
if (objectType.Interfaces.ContainsKey(type.Name))
if (objectType.IsAssignableFrom(type))
{
Visit(objectType);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ private static void ValidateInterfaceImplementation(
if (objectType.Interfaces.Count > 0)
{
foreach (IGrouping<NameString, InterfaceField> fieldGroup in
objectType.Interfaces.Values
objectType.Interfaces
.SelectMany(t => t.Fields)
.GroupBy(t => t.Name))
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ public IEnumerable<ISchemaError> Validate(

foreach (ObjectType objectType in typeSystemObjects.OfType<ObjectType>())
{
foreach (InterfaceType interfaceType in objectType.Interfaces.Values)
foreach (InterfaceType interfaceType in objectType.Interfaces)
{
interfaceTypes.Remove(interfaceType);
}
Expand Down
2 changes: 1 addition & 1 deletion src/Core/Types/Schema.cs
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ public IReadOnlyCollection<ObjectType> GetPossibleTypes(

if (_types.TryGetPossibleTypes(
abstractType.Name,
out ImmutableList<ObjectType> types))
out IReadOnlyList<ObjectType> types))
{
return types;
}
Expand Down
2 changes: 1 addition & 1 deletion src/Core/Types/SchemaSerializer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -226,7 +226,7 @@ private static ObjectTypeDefinitionNode SerializeObjectType(
.Select(t => SerializeDirective(t, referenced))
.ToList();

var interfaces = objectType.Interfaces.Values
var interfaces = objectType.Interfaces
.Select(t => SerializeNamedType(t, referenced))
.ToList();

Expand Down
33 changes: 18 additions & 15 deletions src/Core/Types/SchemaTypes.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using HotChocolate.Types;

Expand All @@ -9,7 +8,7 @@ namespace HotChocolate
internal sealed class SchemaTypes
{
private readonly Dictionary<NameString, INamedType> _types;
private readonly Dictionary<NameString, ImmutableList<ObjectType>> _possibleTypes;
private readonly Dictionary<NameString, List<ObjectType>> _possibleTypes;

public SchemaTypes(SchemaTypesDefinition definition)
{
Expand Down Expand Up @@ -37,9 +36,10 @@ public T GetType<T>(NameString typeName) where T : IType
return type;
}

// TODO : resource
throw new ArgumentException(
"The specified type does not exist or " +
"is not of the specified kind.",
$"The specified type `{typeName}` does not exist or " +
$"is not of the specified kind `{typeof(T).Name}`.",
nameof(typeName));
}

Expand Down Expand Up @@ -78,24 +78,28 @@ public bool TryGetClrType(NameString typeName, out Type clrType)

public bool TryGetPossibleTypes(
string abstractTypeName,
out ImmutableList<ObjectType> types)
out IReadOnlyList<ObjectType> types)
{
return _possibleTypes.TryGetValue(abstractTypeName, out types);
if (_possibleTypes.TryGetValue(abstractTypeName, out List<ObjectType> pt))
{
types = pt;
return true;
}

types = null;
return false;
}

private static Dictionary<NameString, ImmutableList<ObjectType>> CreatePossibleTypeLookup(
private static Dictionary<NameString, List<ObjectType>> CreatePossibleTypeLookup(
IReadOnlyCollection<INamedType> types)
{
var possibleTypes =
new Dictionary<NameString, List<ObjectType>>();
var possibleTypes = new Dictionary<NameString, List<ObjectType>>();

foreach (ObjectType objectType in types.OfType<ObjectType>())
{
foreach (InterfaceType interfaceType in
objectType.Interfaces.Values)
foreach (InterfaceType interfaceType in objectType.Interfaces)
{
if (!possibleTypes.TryGetValue(
interfaceType.Name, out List<ObjectType> pt))
if (!possibleTypes.TryGetValue(interfaceType.Name, out List<ObjectType> pt))
{
pt = new List<ObjectType>();
possibleTypes[interfaceType.Name] = pt;
Expand All @@ -120,8 +124,7 @@ private static Dictionary<NameString, ImmutableList<ObjectType>> CreatePossibleT
}
}

return possibleTypes.ToDictionary(
t => t.Key, t => t.Value.ToImmutableList());
return possibleTypes.ToDictionary(t => t.Key, t => t.Value);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ public override Type ClrType

public Type FieldBindingType { get; set; }

public IList<Type> KnownClrTypes { get; } = new List<Type>();

public IsOfType IsOfType { get; set; }

public ICollection<ITypeReference> Interfaces { get; } =
Expand All @@ -27,8 +29,7 @@ public override Type ClrType
public IBindableList<ObjectFieldDefinition> Fields { get; } =
new BindableList<ObjectFieldDefinition>();

internal override IEnumerable<ILazyTypeConfiguration>
GetConfigurations()
internal override IEnumerable<ILazyTypeConfiguration> GetConfigurations()
{
var configs = new List<ILazyTypeConfiguration>();
configs.AddRange(Configurations);
Expand Down
18 changes: 18 additions & 0 deletions src/Core/Types/Types/Helpers/TypeExtensionHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,24 @@ public static void MergeContextData(
}
}

public static void MergeInterfaces(
ObjectTypeDefinition extension,
ObjectTypeDefinition type)
{
if (extension.Interfaces.Count > 0)
{
foreach (var interfaceReference in extension.Interfaces)
{
type.Interfaces.Add(interfaceReference);
}
}

if (extension.FieldBindingType != typeof(object))
{
type.KnownClrTypes.Add(extension.FieldBindingType);
}
}

public static void MergeTypes(
ICollection<ITypeReference> extensionTypes,
ICollection<ITypeReference> typeTypes)
Expand Down
2 changes: 1 addition & 1 deletion src/Core/Types/Types/Introspection/__Type.cs
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ private IEnumerable<InterfaceType> GetInterfaces(IType type)
{
if (type is ObjectType ot)
{
return ot.Interfaces.Values;
return ot.Interfaces;
}
return null;
}
Expand Down
58 changes: 40 additions & 18 deletions src/Core/Types/Types/ObjectType.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Reflection;
using HotChocolate.Configuration;
using HotChocolate.Language;
using HotChocolate.Resolvers;
Expand All @@ -19,9 +18,8 @@ public class ObjectType
, IHasClrType
, IHasSyntaxNode
{
private readonly Dictionary<NameString, InterfaceType> _interfaces =
new Dictionary<NameString, InterfaceType>();
private readonly Action<IObjectTypeDescriptor> _configure;
private readonly List<InterfaceType> _interfaces = new List<InterfaceType>();
private Action<IObjectTypeDescriptor> _configure;
private IsOfType _isOfType;

protected ObjectType()
Expand All @@ -40,17 +38,20 @@ public ObjectType(Action<IObjectTypeDescriptor> configure)

ISyntaxNode IHasSyntaxNode.SyntaxNode => SyntaxNode;

public IReadOnlyDictionary<NameString, InterfaceType> Interfaces =>
_interfaces;
public IReadOnlyList<InterfaceType> Interfaces => _interfaces;

public FieldCollection<ObjectField> Fields { get; private set; }

IFieldCollection<IOutputField> IComplexOutputType.Fields => Fields;

public bool IsOfType(IResolverContext context, object resolverResult)
=> _isOfType(context, resolverResult);
public bool IsOfType(IResolverContext context, object resolverResult) =>
_isOfType(context, resolverResult);

#region Initialization
public bool IsAssignableFrom(NameString interfaceTypeName) =>
_interfaces.Any(t => t.Name.Equals(interfaceTypeName));

public bool IsAssignableFrom(InterfaceType interfaceType) =>
_interfaces.Contains(interfaceType);

protected override ObjectTypeDefinition CreateDefinition(
IInitializationContext context)
Expand All @@ -59,6 +60,7 @@ protected override ObjectTypeDefinition CreateDefinition(
context.DescriptorContext,
GetType());
_configure(descriptor);
_configure = null;
return descriptor.CreateDefinition();
}

Expand Down Expand Up @@ -129,14 +131,16 @@ private void CompleteInterfaces(
{
if (ClrType != typeof(object))
{
foreach (Type interfaceType in ClrType.GetInterfaces())
TryInferInterfaceUsageFromClrType(context, ClrType);
}

if (definition.KnownClrTypes.Count > 0)
{
definition.KnownClrTypes.Remove(typeof(object));

foreach (Type clrType in definition.KnownClrTypes.Distinct())
{
if (context.TryGetType(
new ClrTypeReference(interfaceType, TypeContext.Output),
out InterfaceType type))
{
_interfaces[type.Name] = type;
}
TryInferInterfaceUsageFromClrType(context, clrType);
}
}

Expand All @@ -153,7 +157,26 @@ private void CompleteInterfaces(
.Build());
}

_interfaces[type.Name] = type;
if (!_interfaces.Contains(type))
{
_interfaces.Add(type);
}
}
}

private void TryInferInterfaceUsageFromClrType(
ICompletionContext context,
Type clrType)
{
foreach (Type interfaceType in clrType.GetInterfaces())
{
if (context.TryGetType(
new ClrTypeReference(interfaceType, TypeContext.Output),
out InterfaceType type)
&& !_interfaces.Contains(type))
{
_interfaces.Add(type);
}
}
}

Expand Down Expand Up @@ -230,6 +253,5 @@ private bool IsOfTypeWithName(
Type type = result.GetType();
return Name.Equals(type.Name);
}
#endregion
}
}
4 changes: 4 additions & 0 deletions src/Core/Types/Types/ObjectTypeExtension.cs
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,10 @@ internal override void Merge(
Definition.Fields,
objectType.Definition.Fields);

TypeExtensionHelper.MergeInterfaces(
Definition,
objectType.Definition);

TypeExtensionHelper.MergeConfigurations(
Definition.Configurations,
objectType.Definition.Configurations);
Expand Down

0 comments on commit 66679d5

Please sign in to comment.