From 04ed91fbe2085d4c00dc92eb3ae556b8f7571f50 Mon Sep 17 00:00:00 2001 From: Michael Staib Date: Sat, 30 Nov 2019 00:11:55 +0100 Subject: [PATCH 01/17] Added Paging and Filtering attribute --- .../Types.Filters/UseFilteringAttribute.cs | 37 +++++++++++++++++ src/Core/Types/Types/Attributes/Argument.cs | 40 +++++++++++++++++++ .../Descriptors/Contracts/IDescriptor~1.cs | 1 - .../Types/Types/Relay/UsePagingAttribute.cs | 39 ++++++++++++++++++ 4 files changed, 116 insertions(+), 1 deletion(-) create mode 100644 src/Core/Types.Filters/UseFilteringAttribute.cs create mode 100644 src/Core/Types/Types/Attributes/Argument.cs create mode 100644 src/Core/Types/Types/Relay/UsePagingAttribute.cs diff --git a/src/Core/Types.Filters/UseFilteringAttribute.cs b/src/Core/Types.Filters/UseFilteringAttribute.cs new file mode 100644 index 00000000000..5c8e392af92 --- /dev/null +++ b/src/Core/Types.Filters/UseFilteringAttribute.cs @@ -0,0 +1,37 @@ +using System; +using System.Linq; +using System.Reflection; + +namespace HotChocolate.Types +{ + public sealed class UseFilteringAttribute : ObjectFieldDescriptorAttribute + { + private static readonly MethodInfo _generic = typeof(FilterObjectFieldDescriptorExtensions) + .GetMethods(BindingFlags.Public | BindingFlags.Static) + .Where(m => m.Name.Equals( + nameof(FilterObjectFieldDescriptorExtensions.UseFiltering), + StringComparison.Ordinal) + && m.GetGenericArguments().Length == 1 + && m.GetParameters().Length == 1 + && m.GetParameters()[0].ParameterType == typeof(IObjectFieldDescriptor)) + .Single(); + + /// + /// Gets or sets the filter type which specifies the filter object structure. + /// + /// The filter type + public Type FilterType { get; set; } + + public override void OnConfigure(IObjectFieldDescriptor descriptor) + { + if (FilterType is null) + { + descriptor.UseFiltering(); + } + else + { + _generic.MakeGenericMethod(FilterType).Invoke(null, new[] { descriptor }); + } + } + } +} \ No newline at end of file diff --git a/src/Core/Types/Types/Attributes/Argument.cs b/src/Core/Types/Types/Attributes/Argument.cs new file mode 100644 index 00000000000..b914ddce965 --- /dev/null +++ b/src/Core/Types/Types/Attributes/Argument.cs @@ -0,0 +1,40 @@ +using System; + +namespace HotChocolate.Types +{ + [AttributeUsage( + AttributeTargets.Property | AttributeTargets.Method, + Inherited = true, + AllowMultiple = true)] + public abstract class ObjectFieldDescriptorAttribute : Attribute + { + public abstract void OnConfigure(IObjectFieldDescriptor descriptor); + } + + [AttributeUsage( + AttributeTargets.Property | AttributeTargets.Method, + Inherited = true, + AllowMultiple = true)] + public abstract class InputFieldDescriptorAttribute : Attribute + { + public abstract void OnConfigure(IInputFieldDescriptor descriptor); + } + + [AttributeUsage( + AttributeTargets.Class | AttributeTargets.Struct, + Inherited = true, + AllowMultiple = true)] + public abstract class ObjectTypeDescriptorAttribute : Attribute + { + public abstract void OnConfigure(IObjectTypeDescriptor descriptor); + } + + [AttributeUsage( + AttributeTargets.Class | AttributeTargets.Struct, + Inherited = true, + AllowMultiple = true)] + public abstract class InputObjectTypeDescriptorAttribute : Attribute + { + public abstract void OnConfigure(IInputObjectTypeDescriptor descriptor); + } +} diff --git a/src/Core/Types/Types/Descriptors/Contracts/IDescriptor~1.cs b/src/Core/Types/Types/Descriptors/Contracts/IDescriptor~1.cs index 93e1bcbb06b..b43ed9dea1b 100644 --- a/src/Core/Types/Types/Descriptors/Contracts/IDescriptor~1.cs +++ b/src/Core/Types/Types/Descriptors/Contracts/IDescriptor~1.cs @@ -1,4 +1,3 @@ -using HotChocolate.Types.Descriptors; using HotChocolate.Types.Descriptors.Definitions; namespace HotChocolate.Types diff --git a/src/Core/Types/Types/Relay/UsePagingAttribute.cs b/src/Core/Types/Types/Relay/UsePagingAttribute.cs new file mode 100644 index 00000000000..87d6336b7cc --- /dev/null +++ b/src/Core/Types/Types/Relay/UsePagingAttribute.cs @@ -0,0 +1,39 @@ +using System; +using System.Linq; +using System.Reflection; + +namespace HotChocolate.Types.Relay +{ + public sealed class UsePagingAttribute : ObjectFieldDescriptorAttribute + { + private static readonly MethodInfo _usePaging = typeof(PagingObjectFieldDescriptorExtensions) + .GetMethods(BindingFlags.Public | BindingFlags.Static) + .Where(m => m.Name.Equals( + nameof(PagingObjectFieldDescriptorExtensions.UsePaging), + StringComparison.Ordinal) + && m.GetGenericArguments().Length == 1 + && m.GetParameters().Length == 1 + && m.GetParameters()[0].ParameterType == typeof(IObjectFieldDescriptor)) + .Single(); + + public UsePagingAttribute(Type schemaType) + { + SchemaType = schemaType; + } + + public Type SchemaType { get; } + + public override void OnConfigure(IObjectFieldDescriptor descriptor) + { + if (SchemaType is null || !typeof(IType).IsAssignableFrom(SchemaType)) + { + throw new SchemaException( + SchemaErrorBuilder.New() + .SetMessage("The UsePaging attribute needs a valid node schema type.") + .SetCode("ATTR_USEPAGING_SCHEMATYPE_INVALID") + .Build()); + } + _usePaging.MakeGenericMethod(SchemaType).Invoke(null, new[] { descriptor }); + } + } +} \ No newline at end of file From 85a2f7f0eb904ad05ef06ffdf8478f2af8cb032e Mon Sep 17 00:00:00 2001 From: Michael Staib Date: Sat, 30 Nov 2019 00:19:39 +0100 Subject: [PATCH 02/17] Added sorting attribute --- src/Core/Types.Sorting/UseSortingAttribute.cs | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 src/Core/Types.Sorting/UseSortingAttribute.cs diff --git a/src/Core/Types.Sorting/UseSortingAttribute.cs b/src/Core/Types.Sorting/UseSortingAttribute.cs new file mode 100644 index 00000000000..62af70630ae --- /dev/null +++ b/src/Core/Types.Sorting/UseSortingAttribute.cs @@ -0,0 +1,37 @@ +using System; +using System.Linq; +using System.Reflection; + +namespace HotChocolate.Types +{ + public sealed class UseSortingAttribute : ObjectFieldDescriptorAttribute + { + private static readonly MethodInfo _generic = typeof(SortObjectFieldDescriptorExtensions) + .GetMethods(BindingFlags.Public | BindingFlags.Static) + .Where(m => m.Name.Equals( + nameof(SortObjectFieldDescriptorExtensions.UseSorting), + StringComparison.Ordinal) + && m.GetGenericArguments().Length == 1 + && m.GetParameters().Length == 1 + && m.GetParameters()[0].ParameterType == typeof(IObjectFieldDescriptor)) + .Single(); + + /// + /// Gets or sets the sort type which specifies the sort object structure. + /// + /// The sort type + public Type SortType { get; set; } + + public override void OnConfigure(IObjectFieldDescriptor descriptor) + { + if (SortType is null) + { + descriptor.UseSorting(); + } + else + { + _generic.MakeGenericMethod(SortType).Invoke(null, new[] { descriptor }); + } + } + } +} \ No newline at end of file From 81a020517f6fbff8d3d251127d4b3451bebb7b44 Mon Sep 17 00:00:00 2001 From: Michael Staib Date: Sat, 30 Nov 2019 22:02:38 +0100 Subject: [PATCH 03/17] Wired up the descriptors with the descriptor attribute base --- src/Core/Types/Types/Attributes/Argument.cs | 63 +++++++++++++++++-- .../Types/Attributes/DescriptorAttribute.cs | 11 ++++ .../Types/Descriptors/ArgumentDescriptor.cs | 21 +++++-- .../Descriptors/ArgumentDescriptorBase~1.cs | 2 +- .../Descriptors/Contracts/IDescriptor.cs | 8 +++ .../Descriptors/Contracts/IDescriptor~1.cs | 3 +- .../Conventions/DefaultTypeInspector.cs | 26 ++++++++ .../Descriptors/Conventions/ITypeInspector.cs | 6 ++ .../Definitions/ArgumentDefinition.cs | 11 +++- .../Descriptors/Definitions/DefinitionBase.cs | 5 +- .../Definitions/EnumValueDefinition.cs | 14 ++++- .../Types/Descriptors/DescriptorBase~1.cs | 2 +- .../DirectiveArgumentDescriptor.cs | 10 +++ .../Descriptors/DirectiveTypeDescriptor.cs | 7 ++- .../Types/Descriptors/EnumTypeDescriptor.cs | 7 ++- .../Types/Descriptors/EnumValueDescriptor.cs | 22 +++++-- .../Types/Descriptors/InputFieldDescriptor.cs | 10 +++ .../Descriptors/InputObjectTypeDescriptor.cs | 7 ++- .../Descriptors/InterfaceFieldDescriptor.cs | 7 ++- .../Descriptors/InterfaceTypeDescriptor.cs | 7 ++- .../Descriptors/ObjectFieldDescriptor.cs | 7 ++- .../Types/Descriptors/ObjectTypeDescriptor.cs | 28 +++++++-- .../Descriptors/ObjectTypeDescriptor~1.cs | 10 ++- .../Descriptors/OutputFieldDescriptorBase.cs | 10 ++- .../Types/Descriptors/SchemaTypeDescriptor.cs | 2 +- .../Types/Descriptors/UnionTypeDescriptor.cs | 18 ++++-- 26 files changed, 271 insertions(+), 53 deletions(-) create mode 100644 src/Core/Types/Types/Attributes/DescriptorAttribute.cs create mode 100644 src/Core/Types/Types/Descriptors/Contracts/IDescriptor.cs diff --git a/src/Core/Types/Types/Attributes/Argument.cs b/src/Core/Types/Types/Attributes/Argument.cs index b914ddce965..f5d4f024836 100644 --- a/src/Core/Types/Types/Attributes/Argument.cs +++ b/src/Core/Types/Types/Attributes/Argument.cs @@ -6,8 +6,17 @@ namespace HotChocolate.Types AttributeTargets.Property | AttributeTargets.Method, Inherited = true, AllowMultiple = true)] - public abstract class ObjectFieldDescriptorAttribute : Attribute + public abstract class ObjectFieldDescriptorAttribute + : DescriptorAttribute { + internal sealed override void TryConfigure(IDescriptor descriptor) + { + if (descriptor is IObjectFieldDescriptor d) + { + OnConfigure(d); + } + } + public abstract void OnConfigure(IObjectFieldDescriptor descriptor); } @@ -15,8 +24,35 @@ public abstract class ObjectFieldDescriptorAttribute : Attribute AttributeTargets.Property | AttributeTargets.Method, Inherited = true, AllowMultiple = true)] - public abstract class InputFieldDescriptorAttribute : Attribute + public abstract class ArgumentDescriptorAttribute + : DescriptorAttribute { + internal sealed override void TryConfigure(IDescriptor descriptor) + { + if (descriptor is IArgumentDescriptor d) + { + OnConfigure(d); + } + } + + public abstract void OnConfigure(IArgumentDescriptor descriptor); + } + + [AttributeUsage( + AttributeTargets.Property | AttributeTargets.Method, + Inherited = true, + AllowMultiple = true)] + public abstract class InputFieldDescriptorAttribute + : DescriptorAttribute + { + internal sealed override void TryConfigure(IDescriptor descriptor) + { + if (descriptor is IInputFieldDescriptor d) + { + OnConfigure(d); + } + } + public abstract void OnConfigure(IInputFieldDescriptor descriptor); } @@ -24,8 +60,17 @@ public abstract class InputFieldDescriptorAttribute : Attribute AttributeTargets.Class | AttributeTargets.Struct, Inherited = true, AllowMultiple = true)] - public abstract class ObjectTypeDescriptorAttribute : Attribute + public abstract class ObjectTypeDescriptorAttribute + : DescriptorAttribute { + internal sealed override void TryConfigure(IDescriptor descriptor) + { + if (descriptor is IObjectTypeDescriptor d) + { + OnConfigure(d); + } + } + public abstract void OnConfigure(IObjectTypeDescriptor descriptor); } @@ -33,8 +78,18 @@ public abstract class ObjectTypeDescriptorAttribute : Attribute AttributeTargets.Class | AttributeTargets.Struct, Inherited = true, AllowMultiple = true)] - public abstract class InputObjectTypeDescriptorAttribute : Attribute + public abstract class InputObjectTypeDescriptorAttribute + : DescriptorAttribute { + internal sealed override void TryConfigure(IDescriptor descriptor) + { + if (descriptor is IInputObjectTypeDescriptor d) + { + OnConfigure(d); + } + } + public abstract void OnConfigure(IInputObjectTypeDescriptor descriptor); } + } diff --git a/src/Core/Types/Types/Attributes/DescriptorAttribute.cs b/src/Core/Types/Types/Attributes/DescriptorAttribute.cs new file mode 100644 index 00000000000..19735ba988d --- /dev/null +++ b/src/Core/Types/Types/Attributes/DescriptorAttribute.cs @@ -0,0 +1,11 @@ +using System; + +namespace HotChocolate.Types +{ + public abstract class DescriptorAttribute + : Attribute + { + internal abstract void TryConfigure(IDescriptor descriptor); + } + +} diff --git a/src/Core/Types/Types/Descriptors/ArgumentDescriptor.cs b/src/Core/Types/Types/Descriptors/ArgumentDescriptor.cs index d575e3d423c..19e41275099 100644 --- a/src/Core/Types/Types/Descriptors/ArgumentDescriptor.cs +++ b/src/Core/Types/Types/Descriptors/ArgumentDescriptor.cs @@ -1,8 +1,8 @@ -using System.Reflection; using System; -using HotChocolate.Utilities; +using System.Reflection; using HotChocolate.Language; using HotChocolate.Types.Descriptors.Definitions; +using HotChocolate.Utilities; namespace HotChocolate.Types.Descriptors { @@ -40,12 +40,21 @@ public ArgumentDescriptor( ParameterInfo parameter) : base(context) { - Definition.Name = - context.Naming.GetArgumentName(parameter); - Definition.Description = - context.Naming.GetArgumentDescription(parameter); + Definition.Name = context.Naming.GetArgumentName(parameter); + Definition.Description = context.Naming.GetArgumentDescription(parameter); Definition.Type = context.Inspector.GetArgumentType(parameter); Definition.DefaultValue = NullValueNode.Default; + Definition.Parameter = parameter; + } + + protected override void OnCreateDefinition(ArgumentDefinition definition) + { + base.OnCreateDefinition(definition); + + if (Definition.Parameter is { }) + { + Context.Inspector.ApplyAttributes(this, Definition.Parameter); + } } public new IArgumentDescriptor SyntaxNode( diff --git a/src/Core/Types/Types/Descriptors/ArgumentDescriptorBase~1.cs b/src/Core/Types/Types/Descriptors/ArgumentDescriptorBase~1.cs index b5d3af15cb4..d3c175fd0a4 100644 --- a/src/Core/Types/Types/Descriptors/ArgumentDescriptorBase~1.cs +++ b/src/Core/Types/Types/Descriptors/ArgumentDescriptorBase~1.cs @@ -16,7 +16,7 @@ protected ArgumentDescriptorBase(IDescriptorContext context) Definition = new T(); } - protected override T Definition { get; } + internal protected override T Definition { get; } protected void SyntaxNode( InputValueDefinitionNode inputValueDefinition) diff --git a/src/Core/Types/Types/Descriptors/Contracts/IDescriptor.cs b/src/Core/Types/Types/Descriptors/Contracts/IDescriptor.cs new file mode 100644 index 00000000000..1312a9d2719 --- /dev/null +++ b/src/Core/Types/Types/Descriptors/Contracts/IDescriptor.cs @@ -0,0 +1,8 @@ +using HotChocolate.Types.Descriptors.Definitions; + +namespace HotChocolate.Types +{ + public interface IDescriptor + { + } +} diff --git a/src/Core/Types/Types/Descriptors/Contracts/IDescriptor~1.cs b/src/Core/Types/Types/Descriptors/Contracts/IDescriptor~1.cs index b43ed9dea1b..c5a2dae1c02 100644 --- a/src/Core/Types/Types/Descriptors/Contracts/IDescriptor~1.cs +++ b/src/Core/Types/Types/Descriptors/Contracts/IDescriptor~1.cs @@ -2,8 +2,7 @@ namespace HotChocolate.Types { - public interface IDescriptor - where T : DefinitionBase + public interface IDescriptor : IDescriptor where T : DefinitionBase { IDescriptorExtension Extend(); } diff --git a/src/Core/Types/Types/Descriptors/Conventions/DefaultTypeInspector.cs b/src/Core/Types/Types/Descriptors/Conventions/DefaultTypeInspector.cs index fa1dab36a41..e1f5e1ae5a5 100644 --- a/src/Core/Types/Types/Descriptors/Conventions/DefaultTypeInspector.cs +++ b/src/Core/Types/Types/Descriptors/Conventions/DefaultTypeInspector.cs @@ -190,6 +190,21 @@ public virtual IEnumerable GetEnumValues(Type enumType) return Enumerable.Empty(); } + public MemberInfo GetEnumValueMember(object value) + { + if (value == null) + { + throw new ArgumentNullException(nameof(value)); + } + + Type enumType = value.GetType(); + if (enumType.IsEnum) + { + return enumType.GetMember(value.ToString()).FirstOrDefault(); + } + return null; + } + private static bool IsIgnored(MemberInfo member) { if (IsToString(member) || IsGetHashCode(member) || IsEquals(member)) @@ -236,5 +251,16 @@ public Type ExtractType(Type type) } public bool IsSchemaType(Type type) => BaseTypes.IsSchemaType(type); + + public void ApplyAttributes( + IDescriptor descriptor, + ICustomAttributeProvider attributeProvider) + { + foreach (var attribute in attributeProvider.GetCustomAttributes(true) + .OfType()) + { + attribute.TryConfigure(descriptor); + } + } } } diff --git a/src/Core/Types/Types/Descriptors/Conventions/ITypeInspector.cs b/src/Core/Types/Types/Descriptors/Conventions/ITypeInspector.cs index ccf90bf224d..81611da51de 100644 --- a/src/Core/Types/Types/Descriptors/Conventions/ITypeInspector.cs +++ b/src/Core/Types/Types/Descriptors/Conventions/ITypeInspector.cs @@ -37,8 +37,14 @@ public interface ITypeInspector IEnumerable GetEnumValues(Type enumType); + MemberInfo GetEnumValueMember(object value); + Type ExtractType(Type type); bool IsSchemaType(Type type); + + void ApplyAttributes( + IDescriptor descriptor, + ICustomAttributeProvider attributeProvider); } } diff --git a/src/Core/Types/Types/Descriptors/Definitions/ArgumentDefinition.cs b/src/Core/Types/Types/Descriptors/Definitions/ArgumentDefinition.cs index 76a33626f27..427c99b4d51 100644 --- a/src/Core/Types/Types/Descriptors/Definitions/ArgumentDefinition.cs +++ b/src/Core/Types/Types/Descriptors/Definitions/ArgumentDefinition.cs @@ -1,12 +1,17 @@ -using HotChocolate.Language; +using System.Reflection; +using HotChocolate.Language; + +#nullable enable namespace HotChocolate.Types.Descriptors.Definitions { public class ArgumentDefinition : FieldDefinitionBase { - public IValueNode DefaultValue { get; set; } + public IValueNode? DefaultValue { get; set; } + + public object? NativeDefaultValue { get; set; } - public object NativeDefaultValue { get; set; } + public ParameterInfo? Parameter { get; set; } } } diff --git a/src/Core/Types/Types/Descriptors/Definitions/DefinitionBase.cs b/src/Core/Types/Types/Descriptors/Definitions/DefinitionBase.cs index 3d7f1060d25..0e302fc5cb6 100644 --- a/src/Core/Types/Types/Descriptors/Definitions/DefinitionBase.cs +++ b/src/Core/Types/Types/Descriptors/Definitions/DefinitionBase.cs @@ -1,4 +1,7 @@ using System.Collections.Generic; +using System.Reflection; + +#nullable enable namespace HotChocolate.Types.Descriptors.Definitions { @@ -14,7 +17,7 @@ protected DefinitionBase() { } // /// Gets or sets the description the type shall have. /// - public string Description { get; set; } + public string? Description { get; set; } /// /// Get access to context data that are copied to the type diff --git a/src/Core/Types/Types/Descriptors/Definitions/EnumValueDefinition.cs b/src/Core/Types/Types/Descriptors/Definitions/EnumValueDefinition.cs index 1ffde71ca67..fe3bf6bb497 100644 --- a/src/Core/Types/Types/Descriptors/Definitions/EnumValueDefinition.cs +++ b/src/Core/Types/Types/Descriptors/Definitions/EnumValueDefinition.cs @@ -1,4 +1,7 @@ -using HotChocolate.Language; +using System.Reflection; +using HotChocolate.Language; + +#nullable enable namespace HotChocolate.Types.Descriptors.Definitions { @@ -6,10 +9,15 @@ public class EnumValueDefinition : TypeDefinitionBase , ICanBeDeprecated { - public string DeprecationReason { get; set; } + public string? DeprecationReason { get; set; } public bool IsDeprecated => !string.IsNullOrEmpty(DeprecationReason); - public object Value { get; set; } + public object? Value { get; set; } + + // + /// Gets or sets the enum value member. + /// + public MemberInfo? Member { get; set; } } } diff --git a/src/Core/Types/Types/Descriptors/DescriptorBase~1.cs b/src/Core/Types/Types/Descriptors/DescriptorBase~1.cs index 3bf1b583d7f..96c08c3a9bd 100644 --- a/src/Core/Types/Types/Descriptors/DescriptorBase~1.cs +++ b/src/Core/Types/Types/Descriptors/DescriptorBase~1.cs @@ -24,7 +24,7 @@ protected DescriptorBase(IDescriptorContext context) IDescriptorContext IHasDescriptorContext.Context => Context; - protected abstract T Definition { get; } + internal protected abstract T Definition { get; } public IDescriptorExtension Extend() { diff --git a/src/Core/Types/Types/Descriptors/DirectiveArgumentDescriptor.cs b/src/Core/Types/Types/Descriptors/DirectiveArgumentDescriptor.cs index ad3e9218110..31c71a5f258 100644 --- a/src/Core/Types/Types/Descriptors/DirectiveArgumentDescriptor.cs +++ b/src/Core/Types/Types/Descriptors/DirectiveArgumentDescriptor.cs @@ -31,6 +31,16 @@ public DirectiveArgumentDescriptor( Definition.Property = property; } + protected override void OnCreateDefinition(DirectiveArgumentDefinition definition) + { + base.OnCreateDefinition(definition); + + if (Definition.Property is { }) + { + Context.Inspector.ApplyAttributes(this, Definition.Property); + } + } + public new IDirectiveArgumentDescriptor SyntaxNode( InputValueDefinitionNode inputValueDefinition) { diff --git a/src/Core/Types/Types/Descriptors/DirectiveTypeDescriptor.cs b/src/Core/Types/Types/Descriptors/DirectiveTypeDescriptor.cs index b93fe5e7d14..0dcd88b4c87 100644 --- a/src/Core/Types/Types/Descriptors/DirectiveTypeDescriptor.cs +++ b/src/Core/Types/Types/Descriptors/DirectiveTypeDescriptor.cs @@ -37,7 +37,7 @@ protected DirectiveTypeDescriptor(IDescriptorContext context) Definition.ClrType = typeof(object); } - protected override DirectiveTypeDefinition Definition { get; } = + internal protected override DirectiveTypeDefinition Definition { get; } = new DirectiveTypeDefinition(); protected ICollection Arguments { get; } = @@ -59,6 +59,11 @@ protected override void OnCreateDefinition( OnCompleteArguments(arguments, handledMembers); definition.Arguments.AddRange(arguments.Values); + + if (Definition.ClrType is { }) + { + Context.Inspector.ApplyAttributes(this, Definition.ClrType); + } } protected virtual void OnCompleteArguments( diff --git a/src/Core/Types/Types/Descriptors/EnumTypeDescriptor.cs b/src/Core/Types/Types/Descriptors/EnumTypeDescriptor.cs index ea9fc2a8455..f102223a345 100644 --- a/src/Core/Types/Types/Descriptors/EnumTypeDescriptor.cs +++ b/src/Core/Types/Types/Descriptors/EnumTypeDescriptor.cs @@ -31,7 +31,7 @@ protected EnumTypeDescriptor(IDescriptorContext context, Type clrType) context.Options.DefaultBindingBehavior; } - protected override EnumTypeDefinition Definition { get; } = + internal protected override EnumTypeDefinition Definition { get; } = new EnumTypeDefinition(); protected ICollection Values { get; } = @@ -51,6 +51,11 @@ protected override void OnCreateDefinition( { definition.Values.Add(value); } + + if (Definition.ClrType is { }) + { + Context.Inspector.ApplyAttributes(this, Definition.ClrType); + } } protected void AddImplicitValues( diff --git a/src/Core/Types/Types/Descriptors/EnumValueDescriptor.cs b/src/Core/Types/Types/Descriptors/EnumValueDescriptor.cs index 4af780990e1..577dbaf5eb0 100644 --- a/src/Core/Types/Types/Descriptors/EnumValueDescriptor.cs +++ b/src/Core/Types/Types/Descriptors/EnumValueDescriptor.cs @@ -8,7 +8,7 @@ public class EnumValueDescriptor : DescriptorBase , IEnumValueDescriptor { - private bool _deprecatedDependecySet; + private bool _deprecatedDependencySet; private DirectiveDefinition _deprecatedDirective; public EnumValueDescriptor(IDescriptorContext context, object value) @@ -21,8 +21,8 @@ public EnumValueDescriptor(IDescriptorContext context, object value) Definition.Name = context.Naming.GetEnumValueName(value); Definition.Value = value; - Definition.Description = - context.Naming.GetEnumValueDescription(value); + Definition.Description = context.Naming.GetEnumValueDescription(value); + Definition.Member = context.Inspector.GetEnumValueMember(value); if (context.Naming.IsDeprecated(value, out string reason)) { @@ -30,9 +30,19 @@ public EnumValueDescriptor(IDescriptorContext context, object value) } } - protected override EnumValueDefinition Definition { get; } = + internal protected override EnumValueDefinition Definition { get; } = new EnumValueDefinition(); + protected override void OnCreateDefinition(EnumValueDefinition definition) + { + base.OnCreateDefinition(definition); + + if (Definition.Member is { }) + { + Context.Inspector.ApplyAttributes(this, Definition.Member); + } + } + public IEnumValueDescriptor SyntaxNode( EnumValueDefinitionNode enumValueDefinition) { @@ -89,14 +99,14 @@ private void AddDeprectedDirective(string reason) new DeprecatedDirective(reason)); Definition.Directives.Add(_deprecatedDirective); - if (!_deprecatedDependecySet) + if (!_deprecatedDependencySet) { Definition.Dependencies.Add(new TypeDependency( new ClrTypeReference( typeof(DeprecatedDirectiveType), TypeContext.None), TypeDependencyKind.Completed)); - _deprecatedDependecySet = true; + _deprecatedDependencySet = true; } } diff --git a/src/Core/Types/Types/Descriptors/InputFieldDescriptor.cs b/src/Core/Types/Types/Descriptors/InputFieldDescriptor.cs index c57add38fd8..e47b9a5986a 100644 --- a/src/Core/Types/Types/Descriptors/InputFieldDescriptor.cs +++ b/src/Core/Types/Types/Descriptors/InputFieldDescriptor.cs @@ -31,6 +31,16 @@ public InputFieldDescriptor( Definition.Type = context.Inspector.GetInputReturnType(property); } + protected override void OnCreateDefinition(InputFieldDefinition definition) + { + base.OnCreateDefinition(definition); + + if (Definition.Property is { }) + { + Context.Inspector.ApplyAttributes(this, Definition.Property); + } + } + public new IInputFieldDescriptor SyntaxNode( InputValueDefinitionNode inputValueDefinition) { diff --git a/src/Core/Types/Types/Descriptors/InputObjectTypeDescriptor.cs b/src/Core/Types/Types/Descriptors/InputObjectTypeDescriptor.cs index 64d3b0c5842..7692e498a91 100644 --- a/src/Core/Types/Types/Descriptors/InputObjectTypeDescriptor.cs +++ b/src/Core/Types/Types/Descriptors/InputObjectTypeDescriptor.cs @@ -34,7 +34,7 @@ protected InputObjectTypeDescriptor(IDescriptorContext context) Definition.ClrType = typeof(object); } - protected override InputObjectTypeDefinition Definition { get; } = + internal protected override InputObjectTypeDefinition Definition { get; } = new InputObjectTypeDefinition(); protected List Fields { get; } = @@ -55,6 +55,11 @@ protected override void OnCreateDefinition( OnCompleteFields(fields, handledProperties); Definition.Fields.AddRange(fields.Values); + + if (Definition.ClrType is { }) + { + Context.Inspector.ApplyAttributes(this, Definition.ClrType); + } } protected virtual void OnCompleteFields( diff --git a/src/Core/Types/Types/Descriptors/InterfaceFieldDescriptor.cs b/src/Core/Types/Types/Descriptors/InterfaceFieldDescriptor.cs index 5a46d4075f2..c4904cb0410 100644 --- a/src/Core/Types/Types/Descriptors/InterfaceFieldDescriptor.cs +++ b/src/Core/Types/Types/Descriptors/InterfaceFieldDescriptor.cs @@ -46,13 +46,18 @@ public InterfaceFieldDescriptor( } } - protected override InterfaceFieldDefinition Definition { get; } = + internal protected override InterfaceFieldDefinition Definition { get; } = new InterfaceFieldDefinition(); protected override void OnCreateDefinition( InterfaceFieldDefinition definition) { CompleteArguments(definition); + + if (Definition.Member is { }) + { + Context.Inspector.ApplyAttributes(this, Definition.Member); + } } private void CompleteArguments(InterfaceFieldDefinition definition) diff --git a/src/Core/Types/Types/Descriptors/InterfaceTypeDescriptor.cs b/src/Core/Types/Types/Descriptors/InterfaceTypeDescriptor.cs index e629213a6bb..b289305094e 100644 --- a/src/Core/Types/Types/Descriptors/InterfaceTypeDescriptor.cs +++ b/src/Core/Types/Types/Descriptors/InterfaceTypeDescriptor.cs @@ -35,7 +35,7 @@ protected InterfaceTypeDescriptor( Definition.ClrType = typeof(object); } - protected override InterfaceTypeDefinition Definition { get; } = + internal protected override InterfaceTypeDefinition Definition { get; } = new InterfaceTypeDefinition(); protected ICollection Fields { get; } = @@ -56,6 +56,11 @@ protected override void OnCreateDefinition( OnCompleteFields(fields, handledMembers); Definition.Fields.AddRange(fields.Values); + + if (Definition.ClrType is { }) + { + Context.Inspector.ApplyAttributes(this, Definition.ClrType); + } } protected virtual void OnCompleteFields( diff --git a/src/Core/Types/Types/Descriptors/ObjectFieldDescriptor.cs b/src/Core/Types/Types/Descriptors/ObjectFieldDescriptor.cs index bcfc6324754..e9029daeafb 100644 --- a/src/Core/Types/Types/Descriptors/ObjectFieldDescriptor.cs +++ b/src/Core/Types/Types/Descriptors/ObjectFieldDescriptor.cs @@ -63,13 +63,18 @@ protected ObjectFieldDescriptor( } } - protected override ObjectFieldDefinition Definition { get; } = + internal protected override ObjectFieldDefinition Definition { get; } = new ObjectFieldDefinition(); protected override void OnCreateDefinition( ObjectFieldDefinition definition) { CompleteArguments(definition); + + if (Definition.Member is { }) + { + Context.Inspector.ApplyAttributes(this, Definition.Member); + } } private void CompleteArguments(ObjectFieldDefinition definition) diff --git a/src/Core/Types/Types/Descriptors/ObjectTypeDescriptor.cs b/src/Core/Types/Types/Descriptors/ObjectTypeDescriptor.cs index 0f7b258c54e..473bf5a37c3 100644 --- a/src/Core/Types/Types/Descriptors/ObjectTypeDescriptor.cs +++ b/src/Core/Types/Types/Descriptors/ObjectTypeDescriptor.cs @@ -35,7 +35,7 @@ public ObjectTypeDescriptor(IDescriptorContext context) Definition.ClrType = typeof(object); } - protected override ObjectTypeDefinition Definition { get; } = + internal protected override ObjectTypeDefinition Definition { get; } = new ObjectTypeDefinition(); protected ICollection Fields { get; } = @@ -59,6 +59,11 @@ protected override void OnCreateDefinition( OnCompleteFields(fields, handledMembers); Definition.Fields.AddRange(fields.Values); + + if (Definition.ClrType is { }) + { + Context.Inspector.ApplyAttributes(this, Definition.ClrType); + } } protected virtual void OnCompleteFields( @@ -98,8 +103,7 @@ private void AddResolvers( Type sourceType, Type resolverType) { - foreach (MemberInfo member in Context.Inspector - .GetMembers(resolverType)) + foreach (MemberInfo member in Context.Inspector.GetMembers(resolverType)) { if (IsResolverRelevant(sourceType, member)) { @@ -227,7 +231,14 @@ public IObjectTypeDescriptor IsOfType(IsOfType isOfType) public IObjectFieldDescriptor Field(NameString name) { - var fieldDescriptor = ObjectFieldDescriptor.New(Context, name); + ObjectFieldDescriptor fieldDescriptor = + Fields.FirstOrDefault(t => t.Definition.Name.Equals(name)); + if (fieldDescriptor is { }) + { + return fieldDescriptor; + } + + fieldDescriptor = ObjectFieldDescriptor.New(Context, name); Fields.Add(fieldDescriptor); return fieldDescriptor; } @@ -247,7 +258,14 @@ public IObjectFieldDescriptor Field( MemberInfo member = propertyOrMethod.ExtractMember(); if (member is PropertyInfo || member is MethodInfo) { - var fieldDescriptor = ObjectFieldDescriptor.New( + ObjectFieldDescriptor fieldDescriptor = + Fields.FirstOrDefault(t => t.Definition.Member == member); + if (fieldDescriptor is { }) + { + return fieldDescriptor; + } + + fieldDescriptor = ObjectFieldDescriptor.New( Context, member, typeof(TResolver)); Fields.Add(fieldDescriptor); return fieldDescriptor; diff --git a/src/Core/Types/Types/Descriptors/ObjectTypeDescriptor~1.cs b/src/Core/Types/Types/Descriptors/ObjectTypeDescriptor~1.cs index fa1cd05e210..d93a19f2864 100644 --- a/src/Core/Types/Types/Descriptors/ObjectTypeDescriptor~1.cs +++ b/src/Core/Types/Types/Descriptors/ObjectTypeDescriptor~1.cs @@ -29,9 +29,13 @@ protected override void OnCompleteFields( { FieldDescriptorUtilities.AddImplicitFields( this, - p => ObjectFieldDescriptor - .New(Context, p) - .CreateDefinition(), + p => + { + // how to fix the field declaration issue + ObjectFieldDescriptor descriptor = ObjectFieldDescriptor.New(Context, p); + Fields.Add(descriptor); + return descriptor.CreateDefinition(); + }, fields, handledMembers); } diff --git a/src/Core/Types/Types/Descriptors/OutputFieldDescriptorBase.cs b/src/Core/Types/Types/Descriptors/OutputFieldDescriptorBase.cs index 0f5c641d074..5cb0cd0ecc6 100644 --- a/src/Core/Types/Types/Descriptors/OutputFieldDescriptorBase.cs +++ b/src/Core/Types/Types/Descriptors/OutputFieldDescriptorBase.cs @@ -4,7 +4,6 @@ using HotChocolate.Properties; using HotChocolate.Types.Descriptors.Definitions; using System.Reflection; -using System.Globalization; namespace HotChocolate.Types.Descriptors { @@ -12,7 +11,7 @@ public abstract class OutputFieldDescriptorBase : DescriptorBase where TDefinition : OutputFieldDefinitionBase { - private bool _deprecatedDependecySet; + private bool _deprecatedDependencySet; private DirectiveDefinition _deprecatedDirective; protected OutputFieldDescriptorBase(IDescriptorContext context) @@ -20,8 +19,7 @@ protected OutputFieldDescriptorBase(IDescriptorContext context) { } - protected IReadOnlyDictionary Parameters - { get; set; } + protected IReadOnlyDictionary Parameters { get; set; } protected void SyntaxNode( FieldDefinitionNode syntaxNode) @@ -141,14 +139,14 @@ private void AddDeprectedDirective(string reason) new DeprecatedDirective(reason)); Definition.Directives.Add(_deprecatedDirective); - if (!_deprecatedDependecySet) + if (!_deprecatedDependencySet) { Definition.Dependencies.Add(new TypeDependency( new ClrTypeReference( typeof(DeprecatedDirectiveType), TypeContext.None), TypeDependencyKind.Completed)); - _deprecatedDependecySet = true; + _deprecatedDependencySet = true; } } diff --git a/src/Core/Types/Types/Descriptors/SchemaTypeDescriptor.cs b/src/Core/Types/Types/Descriptors/SchemaTypeDescriptor.cs index ca269d68474..951a0c51fa9 100644 --- a/src/Core/Types/Types/Descriptors/SchemaTypeDescriptor.cs +++ b/src/Core/Types/Types/Descriptors/SchemaTypeDescriptor.cs @@ -18,7 +18,7 @@ public SchemaTypeDescriptor(IDescriptorContext context, Type type) Definition.Name = context.Naming.GetTypeName(type); } - protected override SchemaTypeDefinition Definition { get; } = + internal protected override SchemaTypeDefinition Definition { get; } = new SchemaTypeDefinition(); public ISchemaTypeDescriptor Name(NameString value) diff --git a/src/Core/Types/Types/Descriptors/UnionTypeDescriptor.cs b/src/Core/Types/Types/Descriptors/UnionTypeDescriptor.cs index 46e62174954..b7d32413727 100644 --- a/src/Core/Types/Types/Descriptors/UnionTypeDescriptor.cs +++ b/src/Core/Types/Types/Descriptors/UnionTypeDescriptor.cs @@ -17,10 +17,8 @@ protected UnionTypeDescriptor(IDescriptorContext context, Type clrType) } Definition.ClrType = clrType; - Definition.Name = - context.Naming.GetTypeName(clrType, TypeKind.Union); - Definition.Description = - context.Naming.GetTypeDescription(clrType, TypeKind.Union); + Definition.Name = context.Naming.GetTypeName(clrType, TypeKind.Union); + Definition.Description = context.Naming.GetTypeDescription(clrType, TypeKind.Union); } protected UnionTypeDescriptor(IDescriptorContext context) @@ -29,9 +27,19 @@ protected UnionTypeDescriptor(IDescriptorContext context) Definition.ClrType = typeof(object); } - protected override UnionTypeDefinition Definition { get; } = + internal protected override UnionTypeDefinition Definition { get; } = new UnionTypeDefinition(); + protected override void OnCreateDefinition(UnionTypeDefinition definition) + { + base.OnCreateDefinition(definition); + + if (Definition.ClrType is { }) + { + Context.Inspector.ApplyAttributes(this, Definition.ClrType); + } + } + public IUnionTypeDescriptor SyntaxNode( UnionTypeDefinitionNode unionTypeDefinitionNode) { From ea70dd1695f01bc5c542f3d01c165b22ee43fd81 Mon Sep 17 00:00:00 2001 From: Michael Staib Date: Sat, 30 Nov 2019 22:25:05 +0100 Subject: [PATCH 04/17] added tests --- .../Types/ObjectTypeAttributeTests.cs | 92 +++++++++++++++++++ src/Core/Types/Types/Attributes/Argument.cs | 35 ------- .../Attributes/ArgumentDescriptorAttribute.cs | 23 +++++ .../ObjectFieldDescriptorAttribute.cs | 23 +++++ 4 files changed, 138 insertions(+), 35 deletions(-) create mode 100644 src/Core/Types.Tests/Types/ObjectTypeAttributeTests.cs create mode 100644 src/Core/Types/Types/Attributes/ArgumentDescriptorAttribute.cs create mode 100644 src/Core/Types/Types/Attributes/ObjectFieldDescriptorAttribute.cs diff --git a/src/Core/Types.Tests/Types/ObjectTypeAttributeTests.cs b/src/Core/Types.Tests/Types/ObjectTypeAttributeTests.cs new file mode 100644 index 00000000000..098d47628bd --- /dev/null +++ b/src/Core/Types.Tests/Types/ObjectTypeAttributeTests.cs @@ -0,0 +1,92 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; +using System.Threading.Tasks; +using HotChocolate.Execution; +using HotChocolate.Resolvers; +using HotChocolate.Types.Descriptors; +using Moq; +using Snapshooter.Xunit; +using Xunit; + +#nullable enable + +namespace HotChocolate.Types +{ + public class ObjectTypeAttributeTests + : TypeTestBase + { + [Fact] + public void ArgumentDescriptorAttribute_Changes_DefaultValue() + { + // act + ISchema schema = SchemaBuilder.New() + .AddQueryType() + .Create(); + + // assert + Assert.Equal( + "abc", + schema.QueryType.Fields["field"].Arguments["argument"].DefaultValue.Value); + } + + [Fact] + public void ObjectFieldDescriptorAttribute_Adds_ContextData() + { + // act + ISchema schema = SchemaBuilder.New() + .AddQueryType() + .Create(); + + // assert + Assert.Equal( + "def", + schema.QueryType.Fields["field"].ContextData["abc"]); + } + + public class Object1 + { + public string GetField([ArgumentDefaultValue("abc")]string argument) + { + throw new NotImplementedException(); + } + } + + public class ArgumentDefaultValueAttribute + : ArgumentDescriptorAttribute + { + public ArgumentDefaultValueAttribute(object defaultValue) + { + DefaultValue = defaultValue; + } + + public object DefaultValue { get; } + + public override void OnConfigure(IArgumentDescriptor descriptor) + { + descriptor.DefaultValue(DefaultValue); + } + } + + public class Object2 + { + [PropertyAddContextData] + public string GetField() + { + throw new NotImplementedException(); + } + } + + public class PropertyAddContextDataAttribute + : ObjectFieldDescriptorAttribute + { + public override void OnConfigure(IObjectFieldDescriptor descriptor) + { + descriptor.Extend().OnBeforeCompletion( + (c, d) => d.ContextData.Add("abc", "def")); + } + } + } +} diff --git a/src/Core/Types/Types/Attributes/Argument.cs b/src/Core/Types/Types/Attributes/Argument.cs index f5d4f024836..be47139831f 100644 --- a/src/Core/Types/Types/Attributes/Argument.cs +++ b/src/Core/Types/Types/Attributes/Argument.cs @@ -2,41 +2,6 @@ namespace HotChocolate.Types { - [AttributeUsage( - AttributeTargets.Property | AttributeTargets.Method, - Inherited = true, - AllowMultiple = true)] - public abstract class ObjectFieldDescriptorAttribute - : DescriptorAttribute - { - internal sealed override void TryConfigure(IDescriptor descriptor) - { - if (descriptor is IObjectFieldDescriptor d) - { - OnConfigure(d); - } - } - - public abstract void OnConfigure(IObjectFieldDescriptor descriptor); - } - - [AttributeUsage( - AttributeTargets.Property | AttributeTargets.Method, - Inherited = true, - AllowMultiple = true)] - public abstract class ArgumentDescriptorAttribute - : DescriptorAttribute - { - internal sealed override void TryConfigure(IDescriptor descriptor) - { - if (descriptor is IArgumentDescriptor d) - { - OnConfigure(d); - } - } - - public abstract void OnConfigure(IArgumentDescriptor descriptor); - } [AttributeUsage( AttributeTargets.Property | AttributeTargets.Method, diff --git a/src/Core/Types/Types/Attributes/ArgumentDescriptorAttribute.cs b/src/Core/Types/Types/Attributes/ArgumentDescriptorAttribute.cs new file mode 100644 index 00000000000..5f7ecab3562 --- /dev/null +++ b/src/Core/Types/Types/Attributes/ArgumentDescriptorAttribute.cs @@ -0,0 +1,23 @@ +using System; + +namespace HotChocolate.Types +{ + [AttributeUsage( + AttributeTargets.Parameter, + Inherited = true, + AllowMultiple = true)] + public abstract class ArgumentDescriptorAttribute + : DescriptorAttribute + { + internal sealed override void TryConfigure(IDescriptor descriptor) + { + if (descriptor is IArgumentDescriptor d) + { + OnConfigure(d); + } + } + + public abstract void OnConfigure(IArgumentDescriptor descriptor); + } + +} diff --git a/src/Core/Types/Types/Attributes/ObjectFieldDescriptorAttribute.cs b/src/Core/Types/Types/Attributes/ObjectFieldDescriptorAttribute.cs new file mode 100644 index 00000000000..1aa1cf25ec3 --- /dev/null +++ b/src/Core/Types/Types/Attributes/ObjectFieldDescriptorAttribute.cs @@ -0,0 +1,23 @@ +using System; + +namespace HotChocolate.Types +{ + [AttributeUsage( + AttributeTargets.Property | AttributeTargets.Method, + Inherited = true, + AllowMultiple = true)] + public abstract class ObjectFieldDescriptorAttribute + : DescriptorAttribute + { + internal sealed override void TryConfigure(IDescriptor descriptor) + { + if (descriptor is IObjectFieldDescriptor d) + { + OnConfigure(d); + } + } + + public abstract void OnConfigure(IObjectFieldDescriptor descriptor); + } + +} From ab23c2496cd850d0d892139524b6d51ab119c7c9 Mon Sep 17 00:00:00 2001 From: Michael Staib Date: Sat, 30 Nov 2019 22:29:20 +0100 Subject: [PATCH 05/17] Added include update field test --- .../Types.Tests/Types/ObjectTypeAttributeTests.cs | 15 +++++++++++++++ src/Core/Types.Tests/Types/ObjectTypeTests.cs | 14 ++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/src/Core/Types.Tests/Types/ObjectTypeAttributeTests.cs b/src/Core/Types.Tests/Types/ObjectTypeAttributeTests.cs index 098d47628bd..bddef0834f0 100644 --- a/src/Core/Types.Tests/Types/ObjectTypeAttributeTests.cs +++ b/src/Core/Types.Tests/Types/ObjectTypeAttributeTests.cs @@ -46,6 +46,21 @@ public void ObjectFieldDescriptorAttribute_Adds_ContextData() schema.QueryType.Fields["field"].ContextData["abc"]); } + [Fact] + public void ObjectFieldDescriptorAttribute_Updated_FieldDefinition() + { + // act + ISchema schema = SchemaBuilder.New() + .AddQueryType(d => + d.Field(t => t.GetField()).Name("foo")) + .Create(); + + // assert + Assert.Equal( + "def", + schema.QueryType.Fields["foo"].ContextData["abc"]); + } + public class Object1 { public string GetField([ArgumentDefaultValue("abc")]string argument) diff --git a/src/Core/Types.Tests/Types/ObjectTypeTests.cs b/src/Core/Types.Tests/Types/ObjectTypeTests.cs index c3b5ecafe8e..a0ab884a6d2 100644 --- a/src/Core/Types.Tests/Types/ObjectTypeTests.cs +++ b/src/Core/Types.Tests/Types/ObjectTypeTests.cs @@ -679,6 +679,20 @@ public void Include_TypeWithOneField_ContainsThisField() Assert.True(fooType.Fields.ContainsField("description")); } + [Fact] + public void Include_TypeWithOneField_And_Update_FieldDefinition() + { + // arrange + // act + ObjectType fooType = + CreateType(new ObjectType(d => d + .Include() + .Field(t => t.Description).Name("desc"))); + + // assert + Assert.True(fooType.Fields.ContainsField("desc")); + } + [Fact] public void NonNullAttribute_StringIsRewritten_NonNullStringType() { From 9e5de3f324879a108ddb651a3313ff6a0632e391 Mon Sep 17 00:00:00 2001 From: Michael Staib Date: Sat, 30 Nov 2019 22:43:09 +0100 Subject: [PATCH 06/17] Added attributes for object type --- .../Types/ObjectTypeAttributeTests.cs | 30 +++++++++++++++++++ src/Core/Types/Types/Attributes/Argument.cs | 18 ----------- .../ObjectTypeDescriptorAttribute.cs | 23 ++++++++++++++ .../Types/Descriptors/ObjectTypeDescriptor.cs | 10 +++---- 4 files changed, 58 insertions(+), 23 deletions(-) create mode 100644 src/Core/Types/Types/Attributes/ObjectTypeDescriptorAttribute.cs diff --git a/src/Core/Types.Tests/Types/ObjectTypeAttributeTests.cs b/src/Core/Types.Tests/Types/ObjectTypeAttributeTests.cs index bddef0834f0..36fe3dda611 100644 --- a/src/Core/Types.Tests/Types/ObjectTypeAttributeTests.cs +++ b/src/Core/Types.Tests/Types/ObjectTypeAttributeTests.cs @@ -61,6 +61,18 @@ public void ObjectFieldDescriptorAttribute_Updated_FieldDefinition() schema.QueryType.Fields["foo"].ContextData["abc"]); } + [Fact] + public void ObjectTypeDescriptorAttribute_Updated_FieldDefinition() + { + // act + ISchema schema = SchemaBuilder.New() + .AddQueryType() + .Create(); + + // assert + Assert.True(schema.QueryType.Fields.ContainsField("abc")); + } + public class Object1 { public string GetField([ArgumentDefaultValue("abc")]string argument) @@ -103,5 +115,23 @@ public override void OnConfigure(IObjectFieldDescriptor descriptor) (c, d) => d.ContextData.Add("abc", "def")); } } + + [ObjectAddField] + public class Object3 + { + public string GetField() + { + throw new NotImplementedException(); + } + } + + public class ObjectAddFieldAttribute + : ObjectTypeDescriptorAttribute + { + public override void OnConfigure(IObjectTypeDescriptor descriptor) + { + descriptor.Field("abc").Resolver("def"); + } + } } } diff --git a/src/Core/Types/Types/Attributes/Argument.cs b/src/Core/Types/Types/Attributes/Argument.cs index be47139831f..890e532eee3 100644 --- a/src/Core/Types/Types/Attributes/Argument.cs +++ b/src/Core/Types/Types/Attributes/Argument.cs @@ -21,24 +21,6 @@ internal sealed override void TryConfigure(IDescriptor descriptor) public abstract void OnConfigure(IInputFieldDescriptor descriptor); } - [AttributeUsage( - AttributeTargets.Class | AttributeTargets.Struct, - Inherited = true, - AllowMultiple = true)] - public abstract class ObjectTypeDescriptorAttribute - : DescriptorAttribute - { - internal sealed override void TryConfigure(IDescriptor descriptor) - { - if (descriptor is IObjectTypeDescriptor d) - { - OnConfigure(d); - } - } - - public abstract void OnConfigure(IObjectTypeDescriptor descriptor); - } - [AttributeUsage( AttributeTargets.Class | AttributeTargets.Struct, Inherited = true, diff --git a/src/Core/Types/Types/Attributes/ObjectTypeDescriptorAttribute.cs b/src/Core/Types/Types/Attributes/ObjectTypeDescriptorAttribute.cs new file mode 100644 index 00000000000..7bd671e906a --- /dev/null +++ b/src/Core/Types/Types/Attributes/ObjectTypeDescriptorAttribute.cs @@ -0,0 +1,23 @@ +using System; + +namespace HotChocolate.Types +{ + [AttributeUsage( + AttributeTargets.Class | AttributeTargets.Struct, + Inherited = true, + AllowMultiple = true)] + public abstract class ObjectTypeDescriptorAttribute + : DescriptorAttribute + { + internal sealed override void TryConfigure(IDescriptor descriptor) + { + if (descriptor is IObjectTypeDescriptor d) + { + OnConfigure(d); + } + } + + public abstract void OnConfigure(IObjectTypeDescriptor descriptor); + } + +} diff --git a/src/Core/Types/Types/Descriptors/ObjectTypeDescriptor.cs b/src/Core/Types/Types/Descriptors/ObjectTypeDescriptor.cs index 473bf5a37c3..1d20822e657 100644 --- a/src/Core/Types/Types/Descriptors/ObjectTypeDescriptor.cs +++ b/src/Core/Types/Types/Descriptors/ObjectTypeDescriptor.cs @@ -47,6 +47,11 @@ public ObjectTypeDescriptor(IDescriptorContext context) protected override void OnCreateDefinition( ObjectTypeDefinition definition) { + if (Definition.ClrType is { }) + { + Context.Inspector.ApplyAttributes(this, Definition.ClrType); + } + var fields = new Dictionary(); var handledMembers = new HashSet(); @@ -59,11 +64,6 @@ protected override void OnCreateDefinition( OnCompleteFields(fields, handledMembers); Definition.Fields.AddRange(fields.Values); - - if (Definition.ClrType is { }) - { - Context.Inspector.ApplyAttributes(this, Definition.ClrType); - } } protected virtual void OnCompleteFields( From f5e7a9b4a08b343910a06481b80606be0b7b59ad Mon Sep 17 00:00:00 2001 From: Michael Staib Date: Sat, 30 Nov 2019 23:01:43 +0100 Subject: [PATCH 07/17] Allowed custom descriptor attributes --- src/Core/Types/Types/Attributes/Argument.cs | 5 ++- .../Attributes/ArgumentDescriptorAttribute.cs | 2 +- .../Types/Attributes/DescriptorAttribute.cs | 2 +- .../ObjectFieldDescriptorAttribute.cs | 2 +- .../ObjectTypeDescriptorAttribute.cs | 2 +- .../Descriptors/Contracts/IDescriptor.cs | 2 -- .../Contracts/IDescriptorExtension.cs | 12 +++---- .../Contracts/IDescriptorExtension~1.cs | 20 ++++++++++++ .../Descriptors/Contracts/IDescriptor~1.cs | 2 ++ .../Descriptors/Definitions/DefinitionBase.cs | 1 - .../Types/Descriptors/DescriptorBase~1.cs | 32 ++++++++++++++++--- 11 files changed, 61 insertions(+), 21 deletions(-) create mode 100644 src/Core/Types/Types/Descriptors/Contracts/IDescriptorExtension~1.cs diff --git a/src/Core/Types/Types/Attributes/Argument.cs b/src/Core/Types/Types/Attributes/Argument.cs index 890e532eee3..6d90ab090a1 100644 --- a/src/Core/Types/Types/Attributes/Argument.cs +++ b/src/Core/Types/Types/Attributes/Argument.cs @@ -10,7 +10,7 @@ namespace HotChocolate.Types public abstract class InputFieldDescriptorAttribute : DescriptorAttribute { - internal sealed override void TryConfigure(IDescriptor descriptor) + internal protected sealed override void TryConfigure(IDescriptor descriptor) { if (descriptor is IInputFieldDescriptor d) { @@ -28,7 +28,7 @@ internal sealed override void TryConfigure(IDescriptor descriptor) public abstract class InputObjectTypeDescriptorAttribute : DescriptorAttribute { - internal sealed override void TryConfigure(IDescriptor descriptor) + internal protected sealed override void TryConfigure(IDescriptor descriptor) { if (descriptor is IInputObjectTypeDescriptor d) { @@ -38,5 +38,4 @@ internal sealed override void TryConfigure(IDescriptor descriptor) public abstract void OnConfigure(IInputObjectTypeDescriptor descriptor); } - } diff --git a/src/Core/Types/Types/Attributes/ArgumentDescriptorAttribute.cs b/src/Core/Types/Types/Attributes/ArgumentDescriptorAttribute.cs index 5f7ecab3562..6876e97bcec 100644 --- a/src/Core/Types/Types/Attributes/ArgumentDescriptorAttribute.cs +++ b/src/Core/Types/Types/Attributes/ArgumentDescriptorAttribute.cs @@ -9,7 +9,7 @@ namespace HotChocolate.Types public abstract class ArgumentDescriptorAttribute : DescriptorAttribute { - internal sealed override void TryConfigure(IDescriptor descriptor) + internal protected sealed override void TryConfigure(IDescriptor descriptor) { if (descriptor is IArgumentDescriptor d) { diff --git a/src/Core/Types/Types/Attributes/DescriptorAttribute.cs b/src/Core/Types/Types/Attributes/DescriptorAttribute.cs index 19735ba988d..4c5eadde546 100644 --- a/src/Core/Types/Types/Attributes/DescriptorAttribute.cs +++ b/src/Core/Types/Types/Attributes/DescriptorAttribute.cs @@ -5,7 +5,7 @@ namespace HotChocolate.Types public abstract class DescriptorAttribute : Attribute { - internal abstract void TryConfigure(IDescriptor descriptor); + internal protected abstract void TryConfigure(IDescriptor descriptor); } } diff --git a/src/Core/Types/Types/Attributes/ObjectFieldDescriptorAttribute.cs b/src/Core/Types/Types/Attributes/ObjectFieldDescriptorAttribute.cs index 1aa1cf25ec3..57433e54e3b 100644 --- a/src/Core/Types/Types/Attributes/ObjectFieldDescriptorAttribute.cs +++ b/src/Core/Types/Types/Attributes/ObjectFieldDescriptorAttribute.cs @@ -9,7 +9,7 @@ namespace HotChocolate.Types public abstract class ObjectFieldDescriptorAttribute : DescriptorAttribute { - internal sealed override void TryConfigure(IDescriptor descriptor) + internal protected sealed override void TryConfigure(IDescriptor descriptor) { if (descriptor is IObjectFieldDescriptor d) { diff --git a/src/Core/Types/Types/Attributes/ObjectTypeDescriptorAttribute.cs b/src/Core/Types/Types/Attributes/ObjectTypeDescriptorAttribute.cs index 7bd671e906a..3a45fc55acd 100644 --- a/src/Core/Types/Types/Attributes/ObjectTypeDescriptorAttribute.cs +++ b/src/Core/Types/Types/Attributes/ObjectTypeDescriptorAttribute.cs @@ -9,7 +9,7 @@ namespace HotChocolate.Types public abstract class ObjectTypeDescriptorAttribute : DescriptorAttribute { - internal sealed override void TryConfigure(IDescriptor descriptor) + internal protected sealed override void TryConfigure(IDescriptor descriptor) { if (descriptor is IObjectTypeDescriptor d) { diff --git a/src/Core/Types/Types/Descriptors/Contracts/IDescriptor.cs b/src/Core/Types/Types/Descriptors/Contracts/IDescriptor.cs index 1312a9d2719..0898f48e669 100644 --- a/src/Core/Types/Types/Descriptors/Contracts/IDescriptor.cs +++ b/src/Core/Types/Types/Descriptors/Contracts/IDescriptor.cs @@ -1,5 +1,3 @@ -using HotChocolate.Types.Descriptors.Definitions; - namespace HotChocolate.Types { public interface IDescriptor diff --git a/src/Core/Types/Types/Descriptors/Contracts/IDescriptorExtension.cs b/src/Core/Types/Types/Descriptors/Contracts/IDescriptorExtension.cs index 2d2c3be5fa8..fb44d0b73d7 100644 --- a/src/Core/Types/Types/Descriptors/Contracts/IDescriptorExtension.cs +++ b/src/Core/Types/Types/Descriptors/Contracts/IDescriptorExtension.cs @@ -1,19 +1,19 @@ using System; -using System.Collections.Generic; using HotChocolate.Configuration; using HotChocolate.Types.Descriptors.Definitions; +#nullable enable + namespace HotChocolate.Types { - public interface IDescriptorExtension - where T : DefinitionBase + public interface IDescriptorExtension { - void OnBeforeCreate(Action configure); + void OnBeforeCreate(Action configure); INamedDependencyDescriptor OnBeforeNaming( - Action configure); + Action configure); ICompletedDependencyDescriptor OnBeforeCompletion( - Action configure); + Action configure); } } diff --git a/src/Core/Types/Types/Descriptors/Contracts/IDescriptorExtension~1.cs b/src/Core/Types/Types/Descriptors/Contracts/IDescriptorExtension~1.cs new file mode 100644 index 00000000000..59ba90f96a6 --- /dev/null +++ b/src/Core/Types/Types/Descriptors/Contracts/IDescriptorExtension~1.cs @@ -0,0 +1,20 @@ +using System; +using HotChocolate.Configuration; +using HotChocolate.Types.Descriptors.Definitions; + +#nullable enable + +namespace HotChocolate.Types +{ + public interface IDescriptorExtension + where T : DefinitionBase + { + void OnBeforeCreate(Action configure); + + INamedDependencyDescriptor OnBeforeNaming( + Action configure); + + ICompletedDependencyDescriptor OnBeforeCompletion( + Action configure); + } +} diff --git a/src/Core/Types/Types/Descriptors/Contracts/IDescriptor~1.cs b/src/Core/Types/Types/Descriptors/Contracts/IDescriptor~1.cs index c5a2dae1c02..2374e594891 100644 --- a/src/Core/Types/Types/Descriptors/Contracts/IDescriptor~1.cs +++ b/src/Core/Types/Types/Descriptors/Contracts/IDescriptor~1.cs @@ -1,5 +1,7 @@ using HotChocolate.Types.Descriptors.Definitions; +#nullable enable + namespace HotChocolate.Types { public interface IDescriptor : IDescriptor where T : DefinitionBase diff --git a/src/Core/Types/Types/Descriptors/Definitions/DefinitionBase.cs b/src/Core/Types/Types/Descriptors/Definitions/DefinitionBase.cs index 0e302fc5cb6..763ae2d3f32 100644 --- a/src/Core/Types/Types/Descriptors/Definitions/DefinitionBase.cs +++ b/src/Core/Types/Types/Descriptors/Definitions/DefinitionBase.cs @@ -1,5 +1,4 @@ using System.Collections.Generic; -using System.Reflection; #nullable enable diff --git a/src/Core/Types/Types/Descriptors/DescriptorBase~1.cs b/src/Core/Types/Types/Descriptors/DescriptorBase~1.cs index 96c08c3a9bd..6924144cd83 100644 --- a/src/Core/Types/Types/Descriptors/DescriptorBase~1.cs +++ b/src/Core/Types/Types/Descriptors/DescriptorBase~1.cs @@ -8,6 +8,7 @@ namespace HotChocolate.Types.Descriptors public abstract class DescriptorBase : IDescriptor , IDescriptorExtension + , IDescriptorExtension , IDefinitionFactory , IHasDescriptorContext where T : DefinitionBase @@ -50,7 +51,13 @@ protected virtual void OnCreateDefinition(T definition) DefinitionBase IDefinitionFactory.CreateDefinition() => CreateDefinition(); - void IDescriptorExtension.OnBeforeCreate(Action configure) + void IDescriptorExtension.OnBeforeCreate(Action configure) => + OnBeforeCreate(configure); + + void IDescriptorExtension.OnBeforeCreate(Action configure) => + OnBeforeCreate(c => configure(c)); + + private void OnBeforeCreate(Action configure) { if (configure == null) { @@ -61,7 +68,15 @@ void IDescriptorExtension.OnBeforeCreate(Action configure) } INamedDependencyDescriptor IDescriptorExtension.OnBeforeNaming( - Action configure) + Action configure) => + OnBeforeNaming(configure); + + INamedDependencyDescriptor IDescriptorExtension.OnBeforeNaming( + Action configure) => + OnBeforeNaming(configure); + + private INamedDependencyDescriptor OnBeforeNaming( + Action configure) { if (configure == null) { @@ -77,9 +92,16 @@ INamedDependencyDescriptor IDescriptorExtension.OnBeforeNaming( return new NamedDependencyDescriptor(configuration); } - ICompletedDependencyDescriptor IDescriptorExtension - .OnBeforeCompletion( - Action configure) + ICompletedDependencyDescriptor IDescriptorExtension.OnBeforeCompletion( + Action configure) => + OnBeforeCompletion(configure); + + ICompletedDependencyDescriptor IDescriptorExtension.OnBeforeCompletion( + Action configure) => + OnBeforeCompletion(configure); + + private ICompletedDependencyDescriptor OnBeforeCompletion( + Action configure) { var configuration = new TypeConfiguration(); configuration.Definition = Definition; From b0a99ece2c1ec0900fa31a41d434c5bc78494672 Mon Sep 17 00:00:00 2001 From: Michael Staib Date: Sun, 1 Dec 2019 21:05:35 +0100 Subject: [PATCH 08/17] Added interface attributes --- .../Types/InterfaceTypeAttributeTests.cs | 132 ++++++++++++++++++ .../Types/ObjectTypeAttributeTests.cs | 2 +- .../InterfaceFieldDescriptorAttribute.cs | 22 +++ .../InterfaceTypeDescriptorAttribute.cs | 22 +++ .../ObjectFieldDescriptorAttribute.cs | 1 - .../ObjectTypeDescriptorAttribute.cs | 1 - .../Descriptors/InterfaceTypeDescriptor.cs | 10 +- 7 files changed, 182 insertions(+), 8 deletions(-) create mode 100644 src/Core/Types.Tests/Types/InterfaceTypeAttributeTests.cs create mode 100644 src/Core/Types/Types/Attributes/InterfaceFieldDescriptorAttribute.cs create mode 100644 src/Core/Types/Types/Attributes/InterfaceTypeDescriptorAttribute.cs diff --git a/src/Core/Types.Tests/Types/InterfaceTypeAttributeTests.cs b/src/Core/Types.Tests/Types/InterfaceTypeAttributeTests.cs new file mode 100644 index 00000000000..e723f89a92a --- /dev/null +++ b/src/Core/Types.Tests/Types/InterfaceTypeAttributeTests.cs @@ -0,0 +1,132 @@ +using System; +using Xunit; + +#nullable enable + +namespace HotChocolate.Types +{ + public class InterfaceTypeAttributeTests + : TypeTestBase + { + [Fact] + public void ArgumentDescriptorAttribute_Changes_DefaultValue() + { + // act + ISchema schema = SchemaBuilder.New() + .AddType() + .ModifyOptions(o => o.StrictValidation = false) + .Create(); + + // assert + Assert.Equal( + "abc", + schema.GetType("Interface1") + .Fields["field"] + .Arguments["argument"] + .DefaultValue + .Value); + } + + [Fact] + public void InterfaceFieldDescriptorAttribute_Adds_ContextData() + { + // act + ISchema schema = SchemaBuilder.New() + .AddType() + .ModifyOptions(o => o.StrictValidation = false) + .Create(); + + // assert + Assert.Equal( + "def", + schema.GetType("Interface2") + .Fields["field"] + .ContextData["abc"]); + } + + [Fact] + public void InterfaceFieldDescriptorAttribute_Updated_FieldDefinition() + { + // act + ISchema schema = SchemaBuilder.New() + .AddInterfaceType(d => + d.Field(t => t.GetField()).Name("foo")) + .ModifyOptions(o => o.StrictValidation = false) + .Create(); + + // assert + Assert.Equal( + "def", + schema.GetType("Interface2") + .Fields["foo"] + .ContextData["abc"]); + } + + [Fact] + public void InterfaceTypeDescriptorAttribute_Add_FieldDefinition() + { + // act + ISchema schema = SchemaBuilder.New() + .AddType() + .ModifyOptions(o => o.StrictValidation = false) + .Create(); + + // assert + Assert.True( + schema.GetType("Interface3") + .Fields.ContainsField("abc")); + } + + public interface Interface1 + { + string GetField([ArgumentDefaultValue("abc")]string argument); + } + + public class ArgumentDefaultValueAttribute + : ArgumentDescriptorAttribute + { + public ArgumentDefaultValueAttribute(object defaultValue) + { + DefaultValue = defaultValue; + } + + public object DefaultValue { get; } + + public override void OnConfigure(IArgumentDescriptor descriptor) + { + descriptor.DefaultValue(DefaultValue); + } + } + + public interface Interface2 + { + [PropertyAddContextData] + string GetField(); + } + + public class PropertyAddContextDataAttribute + : InterfaceFieldDescriptorAttribute + { + public override void OnConfigure(IInterfaceFieldDescriptor descriptor) + { + descriptor.Extend().OnBeforeCompletion( + (c, d) => d.ContextData.Add("abc", "def")); + } + } + + [InterfaceAddField] + public interface Interface3 + { + string GetField(); + } + + public class InterfaceAddFieldAttribute + : InterfaceTypeDescriptorAttribute + { + public override void OnConfigure(IInterfaceTypeDescriptor descriptor) + { + descriptor.Field("abc").Type(); + } + } + } +} diff --git a/src/Core/Types.Tests/Types/ObjectTypeAttributeTests.cs b/src/Core/Types.Tests/Types/ObjectTypeAttributeTests.cs index 36fe3dda611..b0f525efb79 100644 --- a/src/Core/Types.Tests/Types/ObjectTypeAttributeTests.cs +++ b/src/Core/Types.Tests/Types/ObjectTypeAttributeTests.cs @@ -62,7 +62,7 @@ public void ObjectFieldDescriptorAttribute_Updated_FieldDefinition() } [Fact] - public void ObjectTypeDescriptorAttribute_Updated_FieldDefinition() + public void ObjectTypeDescriptorAttribute_Add_FieldDefinition() { // act ISchema schema = SchemaBuilder.New() diff --git a/src/Core/Types/Types/Attributes/InterfaceFieldDescriptorAttribute.cs b/src/Core/Types/Types/Attributes/InterfaceFieldDescriptorAttribute.cs new file mode 100644 index 00000000000..cf908a63fef --- /dev/null +++ b/src/Core/Types/Types/Attributes/InterfaceFieldDescriptorAttribute.cs @@ -0,0 +1,22 @@ +using System; + +namespace HotChocolate.Types +{ + [AttributeUsage( + AttributeTargets.Property | AttributeTargets.Method, + Inherited = true, + AllowMultiple = true)] + public abstract class InterfaceFieldDescriptorAttribute + : DescriptorAttribute + { + internal protected sealed override void TryConfigure(IDescriptor descriptor) + { + if (descriptor is IInterfaceFieldDescriptor d) + { + OnConfigure(d); + } + } + + public abstract void OnConfigure(IInterfaceFieldDescriptor descriptor); + } +} diff --git a/src/Core/Types/Types/Attributes/InterfaceTypeDescriptorAttribute.cs b/src/Core/Types/Types/Attributes/InterfaceTypeDescriptorAttribute.cs new file mode 100644 index 00000000000..57f72ae15bd --- /dev/null +++ b/src/Core/Types/Types/Attributes/InterfaceTypeDescriptorAttribute.cs @@ -0,0 +1,22 @@ +using System; + +namespace HotChocolate.Types +{ + [AttributeUsage( + AttributeTargets.Class | AttributeTargets.Interface, + Inherited = true, + AllowMultiple = true)] + public abstract class InterfaceTypeDescriptorAttribute + : DescriptorAttribute + { + internal protected sealed override void TryConfigure(IDescriptor descriptor) + { + if (descriptor is IInterfaceTypeDescriptor d) + { + OnConfigure(d); + } + } + + public abstract void OnConfigure(IInterfaceTypeDescriptor descriptor); + } +} diff --git a/src/Core/Types/Types/Attributes/ObjectFieldDescriptorAttribute.cs b/src/Core/Types/Types/Attributes/ObjectFieldDescriptorAttribute.cs index 57433e54e3b..dd3908eeb65 100644 --- a/src/Core/Types/Types/Attributes/ObjectFieldDescriptorAttribute.cs +++ b/src/Core/Types/Types/Attributes/ObjectFieldDescriptorAttribute.cs @@ -19,5 +19,4 @@ internal protected sealed override void TryConfigure(IDescriptor descriptor) public abstract void OnConfigure(IObjectFieldDescriptor descriptor); } - } diff --git a/src/Core/Types/Types/Attributes/ObjectTypeDescriptorAttribute.cs b/src/Core/Types/Types/Attributes/ObjectTypeDescriptorAttribute.cs index 3a45fc55acd..be3c4036eb2 100644 --- a/src/Core/Types/Types/Attributes/ObjectTypeDescriptorAttribute.cs +++ b/src/Core/Types/Types/Attributes/ObjectTypeDescriptorAttribute.cs @@ -19,5 +19,4 @@ internal protected sealed override void TryConfigure(IDescriptor descriptor) public abstract void OnConfigure(IObjectTypeDescriptor descriptor); } - } diff --git a/src/Core/Types/Types/Descriptors/InterfaceTypeDescriptor.cs b/src/Core/Types/Types/Descriptors/InterfaceTypeDescriptor.cs index b289305094e..22d4c41a84d 100644 --- a/src/Core/Types/Types/Descriptors/InterfaceTypeDescriptor.cs +++ b/src/Core/Types/Types/Descriptors/InterfaceTypeDescriptor.cs @@ -44,6 +44,11 @@ protected InterfaceTypeDescriptor( protected override void OnCreateDefinition( InterfaceTypeDefinition definition) { + if (Definition.ClrType is { }) + { + Context.Inspector.ApplyAttributes(this, Definition.ClrType); + } + var fields = new Dictionary(); var handledMembers = new HashSet(); @@ -56,11 +61,6 @@ protected override void OnCreateDefinition( OnCompleteFields(fields, handledMembers); Definition.Fields.AddRange(fields.Values); - - if (Definition.ClrType is { }) - { - Context.Inspector.ApplyAttributes(this, Definition.ClrType); - } } protected virtual void OnCompleteFields( From 4bddb93589012b0ed509a36a0bd56e71d5df8a35 Mon Sep 17 00:00:00 2001 From: Michael Staib Date: Sun, 1 Dec 2019 21:30:29 +0100 Subject: [PATCH 09/17] Added more tests --- .../SchemaBuilderExtensions.Types.Tests.cs | 62 ++++++++++++++++++- .../Types/InterfaceTypeAttributeTests.cs | 6 +- .../Types/ObjectTypeAttributeTests.cs | 27 ++++---- .../Types/UnionTypeAttributeTests.cs | 36 +++++++++++ .../SchemaBuilderExtensions.Types.cs | 55 ++++++++++++++++ .../UnionTypeDescriptorAttribute.cs | 22 +++++++ .../Types/Descriptors/UnionTypeDescriptor.cs | 3 +- 7 files changed, 193 insertions(+), 18 deletions(-) create mode 100644 src/Core/Types.Tests/Types/UnionTypeAttributeTests.cs create mode 100644 src/Core/Types/Types/Attributes/UnionTypeDescriptorAttribute.cs diff --git a/src/Core/Types.Tests/Extensions/SchemaBuilderExtensions.Types.Tests.cs b/src/Core/Types.Tests/Extensions/SchemaBuilderExtensions.Types.Tests.cs index c7f8e3f8c60..f37973293cf 100644 --- a/src/Core/Types.Tests/Extensions/SchemaBuilderExtensions.Types.Tests.cs +++ b/src/Core/Types.Tests/Extensions/SchemaBuilderExtensions.Types.Tests.cs @@ -568,6 +568,18 @@ public void AddObjectTypeT_BuilderIsNull_ArgumentNullException() Assert.Throws(action); } + [Fact] + public void AddObjectTypeT2_BuilderIsNull_ArgumentNullException() + { + // arrange + // act + Action action = () => + SchemaBuilderExtensions.AddObjectType(null); + + // assert + Assert.Throws(action); + } + [Fact] public void AddObjectTypeT_ConfigureIsNull_ArgumentNullException() { @@ -710,6 +722,18 @@ public void AddInterfaceTypeT_BuilderIsNull_ArgumentNullException() Assert.Throws(action); } + [Fact] + public void AddInterfaceTypeT2_BuilderIsNull_ArgumentNullException() + { + // arrange + // act + Action action = () => + SchemaBuilderExtensions.AddInterfaceType(null); + + // assert + Assert.Throws(action); + } + [Fact] public void AddInterfaceTypeT_ConfigureIsNull_ArgumentNullException() { @@ -803,6 +827,18 @@ public void AddUnionTypeT_BuilderIsNull_ArgumentNullException() Assert.Throws(action); } + [Fact] + public void AddUnionTypeT2_BuilderIsNull_ArgumentNullException() + { + // arrange + // act + Action action = () => + SchemaBuilderExtensions.AddUnionType(null); + + // assert + Assert.Throws(action); + } + [Fact] public void AddUnionTypeT_ConfigureIsNull_ArgumentNullException() { @@ -896,6 +932,18 @@ public void AddInputObjectTypeT_BuilderIsNull_ArgumentNullException() Assert.Throws(action); } + [Fact] + public void AddInputObjectTypeT2_BuilderIsNull_ArgumentNullException() + { + // arrange + // act + Action action = () => + SchemaBuilderExtensions.AddInputObjectType(null); + + // assert + Assert.Throws(action); + } + [Fact] public void AddInputObjectTypeT_ConfigureIsNull_ArgumentNullException() { @@ -985,6 +1033,18 @@ public void AddEnumTypeT_BuilderIsNull_ArgumentNullException() Assert.Throws(action); } + [Fact] + public void AddEnumTypeT2_BuilderIsNull_ArgumentNullException() + { + // arrange + // act + Action action = () => + SchemaBuilderExtensions.AddEnumType(null); + + // assert + Assert.Throws(action); + } + [Fact] public void AddEnumTypeT_ConfigureIsNull_ArgumentNullException() { @@ -998,7 +1058,7 @@ public void AddEnumTypeT_ConfigureIsNull_ArgumentNullException() Assert.Throws(action); } - [Fact] + [Fact] public void AddEnumTypeT_With_Descriptor() { // arrange diff --git a/src/Core/Types.Tests/Types/InterfaceTypeAttributeTests.cs b/src/Core/Types.Tests/Types/InterfaceTypeAttributeTests.cs index e723f89a92a..09100c7e268 100644 --- a/src/Core/Types.Tests/Types/InterfaceTypeAttributeTests.cs +++ b/src/Core/Types.Tests/Types/InterfaceTypeAttributeTests.cs @@ -13,7 +13,7 @@ public void ArgumentDescriptorAttribute_Changes_DefaultValue() { // act ISchema schema = SchemaBuilder.New() - .AddType() + .AddInterfaceType() .ModifyOptions(o => o.StrictValidation = false) .Create(); @@ -32,7 +32,7 @@ public void InterfaceFieldDescriptorAttribute_Adds_ContextData() { // act ISchema schema = SchemaBuilder.New() - .AddType() + .AddInterfaceType() .ModifyOptions(o => o.StrictValidation = false) .Create(); @@ -67,7 +67,7 @@ public void InterfaceTypeDescriptorAttribute_Add_FieldDefinition() { // act ISchema schema = SchemaBuilder.New() - .AddType() + .AddInterfaceType() .ModifyOptions(o => o.StrictValidation = false) .Create(); diff --git a/src/Core/Types.Tests/Types/ObjectTypeAttributeTests.cs b/src/Core/Types.Tests/Types/ObjectTypeAttributeTests.cs index b0f525efb79..ccfcb26f90a 100644 --- a/src/Core/Types.Tests/Types/ObjectTypeAttributeTests.cs +++ b/src/Core/Types.Tests/Types/ObjectTypeAttributeTests.cs @@ -1,14 +1,4 @@ using System; -using System.Collections; -using System.Collections.Generic; -using System.Linq; -using System.Linq.Expressions; -using System.Threading.Tasks; -using HotChocolate.Execution; -using HotChocolate.Resolvers; -using HotChocolate.Types.Descriptors; -using Moq; -using Snapshooter.Xunit; using Xunit; #nullable enable @@ -52,7 +42,7 @@ public void ObjectFieldDescriptorAttribute_Updated_FieldDefinition() // act ISchema schema = SchemaBuilder.New() .AddQueryType(d => - d.Field(t => t.GetField()).Name("foo")) + d.Field(t => t.GetField()).Name("foo")) .Create(); // assert @@ -73,6 +63,19 @@ public void ObjectTypeDescriptorAttribute_Add_FieldDefinition() Assert.True(schema.QueryType.Fields.ContainsField("abc")); } + [Fact] + public void ObjectTypeDescriptorAttribute_Add_FieldDefinition_2() + { + // act + ISchema schema = SchemaBuilder.New() + .AddObjectType() + .ModifyOptions(o => o.StrictValidation = false) + .Create(); + + // assert + Assert.True(schema.GetType("Object3").Fields.ContainsField("abc")); + } + public class Object1 { public string GetField([ArgumentDefaultValue("abc")]string argument) @@ -130,7 +133,7 @@ public class ObjectAddFieldAttribute { public override void OnConfigure(IObjectTypeDescriptor descriptor) { - descriptor.Field("abc").Resolver("def"); + descriptor.Field("abc").Resolver("def"); } } } diff --git a/src/Core/Types.Tests/Types/UnionTypeAttributeTests.cs b/src/Core/Types.Tests/Types/UnionTypeAttributeTests.cs new file mode 100644 index 00000000000..12518f33f22 --- /dev/null +++ b/src/Core/Types.Tests/Types/UnionTypeAttributeTests.cs @@ -0,0 +1,36 @@ +using Xunit; + +#nullable enable + +namespace HotChocolate.Types +{ + public class UnionTypeAttributeTests + { + [Fact] + public void SetName_Union_Interface() + { + // act + ISchema schema = SchemaBuilder.New() + .AddUnionType() + .AddType() + .ModifyOptions(o => o.StrictValidation = false) + .Create(); + + // assert + Assert.NotNull(schema.GetType("Abc")); + } + + [SetName] + public interface IUnion1 { } + + public class Foo : IUnion1 { } + + public class SetNameAttribute : UnionTypeDescriptorAttribute + { + public override void OnConfigure(IUnionTypeDescriptor descriptor) + { + descriptor.Name("Abc"); + } + } + } +} diff --git a/src/Core/Types/Extensions/SchemaBuilderExtensions.Types.cs b/src/Core/Types/Extensions/SchemaBuilderExtensions.Types.cs index 7cd178c862b..96866dff1a1 100644 --- a/src/Core/Types/Extensions/SchemaBuilderExtensions.Types.cs +++ b/src/Core/Types/Extensions/SchemaBuilderExtensions.Types.cs @@ -268,6 +268,17 @@ public static ISchemaBuilder AddObjectType( return builder.AddType(new ObjectType(configure)); } + public static ISchemaBuilder AddObjectType( + this ISchemaBuilder builder) + { + if (builder == null) + { + throw new ArgumentNullException(nameof(builder)); + } + + return builder.AddType(new ObjectType()); + } + public static ISchemaBuilder AddObjectType( this ISchemaBuilder builder, Action> configure) @@ -302,6 +313,17 @@ public static ISchemaBuilder AddUnionType( return builder.AddType(new UnionType(configure)); } + public static ISchemaBuilder AddUnionType( + this ISchemaBuilder builder) + { + if (builder == null) + { + throw new ArgumentNullException(nameof(builder)); + } + + return builder.AddType(new UnionType()); + } + public static ISchemaBuilder AddUnionType( this ISchemaBuilder builder, Action configure) @@ -336,6 +358,17 @@ public static ISchemaBuilder AddEnumType( return builder.AddType(new EnumType(configure)); } + public static ISchemaBuilder AddEnumType( + this ISchemaBuilder builder) + { + if (builder == null) + { + throw new ArgumentNullException(nameof(builder)); + } + + return builder.AddType(new EnumType()); + } + public static ISchemaBuilder AddEnumType( this ISchemaBuilder builder, Action> configure) @@ -370,6 +403,17 @@ public static ISchemaBuilder AddInterfaceType( return builder.AddType(new InterfaceType(configure)); } + public static ISchemaBuilder AddInterfaceType( + this ISchemaBuilder builder) + { + if (builder == null) + { + throw new ArgumentNullException(nameof(builder)); + } + + return builder.AddType(new InterfaceType()); + } + public static ISchemaBuilder AddInterfaceType( this ISchemaBuilder builder, Action> configure) @@ -404,6 +448,17 @@ public static ISchemaBuilder AddInputObjectType( return builder.AddType(new InputObjectType(configure)); } + public static ISchemaBuilder AddInputObjectType( + this ISchemaBuilder builder) + { + if (builder == null) + { + throw new ArgumentNullException(nameof(builder)); + } + + return builder.AddType(new InputObjectType()); + } + public static ISchemaBuilder AddInputObjectType( this ISchemaBuilder builder, Action> configure) diff --git a/src/Core/Types/Types/Attributes/UnionTypeDescriptorAttribute.cs b/src/Core/Types/Types/Attributes/UnionTypeDescriptorAttribute.cs new file mode 100644 index 00000000000..a94976e54d2 --- /dev/null +++ b/src/Core/Types/Types/Attributes/UnionTypeDescriptorAttribute.cs @@ -0,0 +1,22 @@ +using System; + +namespace HotChocolate.Types +{ + [AttributeUsage( + AttributeTargets.Class | AttributeTargets.Interface, + Inherited = true, + AllowMultiple = true)] + public abstract class UnionTypeDescriptorAttribute + : DescriptorAttribute + { + internal protected sealed override void TryConfigure(IDescriptor descriptor) + { + if (descriptor is IUnionTypeDescriptor d) + { + OnConfigure(d); + } + } + + public abstract void OnConfigure(IUnionTypeDescriptor descriptor); + } +} diff --git a/src/Core/Types/Types/Descriptors/UnionTypeDescriptor.cs b/src/Core/Types/Types/Descriptors/UnionTypeDescriptor.cs index b7d32413727..1c1a20e17b6 100644 --- a/src/Core/Types/Types/Descriptors/UnionTypeDescriptor.cs +++ b/src/Core/Types/Types/Descriptors/UnionTypeDescriptor.cs @@ -32,12 +32,11 @@ protected UnionTypeDescriptor(IDescriptorContext context) protected override void OnCreateDefinition(UnionTypeDefinition definition) { - base.OnCreateDefinition(definition); - if (Definition.ClrType is { }) { Context.Inspector.ApplyAttributes(this, Definition.ClrType); } + base.OnCreateDefinition(definition); } public IUnionTypeDescriptor SyntaxNode( From 5a06b462e910c1bdb93aa9bdad8c4b8a2d89eea9 Mon Sep 17 00:00:00 2001 From: Michael Staib Date: Sun, 1 Dec 2019 21:59:00 +0100 Subject: [PATCH 10/17] Added input object type attributes --- .../Types/InputObjectTypeAttributeTests.cs | 69 +++++++++++++++++++ .../Types/Attributes/DescriptorAttribute.cs | 1 - .../InputFieldDescriptorAttribute.cs | 22 ++++++ ... => InputObjectTypeDescriptorAttribute.cs} | 19 ----- .../Descriptors/InputObjectTypeDescriptor.cs | 10 +-- 5 files changed, 96 insertions(+), 25 deletions(-) create mode 100644 src/Core/Types.Tests/Types/InputObjectTypeAttributeTests.cs create mode 100644 src/Core/Types/Types/Attributes/InputFieldDescriptorAttribute.cs rename src/Core/Types/Types/Attributes/{Argument.cs => InputObjectTypeDescriptorAttribute.cs} (52%) diff --git a/src/Core/Types.Tests/Types/InputObjectTypeAttributeTests.cs b/src/Core/Types.Tests/Types/InputObjectTypeAttributeTests.cs new file mode 100644 index 00000000000..56f3c814c83 --- /dev/null +++ b/src/Core/Types.Tests/Types/InputObjectTypeAttributeTests.cs @@ -0,0 +1,69 @@ +using Xunit; + +namespace HotChocolate.Types +{ + public class InputObjectTypeAttributeTests + { + [Fact] + public void Change_Field_Name_With_Attribute() + { + // act + ISchema schema = SchemaBuilder.New() + .AddInputObjectType() + .ModifyOptions(o => o.StrictValidation = false) + .Create(); + + // assert + Assert.True( + schema.GetType("Object1Input") + .Fields + .ContainsField("bar")); + } + + [Fact] + public void Change_InputObjectType_Name_With_Attribute() + { + // act + ISchema schema = SchemaBuilder.New() + .AddInputObjectType() + .ModifyOptions(o => o.StrictValidation = false) + .Create(); + + // assert + Assert.True( + schema.GetType("Bar") + .Fields + .ContainsField("foo")); + } + + public class Object1 + { + [RenameField] + public string Foo { get; set; } + } + + public class RenameFieldAttribute + : InputFieldDescriptorAttribute + { + public override void OnConfigure(IInputFieldDescriptor descriptor) + { + descriptor.Name("bar"); + } + } + + [RenameType] + public class Object2 + { + public string Foo { get; set; } + } + + public class RenameTypeAttribute + : InputObjectTypeDescriptorAttribute + { + public override void OnConfigure(IInputObjectTypeDescriptor descriptor) + { + descriptor.Name("Bar"); + } + } + } +} diff --git a/src/Core/Types/Types/Attributes/DescriptorAttribute.cs b/src/Core/Types/Types/Attributes/DescriptorAttribute.cs index 4c5eadde546..30c39d17b7b 100644 --- a/src/Core/Types/Types/Attributes/DescriptorAttribute.cs +++ b/src/Core/Types/Types/Attributes/DescriptorAttribute.cs @@ -7,5 +7,4 @@ public abstract class DescriptorAttribute { internal protected abstract void TryConfigure(IDescriptor descriptor); } - } diff --git a/src/Core/Types/Types/Attributes/InputFieldDescriptorAttribute.cs b/src/Core/Types/Types/Attributes/InputFieldDescriptorAttribute.cs new file mode 100644 index 00000000000..91183a23e95 --- /dev/null +++ b/src/Core/Types/Types/Attributes/InputFieldDescriptorAttribute.cs @@ -0,0 +1,22 @@ +using System; + +namespace HotChocolate.Types +{ + [AttributeUsage( + AttributeTargets.Property | AttributeTargets.Method, + Inherited = true, + AllowMultiple = true)] + public abstract class InputFieldDescriptorAttribute + : DescriptorAttribute + { + internal protected sealed override void TryConfigure(IDescriptor descriptor) + { + if (descriptor is IInputFieldDescriptor d) + { + OnConfigure(d); + } + } + + public abstract void OnConfigure(IInputFieldDescriptor descriptor); + } +} diff --git a/src/Core/Types/Types/Attributes/Argument.cs b/src/Core/Types/Types/Attributes/InputObjectTypeDescriptorAttribute.cs similarity index 52% rename from src/Core/Types/Types/Attributes/Argument.cs rename to src/Core/Types/Types/Attributes/InputObjectTypeDescriptorAttribute.cs index 6d90ab090a1..87ddcfce140 100644 --- a/src/Core/Types/Types/Attributes/Argument.cs +++ b/src/Core/Types/Types/Attributes/InputObjectTypeDescriptorAttribute.cs @@ -2,25 +2,6 @@ namespace HotChocolate.Types { - - [AttributeUsage( - AttributeTargets.Property | AttributeTargets.Method, - Inherited = true, - AllowMultiple = true)] - public abstract class InputFieldDescriptorAttribute - : DescriptorAttribute - { - internal protected sealed override void TryConfigure(IDescriptor descriptor) - { - if (descriptor is IInputFieldDescriptor d) - { - OnConfigure(d); - } - } - - public abstract void OnConfigure(IInputFieldDescriptor descriptor); - } - [AttributeUsage( AttributeTargets.Class | AttributeTargets.Struct, Inherited = true, diff --git a/src/Core/Types/Types/Descriptors/InputObjectTypeDescriptor.cs b/src/Core/Types/Types/Descriptors/InputObjectTypeDescriptor.cs index 7692e498a91..7dc5a1563ba 100644 --- a/src/Core/Types/Types/Descriptors/InputObjectTypeDescriptor.cs +++ b/src/Core/Types/Types/Descriptors/InputObjectTypeDescriptor.cs @@ -43,6 +43,11 @@ protected InputObjectTypeDescriptor(IDescriptorContext context) protected override void OnCreateDefinition( InputObjectTypeDefinition definition) { + if (Definition.ClrType is { }) + { + Context.Inspector.ApplyAttributes(this, Definition.ClrType); + } + var fields = new Dictionary(); var handledProperties = new HashSet(); @@ -55,11 +60,6 @@ protected override void OnCreateDefinition( OnCompleteFields(fields, handledProperties); Definition.Fields.AddRange(fields.Values); - - if (Definition.ClrType is { }) - { - Context.Inspector.ApplyAttributes(this, Definition.ClrType); - } } protected virtual void OnCompleteFields( From 7e3074c6a5f4d8691a855f21426daf1cd9cb2a16 Mon Sep 17 00:00:00 2001 From: Michael Staib Date: Sun, 1 Dec 2019 22:29:10 +0100 Subject: [PATCH 11/17] Fixed field update issue --- .../Descriptors/DirectiveTypeDescriptor.cs | 19 ++++++---- .../Descriptors/DirectiveTypeDescriptor~1.cs | 10 +++++- .../Descriptors/InputObjectTypeDescriptor.cs | 13 +++++-- .../InputObjectTypeDescriptor~1.cs | 14 ++++++-- .../Descriptors/InterfaceTypeDescriptor.cs | 9 ++++- .../Descriptors/InterfaceTypeDescriptor~1.cs | 10 +++++- .../Descriptors/OutputFieldDescriptorBase.cs | 36 ++++++++++++++----- 7 files changed, 88 insertions(+), 23 deletions(-) diff --git a/src/Core/Types/Types/Descriptors/DirectiveTypeDescriptor.cs b/src/Core/Types/Types/Descriptors/DirectiveTypeDescriptor.cs index 0dcd88b4c87..619358d97e6 100644 --- a/src/Core/Types/Types/Descriptors/DirectiveTypeDescriptor.cs +++ b/src/Core/Types/Types/Descriptors/DirectiveTypeDescriptor.cs @@ -46,6 +46,11 @@ protected DirectiveTypeDescriptor(IDescriptorContext context) protected override void OnCreateDefinition( DirectiveTypeDefinition definition) { + if (Definition.ClrType is { }) + { + Context.Inspector.ApplyAttributes(this, Definition.ClrType); + } + var arguments = new Dictionary(); var handledMembers = new HashSet(); @@ -59,11 +64,6 @@ protected override void OnCreateDefinition( OnCompleteArguments(arguments, handledMembers); definition.Arguments.AddRange(arguments.Values); - - if (Definition.ClrType is { }) - { - Context.Inspector.ApplyAttributes(this, Definition.ClrType); - } } protected virtual void OnCompleteArguments( @@ -93,7 +93,14 @@ public IDirectiveTypeDescriptor Description(string value) public IDirectiveArgumentDescriptor Argument(NameString name) { - var descriptor = new DirectiveArgumentDescriptor( + DirectiveArgumentDescriptor descriptor = + Arguments.FirstOrDefault(t => t.Definition.Name.Equals(name)); + if (descriptor is { }) + { + return descriptor; + } + + descriptor = new DirectiveArgumentDescriptor( Context, name.EnsureNotEmpty(nameof(name))); Arguments.Add(descriptor); diff --git a/src/Core/Types/Types/Descriptors/DirectiveTypeDescriptor~1.cs b/src/Core/Types/Types/Descriptors/DirectiveTypeDescriptor~1.cs index 47cfe2851f3..16cf9722e90 100644 --- a/src/Core/Types/Types/Descriptors/DirectiveTypeDescriptor~1.cs +++ b/src/Core/Types/Types/Descriptors/DirectiveTypeDescriptor~1.cs @@ -7,6 +7,7 @@ using HotChocolate.Resolvers; using HotChocolate.Types.Descriptors.Definitions; using HotChocolate.Properties; +using System.Linq; namespace HotChocolate.Types.Descriptors { @@ -88,7 +89,14 @@ public IDirectiveArgumentDescriptor Argument( if (property.ExtractMember() is PropertyInfo p) { - var descriptor = new DirectiveArgumentDescriptor(Context, p); + DirectiveArgumentDescriptor descriptor = + Arguments.FirstOrDefault(t => t.Definition.Property == p); + if (descriptor is { }) + { + return descriptor; + } + + descriptor = new DirectiveArgumentDescriptor(Context, p); Arguments.Add(descriptor); return descriptor; } diff --git a/src/Core/Types/Types/Descriptors/InputObjectTypeDescriptor.cs b/src/Core/Types/Types/Descriptors/InputObjectTypeDescriptor.cs index 7dc5a1563ba..347285ca5f2 100644 --- a/src/Core/Types/Types/Descriptors/InputObjectTypeDescriptor.cs +++ b/src/Core/Types/Types/Descriptors/InputObjectTypeDescriptor.cs @@ -89,11 +89,18 @@ public IInputObjectTypeDescriptor Description(string value) public IInputFieldDescriptor Field(NameString name) { - var field = new InputFieldDescriptor( + InputFieldDescriptor fieldDescriptor = + Fields.FirstOrDefault(t => t.Definition.Name.Equals(name)); + if (fieldDescriptor is { }) + { + return fieldDescriptor; + } + + fieldDescriptor = new InputFieldDescriptor( Context, name.EnsureNotEmpty(nameof(name))); - Fields.Add(field); - return field; + Fields.Add(fieldDescriptor); + return fieldDescriptor; } public IInputObjectTypeDescriptor Directive(T directive) diff --git a/src/Core/Types/Types/Descriptors/InputObjectTypeDescriptor~1.cs b/src/Core/Types/Types/Descriptors/InputObjectTypeDescriptor~1.cs index 7cf2f173da9..b3958055445 100644 --- a/src/Core/Types/Types/Descriptors/InputObjectTypeDescriptor~1.cs +++ b/src/Core/Types/Types/Descriptors/InputObjectTypeDescriptor~1.cs @@ -5,6 +5,7 @@ using HotChocolate.Utilities; using HotChocolate.Language; using HotChocolate.Types.Descriptors.Definitions; +using System.Linq; namespace HotChocolate.Types.Descriptors { @@ -77,9 +78,16 @@ public IInputFieldDescriptor Field( { if (property.ExtractMember() is PropertyInfo p) { - var field = new InputFieldDescriptor(Context, p); - Fields.Add(field); - return field; + InputFieldDescriptor fieldDescriptor = + Fields.FirstOrDefault(t => t.Definition.Property == p); + if (fieldDescriptor is { }) + { + return fieldDescriptor; + } + + fieldDescriptor = new InputFieldDescriptor(Context, p); + Fields.Add(fieldDescriptor); + return fieldDescriptor; } throw new ArgumentException( diff --git a/src/Core/Types/Types/Descriptors/InterfaceTypeDescriptor.cs b/src/Core/Types/Types/Descriptors/InterfaceTypeDescriptor.cs index 22d4c41a84d..36733f18db7 100644 --- a/src/Core/Types/Types/Descriptors/InterfaceTypeDescriptor.cs +++ b/src/Core/Types/Types/Descriptors/InterfaceTypeDescriptor.cs @@ -90,7 +90,14 @@ public IInterfaceTypeDescriptor Description(string value) public IInterfaceFieldDescriptor Field(NameString name) { - var fieldDescriptor = new InterfaceFieldDescriptor( + InterfaceFieldDescriptor fieldDescriptor = + Fields.FirstOrDefault(t => t.Definition.Name.Equals(name)); + if (fieldDescriptor is { }) + { + return fieldDescriptor; + } + + fieldDescriptor = InterfaceFieldDescriptor.New( Context, name.EnsureNotEmpty(nameof(name))); Fields.Add(fieldDescriptor); diff --git a/src/Core/Types/Types/Descriptors/InterfaceTypeDescriptor~1.cs b/src/Core/Types/Types/Descriptors/InterfaceTypeDescriptor~1.cs index 2328a200882..36a34502b22 100644 --- a/src/Core/Types/Types/Descriptors/InterfaceTypeDescriptor~1.cs +++ b/src/Core/Types/Types/Descriptors/InterfaceTypeDescriptor~1.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Linq; using System.Linq.Expressions; using System.Reflection; using HotChocolate.Language; @@ -83,7 +84,14 @@ public IInterfaceFieldDescriptor Field( MemberInfo member = propertyOrMethod.ExtractMember(); if (member is PropertyInfo || member is MethodInfo) { - var fieldDescriptor = new InterfaceFieldDescriptor( + InterfaceFieldDescriptor fieldDescriptor = + Fields.FirstOrDefault(t => t.Definition.Member == member); + if (fieldDescriptor is { }) + { + return fieldDescriptor; + } + + fieldDescriptor = new InterfaceFieldDescriptor( Context, member); Fields.Add(fieldDescriptor); return fieldDescriptor; diff --git a/src/Core/Types/Types/Descriptors/OutputFieldDescriptorBase.cs b/src/Core/Types/Types/Descriptors/OutputFieldDescriptorBase.cs index 5cb0cd0ecc6..fe4a47d4791 100644 --- a/src/Core/Types/Types/Descriptors/OutputFieldDescriptorBase.cs +++ b/src/Core/Types/Types/Descriptors/OutputFieldDescriptorBase.cs @@ -4,6 +4,7 @@ using HotChocolate.Properties; using HotChocolate.Types.Descriptors.Definitions; using System.Reflection; +using System.Linq; namespace HotChocolate.Types.Descriptors { @@ -19,8 +20,21 @@ protected OutputFieldDescriptorBase(IDescriptorContext context) { } + protected ICollection Arguments { get; } = + new List(); + protected IReadOnlyDictionary Parameters { get; set; } + protected override void OnCreateDefinition(TDefinition definition) + { + base.OnCreateDefinition(definition); + + foreach (ArgumentDescriptor argument in Arguments) + { + Definition.Arguments.Add(argument.CreateDefinition()); + } + } + protected void SyntaxNode( FieldDefinitionNode syntaxNode) { @@ -96,16 +110,22 @@ protected void Argument( name.EnsureNotEmpty(nameof(name)); - ArgumentDescriptor descriptor = - Parameters != null - && Parameters.TryGetValue(name, out ParameterInfo p) - ? ArgumentDescriptor.New(Context, p) - : ArgumentDescriptor.New(Context, name); + ParameterInfo parameter = null; + Parameters?.TryGetValue(name, out parameter); - argument(descriptor); + ArgumentDescriptor descriptor = parameter is null + ? Arguments.FirstOrDefault(t => t.Definition.Name.Equals(name)) + : Arguments.FirstOrDefault(t => t.Definition.Parameter == parameter); + + if (descriptor is null) + { + descriptor = parameter is null + ? ArgumentDescriptor.New(Context, name) + : ArgumentDescriptor.New(Context, parameter); + Arguments.Add(descriptor); + } - ArgumentDefinition definition = descriptor.CreateDefinition(); - Definition.Arguments.Add(definition); + argument(descriptor); } public void Deprecated(string reason) From 7a1e5f895da720636270a5787cae2e8ee201afaf Mon Sep 17 00:00:00 2001 From: Michael Staib Date: Sun, 1 Dec 2019 22:36:15 +0100 Subject: [PATCH 12/17] reformatted file --- .../Types/Types/Descriptors/DirectiveTypeDescriptor~1.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Core/Types/Types/Descriptors/DirectiveTypeDescriptor~1.cs b/src/Core/Types/Types/Descriptors/DirectiveTypeDescriptor~1.cs index 16cf9722e90..004b66481b6 100644 --- a/src/Core/Types/Types/Descriptors/DirectiveTypeDescriptor~1.cs +++ b/src/Core/Types/Types/Descriptors/DirectiveTypeDescriptor~1.cs @@ -1,13 +1,13 @@ using System; using System.Collections.Generic; +using System.Linq; using System.Linq.Expressions; using System.Reflection; -using HotChocolate.Utilities; using HotChocolate.Language; +using HotChocolate.Properties; using HotChocolate.Resolvers; using HotChocolate.Types.Descriptors.Definitions; -using HotChocolate.Properties; -using System.Linq; +using HotChocolate.Utilities; namespace HotChocolate.Types.Descriptors { From 104cff497badf49eb9e87b606a1f07bcb6eb34d7 Mon Sep 17 00:00:00 2001 From: Michael Staib Date: Sun, 1 Dec 2019 22:52:50 +0100 Subject: [PATCH 13/17] Fixed Argument Initialization --- .../Types/Types/Descriptors/InterfaceFieldDescriptor.cs | 2 ++ src/Core/Types/Types/Descriptors/ObjectFieldDescriptor.cs | 2 ++ src/Core/Types/Types/Descriptors/ObjectTypeDescriptor.cs | 6 ++---- .../Types/Types/Descriptors/OutputFieldDescriptorBase.cs | 4 ++-- 4 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/Core/Types/Types/Descriptors/InterfaceFieldDescriptor.cs b/src/Core/Types/Types/Descriptors/InterfaceFieldDescriptor.cs index c4904cb0410..2dbe5b29ace 100644 --- a/src/Core/Types/Types/Descriptors/InterfaceFieldDescriptor.cs +++ b/src/Core/Types/Types/Descriptors/InterfaceFieldDescriptor.cs @@ -52,6 +52,8 @@ public InterfaceFieldDescriptor( protected override void OnCreateDefinition( InterfaceFieldDefinition definition) { + base.OnCreateDefinition(definition); + CompleteArguments(definition); if (Definition.Member is { }) diff --git a/src/Core/Types/Types/Descriptors/ObjectFieldDescriptor.cs b/src/Core/Types/Types/Descriptors/ObjectFieldDescriptor.cs index e9029daeafb..5c8e6b55102 100644 --- a/src/Core/Types/Types/Descriptors/ObjectFieldDescriptor.cs +++ b/src/Core/Types/Types/Descriptors/ObjectFieldDescriptor.cs @@ -69,6 +69,8 @@ protected ObjectFieldDescriptor( protected override void OnCreateDefinition( ObjectFieldDefinition definition) { + base.OnCreateDefinition(definition); + CompleteArguments(definition); if (Definition.Member is { }) diff --git a/src/Core/Types/Types/Descriptors/ObjectTypeDescriptor.cs b/src/Core/Types/Types/Descriptors/ObjectTypeDescriptor.cs index 1d20822e657..f5ccd064d83 100644 --- a/src/Core/Types/Types/Descriptors/ObjectTypeDescriptor.cs +++ b/src/Core/Types/Types/Descriptors/ObjectTypeDescriptor.cs @@ -23,10 +23,8 @@ public ObjectTypeDescriptor(IDescriptorContext context, Type clrType) } Definition.ClrType = clrType; - Definition.Name = - context.Naming.GetTypeName(clrType, TypeKind.Object); - Definition.Description = - context.Naming.GetTypeDescription(clrType, TypeKind.Object); + Definition.Name = context.Naming.GetTypeName(clrType, TypeKind.Object); + Definition.Description = context.Naming.GetTypeDescription(clrType, TypeKind.Object); } public ObjectTypeDescriptor(IDescriptorContext context) diff --git a/src/Core/Types/Types/Descriptors/OutputFieldDescriptorBase.cs b/src/Core/Types/Types/Descriptors/OutputFieldDescriptorBase.cs index fe4a47d4791..1aefdd679ff 100644 --- a/src/Core/Types/Types/Descriptors/OutputFieldDescriptorBase.cs +++ b/src/Core/Types/Types/Descriptors/OutputFieldDescriptorBase.cs @@ -120,8 +120,8 @@ protected void Argument( if (descriptor is null) { descriptor = parameter is null - ? ArgumentDescriptor.New(Context, name) - : ArgumentDescriptor.New(Context, parameter); + ? ArgumentDescriptor.New(Context, name) + : ArgumentDescriptor.New(Context, parameter); Arguments.Add(descriptor); } From a40c38132f7eb7addc72f9433e1898cad9b3d1be Mon Sep 17 00:00:00 2001 From: Michael Staib Date: Sun, 1 Dec 2019 23:39:18 +0100 Subject: [PATCH 14/17] Added enum type attribute --- .../Types/EnumTypeDescriptorAttributeTests.cs | 69 +++++++++++++++++++ src/Core/Types.Tests/Types/EnumTypeTests.cs | 14 ++-- .../Attributes/ArgumentDescriptorAttribute.cs | 1 - .../Attributes/EnumTypeDescriptorAttribute.cs | 22 ++++++ .../EnumValueDescriptorAttribute.cs | 22 ++++++ .../Types/Descriptors/EnumTypeDescriptor.cs | 41 ++++++----- 6 files changed, 140 insertions(+), 29 deletions(-) create mode 100644 src/Core/Types.Tests/Types/EnumTypeDescriptorAttributeTests.cs create mode 100644 src/Core/Types/Types/Attributes/EnumTypeDescriptorAttribute.cs create mode 100644 src/Core/Types/Types/Attributes/EnumValueDescriptorAttribute.cs diff --git a/src/Core/Types.Tests/Types/EnumTypeDescriptorAttributeTests.cs b/src/Core/Types.Tests/Types/EnumTypeDescriptorAttributeTests.cs new file mode 100644 index 00000000000..f70d6ea418f --- /dev/null +++ b/src/Core/Types.Tests/Types/EnumTypeDescriptorAttributeTests.cs @@ -0,0 +1,69 @@ +using System.Linq; +using Xunit; + +namespace HotChocolate.Types +{ + public class EnumTypeDescriptorAttributeTests + { + [Fact] + public void Change_Value_Name_With_Attribute() + { + // act + ISchema schema = SchemaBuilder.New() + .AddEnumType() + .ModifyOptions(o => o.StrictValidation = false) + .Create(); + + // assert + EnumValue value = schema.GetType("Enum1").Values.First(); + Assert.Equal("ABC", value.Name); + } + + [Fact] + public void Change_Type_Name_With_Attribute() + { + // act + ISchema schema = SchemaBuilder.New() + .AddEnumType() + .ModifyOptions(o => o.StrictValidation = false) + .Create(); + + // assert + Assert.NotNull(schema.GetType("Abc")); + } + + public enum Enum1 + { + + [RenameValue] + Value1, + Value2 + } + + public class RenameValueAttribute + : EnumValueDescriptorAttribute + { + public override void OnConfigure(IEnumValueDescriptor descriptor) + { + descriptor.Name("ABC"); + } + } + + [RenameType] + public enum Enum2 + { + + Value1, + Value2 + } + + public class RenameTypeAttribute + : EnumTypeDescriptorAttribute + { + public override void OnConfigure(IEnumTypeDescriptor descriptor) + { + descriptor.Name("Abc"); + } + } + } +} diff --git a/src/Core/Types.Tests/Types/EnumTypeTests.cs b/src/Core/Types.Tests/Types/EnumTypeTests.cs index f0554b7bb53..72ced9aa38d 100644 --- a/src/Core/Types.Tests/Types/EnumTypeTests.cs +++ b/src/Core/Types.Tests/Types/EnumTypeTests.cs @@ -95,7 +95,7 @@ public void EnumType_WithDirectives() .Location(DirectiveLocation.Enum))); c.RegisterType(new EnumType(d => d - .Directive(new DirectiveNode("bar")))); + .Directive(new DirectiveNode("bar")))); c.Options.StrictValidation = false; }); @@ -170,7 +170,7 @@ public void ExplicitEnumType_OnlyContainDeclaredValues() Assert.Null(value); } - [Fact] + [Fact] public void ExplicitEnumType_OnlyContainDeclaredValues_2() { // act @@ -298,7 +298,7 @@ public void EnumValue_WithDirectives() c.RegisterType(new EnumType(d => d .Name("Foo") .Item("baz") - .Directive(new DirectiveNode("bar")))); + .Directive(new DirectiveNode("bar")))); c.Options.StrictValidation = false; }); @@ -348,7 +348,7 @@ public void Serialize_EnumValue_WithDirectives() c.RegisterType(new EnumType(d => d .Name("Foo") .Item("baz") - .Directive(new DirectiveNode("bar")))); + .Directive(new DirectiveNode("bar")))); c.Options.StrictValidation = false; }); @@ -395,7 +395,7 @@ public void EnumValue_WithDirectivesTInstance() c.RegisterType(new EnumType(d => d .Name("Foo") .Item("baz") - .Directive(new Bar()))); + .Directive(new Bar()))); c.Options.StrictValidation = false; }); @@ -464,7 +464,7 @@ public void Deprecate_Obsolete_Values() .Name("Query") .Field("foo") .Type() - .Resolver("bar")) + .Resolver("bar")) .AddType() .Create(); @@ -481,7 +481,7 @@ public void Deprecate_Fields_With_Deprecated_Attribute() .Name("Query") .Field("foo") .Type() - .Resolver("bar")) + .Resolver("bar")) .AddType() .Create(); diff --git a/src/Core/Types/Types/Attributes/ArgumentDescriptorAttribute.cs b/src/Core/Types/Types/Attributes/ArgumentDescriptorAttribute.cs index 6876e97bcec..6944d2df240 100644 --- a/src/Core/Types/Types/Attributes/ArgumentDescriptorAttribute.cs +++ b/src/Core/Types/Types/Attributes/ArgumentDescriptorAttribute.cs @@ -19,5 +19,4 @@ internal protected sealed override void TryConfigure(IDescriptor descriptor) public abstract void OnConfigure(IArgumentDescriptor descriptor); } - } diff --git a/src/Core/Types/Types/Attributes/EnumTypeDescriptorAttribute.cs b/src/Core/Types/Types/Attributes/EnumTypeDescriptorAttribute.cs new file mode 100644 index 00000000000..5135e1122ad --- /dev/null +++ b/src/Core/Types/Types/Attributes/EnumTypeDescriptorAttribute.cs @@ -0,0 +1,22 @@ +using System; + +namespace HotChocolate.Types +{ + [AttributeUsage( + AttributeTargets.Enum | AttributeTargets.Class | AttributeTargets.Struct, + Inherited = true, + AllowMultiple = true)] + public abstract class EnumTypeDescriptorAttribute + : DescriptorAttribute + { + internal protected sealed override void TryConfigure(IDescriptor descriptor) + { + if (descriptor is IEnumTypeDescriptor d) + { + OnConfigure(d); + } + } + + public abstract void OnConfigure(IEnumTypeDescriptor descriptor); + } +} diff --git a/src/Core/Types/Types/Attributes/EnumValueDescriptorAttribute.cs b/src/Core/Types/Types/Attributes/EnumValueDescriptorAttribute.cs new file mode 100644 index 00000000000..ec2347f77f4 --- /dev/null +++ b/src/Core/Types/Types/Attributes/EnumValueDescriptorAttribute.cs @@ -0,0 +1,22 @@ +using System; + +namespace HotChocolate.Types +{ + [AttributeUsage( + AttributeTargets.Field, + Inherited = true, + AllowMultiple = true)] + public abstract class EnumValueDescriptorAttribute + : DescriptorAttribute + { + internal protected sealed override void TryConfigure(IDescriptor descriptor) + { + if (descriptor is IEnumValueDescriptor d) + { + OnConfigure(d); + } + } + + public abstract void OnConfigure(IEnumValueDescriptor descriptor); + } +} diff --git a/src/Core/Types/Types/Descriptors/EnumTypeDescriptor.cs b/src/Core/Types/Types/Descriptors/EnumTypeDescriptor.cs index f102223a345..1ed8f8a8840 100644 --- a/src/Core/Types/Types/Descriptors/EnumTypeDescriptor.cs +++ b/src/Core/Types/Types/Descriptors/EnumTypeDescriptor.cs @@ -14,21 +14,16 @@ protected EnumTypeDescriptor(IDescriptorContext context) : base(context) { Definition.ClrType = typeof(object); - Definition.Values.BindingBehavior = - context.Options.DefaultBindingBehavior; + Definition.Values.BindingBehavior = context.Options.DefaultBindingBehavior; } protected EnumTypeDescriptor(IDescriptorContext context, Type clrType) : base(context) { - Definition.ClrType = clrType - ?? throw new ArgumentNullException(nameof(clrType)); - Definition.Name = context.Naming.GetTypeName( - clrType, TypeKind.Enum); - Definition.Description = context.Naming.GetTypeDescription( - clrType, TypeKind.Enum); - Definition.Values.BindingBehavior = - context.Options.DefaultBindingBehavior; + Definition.ClrType = clrType ?? throw new ArgumentNullException(nameof(clrType)); + Definition.Name = context.Naming.GetTypeName(clrType, TypeKind.Enum); + Definition.Description = context.Naming.GetTypeDescription(clrType, TypeKind.Enum); + Definition.Values.BindingBehavior = context.Options.DefaultBindingBehavior; } internal protected override EnumTypeDefinition Definition { get; } = @@ -40,9 +35,12 @@ protected EnumTypeDescriptor(IDescriptorContext context, Type clrType) protected override void OnCreateDefinition( EnumTypeDefinition definition) { - var values = - Values.Select(t => t.CreateDefinition()) - .ToDictionary(t => t.Value); + if (Definition.ClrType is { }) + { + Context.Inspector.ApplyAttributes(this, Definition.ClrType); + } + + var values = Values.Select(t => t.CreateDefinition()).ToDictionary(t => t.Value); AddImplicitValues(definition, values); definition.Values.Clear(); @@ -51,11 +49,6 @@ protected override void OnCreateDefinition( { definition.Values.Add(value); } - - if (Definition.ClrType is { }) - { - Context.Inspector.ApplyAttributes(this, Definition.ClrType); - } } protected void AddImplicitValues( @@ -64,8 +57,7 @@ protected void AddImplicitValues( { if (typeDefinition.Values.IsImplicitBinding()) { - foreach (object value in Context.Inspector - .GetEnumValues(typeDefinition.ClrType)) + foreach (object value in Context.Inspector.GetEnumValues(typeDefinition.ClrType)) { EnumValueDefinition valueDefinition = EnumValueDescriptor.New(Context, value) @@ -117,7 +109,14 @@ public IEnumTypeDescriptor BindValuesImplicitly() => public IEnumValueDescriptor Item(T value) { - var descriptor = new EnumValueDescriptor(Context, value); + EnumValueDescriptor descriptor = Values.FirstOrDefault(t => + t.Definition.Value.Equals(value)); + if (descriptor is { }) + { + return descriptor; + } + + descriptor = new EnumValueDescriptor(Context, value); Values.Add(descriptor); return descriptor; } From 4405d643f40214f297908e2872037ef92bfc01f0 Mon Sep 17 00:00:00 2001 From: Michael Staib Date: Sun, 1 Dec 2019 23:48:01 +0100 Subject: [PATCH 15/17] Added filter attribute tests --- .../QueryableFilterAttributeTests.cs | 88 +++++++++++++++++++ ...teTests.Create_Schema_With_FilterType.snap | 58 ++++++++++++ ...chema_With_FilterType_With_Fluent_API.snap | 25 ++++++ 3 files changed, 171 insertions(+) create mode 100644 src/Core/Types.Filters.Tests/QueryableFilterAttributeTests.cs create mode 100644 src/Core/Types.Filters.Tests/__snapshots__/QueryableFilterAttributeTests.Create_Schema_With_FilterType.snap create mode 100644 src/Core/Types.Filters.Tests/__snapshots__/QueryableFilterAttributeTests.Create_Schema_With_FilterType_With_Fluent_API.snap diff --git a/src/Core/Types.Filters.Tests/QueryableFilterAttributeTests.cs b/src/Core/Types.Filters.Tests/QueryableFilterAttributeTests.cs new file mode 100644 index 00000000000..8cfd91a30a9 --- /dev/null +++ b/src/Core/Types.Filters.Tests/QueryableFilterAttributeTests.cs @@ -0,0 +1,88 @@ +using System.Collections.Generic; +using HotChocolate.Execution; +using Snapshooter.Xunit; +using Xunit; + +namespace HotChocolate.Types.Filters +{ + public class QueryableFilterAttributeTests + { + [Fact] + public void Create_Schema_With_FilterType() + { + // arrange + // act + ISchema schema = SchemaBuilder.New() + .AddQueryType() + .Create(); + + // assert + schema.ToString().MatchSnapshot(); + } + + [Fact] + public void Create_Schema_With_FilterType_With_Fluent_API() + { + // arrange + // act + ISchema schema = SchemaBuilder.New() + .AddQueryType() + .Create(); + + // assert + schema.ToString().MatchSnapshot(); + } + + public class Query1 + { + [UseFiltering] + public IEnumerable Foos { get; } = new[] + { + new Foo { Bar = "aa", Baz = 1, Qux = 1 }, + new Foo { Bar = "ba", Baz = 1 }, + new Foo { Bar = "ca", Baz = 2 }, + new Foo { Bar = "ab", Baz = 2 }, + new Foo { Bar = "ac", Baz = 2 }, + new Foo { Bar = "ad", Baz = 2 }, + new Foo { Bar = null, Baz = 0 } + }; + } + + public class Query2 + { + [UseFiltering(FilterType = typeof(FooFilterType))] + public IEnumerable Foos { get; } = new[] + { + new Foo { Bar = "aa", Baz = 1, Qux = 1 }, + new Foo { Bar = "ba", Baz = 1 }, + new Foo { Bar = "ca", Baz = 2 }, + new Foo { Bar = "ab", Baz = 2 }, + new Foo { Bar = "ac", Baz = 2 }, + new Foo { Bar = "ad", Baz = 2 }, + new Foo { Bar = null, Baz = 0 } + }; + } + + public class FooFilterType : FilterInputType + { + protected override void Configure(IFilterInputTypeDescriptor descriptor) + { + descriptor.BindFieldsExplicitly() + .Filter(m => m.Bar) + .BindFiltersExplicitly() + .AllowEquals(); + } + } + + public class Foo + { + public string Bar { get; set; } + + [GraphQLType(typeof(NonNullType))] + public long Baz { get; set; } + + [GraphQLType(typeof(IntType))] + public int? Qux { get; set; } + } + } +} diff --git a/src/Core/Types.Filters.Tests/__snapshots__/QueryableFilterAttributeTests.Create_Schema_With_FilterType.snap b/src/Core/Types.Filters.Tests/__snapshots__/QueryableFilterAttributeTests.Create_Schema_With_FilterType.snap new file mode 100644 index 00000000000..03978ae29ad --- /dev/null +++ b/src/Core/Types.Filters.Tests/__snapshots__/QueryableFilterAttributeTests.Create_Schema_With_FilterType.snap @@ -0,0 +1,58 @@ +schema { + query: Query1 +} + +type Foo { + bar: String + baz: Int! + qux: Int +} + +type Query1 { + foos(where: FooFilter): [Foo] +} + +input FooFilter { + AND: [FooFilter!] + bar: String + bar_contains: String + bar_ends_with: String + bar_in: [String] + bar_not: String + bar_not_contains: String + bar_not_ends_with: String + bar_not_in: [String] + bar_not_starts_with: String + bar_starts_with: String + baz: Int + baz_gt: Int + baz_gte: Int + baz_in: [Int!] + baz_lt: Int + baz_lte: Int + baz_not: Int + baz_not_gt: Int + baz_not_gte: Int + baz_not_in: [Int!] + baz_not_lt: Int + baz_not_lte: Int + OR: [FooFilter!] + qux: Int + qux_gt: Int + qux_gte: Int + qux_in: [Int] + qux_lt: Int + qux_lte: Int + qux_not: Int + qux_not_gt: Int + qux_not_gte: Int + qux_not_in: [Int] + qux_not_lt: Int + qux_not_lte: Int +} + +"The `Int` scalar type represents non-fractional signed whole numeric values. Int can represent values between -(2^31) and 2^31 - 1." +scalar Int + +"The `String` scalar type represents textual data, represented as UTF-8 character sequences. The String type is most often used by GraphQL to represent free-form human-readable text." +scalar String diff --git a/src/Core/Types.Filters.Tests/__snapshots__/QueryableFilterAttributeTests.Create_Schema_With_FilterType_With_Fluent_API.snap b/src/Core/Types.Filters.Tests/__snapshots__/QueryableFilterAttributeTests.Create_Schema_With_FilterType_With_Fluent_API.snap new file mode 100644 index 00000000000..ca4d9d2d3fd --- /dev/null +++ b/src/Core/Types.Filters.Tests/__snapshots__/QueryableFilterAttributeTests.Create_Schema_With_FilterType_With_Fluent_API.snap @@ -0,0 +1,25 @@ +schema { + query: Query2 +} + +type Foo { + bar: String + baz: Int! + qux: Int +} + +type Query2 { + foos(where: FooFilter): [Foo] +} + +input FooFilter { + AND: [FooFilter!] + bar: String + OR: [FooFilter!] +} + +"The `Int` scalar type represents non-fractional signed whole numeric values. Int can represent values between -(2^31) and 2^31 - 1." +scalar Int + +"The `String` scalar type represents textual data, represented as UTF-8 character sequences. The String type is most often used by GraphQL to represent free-form human-readable text." +scalar String From a6af7c514711153440a813260e06cb0f7ed5adbf Mon Sep 17 00:00:00 2001 From: Michael Staib Date: Mon, 2 Dec 2019 00:13:55 +0100 Subject: [PATCH 16/17] Added sort attribute --- .../SortingAttributeTests.cs | 68 +++++++++++++++++++ ...buteTests.Use_Attribute_With_SortType.snap | 27 ++++++++ ...eTests.Use_Attribute_Without_SortType.snap | 28 ++++++++ 3 files changed, 123 insertions(+) create mode 100644 src/Core/Types.Sorting.Tests/SortingAttributeTests.cs create mode 100644 src/Core/Types.Sorting.Tests/__snapshots__/SortingAttributeTests.Use_Attribute_With_SortType.snap create mode 100644 src/Core/Types.Sorting.Tests/__snapshots__/SortingAttributeTests.Use_Attribute_Without_SortType.snap diff --git a/src/Core/Types.Sorting.Tests/SortingAttributeTests.cs b/src/Core/Types.Sorting.Tests/SortingAttributeTests.cs new file mode 100644 index 00000000000..c82c80bbc9d --- /dev/null +++ b/src/Core/Types.Sorting.Tests/SortingAttributeTests.cs @@ -0,0 +1,68 @@ +using System.Collections.Generic; +using Snapshooter.Xunit; +using Xunit; + +namespace HotChocolate.Types.Sorting +{ + public class SortingAttributeTests + { + [Fact] + public void Use_Attribute_Without_SortType() + { + // act + ISchema schema = SchemaBuilder.New() + .AddQueryType() + .Create(); + + // assert + schema.ToString().MatchSnapshot(); + } + + [Fact] + public void Use_Attribute_With_SortType() + { + // act + ISchema schema = SchemaBuilder.New() + .AddQueryType() + .Create(); + + // assert + schema.ToString().MatchSnapshot(); + } + + public class Query1 + { + [UseSorting] + public IEnumerable Models { get; } = new List + { + new Model { Foo = "Abc", Bar = 1 }, + new Model { Foo = "Abc", Bar = 2 } + }; + } + + public class Query2 + { + [UseSorting(SortType = typeof(ModelSortType))] + public IEnumerable Models { get; } = new List + { + new Model { Foo = "Abc", Bar = 1 }, + new Model { Foo = "Abc", Bar = 2 } + }; + } + + public class ModelSortType : SortInputType + { + protected override void Configure(ISortInputTypeDescriptor descriptor) + { + descriptor.BindFieldsExplicitly().Sortable(t => t.Bar); + } + } + + public class Model + { + public string Foo { get; set; } + + public int Bar { get; set; } + } + } +} \ No newline at end of file diff --git a/src/Core/Types.Sorting.Tests/__snapshots__/SortingAttributeTests.Use_Attribute_With_SortType.snap b/src/Core/Types.Sorting.Tests/__snapshots__/SortingAttributeTests.Use_Attribute_With_SortType.snap new file mode 100644 index 00000000000..ce213690eae --- /dev/null +++ b/src/Core/Types.Sorting.Tests/__snapshots__/SortingAttributeTests.Use_Attribute_With_SortType.snap @@ -0,0 +1,27 @@ +schema { + query: Query2 +} + +type Model { + bar: Int! + foo: String +} + +type Query2 { + models(order_by: ModelSort): [Model] +} + +input ModelSort { + bar: SortOperationKind +} + +enum SortOperationKind { + ASC + DESC +} + +"The `Int` scalar type represents non-fractional signed whole numeric values. Int can represent values between -(2^31) and 2^31 - 1." +scalar Int + +"The `String` scalar type represents textual data, represented as UTF-8 character sequences. The String type is most often used by GraphQL to represent free-form human-readable text." +scalar String diff --git a/src/Core/Types.Sorting.Tests/__snapshots__/SortingAttributeTests.Use_Attribute_Without_SortType.snap b/src/Core/Types.Sorting.Tests/__snapshots__/SortingAttributeTests.Use_Attribute_Without_SortType.snap new file mode 100644 index 00000000000..73296333545 --- /dev/null +++ b/src/Core/Types.Sorting.Tests/__snapshots__/SortingAttributeTests.Use_Attribute_Without_SortType.snap @@ -0,0 +1,28 @@ +schema { + query: Query1 +} + +type Model { + bar: Int! + foo: String +} + +type Query1 { + models(order_by: ModelSort): [Model] +} + +input ModelSort { + bar: SortOperationKind + foo: SortOperationKind +} + +enum SortOperationKind { + ASC + DESC +} + +"The `Int` scalar type represents non-fractional signed whole numeric values. Int can represent values between -(2^31) and 2^31 - 1." +scalar Int + +"The `String` scalar type represents textual data, represented as UTF-8 character sequences. The String type is most often used by GraphQL to represent free-form human-readable text." +scalar String From db49a2dffa626889da1acc50c959cff153b8a7ac Mon Sep 17 00:00:00 2001 From: Michael Staib Date: Mon, 2 Dec 2019 00:16:29 +0100 Subject: [PATCH 17/17] Fixed sonar issues --- src/Core/Types.Filters/UseFilteringAttribute.cs | 5 ++--- src/Core/Types.Sorting/UseSortingAttribute.cs | 5 ++--- src/Core/Types/Types/Relay/UsePagingAttribute.cs | 9 ++++----- 3 files changed, 8 insertions(+), 11 deletions(-) diff --git a/src/Core/Types.Filters/UseFilteringAttribute.cs b/src/Core/Types.Filters/UseFilteringAttribute.cs index 5c8e392af92..288dd7a8887 100644 --- a/src/Core/Types.Filters/UseFilteringAttribute.cs +++ b/src/Core/Types.Filters/UseFilteringAttribute.cs @@ -8,13 +8,12 @@ public sealed class UseFilteringAttribute : ObjectFieldDescriptorAttribute { private static readonly MethodInfo _generic = typeof(FilterObjectFieldDescriptorExtensions) .GetMethods(BindingFlags.Public | BindingFlags.Static) - .Where(m => m.Name.Equals( + .Single(m => m.Name.Equals( nameof(FilterObjectFieldDescriptorExtensions.UseFiltering), StringComparison.Ordinal) && m.GetGenericArguments().Length == 1 && m.GetParameters().Length == 1 - && m.GetParameters()[0].ParameterType == typeof(IObjectFieldDescriptor)) - .Single(); + && m.GetParameters()[0].ParameterType == typeof(IObjectFieldDescriptor)); /// /// Gets or sets the filter type which specifies the filter object structure. diff --git a/src/Core/Types.Sorting/UseSortingAttribute.cs b/src/Core/Types.Sorting/UseSortingAttribute.cs index 62af70630ae..be064a4095d 100644 --- a/src/Core/Types.Sorting/UseSortingAttribute.cs +++ b/src/Core/Types.Sorting/UseSortingAttribute.cs @@ -8,13 +8,12 @@ public sealed class UseSortingAttribute : ObjectFieldDescriptorAttribute { private static readonly MethodInfo _generic = typeof(SortObjectFieldDescriptorExtensions) .GetMethods(BindingFlags.Public | BindingFlags.Static) - .Where(m => m.Name.Equals( + .Single(m => m.Name.Equals( nameof(SortObjectFieldDescriptorExtensions.UseSorting), StringComparison.Ordinal) && m.GetGenericArguments().Length == 1 && m.GetParameters().Length == 1 - && m.GetParameters()[0].ParameterType == typeof(IObjectFieldDescriptor)) - .Single(); + && m.GetParameters()[0].ParameterType == typeof(IObjectFieldDescriptor)); /// /// Gets or sets the sort type which specifies the sort object structure. diff --git a/src/Core/Types/Types/Relay/UsePagingAttribute.cs b/src/Core/Types/Types/Relay/UsePagingAttribute.cs index 87d6336b7cc..90ae123d5fd 100644 --- a/src/Core/Types/Types/Relay/UsePagingAttribute.cs +++ b/src/Core/Types/Types/Relay/UsePagingAttribute.cs @@ -6,15 +6,14 @@ namespace HotChocolate.Types.Relay { public sealed class UsePagingAttribute : ObjectFieldDescriptorAttribute { - private static readonly MethodInfo _usePaging = typeof(PagingObjectFieldDescriptorExtensions) + private static readonly MethodInfo _generic = typeof(PagingObjectFieldDescriptorExtensions) .GetMethods(BindingFlags.Public | BindingFlags.Static) - .Where(m => m.Name.Equals( + .Single(m => m.Name.Equals( nameof(PagingObjectFieldDescriptorExtensions.UsePaging), StringComparison.Ordinal) && m.GetGenericArguments().Length == 1 && m.GetParameters().Length == 1 - && m.GetParameters()[0].ParameterType == typeof(IObjectFieldDescriptor)) - .Single(); + && m.GetParameters()[0].ParameterType == typeof(IObjectFieldDescriptor)); public UsePagingAttribute(Type schemaType) { @@ -33,7 +32,7 @@ public override void OnConfigure(IObjectFieldDescriptor descriptor) .SetCode("ATTR_USEPAGING_SCHEMATYPE_INVALID") .Build()); } - _usePaging.MakeGenericMethod(SchemaType).Invoke(null, new[] { descriptor }); + _generic.MakeGenericMethod(SchemaType).Invoke(null, new[] { descriptor }); } } } \ No newline at end of file