Skip to content

Commit

Permalink
Allow to override the enum type name and value comparer (#5297)
Browse files Browse the repository at this point in the history
  • Loading branch information
michaelstaib committed Aug 12, 2022
1 parent 74f969e commit 337af7a
Show file tree
Hide file tree
Showing 12 changed files with 253 additions and 304 deletions.
3 changes: 3 additions & 0 deletions src/HotChocolate/Core/src/Types/HotChocolate.Types.csproj
Expand Up @@ -72,6 +72,9 @@
<Compile Update="SchemaErrorBuilder.Error.cs">
<DependentUpon>SchemaErrorBuilder.cs</DependentUpon>
</Compile>
<Compile Update="Types\EnumType.Initialization.cs">
<DependentUpon>EnumType.cs</DependentUpon>
</Compile>
</ItemGroup>

<ItemGroup>
Expand Down
@@ -1,9 +1,13 @@
using System;
using System.Collections.Generic;
using HotChocolate.Language;
using HotChocolate.Types.Descriptors.Definitions;

namespace HotChocolate.Types;

/// <summary>
/// A fluent configuration API for GraphQL enum types.
/// </summary>
public interface IEnumTypeDescriptor
: IDescriptor<EnumTypeDefinition>
, IFluent
Expand Down Expand Up @@ -34,6 +38,12 @@ public interface IEnumTypeDescriptor
/// </param>
IEnumTypeDescriptor Description(string value);

/// <summary>
/// Defines a value that should be included on the enum type.
/// </summary>
/// <param name="value">
/// The value to include.
/// </param>
[Obsolete("Use `Value`.")]
IEnumValueDescriptor Item<T>(T value);

Expand All @@ -45,9 +55,21 @@ public interface IEnumTypeDescriptor
/// </param>
IEnumValueDescriptor Value<T>(T value);

/// <summary>
/// Specifies if the enum values shall be inferred or explicitly specfied.
/// </summary>
/// <param name="behavior">
/// The binding behavior.
/// </param>
[Obsolete("Use `BindValues`.")]
IEnumTypeDescriptor BindItems(BindingBehavior behavior);

/// <summary>
/// Specifies if the enum values shall be inferred or explicitly specfied.
/// </summary>
/// <param name="behavior">
/// The binding behavior.
/// </param>
IEnumTypeDescriptor BindValues(BindingBehavior behavior);

/// <summary>
Expand All @@ -61,13 +83,55 @@ public interface IEnumTypeDescriptor
/// </summary>
IEnumTypeDescriptor BindValuesImplicitly();

IEnumTypeDescriptor Directive<T>(
T directiveInstance)
where T : class;
/// <summary>
/// Specifies the enum name comparer that will be used to validate
/// if an enum name represents an enum value of this type.
/// </summary>
/// <param name="comparer">
/// The equality comparer for enum names.
/// </param>
IEnumTypeDescriptor NameComparer(IEqualityComparer<string> comparer);

IEnumTypeDescriptor Directive<T>()
where T : class, new();
/// <summary>
/// Specifies the runtime value comparer that will be used to validate
/// if a runtime value represents a GraphQL enum value of this type.
/// </summary>
/// <param name="comparer">
/// The equality comparer for enum names.
/// </param>
IEnumTypeDescriptor ValueComparer(IEqualityComparer<object> comparer);

/// <summary>
/// Annotates a directive to this type.
/// </summary>
/// <param name="directiveInstance">
/// The directive that shall be annotated to this type.
/// </param>
/// <typeparam name="TDirective">
/// The type of the directive instance.
/// </typeparam>
IEnumTypeDescriptor Directive<TDirective>(
TDirective directiveInstance)
where TDirective : class;

/// <summary>
/// Annotates a directive to this type.
/// </summary>
/// <typeparam name="TDirective">
/// The type of the directive instance.
/// </typeparam>
IEnumTypeDescriptor Directive<TDirective>()
where TDirective : class, new();

/// <summary>
/// Annotates a directive to this type.
/// </summary>
/// <param name="name">
/// The name of the directive.
/// </param>
/// <param name="arguments">
/// The argument values that the directive instance shall have.
/// </param>
IEnumTypeDescriptor Directive(
string name,
params ArgumentNode[] arguments);
Expand Down
@@ -1,10 +1,17 @@
using System;
using System.Collections.Generic;
using HotChocolate.Language;
using HotChocolate.Types.Descriptors.Definitions;

namespace HotChocolate.Types;

public interface IEnumTypeDescriptor<T>
/// <summary>
/// A fluent configuration API for GraphQL enum types.
/// </summary>
/// <typeparam name="TRuntimeType">
/// The runtime type.
/// </typeparam>"
public interface IEnumTypeDescriptor<TRuntimeType>
: IDescriptor<EnumTypeDefinition>
, IFluent
{
Expand All @@ -15,7 +22,7 @@ public interface IEnumTypeDescriptor<T>
/// <param name="enumTypeDefinition">
/// The the type definition node.
/// </param>
IEnumTypeDescriptor<T> SyntaxNode(
IEnumTypeDescriptor<TRuntimeType> SyntaxNode(
EnumTypeDefinitionNode enumTypeDefinition);

/// <summary>
Expand All @@ -24,51 +31,111 @@ public interface IEnumTypeDescriptor<T>
/// <param name="value">
/// The name value.
/// </param>
IEnumTypeDescriptor<T> Name(string value);
IEnumTypeDescriptor<TRuntimeType> Name(string value);

/// <summary>
/// Defines the description that the enum type shall have.
/// </summary>
/// <param name="value">
/// The description value.
/// </param>
IEnumTypeDescriptor<T> Description(string value);
IEnumTypeDescriptor<TRuntimeType> Description(string value);

/// <summary>
/// Defines a value that should be included on the enum type.
/// </summary>
/// <param name="value">
/// The value to include.
/// </param>
[Obsolete("Use `Value`.")]
IEnumValueDescriptor Item(T value);
IEnumValueDescriptor Item(TRuntimeType value);

/// <summary>
/// Defines a value that should be included on the enum type.
/// </summary>
/// <param name="value">
/// The value to include.
/// </param>
IEnumValueDescriptor Value(T value);
IEnumValueDescriptor Value(TRuntimeType value);

/// <summary>
/// Specifies if the enum values shall be inferred or explicitly specfied.
/// </summary>
/// <param name="behavior">
/// The binding behavior.
/// </param>
[Obsolete("Use `BindValues`.")]
IEnumTypeDescriptor<T> BindItems(BindingBehavior behavior);
IEnumTypeDescriptor<TRuntimeType> BindItems(BindingBehavior behavior);

IEnumTypeDescriptor<T> BindValues(BindingBehavior behavior);
/// <summary>
/// Specifies if the enum values shall be inferred or explicitly specfied.
/// </summary>
/// <param name="behavior">
/// The binding behavior.
/// </param>
IEnumTypeDescriptor<TRuntimeType> BindValues(BindingBehavior behavior);

/// <summary>
/// Defines that all enum values have to be specified explicitly.
/// </summary>
IEnumTypeDescriptor<T> BindValuesExplicitly();
IEnumTypeDescriptor<TRuntimeType> BindValuesExplicitly();

/// <summary>
/// Defines that all enum values shall be inferred
/// from the associated .Net type,
/// </summary>
IEnumTypeDescriptor<T> BindValuesImplicitly();
IEnumTypeDescriptor<TRuntimeType> BindValuesImplicitly();

IEnumTypeDescriptor<T> Directive<TDirective>(
/// <summary>
/// Specifies the enum name comparer that will be used to validate
/// if an enum name represents an enum value of this type.
/// </summary>
/// <param name="comparer">
/// The equality comparer for enum names.
/// </param>
IEnumTypeDescriptor NameComparer(IEqualityComparer<string> comparer);

/// <summary>
/// Specifies the runtime value comparer that will be used to validate
/// if a runtime value represents a GraphQL enum value of this type.
/// </summary>
/// <param name="comparer">
/// The equality comparer for enum names.
/// </param>
IEnumTypeDescriptor ValueComparer(IEqualityComparer<object> comparer);

/// <summary>
/// Annotates a directive to this type.
/// </summary>
/// <param name="directiveInstance">
/// The directive that shall be annotated to this type.
/// </param>
/// <typeparam name="TDirective">
/// The type of the directive instance.
/// </typeparam>
IEnumTypeDescriptor<TRuntimeType> Directive<TDirective>(
TDirective directiveInstance)
where TDirective : class;

IEnumTypeDescriptor<T> Directive<TDirective>()
/// <summary>
/// Annotates a directive to this type.
/// </summary>
/// <typeparam name="TDirective">
/// The type of the directive instance.
/// </typeparam>
IEnumTypeDescriptor<TRuntimeType> Directive<TDirective>()
where TDirective : class, new();

IEnumTypeDescriptor<T> Directive(
/// <summary>
/// Annotates a directive to this type.
/// </summary>
/// <param name="name">
/// The name of the directive.
/// </param>
/// <param name="arguments">
/// The argument values that the directive instance shall have.
/// </param>
IEnumTypeDescriptor<TRuntimeType> Directive(
string name,
params ArgumentNode[] arguments);
}
Expand Up @@ -31,6 +31,18 @@ public class EnumTypeDefinition : TypeDefinitionBase<EnumTypeDefinitionNode>
Description = description;
}

/// <summary>
/// Gets or sets the enum name comparer that will be used to validate
/// if an enum name represents an enum value of this type.
/// </summary>
public IEqualityComparer<string> NameComparer { get; set; } = StringComparer.Ordinal;

/// <summary>
/// Gets or sets the runtime value comparer that will be used to validate
/// if a runtime value represents a GraphQL enum value of this type.
/// </summary>
public IEqualityComparer<object> ValueComparer { get; set; } = DefaultValueComparer.Instance;

/// <summary>
/// Gets the enum values.
/// </summary>
Expand Down Expand Up @@ -58,4 +70,15 @@ public override IEnumerable<ITypeSystemMemberConfiguration> GetConfigurations()

return configs ?? Enumerable.Empty<ITypeSystemMemberConfiguration>();
}

private sealed class DefaultValueComparer : IEqualityComparer<object>
{
bool IEqualityComparer<object>.Equals(object? x, object? y)
=> Equals(x, y);

int IEqualityComparer<object>.GetHashCode(object obj)
=> obj.GetHashCode();

public static DefaultValueComparer Instance { get; } = new();
}
}
Expand Up @@ -121,6 +121,18 @@ public IEnumTypeDescriptor Description(string value)
public IEnumTypeDescriptor BindValuesImplicitly() =>
BindValues(BindingBehavior.Implicit);

public IEnumTypeDescriptor NameComparer(IEqualityComparer<string> comparer)
{
Definition.NameComparer = comparer ?? throw new ArgumentNullException(nameof(comparer));
return this;
}

public IEnumTypeDescriptor ValueComparer(IEqualityComparer<object> comparer)
{
Definition.ValueComparer = comparer ?? throw new ArgumentNullException(nameof(comparer));
return this;
}

[Obsolete("Use `Value`.")]
public IEnumValueDescriptor Item<T>(T value) => Value(value);

Expand Down
Expand Up @@ -14,8 +14,8 @@ namespace HotChocolate.Types;

public partial class EnumType
{
private readonly Dictionary<string, IEnumValue> _enumValues = new();
private readonly Dictionary<object, IEnumValue> _valueLookup = new();
private Dictionary<string, IEnumValue> _enumValues = default!;
private Dictionary<object, IEnumValue> _valueLookup = default!;
private Action<IEnumTypeDescriptor>? _configure;
private INamingConventions _naming = default!;

Expand Down Expand Up @@ -97,6 +97,9 @@ protected override EnumTypeDefinition CreateDefinition(ITypeDiscoveryContext con
{
base.OnCompleteType(context, definition);

_enumValues = new Dictionary<string, IEnumValue>(definition.NameComparer);
_valueLookup = new Dictionary<object, IEnumValue>(definition.ValueComparer);

_naming = context.DescriptorContext.Naming;
SyntaxNode = definition.SyntaxNode;

Expand Down

0 comments on commit 337af7a

Please sign in to comment.