public void GetGraphTypeFromType_Matrix(Type type, bool nullable, TypeMappingMode typeMappingMode, Type expectedType) { if (expectedType == null) { Should.Throw <ArgumentOutOfRangeException>(() => type.GetGraphTypeFromType(nullable, typeMappingMode)); } else { type.GetGraphTypeFromType(nullable, typeMappingMode).ShouldBe(expectedType); } }
/// <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> public static Type GetGraphTypeFromType(this Type type, bool isNullable = false, TypeMappingMode mode = TypeMappingMode.UseBuiltInScalarMappings) { while (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(IDataLoaderResult <>)) { type = type.GetGenericArguments()[0]; } if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable <>)) { type = type.GetGenericArguments()[0]; if (isNullable == false) { 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, clrElementType.IsNullable(), mode); // isNullable from elementType, not from parent array graphType = typeof(ListGraphType <>).MakeGenericType(elementType); } else if (IsAnIEnumerable(type)) { var clrElementType = GetEnumerableElementType(type); var elementType = GetGraphTypeFromType(clrElementType, clrElementType.IsNullable(), mode); // isNullable from elementType, not from parent container graphType = typeof(ListGraphType <>).MakeGenericType(elementType); } else { 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; } } if (graphType == null) { if (mode == TypeMappingMode.UseBuiltInScalarMappings || !GlobalSwitches.UseRuntimeTypeMappings) { SchemaTypes.BuiltInScalarMappings.TryGetValue(type, out graphType); } else if (!type.IsEnum) { graphType = (mode == TypeMappingMode.OutputType ? typeof(GraphQLClrOutputTypeReference <>) : typeof(GraphQLClrInputTypeReference <>)).MakeGenericType(type); } } } if (graphType == null) { 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."); } } if (!isNullable) { graphType = typeof(NonNullGraphType <>).MakeGenericType(graphType); } return(graphType); }
/// <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> public static Type GetGraphTypeFromType(this 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 (IsAnIEnumerable(type)) { var clrElementType = GetEnumerableElementType(type); 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);