Skip to content
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
183 changes: 0 additions & 183 deletions src/GraphQL.DI/DIObjectGraphType.cs
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Threading.Tasks;
using GraphQL.DataLoader;
using GraphQL.Types;
using Microsoft.Extensions.DependencyInjection;

Expand Down Expand Up @@ -95,186 +93,5 @@ protected override ArgumentInformation GetArgumentInformation<TParameterType>(Fi
argumentInfo.ApplyAttributes();
return argumentInfo;
}

#region Patch for IEnumerable
/// <inheritdoc/>
protected override TypeInformation GetTypeInformation(MemberInfo memberInfo)
{
var typeInformation = memberInfo switch
{
PropertyInfo propertyInfo => new MyTypeInformation(propertyInfo, false),
MethodInfo methodInfo => new MyTypeInformation(methodInfo),
FieldInfo fieldInfo => new MyTypeInformation(fieldInfo, false),
_ => throw new ArgumentOutOfRangeException(nameof(memberInfo), "Only properties, methods and fields are supported."),
};
typeInformation.ApplyAttributes();
return typeInformation;
}

private class MyTypeInformation : TypeInformation
{
public MyTypeInformation(PropertyInfo propertyInfo, bool isInput) : base(propertyInfo, isInput) { }
public MyTypeInformation(MethodInfo methodInfo) : base(methodInfo) { }
public MyTypeInformation(FieldInfo fieldInfo, bool isInput) : base(fieldInfo, isInput) { }

public override Type ConstructGraphType()
{
var type = GraphType;
if (type != null)
{
if (!IsNullable)
type = typeof(NonNullGraphType<>).MakeGenericType(type);
}
else
{
type = GetGraphTypeFromType(Type, IsNullable, IsInputType ? TypeMappingMode.InputType : TypeMappingMode.OutputType);
}
if (IsList)
{
type = typeof(ListGraphType<>).MakeGenericType(type);
if (!ListIsNullable)
type = typeof(NonNullGraphType<>).MakeGenericType(type);
}
return type;
}

/// <summary>
/// Gets the graph type for the indicated type.
/// </summary>
/// <param name="type">The type for which a graph type is desired.</param>
/// <param name="isNullable">if set to <c>false</c> if the type explicitly non-nullable.</param>
/// <param name="mode">Mode to use when mapping CLR type to GraphType.</param>
/// <returns>A Type object representing a GraphType that matches the indicated type.</returns>
/// <remarks>This can handle arrays, lists and other collections implementing IEnumerable.</remarks>
private static Type GetGraphTypeFromType(Type type, bool isNullable = false, TypeMappingMode mode = TypeMappingMode.UseBuiltInScalarMappings)
{
while (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(IDataLoaderResult<>))
{
type = type.GetGenericArguments()[0];
}

if (type == typeof(IDataLoaderResult))
{
type = typeof(object);
}

if (typeof(Task).IsAssignableFrom(type))
throw new ArgumentOutOfRangeException(nameof(type), "Task types cannot be coerced to a graph type; please unwrap the task type before calling this method.");

if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>))
{
type = type.GetGenericArguments()[0];
if (!isNullable)
{
throw new ArgumentOutOfRangeException(nameof(isNullable),
$"Explicitly nullable type: Nullable<{type.Name}> cannot be coerced to a non nullable GraphQL type.");
}
}

Type? graphType = null;

if (type.IsArray)
{
var clrElementType = type.GetElementType()!;
var elementType = GetGraphTypeFromType(clrElementType, IsNullableType(clrElementType), mode); // isNullable from elementType, not from parent array
graphType = typeof(ListGraphType<>).MakeGenericType(elementType);
}
else if (TryGetEnumerableElementType(type, out var clrElementType))
{
var elementType = GetGraphTypeFromType(clrElementType!, IsNullableType(clrElementType!), mode); // isNullable from elementType, not from parent container
graphType = typeof(ListGraphType<>).MakeGenericType(elementType);
}
else
{
#pragma warning disable CS0618 // Type or member is obsolete
var attr = type.GetCustomAttribute<GraphQLMetadataAttribute>();
if (attr != null)
{
if (mode == TypeMappingMode.InputType)
graphType = attr.InputType;
else if (mode == TypeMappingMode.OutputType)
graphType = attr.OutputType;
else if (attr.InputType == attr.OutputType) // scalar
graphType = attr.InputType;
}
#pragma warning restore CS0618 // Type or member is obsolete

if (mode == TypeMappingMode.InputType)
{
var inputAttr = type.GetCustomAttribute<InputTypeAttribute>();
if (inputAttr != null)
graphType = inputAttr.InputType;
}
else if (mode == TypeMappingMode.OutputType)
{
var outputAttr = type.GetCustomAttribute<OutputTypeAttribute>();
if (outputAttr != null)
graphType = outputAttr.OutputType;
}

if (graphType == null)
{
if (mode == TypeMappingMode.UseBuiltInScalarMappings)
{
if (!SchemaTypes.BuiltInScalarMappings.TryGetValue(type, out graphType))
{
if (type.IsEnum)
{
graphType = typeof(EnumerationGraphType<>).MakeGenericType(type);
}
else
{
throw new ArgumentOutOfRangeException(nameof(type), $"The CLR type '{type.FullName}' cannot be coerced effectively to a GraphQL type.");
}
}
}
else
{
graphType = (mode == TypeMappingMode.OutputType ? typeof(GraphQLClrOutputTypeReference<>) : typeof(GraphQLClrInputTypeReference<>)).MakeGenericType(type);
}
}
}

if (!isNullable)
{
graphType = typeof(NonNullGraphType<>).MakeGenericType(graphType);
}

return graphType;

//TODO: rewrite nullability condition in v5
static bool IsNullableType(Type type) => !type.IsValueType || type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>);
}

private static readonly Type[] _enumerableTypes = new[] {
typeof(IEnumerable<>),
typeof(IList<>),
typeof(List<>),
typeof(ICollection<>),
typeof(IReadOnlyCollection<>),
typeof(IReadOnlyList<>),
typeof(HashSet<>),
typeof(ISet<>),
};

private static bool TryGetEnumerableElementType(Type type, out Type? elementType)
{
if (type == typeof(IEnumerable))
{
elementType = typeof(object);
return true;
}

if (!type.IsGenericType || !_enumerableTypes.Contains(type.GetGenericTypeDefinition()))
{
elementType = null;
return false;
}

elementType = type.GetGenericArguments()[0];
return true;
}
}
#endregion
}
}
2 changes: 0 additions & 2 deletions src/GraphQL.DI/GraphQLBuilderExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using GraphQL.Types;

namespace GraphQL.DI
{
Expand Down