From 1de7cf865771789ca824814c5023806addca605c Mon Sep 17 00:00:00 2001 From: PascalSenn Date: Wed, 4 Nov 2020 12:32:41 +0100 Subject: [PATCH] Add conventions to executor builder (#2532) --- ...estExecutorBuilderExtensions.Convention.cs | 298 ++++++++++++++++++ .../Properties/Resources.Designer.cs | 6 + .../src/Execution/Properties/Resources.resx | 59 ++-- .../Core/src/Execution/ThrowHelper.cs | 9 + 4 files changed, 344 insertions(+), 28 deletions(-) create mode 100644 src/HotChocolate/Core/src/Execution/DependencyInjection/SchemaRequestExecutorBuilderExtensions.Convention.cs diff --git a/src/HotChocolate/Core/src/Execution/DependencyInjection/SchemaRequestExecutorBuilderExtensions.Convention.cs b/src/HotChocolate/Core/src/Execution/DependencyInjection/SchemaRequestExecutorBuilderExtensions.Convention.cs new file mode 100644 index 00000000000..dbf33834eaf --- /dev/null +++ b/src/HotChocolate/Core/src/Execution/DependencyInjection/SchemaRequestExecutorBuilderExtensions.Convention.cs @@ -0,0 +1,298 @@ +using System; +using HotChocolate; +using HotChocolate.Execution.Configuration; +using HotChocolate.Execution.Properties; +using HotChocolate.Types.Descriptors; +using HotChocolate.Utilities; +using static HotChocolate.Execution.ThrowHelper; + +namespace Microsoft.Extensions.DependencyInjection +{ + public static partial class SchemaRequestExecutorBuilderExtensions + { + public static IRequestExecutorBuilder AddConvention( + this IRequestExecutorBuilder builder, + Type convention, + CreateConvention factory, + string? scope = null) + { + if (builder is null) + { + throw new ArgumentNullException(nameof(builder)); + } + + if (convention is null) + { + throw new ArgumentNullException(nameof(convention)); + } + + if (factory is null) + { + throw new ArgumentNullException(nameof(factory)); + } + + return builder.ConfigureSchema(b => b.AddConvention(convention, factory, scope)); + } + + public static IRequestExecutorBuilder TryAddConvention( + this IRequestExecutorBuilder builder, + Type convention, + CreateConvention factory, + string? scope = null) + { + if (builder is null) + { + throw new ArgumentNullException(nameof(builder)); + } + + if (convention is null) + { + throw new ArgumentNullException(nameof(convention)); + } + + if (factory is null) + { + throw new ArgumentNullException(nameof(factory)); + } + + return builder.ConfigureSchema(b => b.TryAddConvention(convention, factory, scope)); + } + + public static IRequestExecutorBuilder AddConvention( + this IRequestExecutorBuilder builder, + Type type, + string? scope = null) + { + if (builder is null) + { + throw new ArgumentNullException(nameof(builder)); + } + + return builder.ConfigureSchema(b => b.AddConvention(typeof(T), type, scope)); + } + + public static IRequestExecutorBuilder AddConvention( + this IRequestExecutorBuilder builder, + CreateConvention conventionFactory, + string? scope = null) + { + if (builder is null) + { + throw new ArgumentNullException(nameof(builder)); + } + + return builder.ConfigureSchema( + b => b.AddConvention(typeof(T), conventionFactory, scope)); + } + + public static IRequestExecutorBuilder AddConvention( + this IRequestExecutorBuilder builder, + Type convention, + IConvention concreteConvention, + string? scope = null) + { + if (builder is null) + { + throw new ArgumentNullException(nameof(builder)); + } + + if (convention is null) + { + throw new ArgumentNullException(nameof(convention)); + } + + if (concreteConvention is null) + { + throw new ArgumentNullException(nameof(concreteConvention)); + } + + if (!typeof(IConvention).IsAssignableFrom(convention)) + { + throw new ArgumentException( + Resources.RequestExecutorBuilder_Convention_NotSuppported, + nameof(convention)); + } + + return builder.ConfigureSchema( + b => b.AddConvention(convention, (s) => concreteConvention, scope)); + } + + public static IRequestExecutorBuilder AddConvention( + this IRequestExecutorBuilder builder, + Type convention, + Type concreteConvention, + string? scope = null) + { + if (builder is null) + { + throw new ArgumentNullException(nameof(builder)); + } + + if (convention is null) + { + throw new ArgumentNullException(nameof(convention)); + } + + if (concreteConvention is null) + { + throw new ArgumentNullException(nameof(concreteConvention)); + } + + if (!typeof(IConvention).IsAssignableFrom(convention)) + { + throw new ArgumentException( + Resources.RequestExecutorBuilder_Convention_NotSuppported, + nameof(convention)); + } + + if (!typeof(IConvention).IsAssignableFrom(concreteConvention)) + { + throw new ArgumentException( + Resources.RequestExecutorBuilder_Convention_NotSuppported, + nameof(convention)); + } + + return builder.ConfigureSchema( + b => b.AddConvention( + convention, + s => + { + if (s.TryGetOrCreateService( + concreteConvention, + out IConvention convention)) + { + return convention; + } + + throw Convention_UnableToCreateConvention(concreteConvention); + }, + scope)); + } + + public static IRequestExecutorBuilder AddConvention( + this IRequestExecutorBuilder builder, + IConvention convention, + string? scope = null) + where T : IConvention => + builder.ConfigureSchema(b => b.AddConvention(typeof(T), convention, scope)); + + public static IRequestExecutorBuilder AddConvention( + this IRequestExecutorBuilder builder, + string? scope = null) + where TConvetion : IConvention + where TConcreteConvention : IConvention => + builder.ConfigureSchema( + b => b.AddConvention(typeof(TConvetion), typeof(TConcreteConvention), scope)); + + public static IRequestExecutorBuilder TryAddConvention( + this IRequestExecutorBuilder builder, + Type convention, + IConvention concreteConvention, + string? scope = null) + { + if (builder is null) + { + throw new ArgumentNullException(nameof(builder)); + } + + if (convention is null) + { + throw new ArgumentNullException(nameof(convention)); + } + + if (concreteConvention is null) + { + throw new ArgumentNullException(nameof(concreteConvention)); + } + + if (!typeof(IConvention).IsAssignableFrom(convention)) + { + throw new ArgumentException( + Resources.RequestExecutorBuilder_Convention_NotSuppported, + nameof(convention)); + } + + return builder.ConfigureSchema( + b => b.TryAddConvention(convention, s => concreteConvention, scope)); + } + + public static IRequestExecutorBuilder TryAddConvention( + this IRequestExecutorBuilder builder, + Type convention, + Type concreteConvention, + string? scope = null) + { + if (builder is null) + { + throw new ArgumentNullException(nameof(builder)); + } + + if (convention is null) + { + throw new ArgumentNullException(nameof(convention)); + } + + if (concreteConvention is null) + { + throw new ArgumentNullException(nameof(concreteConvention)); + } + + if (!typeof(IConvention).IsAssignableFrom(convention)) + { + throw new ArgumentException( + Resources.RequestExecutorBuilder_Convention_NotSuppported, + nameof(convention)); + } + + if (!typeof(IConvention).IsAssignableFrom(concreteConvention)) + { + throw new ArgumentException( + Resources.RequestExecutorBuilder_Convention_NotSuppported, + nameof(convention)); + } + + return builder.ConfigureSchema( + b => b.TryAddConvention( + convention, + s => + { + if (s.TryGetOrCreateService(concreteConvention, out IConvention? c)) + { + return c; + } + + throw Convention_UnableToCreateConvention(concreteConvention); + }, + scope)); + } + + public static IRequestExecutorBuilder TryAddConvention( + this IRequestExecutorBuilder builder, + CreateConvention conventionFactory, + string? scope = null) + where T : IConvention => + builder.ConfigureSchema(b => b.TryAddConvention(typeof(T), conventionFactory, scope)); + + public static IRequestExecutorBuilder TryAddConvention( + this IRequestExecutorBuilder builder, + Type type, + string? scope = null) + where T : IConvention => + builder.ConfigureSchema(b => b.TryAddConvention(typeof(T), type, scope)); + + public static IRequestExecutorBuilder TryAddConvention( + this IRequestExecutorBuilder builder, + IConvention convention, + string? scope = null) + where T : IConvention => + builder.ConfigureSchema(b => b.TryAddConvention(typeof(T), convention, scope)); + + public static IRequestExecutorBuilder TryAddConvention( + this IRequestExecutorBuilder builder, + string? scope = null) + where TConvention : IConvention + where TConcreteConvention : class, TConvention => + builder.ConfigureSchema( + b => b.TryAddConvention(typeof(TConvention), typeof(TConcreteConvention), scope)); + } +} diff --git a/src/HotChocolate/Core/src/Execution/Properties/Resources.Designer.cs b/src/HotChocolate/Core/src/Execution/Properties/Resources.Designer.cs index 35d330f008b..a744227a535 100644 --- a/src/HotChocolate/Core/src/Execution/Properties/Resources.Designer.cs +++ b/src/HotChocolate/Core/src/Execution/Properties/Resources.Designer.cs @@ -290,5 +290,11 @@ internal class Resources { return ResourceManager.GetString("ExecutionRequestExecutorExtensions_ExecuteAsync_QueryCannotBeNullOrEmpty", resourceCulture); } } + + internal static string RequestExecutorBuilder_Convention_NotSuppported { + get { + return ResourceManager.GetString("RequestExecutorBuilder_Convention_NotSuppported", resourceCulture); + } + } } } diff --git a/src/HotChocolate/Core/src/Execution/Properties/Resources.resx b/src/HotChocolate/Core/src/Execution/Properties/Resources.resx index e871aedde2f..9394d012cbf 100644 --- a/src/HotChocolate/Core/src/Execution/Properties/Resources.resx +++ b/src/HotChocolate/Core/src/Execution/Properties/Resources.resx @@ -1,17 +1,17 @@  - @@ -240,4 +240,7 @@ The query cannot be null or empty. - \ No newline at end of file + + The specified convention type is not supported. + + diff --git a/src/HotChocolate/Core/src/Execution/ThrowHelper.cs b/src/HotChocolate/Core/src/Execution/ThrowHelper.cs index 7ba6f4f7af7..ac8e84e094c 100644 --- a/src/HotChocolate/Core/src/Execution/ThrowHelper.cs +++ b/src/HotChocolate/Core/src/Execution/ThrowHelper.cs @@ -276,5 +276,14 @@ internal static class ThrowHelper .SetMessage("The operation has no selections.") .AddLocation(syntaxNode) .Build()); + + public static SchemaException Convention_UnableToCreateConvention( + Type convention) => + new SchemaException( + SchemaErrorBuilder.New() + .SetMessage( + "Unable to create a convention instance from {0}.", + convention.FullName ?? convention.Name) + .Build()); } }