Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Mutation Conventions #4519

Merged
merged 32 commits into from
Dec 8, 2021
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
0981a57
Started work on mutation conventions
michaelstaib Dec 2, 2021
54e7c5e
Started work on payloads
michaelstaib Dec 2, 2021
4a267c7
Added basic functionality
michaelstaib Dec 2, 2021
d85fc41
Refinements
michaelstaib Dec 2, 2021
6e350c1
wip
michaelstaib Dec 3, 2021
1ec321e
wip
michaelstaib Dec 3, 2021
2401a5c
Added parameter expression builder
michaelstaib Dec 3, 2021
d4150ed
Addded code first
michaelstaib Dec 3, 2021
39243c0
Rworked how we rewrite arguments
michaelstaib Dec 6, 2021
15d2f8e
Moved FieldInfo into separate file
michaelstaib Dec 6, 2021
bde0978
Fixed compile issue
michaelstaib Dec 6, 2021
9c598ad
Integrated Errors
michaelstaib Dec 7, 2021
a9c9e79
Handle NonNull
michaelstaib Dec 7, 2021
278984e
Fixed tests
michaelstaib Dec 7, 2021
1650337
Fixed middleware cleanup algorithm
michaelstaib Dec 7, 2021
94c7e2b
Added more tests
michaelstaib Dec 7, 2021
5fe9e87
cleanup
michaelstaib Dec 7, 2021
0c58288
Cleanup
michaelstaib Dec 7, 2021
24993fe
Cleanup
michaelstaib Dec 7, 2021
3c7c5f5
Merge branch 'main' into mst/mutationConventions
michaelstaib Dec 7, 2021
3e31e44
exclude generic attributes when not .net 6
michaelstaib Dec 7, 2021
c87a205
disabled generic attributes
michaelstaib Dec 7, 2021
f4a383d
removed records from tests
michaelstaib Dec 7, 2021
914a68e
cleanup
michaelstaib Dec 7, 2021
801074b
Cleanup
michaelstaib Dec 7, 2021
abc125f
Refinements
michaelstaib Dec 8, 2021
50ef772
Cleanup
michaelstaib Dec 8, 2021
5cd23e0
reverted modifier change
michaelstaib Dec 8, 2021
679c333
Refined
michaelstaib Dec 8, 2021
4fe15e1
Introduced output field info
michaelstaib Dec 8, 2021
eb339bb
Fixed compile issue
michaelstaib Dec 8, 2021
2f56b3a
Fixed Data Tests
michaelstaib Dec 8, 2021
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
14 changes: 7 additions & 7 deletions src/HotChocolate/Core/src/Abstractions/AttributeExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ public static string GetGraphQLName(this Type type)
}

TypeInfo typeInfo = type.GetTypeInfo();
string name = typeInfo.IsDefined(typeof(GraphQLNameAttribute), false)
var name = typeInfo.IsDefined(typeof(GraphQLNameAttribute), false)
? typeInfo.GetCustomAttribute<GraphQLNameAttribute>()!.Name
: GetFromType(typeInfo);

Expand All @@ -36,7 +36,7 @@ public static string GetGraphQLName(this PropertyInfo property)
throw new ArgumentNullException(nameof(property));
}

string name = property.IsDefined(
var name = property.IsDefined(
typeof(GraphQLNameAttribute), false)
? property.GetCustomAttribute<GraphQLNameAttribute>()!.Name
: NormalizeName(property.Name);
Expand All @@ -51,7 +51,7 @@ public static string GetGraphQLName(this MethodInfo method)
throw new ArgumentNullException(nameof(method));
}

string name = method.IsDefined(
var name = method.IsDefined(
typeof(GraphQLNameAttribute), false)
? method.GetCustomAttribute<GraphQLNameAttribute>()!.Name
: NormalizeMethodName(method);
Expand All @@ -66,7 +66,7 @@ public static string GetGraphQLName(this ParameterInfo parameter)
throw new ArgumentNullException(nameof(parameter));
}

string name = parameter.IsDefined(
var name = parameter.IsDefined(
typeof(GraphQLNameAttribute), false)
? parameter.GetCustomAttribute<GraphQLNameAttribute>()!.Name
: NormalizeName(parameter.Name!);
Expand Down Expand Up @@ -97,7 +97,7 @@ public static string GetGraphQLName(this MemberInfo member)

private static string NormalizeMethodName(MethodInfo method)
{
string name = method.Name;
var name = method.Name;

if (name.StartsWith(_get, StringComparison.Ordinal)
&& name.Length > _get.Length)
Expand Down Expand Up @@ -140,7 +140,7 @@ private static bool IsAsyncMethod(Type returnType)
typeof(GraphQLDescriptionAttribute),
false))
{
GraphQLDescriptionAttribute attribute =
var attribute =
(GraphQLDescriptionAttribute)
attributeProvider.GetCustomAttributes(
typeof(GraphQLDescriptionAttribute),
Expand Down Expand Up @@ -181,7 +181,7 @@ private static string GetFromType(Type type)
{
if (type.GetTypeInfo().IsGenericType)
{
string name = type.GetTypeInfo()
var name = type.GetTypeInfo()
.GetGenericTypeDefinition()
.Name;

Expand Down
5 changes: 5 additions & 0 deletions src/HotChocolate/Core/src/Abstractions/WellKnownMiddleware.cs
Original file line number Diff line number Diff line change
Expand Up @@ -64,4 +64,9 @@ public static class WellKnownMiddleware
/// This key identifies a resolver service middleware.
/// </summary>
public const string ResolverService = "HotChocolate.Resolvers.ResolverService";

/// <summary>
/// This key identifies the mutation convention middleware.
/// </summary>
public const string MutationConvention = "HotChocolate.Types.Mutations.Conventions";
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@
<RootNamespace>HotChocolate.Execution</RootNamespace>
</PropertyGroup>

<ItemGroup>
<InternalsVisibleTo Include="HotChocolate.Types.Mutations" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\Abstractions\HotChocolate.Abstractions.csproj" />
<ProjectReference Include="..\Fetching\HotChocolate.Fetching.csproj" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,18 +43,18 @@ public static bool TryCoerceArguments(
{
if (argument.IsFinal)
{
args.Add(argument.Argument.Name, argument);
args.Add(argument.Name, argument);
}
else
{
IValueNode literal = VariableRewriter.Rewrite(
argument.ValueLiteral!,
argument.Type,
argument.Argument.DefaultValue,
argument.DefaultValue,
resolverContext.Variables);

args.Add(argument.Argument.Name, new ArgumentValue(
argument.Argument,
args.Add(argument.Name, new ArgumentValue(
argument,
literal.TryGetValueKind(out ValueKind kind)
? kind
: ValueKind.Unknown,
Expand Down
59 changes: 51 additions & 8 deletions src/HotChocolate/Core/src/Execution/Processing/ArgumentValue.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,19 @@

namespace HotChocolate.Execution.Processing;

public sealed class ArgumentValue
public sealed class ArgumentValue : IInputFieldInfo
{
private readonly IInputFieldInfo _argument;

public ArgumentValue(
IInputField argument,
IInputFieldInfo argument,
ValueKind kind,
bool isFinal,
bool isImplicit,
object? value,
IValueNode valueLiteral)
{
Argument = argument ?? throw new ArgumentNullException(nameof(argument));
_argument = argument ?? throw new ArgumentNullException(nameof(argument));
Kind = kind;
IsFinal = isFinal;
IsImplicit = isImplicit;
Expand All @@ -24,9 +26,9 @@ public ArgumentValue(
ValueLiteral = valueLiteral ?? throw new ArgumentNullException(nameof(valueLiteral));
}

public ArgumentValue(IInputField argument, IError error)
public ArgumentValue(IInputFieldInfo argument, IError error)
{
Argument = argument ?? throw new ArgumentNullException(nameof(argument));
_argument = argument ?? throw new ArgumentNullException(nameof(argument));
Error = error ?? throw new ArgumentNullException(nameof(error));
HasError = true;
IsFinal = true;
Expand All @@ -35,23 +37,64 @@ public ArgumentValue(IInputField argument, IError error)
ValueLiteral = null;
}

public IInputField Argument { get; }
/// <summary>
/// Gets the argument name.
/// </summary>
public NameString Name => _argument.Name;

/// <summary>
/// Gets the argument field coordinate.
/// </summary>
public FieldCoordinate Coordinate => _argument.Coordinate;

/// <summary>
/// Gets the argument type.
/// </summary>
public IInputType Type => _argument.Type;

public IInputType Type => Argument.Type;
/// <summary>
/// Gets the argument runtime type.
/// </summary>
public Type RuntimeType => _argument.RuntimeType;

public IInputValueFormatter? Formatter => Argument.Formatter;
/// <summary>
/// Gets the argument default value.
/// </summary>
public IValueNode? DefaultValue => _argument.DefaultValue;

/// <summary>
/// Return an optional input value formatter.
/// </summary>
public IInputValueFormatter? Formatter => _argument.Formatter;

public ValueKind? Kind { get; }

/// <summary>
/// Defines if this argument value is fully coerced and
/// need no post processing.
/// </summary>
public bool IsFinal { get; }

/// <summary>
/// Defines if this argument value has errors.
/// </summary>
public bool HasError { get; }

public bool IsImplicit { get; }

/// <summary>
/// Gets the runtime value representation of this argument.
/// </summary>
public object? Value { get; }

/// <summary>
/// Gets the value literal of this argument value.
/// </summary>
public IValueNode? ValueLiteral { get; }

/// <summary>
/// If this argument has error this represents the argument error.
/// </summary>
public IError? Error { get; }

}
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ private T CoerceArgumentValue<T>(ArgumentValue argument)
// runtime version we can skip over parsing it.
if (!argument.IsFinal)
{
value = _parser.ParseLiteral(argument.ValueLiteral!, argument.Argument, typeof(T));
value = _parser.ParseLiteral(argument.ValueLiteral!, argument, typeof(T));
}

if (value is null)
Expand All @@ -111,15 +111,15 @@ private T CoerceArgumentValue<T>(ArgumentValue argument)
throw ResolverContext_LiteralsNotSupported(
_selection.SyntaxNode,
Path,
argument.Argument.Name,
argument.Name,
typeof(T));
}

// we are unable to convert the argument to the request type.
throw ResolverContext_CannotConvertArgument(
_selection.SyntaxNode,
Path,
argument.Argument.Name,
argument.Name,
typeof(T));
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
using System;
using System.Collections.Generic;
using HotChocolate.Language;
using HotChocolate.Resolvers;
Expand Down Expand Up @@ -155,7 +154,7 @@ private T CoerceArgumentValue<T>(ArgumentValue argument)
{
value = _parentContext._parser.ParseLiteral(
argument.ValueLiteral!,
argument.Argument,
argument,
typeof(T));
}

Expand All @@ -177,7 +176,7 @@ private T CoerceArgumentValue<T>(ArgumentValue argument)
if (typeof(IValueNode).IsAssignableFrom(typeof(T)))
{
throw ResolverContext_LiteralsNotSupported(
_selection.SyntaxNode, _path, argument.Argument.Name, typeof(T));
_selection.SyntaxNode, _path, argument.Name, typeof(T));
}

// If the object is internally held as a dictionary structure we will try to
Expand All @@ -204,7 +203,7 @@ private T CoerceArgumentValue<T>(ArgumentValue argument)

// we are unable to convert the argument to the request type.
throw ResolverContext_CannotConvertArgument(
_selection.SyntaxNode, _path, argument.Argument.Name, typeof(T));
_selection.SyntaxNode, _path, argument.Name, typeof(T));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,27 +10,53 @@ public static class MutationRequestExecutorBuilderExtensions
/// <param name="builder">
/// The request executor builder
/// </param>
/// <param name="applyToAllMutations">
/// Defines if the mutation convention defaults shall be applied to all mutations.
/// </param>
/// <returns>
/// The request executor builder
/// </returns>
/// <exception cref="ArgumentNullException">
/// The <paramref name="builder"/> is null.
/// </exception>
public static IRequestExecutorBuilder EnableMutationConventions(
this IRequestExecutorBuilder builder)
public static IRequestExecutorBuilder AddMutationConventions(
this IRequestExecutorBuilder builder,
bool applyToAllMutations = false)
=> AddMutationConventions(
builder,
new MutationConventionOptions
{
ApplyToAllMutations = applyToAllMutations
});

/// <summary>
/// Enables mutation conventions which will simplify creating GraphQL mutations.
/// </summary>
/// <param name="builder">
/// The request executor builder
/// </param>
/// <param name="options">
/// The mutation convention options.
/// </param>
/// <returns>
/// The request executor builder
/// </returns>
/// <exception cref="ArgumentNullException">
/// The <paramref name="builder"/> is null.
/// </exception>
public static IRequestExecutorBuilder AddMutationConventions(
this IRequestExecutorBuilder builder,
MutationConventionOptions options)
{
if (builder is null)
{
throw new ArgumentNullException(nameof(builder));
}

builder
.ConfigureSchema(c => c.ContextData[MutationContextDataKeys.Options] = options)
.TryAddTypeInterceptor<ErrorTypeInterceptor>()
.TryAddTypeInterceptor<InputArgumentTypeInterceptor>()
.TryAddTypeInterceptor<PayloadTypeInterceptor>()
.Services
.AddSingleton<IParameterExpressionBuilder, InputParameterExpressionBuilder>()
.AddSingleton<IParameterExpressionBuilder, InputArgumentParameterExpressionBuilder>();
.TryAddTypeInterceptor<MutationConventionTypeInterceptor>();

return builder;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using static HotChocolate.Types.ErrorContextData;
using static HotChocolate.Types.ErrorContextDataKeys;

namespace HotChocolate.Types;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
namespace HotChocolate.Types;

internal static class ErrorContextData
internal static class ErrorContextDataKeys
{
/// <summary>
/// Stores the definition of the errors on the context data
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ public async ValueTask InvokeAsync(IMiddlewareContext context)
throw;
}

context.SetScopedValue(ErrorContextData.Errors, errors);
context.SetScopedValue(ErrorContextDataKeys.Errors, errors);
context.Result = ErrorObject;
}
catch (Exception ex)
Expand All @@ -69,7 +69,7 @@ public async ValueTask InvokeAsync(IMiddlewareContext context)
throw;
}

context.SetScopedValue(ErrorContextData.Errors,
context.SetScopedValue(ErrorContextDataKeys.Errors,
new[]
{
error
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ private void RewriteMessageFieldToNonNullableStringType(
{
// if a user provides his/her own error interface we will not rewrite the message type
// and the user is responsible for ensuring that type and interface align.
if (context.ContextData.ContainsKey(ErrorContextData.ErrorType))
if (context.ContextData.ContainsKey(ErrorContextDataKeys.ErrorType))
{
return;
}
Expand Down
Loading