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
Original file line number Diff line number Diff line change
Expand Up @@ -39,21 +39,15 @@ protected void Deprecated(string? reason)

/// <inheritdoc cref="IArgumentDescriptor.Deprecated()"/>
protected void Deprecated()
{
Configuration.DeprecationReason = DirectiveNames.Deprecated.Arguments.DefaultReason;
}
=> Configuration.DeprecationReason = DirectiveNames.Deprecated.Arguments.DefaultReason;

/// <inheritdoc cref="IArgumentDescriptor.Description(string)"/>
protected void Description(string value)
{
Configuration.Description = value;
}
/// <inheritdoc cref="IArgumentDescriptor.Description(string?)"/>
protected void Description(string? value)
=> Configuration.Description = value;

/// <inheritdoc cref="IArgumentDescriptor.Type{TInputType}()"/>
public void Type<TInputType>() where TInputType : IInputType
{
Type(typeof(TInputType));
}
=> Type(typeof(TInputType));

/// <summary>
/// Sets the type of the argument
Expand All @@ -71,6 +65,8 @@ public void Type<TInputType>() where TInputType : IInputType
/// </summary>
public void Type(Type type)
{
ArgumentNullException.ThrowIfNull(type);

var typeInfo = Context.TypeInspector.CreateTypeInfo(type);

if (typeInfo.IsSchemaType && !typeInfo.IsInputType())
Expand Down Expand Up @@ -133,7 +129,7 @@ public void Type(ITypeNode typeNode)
Configuration.SetMoreSpecificType(typeNode, TypeContext.Input);
}

/// <inheritdoc cref="IArgumentDescriptor.DefaultValue(IValueNode)"/>
/// <inheritdoc cref="IArgumentDescriptor.DefaultValue(IValueNode?)"/>
public void DefaultValue(IValueNode? value)
{
Configuration.DefaultValue = value ?? NullValueNode.Default;
Expand All @@ -150,6 +146,11 @@ public void DefaultValue(object? value)
}
else
{
if (TryCoerceEnumUnderlyingValue(value, out var enumValue))
{
value = enumValue;
}

var type = Context.TypeInspector.GetType(value.GetType());
Configuration.SetMoreSpecificType(type, TypeContext.Input);
Configuration.RuntimeDefaultValue = value;
Expand All @@ -168,4 +169,32 @@ public void Directive<TDirective>(TDirective directiveInstance) where TDirective
/// <inheritdoc cref="IArgumentDescriptor.Directive(string, ArgumentNode[])"/>
public void Directive(string name, params ArgumentNode[] arguments)
=> Configuration.AddDirective(name, arguments);

private bool TryCoerceEnumUnderlyingValue(object value, out object enumValue)
{
enumValue = default!;

if (Configuration.Type is not ExtendedTypeReference typeReference)
{
return false;
}

var clrType = Nullable.GetUnderlyingType(typeReference.Type.Source)
?? typeReference.Type.Source;

if (!clrType.IsEnum)
{
return false;
}

var underlyingType = Enum.GetUnderlyingType(clrType);

if (value.GetType() != underlyingType)
{
return false;
}

enumValue = Enum.ToObject(clrType, value);
return true;
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
#nullable disable

using HotChocolate.Language;
using HotChocolate.Types.Descriptors.Configurations;

Expand All @@ -26,7 +24,7 @@ public interface IArgumentDescriptor
/// </code>
/// </example>
/// </summary>
IArgumentDescriptor Deprecated(string reason);
IArgumentDescriptor Deprecated(string? reason);

/// <summary>
/// Marks the argument as deprecated
Expand Down Expand Up @@ -65,7 +63,7 @@ public interface IArgumentDescriptor
/// </example>
/// </summary>
/// <param name="value">The description</param>
IArgumentDescriptor Description(string value);
IArgumentDescriptor Description(string? value);

/// <summary>
/// Sets the type of the argument
Expand Down Expand Up @@ -149,7 +147,7 @@ IArgumentDescriptor Type<TInputType>(TInputType inputType)
/// </example>
/// </summary>
/// <param name="value"></param>
IArgumentDescriptor DefaultValue(IValueNode value);
IArgumentDescriptor DefaultValue(IValueNode? value);

/// <summary>
/// Sets the default value of this argument
Expand All @@ -166,7 +164,7 @@ IArgumentDescriptor Type<TInputType>(TInputType inputType)
/// </example>
/// </summary>
/// <param name="value"></param>
IArgumentDescriptor DefaultValue(object value);
IArgumentDescriptor DefaultValue(object? value);

/// <summary>
/// Sets a directive on the argument
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
namespace HotChocolate.Types;

public class Issue7040ReproTests
{
[Fact]
public void Enum_DefaultValueAttribute_With_Integer_Default_Does_Not_Downgrade_To_Int()
{
SchemaBuilder.New()
.AddInputObjectType<InputWithEnumIntDefault>()
.ModifyOptions(o => o.StrictValidation = false)
.Create()
.MatchSnapshot();
}

public class InputWithEnumIntDefault
{
// The F# compiler boxes enum values as their underlying type when passed
// to attribute constructors that accept object. So [<DefaultValue(MyEnum.Value1)>]
// in F# arrives at runtime as [DefaultValue(0)] rather than [DefaultValue(MyEnum.Value1)].
// We use the integer literal here to reproduce that behavior in C#.
[DefaultValue(0)]
public Issue7040Enum Enum { get; set; }
}

public enum Issue7040Enum
{
Value1 = 0,
Value2 = 1
}
}
Loading