diff --git a/src/HotChocolate/Core/src/Types/Internal/FieldInitHelper.cs b/src/HotChocolate/Core/src/Types/Internal/FieldInitHelper.cs index 5d8b014245c..04847d7ebd0 100644 --- a/src/HotChocolate/Core/src/Types/Internal/FieldInitHelper.cs +++ b/src/HotChocolate/Core/src/Types/Internal/FieldInitHelper.cs @@ -91,21 +91,6 @@ public static TField[] CompleteFields( maxFieldCount); } - public static TField[] CompleteFields( - ITypeCompletionContext context, - ITypeSystemMember declaringMember, - TField[] fields) - where TField : class, IFieldDefinition - { - ArgumentNullException.ThrowIfNull(context); - ArgumentNullException.ThrowIfNull(declaringMember); - ArgumentNullException.ThrowIfNull(fields); - - CompleteFieldsInternal(context, declaringMember, fields); - - return fields; - } - public static TField[] CompleteFieldsInternal( ITypeCompletionContext context, ITypeSystemMember declaringMember, diff --git a/src/HotChocolate/Data/src/Data/Filters/Fields/AndField.cs b/src/HotChocolate/Data/src/Data/Filters/Fields/AndField.cs index a2396038e8a..f3241d461cc 100644 --- a/src/HotChocolate/Data/src/Data/Filters/Fields/AndField.cs +++ b/src/HotChocolate/Data/src/Data/Filters/Fields/AndField.cs @@ -9,8 +9,8 @@ public sealed class AndField : FilterOperationField , IAndField { - internal AndField(IDescriptorContext context, int index, string? scope) - : base(CreateConfiguration(context, scope), index) + internal AndField(FilterOperationFieldConfiguration configuration, int index) + : base(configuration, index) { } @@ -31,7 +31,7 @@ protected override void OnCompleteField( base.OnCompleteField(context, declaringMember, definition); } - private static FilterOperationFieldConfiguration CreateConfiguration( + internal static FilterOperationFieldConfiguration CreateConfiguration( IDescriptorContext context, string? scope) => FilterOperationFieldDescriptor diff --git a/src/HotChocolate/Data/src/Data/Filters/Fields/OrField.cs b/src/HotChocolate/Data/src/Data/Filters/Fields/OrField.cs index c8586d4a84f..a6b66236403 100644 --- a/src/HotChocolate/Data/src/Data/Filters/Fields/OrField.cs +++ b/src/HotChocolate/Data/src/Data/Filters/Fields/OrField.cs @@ -9,8 +9,8 @@ public sealed class OrField : FilterOperationField , IOrField { - internal OrField(IDescriptorContext context, int index, string? scope) - : base(CreateConfiguration(context, scope), index) + internal OrField(FilterOperationFieldConfiguration configuration, int index) + : base(configuration, index) { } @@ -31,7 +31,7 @@ protected override void OnCompleteField( base.OnCompleteField(context, declaringMember, definition); } - private static FilterOperationFieldConfiguration CreateConfiguration( + internal static FilterOperationFieldConfiguration CreateConfiguration( IDescriptorContext context, string? scope) => FilterOperationFieldDescriptor diff --git a/src/HotChocolate/Data/src/Data/Filters/FilterInputType.cs b/src/HotChocolate/Data/src/Data/Filters/FilterInputType.cs index ee1b345de5e..fb5d5196ee9 100644 --- a/src/HotChocolate/Data/src/Data/Filters/FilterInputType.cs +++ b/src/HotChocolate/Data/src/Data/Filters/FilterInputType.cs @@ -79,44 +79,46 @@ protected override InputFieldCollection OnCompleteFields( ITypeCompletionContext context, InputObjectTypeConfiguration definition) { - var fields = new InputField[definition.Fields.Count + 2]; - var index = 0; - + var fieldConfigurations = new List(definition.Fields.Count + 2); if (definition is FilterInputTypeConfiguration { UseAnd: true } def) { - fields[index] = new AndField(context.DescriptorContext, index, def.Scope); - index++; + fieldConfigurations.Add(AndField.CreateConfiguration(context.DescriptorContext, def.Scope)); } if (definition is FilterInputTypeConfiguration { UseOr: true } defOr) { - fields[index] = new OrField(context.DescriptorContext, index, defOr.Scope); - index++; + fieldConfigurations.Add(OrField.CreateConfiguration(context.DescriptorContext, defOr.Scope)); } - foreach (var fieldDefinition in - definition.Fields.Where(t => !t.Ignore)) + foreach (var fieldDefinition in definition.Fields.Where(t => !t.Ignore)) { switch (fieldDefinition) { case FilterOperationFieldConfiguration operation: - fields[index] = new FilterOperationField(operation, index); - index++; + fieldConfigurations.Add(operation); break; case FilterFieldConfiguration field: - fields[index] = new FilterField(field, index); - index++; + fieldConfigurations.Add(field); break; } } - if (fields.Length > index) - { - Array.Resize(ref fields, index); - } - - return new InputFieldCollection(CompleteFields(context, this, fields)); + return new InputFieldCollection( + CompleteFields( + context, + this, + fieldConfigurations, + CreateField)); + static InputField CreateField(FieldConfiguration fieldDef, int index) => + fieldDef switch + { + FilterOperationFieldConfiguration { Id: DefaultFilterOperations.And } op => new AndField(op, index), + FilterOperationFieldConfiguration { Id: DefaultFilterOperations.Or } op => new OrField(op, index), + FilterOperationFieldConfiguration op => new FilterOperationField(op, index), + FilterFieldConfiguration field => new FilterField(field, index), + _ => throw new ArgumentException("Unsupported field type", nameof(fieldDef)) + }; } // we are disabling the default configure method so diff --git a/src/HotChocolate/Data/src/Data/Sorting/SortInputType.cs b/src/HotChocolate/Data/src/Data/Sorting/SortInputType.cs index c0b1740b9ff..c4b7eca8a23 100644 --- a/src/HotChocolate/Data/src/Data/Sorting/SortInputType.cs +++ b/src/HotChocolate/Data/src/Data/Sorting/SortInputType.cs @@ -74,24 +74,23 @@ protected override InputFieldCollection OnCompleteFields( ITypeCompletionContext context, InputObjectTypeConfiguration configuration) { - var fields = new InputField[configuration.Fields.Count]; - var index = 0; + var fieldConfigurations = new List(configuration.Fields.Count); foreach (var fieldDefinition in configuration.Fields) { if (fieldDefinition is SortFieldConfiguration { Ignore: false } field) { - fields[index] = new SortField(field, index); - index++; + fieldConfigurations.Add(field); } } - if (fields.Length < index) - { - Array.Resize(ref fields, index); - } - - return new InputFieldCollection(CompleteFields(context, this, fields)); + return new InputFieldCollection( + CompleteFields( + context, + this, + fieldConfigurations, + CreateField)); + static InputField CreateField(SortFieldConfiguration fieldDef, int index) => new SortField(fieldDef, index); } // we are disabling the default configure method so diff --git a/src/HotChocolate/Data/test/Data.Filters.Tests/FilterInputTypeTest.cs b/src/HotChocolate/Data/test/Data.Filters.Tests/FilterInputTypeTest.cs index 0926dc03e85..194f3dcff3e 100644 --- a/src/HotChocolate/Data/test/Data.Filters.Tests/FilterInputTypeTest.cs +++ b/src/HotChocolate/Data/test/Data.Filters.Tests/FilterInputTypeTest.cs @@ -407,6 +407,20 @@ public async Task Execute_CoerceWhereArgument_MatchesSnapshot() result.MatchSnapshot(); } + [Fact] + public void FilterInputType_Honors_SortFieldsByName() + { + // arrange + // act + var schema = CreateSchema( + s => s + .AddType(new FilterInputType()) + .ModifyOptions(x => x.SortFieldsByName = true)); + + // assert + schema.MatchSnapshot(); + } + public class FooDirectiveType : DirectiveType { @@ -608,4 +622,6 @@ public class FilterWithStruct } public record struct ExampleValueType(string Foo, string Bar); + + public record FilterWithNonAlphabeticallyMembers(int X, int A, int Y, int Z, int B); } diff --git a/src/HotChocolate/Data/test/Data.Filters.Tests/__snapshots__/FilterInputTypeTest.FilterInputType_Honors_SortFieldsByName.graphql b/src/HotChocolate/Data/test/Data.Filters.Tests/__snapshots__/FilterInputTypeTest.FilterInputType_Honors_SortFieldsByName.graphql new file mode 100644 index 00000000000..61c607b7590 --- /dev/null +++ b/src/HotChocolate/Data/test/Data.Filters.Tests/__snapshots__/FilterInputTypeTest.FilterInputType_Honors_SortFieldsByName.graphql @@ -0,0 +1,32 @@ +schema { + query: Query +} + +type Query { + foo: String +} + +input FilterWithNonAlphabeticallyMembersFilterInput { + a: IntOperationFilterInput + and: [FilterWithNonAlphabeticallyMembersFilterInput!] + b: IntOperationFilterInput + or: [FilterWithNonAlphabeticallyMembersFilterInput!] + x: IntOperationFilterInput + y: IntOperationFilterInput + z: IntOperationFilterInput +} + +input IntOperationFilterInput { + eq: Int + gt: Int + gte: Int + in: [Int] + lt: Int + lte: Int + neq: Int + ngt: Int + ngte: Int + nin: [Int] + nlt: Int + nlte: Int +} diff --git a/src/HotChocolate/Data/test/Data.Sorting.Tests/SortInputTypeTests.cs b/src/HotChocolate/Data/test/Data.Sorting.Tests/SortInputTypeTests.cs index 989786b6d15..7a0270cdda8 100644 --- a/src/HotChocolate/Data/test/Data.Sorting.Tests/SortInputTypeTests.cs +++ b/src/HotChocolate/Data/test/Data.Sorting.Tests/SortInputTypeTests.cs @@ -237,6 +237,20 @@ public void SortInputType_Should_InfereType_When_ItIsAInterface() schema.ToString().MatchSnapshot(); } + [Fact] + public void SortInputType_Honors_SortFieldsByName() + { + // arrange + // act + var schema = CreateSchema( + s => s + .AddType(new SortInputType()) + .ModifyOptions(x => x.SortFieldsByName = true)); + + // assert + schema.MatchSnapshot(); + } + public class IgnoreTest { public int Id { get; set; } @@ -368,4 +382,6 @@ protected override void Configure(IObjectTypeDescriptor> descripto descriptor.Field(x => x.Root).UseFiltering(); } } + + public record SortTypeWithNonAlphabeticallyMembers(int X, int A, int Y, int Z, int B); } diff --git a/src/HotChocolate/Data/test/Data.Sorting.Tests/__snapshots__/SortInputTypeTests.SortInputType_Honors_SortFieldsByName.graphql b/src/HotChocolate/Data/test/Data.Sorting.Tests/__snapshots__/SortInputTypeTests.SortInputType_Honors_SortFieldsByName.graphql new file mode 100644 index 00000000000..b52be04043c --- /dev/null +++ b/src/HotChocolate/Data/test/Data.Sorting.Tests/__snapshots__/SortInputTypeTests.SortInputType_Honors_SortFieldsByName.graphql @@ -0,0 +1,20 @@ +schema { + query: Query +} + +type Query { + foo: String +} + +input SortTypeWithNonAlphabeticallyMembersSortInput { + a: SortEnumType + b: SortEnumType + x: SortEnumType + y: SortEnumType + z: SortEnumType +} + +enum SortEnumType { + ASC + DESC +}