Skip to content

Commit

Permalink
Allow to override the enum type name and value comparer
Browse files Browse the repository at this point in the history
  • Loading branch information
michaelstaib committed Aug 12, 2022
1 parent f3db120 commit cfdc549
Show file tree
Hide file tree
Showing 7 changed files with 273 additions and 12 deletions.
32 changes: 32 additions & 0 deletions src/HotChocolate/Core/src/Abstractions/NameString.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Globalization;
using HotChocolate.Language;
Expand Down Expand Up @@ -234,3 +236,33 @@ internal static NameString ConvertFromString(string s)
? new NameString()
: new NameString(s);
}

/// <summary>
/// Provides comparers for <see cref="NameString"/>.
/// </summary>
public static class NameStringComparer
{
public static IEqualityComparer<NameString> Ordinal { get; } =
new OrdinalComparer();

public static IEqualityComparer<NameString> OrdinalIgnoreCase { get; } =
new OrdinalIgnoreCaseComparer();

private sealed class OrdinalIgnoreCaseComparer : IEqualityComparer<NameString>
{
public bool Equals(NameString x, NameString y)
=> x.Equals(y, StringComparison.OrdinalIgnoreCase);

public int GetHashCode(NameString obj)
=> StringComparer.OrdinalIgnoreCase.GetHashCode(obj.Value);
}

private sealed class OrdinalComparer : IEqualityComparer<NameString>
{
public bool Equals(NameString x, NameString y)
=> x.Equals(y, StringComparison.Ordinal);

public int GetHashCode(NameString obj)
=> obj.Value.GetHashCode();
}
}
Original file line number Diff line number Diff line change
@@ -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 @@ IEnumTypeDescriptor SyntaxNode(
/// </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 @@ IEnumTypeDescriptor SyntaxNode(
/// </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 @@ IEnumTypeDescriptor SyntaxNode(
/// </summary>
IEnumTypeDescriptor BindValuesImplicitly();

/// <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<NameString> 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="T">
/// The type of the directive instance.
/// </typeparam>
IEnumTypeDescriptor Directive<T>(
T directiveInstance)
where T : class;

/// <summary>
/// Annotates a directive to this type.
/// </summary>
/// <typeparam name="T">
/// The type of the directive instance.
/// </typeparam>
IEnumTypeDescriptor Directive<T>()
where T : 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(
NameString name,
params ArgumentNode[] arguments);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,16 @@
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>
/// <typeparam name="T">
/// The runtime type.
/// </typeparam>"
public interface IEnumTypeDescriptor<T>
: IDescriptor<EnumTypeDefinition>
, IFluent
Expand Down Expand Up @@ -34,6 +41,12 @@ IEnumTypeDescriptor<T> SyntaxNode(
/// </param>
IEnumTypeDescriptor<T> 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);

Expand All @@ -45,9 +58,21 @@ IEnumTypeDescriptor<T> SyntaxNode(
/// </param>
IEnumValueDescriptor Value(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<T> BindItems(BindingBehavior behavior);

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

/// <summary>
Expand All @@ -61,13 +86,55 @@ IEnumTypeDescriptor<T> SyntaxNode(
/// </summary>
IEnumTypeDescriptor<T> BindValuesImplicitly();

/// <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<NameString> 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<T> 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<T> 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<T> Directive(
NameString name,
params ArgumentNode[] arguments);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,20 @@ public EnumTypeDefinition(
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<NameString> NameComparer { get; set; } =
NameStringComparer.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 @@ -57,4 +71,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();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,18 @@ public IEnumTypeDescriptor BindValuesExplicitly() =>
public IEnumTypeDescriptor BindValuesImplicitly() =>
BindValues(BindingBehavior.Implicit);

public IEnumTypeDescriptor NameComparer(IEqualityComparer<NameString> 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<T>(value);

Expand Down
10 changes: 6 additions & 4 deletions src/HotChocolate/Core/src/Types/Types/EnumType.Initialization.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using HotChocolate.Configuration;
using HotChocolate.Internal;
using HotChocolate.Properties;
Expand All @@ -14,8 +13,8 @@ namespace HotChocolate.Types;

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

Expand Down Expand Up @@ -97,6 +96,9 @@ protected override void OnCompleteType(
{
base.OnCompleteType(context, definition);

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

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

Expand All @@ -112,7 +114,7 @@ protected override void OnCompleteType(
}
}

if (!Values.Any())
if (Values.Count == 0)
{
context.ReportError(
SchemaErrorBuilder.New()
Expand Down
Loading

0 comments on commit cfdc549

Please sign in to comment.