Skip to content

Commit

Permalink
Merge pull request #20 from appany/0.1.7
Browse files Browse the repository at this point in the history
Use error builder interface, rename locals, ValidationBuilder defaults
  • Loading branch information
sergeyshaykhullin authored Jan 29, 2021
2 parents 9f3f435 + 6fab838 commit 3df540b
Show file tree
Hide file tree
Showing 21 changed files with 98 additions and 82 deletions.
2 changes: 1 addition & 1 deletion src/AppAny.HotChocolate.FluentValidation.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<Nullable>enable</Nullable>
<Version>0.1.6</Version>
<Version>0.1.7</Version>
<LangVersion>9</LangVersion>
<EmbedUntrackedSources>true</EmbedUntrackedSources>
<IncludeSymbols>true</IncludeSymbols>
Expand Down
4 changes: 2 additions & 2 deletions src/Builders/CanSkipValidation.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
namespace AppAny.HotChocolate.FluentValidation
{
public interface CanSkipValidation<TConfigurator>
public interface CanSkipValidation<TBuilder>
{
/// <summary>
/// Implementation specific. Can add or override <see cref="SkipValidation"/>
/// </summary>
TConfigurator SkipValidation(SkipValidation skipValidation);
TBuilder SkipValidation(SkipValidation skipValidation);
}
}
4 changes: 2 additions & 2 deletions src/Builders/CanUseErrorMappers.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
namespace AppAny.HotChocolate.FluentValidation
{
public interface CanUseErrorMappers<TConfigurator>
public interface CanUseErrorMappers<TBuilder>
{
/// <summary>
/// Implementation specific. Can add or override <see cref="ErrorMapper"/>
/// </summary>
TConfigurator UseErrorMappers(params ErrorMapper[] errorMappers);
TBuilder UseErrorMappers(params ErrorMapper[] errorMappers);
}
}
4 changes: 2 additions & 2 deletions src/Builders/CanUseInputValidatorProviders.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
namespace AppAny.HotChocolate.FluentValidation
{
public interface CanUseInputValidatorProviders<TConfigurator>
public interface CanUseInputValidatorProviders<TBuilder>
{
/// <summary>
/// Implementation specific. Can add or override <see cref="InputValidatorProvider"/>
/// </summary>
TConfigurator UseInputValidatorProviders(params InputValidatorProvider[] inputValidatorProviders);
TBuilder UseInputValidatorProviders(params InputValidatorProvider[] inputValidatorProviders);
}
}
8 changes: 3 additions & 5 deletions src/Extensions/ArgumentDescriptorExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,11 @@ public static IArgumentDescriptor UseFluentValidation(
this IArgumentDescriptor argumentDescriptor,
Action<ArgumentValidationBuilder> configure)
{
argumentDescriptor.Extend().OnBeforeCreate(definition =>
argumentDescriptor.Extend().OnBeforeCreate(argumentDefinition =>
{
var options = definition.ContextData.GetOrCreateArgumentOptions();
var options = argumentDefinition.ContextData.GetOrCreateArgumentOptions();

var configurator = new DefaultArgumentValidationBuilder(options);

configure.Invoke(configurator);
configure.Invoke(new DefaultArgumentValidationBuilder(options));
});

return argumentDescriptor;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

namespace AppAny.HotChocolate.FluentValidation
{
public static class ArgumentValidationConfiguratorExtensions
public static class ArgumentValidationBuilderExtensions
{
/// <summary>
/// Overrides global <see cref="InputValidatorProvider"/>.
Expand Down
6 changes: 3 additions & 3 deletions src/Extensions/CanSkipValidationExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@ public static class CanSkipValidationExtensions
/// <summary>
/// Always skips validation <see cref="ValidationDefaults.SkipValidation.Skip"/>
/// </summary>
public static TConfigurator SkipValidation<TConfigurator>(
this CanSkipValidation<TConfigurator> configurator)
public static TBuilder SkipValidation<TBuilder>(
this CanSkipValidation<TBuilder> builder)
{
return configurator.SkipValidation(ValidationDefaults.SkipValidation.Skip);
return builder.SkipValidation(ValidationDefaults.SkipValidation.Skip);
}
}
}
18 changes: 9 additions & 9 deletions src/Extensions/CanUseErrorMappersExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@ public static class CanUseErrorMappersExtensions
/// <summary>
/// Uses default <see cref="ErrorMapper"/>. See <see cref="ValidationDefaults.ErrorMappers.Default"/>
/// </summary>
public static TConfigurator UseDefaultErrorMapper<TConfigurator>(
this CanUseErrorMappers<TConfigurator> configurator,
public static TBuilder UseDefaultErrorMapper<TBuilder>(
this CanUseErrorMappers<TBuilder> builder,
params ErrorMapper[] errorMappers)
{
return configurator.UseErrorMappers(
return builder.UseErrorMappers(
new ErrorMapper[] { ValidationDefaults.ErrorMappers.Default }
.Concat(errorMappers)
.ToArray());
Expand All @@ -20,11 +20,11 @@ public static TConfigurator UseDefaultErrorMapper<TConfigurator>(
/// <summary>
/// Adds default <see cref="ErrorMapper"/> with details. See <see cref="ValidationDefaults.ErrorMappers.Default"/> and <see cref="ValidationDefaults.ErrorMappers.Details"/>
/// </summary>
public static TConfigurator UseDefaultErrorMapperWithDetails<TConfigurator>(
this CanUseErrorMappers<TConfigurator> configurator,
public static TBuilder UseDefaultErrorMapperWithDetails<TBuilder>(
this CanUseErrorMappers<TBuilder> builder,
params ErrorMapper[] errorMappers)
{
return configurator.UseErrorMappers(
return builder.UseErrorMappers(
new ErrorMapper[]
{
ValidationDefaults.ErrorMappers.Default,
Expand All @@ -37,11 +37,11 @@ public static TConfigurator UseDefaultErrorMapperWithDetails<TConfigurator>(
/// <summary>
/// Adds default <see cref="ErrorMapper"/> with details. See <see cref="ValidationDefaults.ErrorMappers.Default"/> and <see cref="ValidationDefaults.ErrorMappers.Details"/>
/// </summary>
public static TConfigurator UseDefaultErrorMapperWithExtendedDetails<TConfigurator>(
this CanUseErrorMappers<TConfigurator> configurator,
public static TBuilder UseDefaultErrorMapperWithExtendedDetails<TBuilder>(
this CanUseErrorMappers<TBuilder> builder,
params ErrorMapper[] errorMappers)
{
return configurator.UseErrorMappers(
return builder.UseErrorMappers(
new ErrorMapper[]
{
ValidationDefaults.ErrorMappers.Default,
Expand Down
6 changes: 3 additions & 3 deletions src/Extensions/CanUseInputValidatorProvidersExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@ public static class CanUseInputValidatorProvidersExtensions
/// <summary>
/// Adds default <see cref="InputValidatorProvider"/>. See <see cref="ValidationDefaults.InputValidatorProviders.Default"/>
/// </summary>
public static TConfigurator UseDefaultInputValidatorProvider<TConfigurator>(
this CanUseInputValidatorProviders<TConfigurator> configurator,
public static TBuilder UseDefaultInputValidatorProvider<TBuilder>(
this CanUseInputValidatorProviders<TBuilder> builder,
params InputValidatorProvider[] inputValidatorProviders)
{
return configurator.UseInputValidatorProviders(
return builder.UseInputValidatorProviders(
new InputValidatorProvider[] { ValidationDefaults.InputValidatorProviders.Default }
.Concat(inputValidatorProviders)
.ToArray());
Expand Down
5 changes: 3 additions & 2 deletions src/Extensions/InputValidatorProviderContextExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
using System;
using System.Collections.Concurrent;
using FluentValidation;
using HotChocolate.Types;

namespace AppAny.HotChocolate.FluentValidation
{
internal static class InputValidatorProviderContextExtensions
{
private static readonly ConcurrentDictionary<Type, Type> ArgumentTypeToValidatorType = new();

public static Type GetGenericValidatorType(this InputValidatorProviderContext inputValidatorProviderContext)
public static Type GetGenericValidatorType(this IInputField inputField)
{
return ArgumentTypeToValidatorType.GetOrAdd(
inputValidatorProviderContext.Argument.RuntimeType,
inputField.RuntimeType,
argumentType => typeof(IValidator<>).MakeGenericType(argumentType));
}
}
Expand Down
8 changes: 1 addition & 7 deletions src/Extensions/RequestExecutorBuilderExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,7 @@ public static IRequestExecutorBuilder AddFluentValidation(
{
builder.ConfigureSchemaServices(services =>
{
var configurator = new DefaultValidationBuilder(services);

configurator.UseDefaultErrorMapper();
configurator.UseDefaultInputValidatorProvider();
configurator.SkipValidation(ValidationDefaults.SkipValidation.Default);

configure.Invoke(configurator);
configure.Invoke(ValidationDefaults.ValidationBuilders.Default(services));
});

builder.ConfigureSchema(schemaBuilder =>
Expand Down
3 changes: 1 addition & 2 deletions src/InputValidatorProvider/InputValidatorProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,5 @@ namespace AppAny.HotChocolate.FluentValidation
/// <summary>
/// Resolves <see cref="InputValidator"/> by specified convention
/// </summary>
public delegate InputValidator InputValidatorProvider(
InputValidatorProviderContext inputValidatorProviderContext);
public delegate InputValidator InputValidatorProvider(InputValidatorProviderContext inputValidatorProviderContext);
}
2 changes: 1 addition & 1 deletion src/Mapping/ErrorMapper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,5 @@ namespace AppAny.HotChocolate.FluentValidation
/// <summary>
/// Maps validation result to <see cref="IError"/> properties
/// </summary>
public delegate void ErrorMapper(ErrorBuilder errorBuilder, ErrorMappingContext mappingContext);
public delegate void ErrorMapper(IErrorBuilder errorBuilder, ErrorMappingContext mappingContext);
}
45 changes: 34 additions & 11 deletions src/ValidationDefaults.cs
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ public static class ErrorMappers
/// <summary>
/// Maps graphql error code, path and message
/// </summary>
public static void Default(ErrorBuilder errorBuilder, ErrorMappingContext mappingContext)
public static void Default(IErrorBuilder errorBuilder, ErrorMappingContext mappingContext)
{
errorBuilder
.SetCode(Code)
Expand All @@ -87,7 +87,7 @@ public static void Default(ErrorBuilder errorBuilder, ErrorMappingContext mappin
/// <summary>
/// Maps useful extensions about input field, property, used validator, invalid value and severity
/// </summary>
public static void Details(ErrorBuilder errorBuilder, ErrorMappingContext mappingContext)
public static void Details(IErrorBuilder errorBuilder, ErrorMappingContext mappingContext)
{
errorBuilder
.SetExtension(ExtensionKeys.ValidatorKey, mappingContext.ValidationFailure.ErrorCode)
Expand All @@ -100,7 +100,7 @@ public static void Details(ErrorBuilder errorBuilder, ErrorMappingContext mappin
/// <summary>
/// Maps custom state and formatted message placeholder values
/// </summary>
public static void Extended(ErrorBuilder errorBuilder, ErrorMappingContext mappingContext)
public static void Extended(IErrorBuilder errorBuilder, ErrorMappingContext mappingContext)
{
errorBuilder
.SetExtension(ExtensionKeys.CustomStateKey, mappingContext.ValidationFailure.CustomState)
Expand All @@ -124,7 +124,7 @@ public static InputValidator FromValidator(IValidator validator)
{
var validationContext = new ValidationContext<object>(argument);

return await validator.ValidateAsync(validationContext, cancellationToken);
return await validator.ValidateAsync(validationContext, cancellationToken).ConfigureAwait(false);
};
}

Expand All @@ -141,7 +141,8 @@ public static InputValidator FromValidators(IEnumerable<IValidator> validators)

foreach (var validator in validators)
{
var validatorResult = await validator.ValidateAsync(validationContext, cancellationToken);
var validatorResult = await validator.ValidateAsync(
validationContext, cancellationToken).ConfigureAwait(false);

if (validationResult is null)
{
Expand Down Expand Up @@ -173,7 +174,7 @@ public static InputValidator FromValidatorWithStrategy<TInput>(
(TInput)argument,
validationStrategy);

return await validator.ValidateAsync(validationContext, cancellationToken);
return await validator.ValidateAsync(validationContext, cancellationToken).ConfigureAwait(false);
};
}

Expand All @@ -194,7 +195,8 @@ public static InputValidator FromValidatorsWithStrategy<TInput>(

foreach (var validator in validators)
{
var validatorResult = await validator.ValidateAsync(validationContext, cancellationToken);
var validatorResult = await validator.ValidateAsync(
validationContext, cancellationToken).ConfigureAwait(false);

if (validationResult is null)
{
Expand Down Expand Up @@ -224,10 +226,14 @@ public static class InputValidatorProviders
/// </summary>
public static InputValidator Default(InputValidatorProviderContext inputValidatorProviderContext)
{
var validatorType = inputValidatorProviderContext.GetGenericValidatorType();
var validatorType = inputValidatorProviderContext.Argument.GetGenericValidatorType();

return InputValidators.FromValidators(
(IEnumerable<IValidator>)inputValidatorProviderContext.MiddlewareContext.Services.GetServices(validatorType));
var validators = (IEnumerable<IValidator>)inputValidatorProviderContext
.MiddlewareContext
.Services
.GetServices(validatorType);

return InputValidators.FromValidators(validators);
}
}

Expand All @@ -238,12 +244,29 @@ public static class ValidationStrategies
{
/// <summary>
/// Doing nothing by default.
/// To override validation strategy use <see cref="ArgumentValidationConfiguratorExtensions.UseValidator"/>
/// To override validation strategy use <see cref="ArgumentValidationBuilderExtensions.UseValidator"/>
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void Default<TInput>(ValidationStrategy<TInput> validationStrategy)
{
}
}

/// <summary>
/// Default <see cref="ValidationBuilder"/> implementation factories
/// </summary>
public static class ValidationBuilders
{
/// <summary>
/// Creates and configures default <see cref="ValidationBuilder"/>
/// </summary>
public static ValidationBuilder Default(IServiceCollection services)
{
return new DefaultValidationBuilder(services)
.UseDefaultErrorMapper()
.UseDefaultInputValidatorProvider()
.SkipValidation(SkipValidation.Default);
}
}
}
}
13 changes: 7 additions & 6 deletions src/ValidationFieldMiddleware.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,7 @@ public static FieldDelegate Use(FieldDelegate next)
{
var arguments = middlewareContext.Field.Arguments;

var options = middlewareContext.Schema.Services!
.GetRequiredService<IOptions<InputValidationOptions>>().Value;
var options = middlewareContext.Schema.Services!.GetRequiredService<IOptions<InputValidationOptions>>().Value;

// TODO: Validate only passed arguments
for (var argumentIndex = 0; argumentIndex < arguments.Count; argumentIndex++)
Expand All @@ -34,14 +33,15 @@ public static FieldDelegate Use(FieldDelegate next)

var skipValidation = argumentOptions.SkipValidation ?? options.SkipValidation;

if (await skipValidation.Invoke(new SkipValidationContext(middlewareContext, argument)))
if (await skipValidation.Invoke(
new SkipValidationContext(middlewareContext, argument)).ConfigureAwait(false))
{
continue;
}

var input = middlewareContext.ArgumentValue<object?>(argument.Name);
var argumentValue = middlewareContext.ArgumentValue<object?>(argument.Name);

if (input is null)
if (argumentValue is null)
{
continue;
}
Expand All @@ -57,7 +57,8 @@ public static FieldDelegate Use(FieldDelegate next)
middlewareContext,
argument));

var validationResult = await inputValidator.Invoke(input, middlewareContext.RequestAborted);
var validationResult = await inputValidator.Invoke(
argumentValue, middlewareContext.RequestAborted).ConfigureAwait(false);

if (validationResult?.IsValid is null or true)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,9 @@ public async Task Should_Pass_Values_UseFluentValidation()
{
var executor = await TestSetup.CreateRequestExecutor(builder =>
builder.AddFluentValidation()
.AddMutationType(new TestMutation(arg => arg.UseFluentValidation(configurator =>
.AddMutationType(new TestMutation(arg => arg.UseFluentValidation(opt =>
{
configurator.UseErrorMappers(
opt.UseErrorMappers(
ValidationDefaults.ErrorMappers.Default,
(_, context) =>
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,9 @@ public async Task Should_Pass_Values_UseFluentValidation()
{
var executor = await TestSetup.CreateRequestExecutor(builder =>
builder.AddFluentValidation(opt => opt.UseErrorMappers(ValidationDefaults.ErrorMappers.Default))
.AddMutationType(new TestMutation(arg => arg.UseFluentValidation(configurator =>
.AddMutationType(new TestMutation(arg => arg.UseFluentValidation(opt =>
{
configurator.UseInputValidatorProviders(context =>
opt.UseInputValidatorProviders(context =>
{
Assert.Equal(typeof(TestPersonInput), context.Argument.RuntimeType);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,9 @@ public async Task Should_HaveNullResult_WithValidatorOverride()
{
var executor = await TestSetup.CreateRequestExecutor(builder =>
builder.AddFluentValidation(opt => opt.UseErrorMappers(ValidationDefaults.ErrorMappers.Default))
.AddMutationType(new TestMutation(arg => arg.UseFluentValidation(configurator =>
.AddMutationType(new TestMutation(arg => arg.UseFluentValidation(opt =>
{
configurator.UseValidator<NotEmptyNameValidator>();
opt.UseValidator<NotEmptyNameValidator>();
})))
.Services.AddTransient<NotEmptyNameValidator>());

Expand All @@ -69,9 +69,9 @@ public async Task Should_Throw_NoMessageSet()
{
var executor = await TestSetup.CreateRequestExecutor(builder =>
builder.AddFluentValidation(opt => opt.UseErrorMappers(ValidationDefaults.ErrorMappers.Details))
.AddMutationType(new TestMutation(arg => arg.UseFluentValidation(configurator =>
.AddMutationType(new TestMutation(arg => arg.UseFluentValidation(opt =>
{
configurator.UseValidator<NotEmptyNameValidator>();
opt.UseValidator<NotEmptyNameValidator>();
})))
.Services.AddTransient<NotEmptyNameValidator>());

Expand Down
Loading

0 comments on commit 3df540b

Please sign in to comment.