Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using System.Text;
using HotChocolate.Features;
using HotChocolate.Types.Helpers;
using static HotChocolate.Resolvers.FieldClassMiddlewareFactory;
Expand Down Expand Up @@ -207,7 +208,7 @@ private void TryApplyInputConvention(
TypeMemHelper.Return(argumentNameMap);
}

var inputTypeName = options.FormatInputTypeName(mutation.Name);
var inputTypeName = options.FormatInputTypeName(mutation);

if (_typeRegistry.NameRefs.ContainsKey(inputTypeName))
{
Expand Down Expand Up @@ -278,7 +279,7 @@ private void TryApplyPayloadConvention(
Options options)
{
var typeRef = mutation.Type;
var payloadTypeName = options.FormatPayloadTypeName(mutation.Name);
var payloadTypeName = options.FormatPayloadTypeName(mutation);

// we ensure that we can resolve the mutation result type.
if (!_typeLookup.TryNormalizeReference(typeRef!, out typeRef)
Expand Down Expand Up @@ -396,7 +397,7 @@ private void TryApplyPayloadConvention(

// now that everything is put in place we will create the error types and
// the error middleware.
var errorTypeName = options.FormatErrorTypeName(mutation.Name);
var errorTypeName = options.FormatErrorTypeName(mutation);
RegisterErrorType(CreateErrorType(errorTypeName, errorDefinitions), mutation.Name);
var errorListTypeRef = Parse($"[{errorTypeName}!]");
payloadTypeDef.Fields.Add(
Expand Down Expand Up @@ -434,7 +435,7 @@ private void TryApplyPayloadConvention(
if (errorDefinitions.Count > 0)
{
// create error type
var errorTypeName = options.FormatErrorTypeName(mutation.Name);
var errorTypeName = options.FormatErrorTypeName(mutation);
RegisterErrorType(CreateErrorType(errorTypeName, errorDefinitions), mutation.Name);
var errorListTypeRef = Parse($"[{errorTypeName}!]");
errorField = new FieldDef(options.PayloadErrorsFieldName, errorListTypeRef);
Expand Down Expand Up @@ -864,34 +865,40 @@ private readonly ref struct Options(
public bool Apply { get; } = apply ??
MutationConventionOptionDefaults.ApplyToAllMutations;

public string FormatInputTypeName(string mutationName)
public string FormatInputTypeName(ObjectFieldConfiguration mutation)
=> InputTypeNamePattern.Replace(
$"{{{MutationConventionOptionDefaults.MutationName}}}",
FormatMutationName(mutationName));
FormatMutationName(mutation));

public string FormatPayloadTypeName(string mutationName)
public string FormatPayloadTypeName(ObjectFieldConfiguration mutation)
=> PayloadTypeNamePattern.Replace(
$"{{{MutationConventionOptionDefaults.MutationName}}}",
FormatMutationName(mutationName));
FormatMutationName(mutation));

public string FormatErrorTypeName(string mutationName)
public string FormatErrorTypeName(ObjectFieldConfiguration mutation)
=> PayloadErrorTypeNamePattern.Replace(
$"{{{MutationConventionOptionDefaults.MutationName}}}",
FormatMutationName(mutationName));
FormatMutationName(mutation));
Comment on lines +878 to +881

private static string FormatMutationName(ObjectFieldConfiguration mutation)
{
ArgumentNullException.ThrowIfNull(mutation);

return mutation.DisableMutationReformatting
? mutation.Name
: FormatMutationName(mutation.Name);
}

private static string FormatMutationName(string mutationName)
{
if (string.IsNullOrEmpty(mutationName))
{
return mutationName;
}
ArgumentException.ThrowIfNullOrEmpty(mutationName);

if (mutationName.IndexOf('_', StringComparison.Ordinal) < 0)
if (!mutationName.Contains('_'))
{
return char.ToUpperInvariant(mutationName[0]) + mutationName[1..];
}

var builder = new System.Text.StringBuilder(mutationName.Length);
var builder = new StringBuilder(mutationName.Length);
var upperNext = true;

foreach (var c in mutationName)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,5 +47,6 @@ internal enum CoreFieldFlags : long
UsesProjections = 1L << 31,
ImplicitField = 1L << 32,
BatchResolver = 1L << 33,
MemberReplacement = 1L << 34
MemberReplacement = 1L << 34,
DisableMutationReformatting = 1L << 35
}
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,26 @@ public bool IsParallelExecutable
}
}

/// <summary>
/// If this field is a mutation to which mutation conventions are applied,
/// this flag indicates that the field name should not be reformatted.
/// </summary>
public bool DisableMutationReformatting
{
get => (Flags & CoreFieldFlags.DisableMutationReformatting) == CoreFieldFlags.DisableMutationReformatting;
set
{
if (value)
{
Flags |= CoreFieldFlags.DisableMutationReformatting;
}
else
{
Flags &= ~CoreFieldFlags.DisableMutationReformatting;
}
}
}

/// <summary>
/// Defines in which DI scope this field is executed.
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1319,6 +1319,32 @@ public async Task MutationConvention_With_SnakeCase_ObjectField_NamingConvention
Assert.DoesNotContain("userName: String!", schemaText);
}

[Fact]
public async Task MutationConvention_With_DisabledMutationReformatting_Uses_Field_Name()
{
var schema =
await new ServiceCollection()
.AddGraphQL()
.AddMutationType<MutationWithDisabledReformatting>()
.AddMutationConventions(
new MutationConventionOptions
{
ApplyToAllMutations = true,
InputTypeNamePattern = "{MutationName}InputType",
PayloadTypeNamePattern = "{MutationName}PayloadType"
})
.ModifyOptions(o => o.StrictValidation = false)
.BuildSchemaAsync();

var schemaText = schema.ToString();

Assert.Contains("ch_myMutation(input: ch_myMutationInputType!): ch_myMutationPayloadType!", schemaText);
Assert.Contains("input ch_myMutationInputType {", schemaText);
Assert.Contains("type ch_myMutationPayloadType {", schemaText);
Assert.DoesNotContain("ChMyMutationInputType", schemaText);
Assert.DoesNotContain("ChMyMutationPayloadType", schemaText);
}

[Fact]
public async Task Mutation_With_ErrorAnnotatedAndCustomInterface_LateAndEarlyRegistration()
{
Expand Down Expand Up @@ -1575,6 +1601,12 @@ public User DoSomething(string name)
}
}

[PrefixMutationFields("ch_")]
public class MutationWithDisabledReformatting
{
public string MyMutation(string value) => value;
}

public class SimpleMutationWithSingleError
{
[Error(typeof(CustomException))]
Expand Down Expand Up @@ -2035,4 +2067,29 @@ private static string ToSnakeCase(string memberName)
[System.Text.RegularExpressions.GeneratedRegex(@"[A-Z]{2,}(?=[A-Z][a-z]+[0-9]*|\b)|[A-Z]?[a-z]+[0-9]*|[A-Z]|[0-9]+")]
private static partial System.Text.RegularExpressions.Regex SnakeCasePatternRegex();
}

public sealed class PrefixMutationFieldsAttribute(string prefix) : ObjectTypeDescriptorAttribute
{
protected override void OnConfigure(
IDescriptorContext context,
IObjectTypeDescriptor descriptor,
Type? type)
{
if (type is null)
{
return;
}

descriptor
.Extend()
.OnBeforeCreate((_, definition) =>
{
foreach (var field in definition.Fields)
{
field.Name = prefix + field.Name;
field.DisableMutationReformatting = true;
}
});
}
}
}
Loading