Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,13 @@ namespace HotChocolate.Data;
/// <summary>
/// Registers the middleware and adds the arguments for filtering
/// </summary>
public class UseFilteringAttribute : ObjectFieldDescriptorAttribute
[AttributeUsage(
AttributeTargets.Property | AttributeTargets.Method,
Inherited = true,
AllowMultiple = true)]
public class UseFilteringAttribute : DescriptorAttribute
{
private static readonly MethodInfo s_generic = typeof(FilterObjectFieldDescriptorExtensions)
private static readonly MethodInfo s_genericObject = typeof(FilterObjectFieldDescriptorExtensions)
.GetMethods(BindingFlags.Public | BindingFlags.Static)
.Single(
m => m.Name.Equals(
Expand All @@ -20,6 +24,16 @@ public class UseFilteringAttribute : ObjectFieldDescriptorAttribute
&& m.GetParameters().Length == 2
&& m.GetParameters()[0].ParameterType == typeof(IObjectFieldDescriptor));

private static readonly MethodInfo s_genericInterface = typeof(FilterObjectFieldDescriptorExtensions)
.GetMethods(BindingFlags.Public | BindingFlags.Static)
.Single(
m => m.Name.Equals(
nameof(FilterObjectFieldDescriptorExtensions.UseFiltering),
StringComparison.Ordinal)
&& m.GetGenericArguments().Length == 1
&& m.GetParameters().Length == 2
&& m.GetParameters()[0].ParameterType == typeof(IInterfaceFieldDescriptor));

public UseFilteringAttribute(Type? filterType = null, [CallerLineNumber] int order = 0)
{
Type = filterType;
Expand All @@ -38,19 +52,35 @@ public UseFilteringAttribute(Type? filterType = null, [CallerLineNumber] int ord
/// <value>The name of the scope</value>
public string? Scope { get; set; }

/// <inheritdoc />
protected override void OnConfigure(
protected internal override void TryConfigure(
IDescriptorContext context,
IObjectFieldDescriptor descriptor,
MemberInfo? member)
IDescriptor descriptor,
ICustomAttributeProvider? attributeProvider)
{
if (Type is null)
if (descriptor is IObjectFieldDescriptor objectFieldDescriptor)
{
descriptor.UseFiltering(Scope);
if (Type is null)
{
objectFieldDescriptor.UseFiltering(Scope);
}
else
{
s_genericObject.MakeGenericMethod(Type).Invoke(null, [objectFieldDescriptor, Scope]);
}
}
else

if (descriptor is IInterfaceFieldDescriptor interfaceFieldDescriptor)
{
s_generic.MakeGenericMethod(Type).Invoke(null, [descriptor, Scope]);
if (Type is null)
{
interfaceFieldDescriptor.UseFiltering(Scope);
}
else
{
s_genericInterface.MakeGenericMethod(Type).Invoke(
null,
[interfaceFieldDescriptor, Scope]);
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
using System.Globalization;
using System.Reflection;
using System.Diagnostics.CodeAnalysis;
using HotChocolate.Configuration;
using HotChocolate.Data;
using HotChocolate.Data.Filters;
using HotChocolate.Internal;
using HotChocolate.Types.Descriptors;
using HotChocolate.Types.Descriptors.Configurations;
using static HotChocolate.Data.DataResources;
Expand Down Expand Up @@ -99,6 +101,85 @@ public static IObjectFieldDescriptor UseFiltering(
return UseFiltering(descriptor, filterType, null, scope);
}

/// <summary>
/// Adds filtering arguments to an interface field.
/// </summary>
/// <param name="descriptor">The field descriptor where the arguments are applied to</param>
/// <param name="scope">Specifies what scope should be used for the
/// <see cref="FilterConvention" /></param>
public static IInterfaceFieldDescriptor UseFiltering(
this IInterfaceFieldDescriptor descriptor,
string? scope = null)
{
ArgumentNullException.ThrowIfNull(descriptor);

return UseFiltering(descriptor, null, null, scope);
}

/// <summary>
/// Adds filtering arguments to an interface field.
/// </summary>
/// <param name="descriptor">The field descriptor where the arguments are applied to</param>
/// <param name="scope">Specifies what scope should be used for the
/// <see cref="FilterConvention" /></param>
/// <typeparam name="T">Either a runtime type or a <see cref="FilterInputType"/></typeparam>
public static IInterfaceFieldDescriptor UseFiltering<T>(
this IInterfaceFieldDescriptor descriptor,
string? scope = null)
{
ArgumentNullException.ThrowIfNull(descriptor);

var filterType =
typeof(IFilterInputType).IsAssignableFrom(typeof(T))
? typeof(T)
: typeof(FilterInputType<>).MakeGenericType(typeof(T));

return UseFiltering(descriptor, filterType, null, scope);
}

/// <summary>
/// Adds filtering arguments to an interface field.
/// </summary>
/// <param name="descriptor">The field descriptor where the arguments are applied to</param>
/// <param name="configure">Configures the filter input types that is used by the field
/// </param>
/// <param name="scope">Specifies what scope should be used for the
/// <see cref="FilterConvention" /></param>
public static IInterfaceFieldDescriptor UseFiltering<T>(
this IInterfaceFieldDescriptor descriptor,
Action<IFilterInputTypeDescriptor<T>> configure,
string? scope = null)
{
ArgumentNullException.ThrowIfNull(descriptor);
ArgumentNullException.ThrowIfNull(configure);

var filterType = new FilterInputType<T>(configure);
return UseFiltering(descriptor, filterType.GetType(), filterType, scope);
}

/// <summary>
/// Adds filtering arguments to an interface field.
/// </summary>
/// <param name="descriptor">The field descriptor where the arguments are applied to</param>
/// <param name="type">Either a runtime type or a <see cref="FilterInputType"/></param>
/// <param name="scope">Specifies what scope should be used for the
/// <see cref="FilterConvention" /></param>
public static IInterfaceFieldDescriptor UseFiltering(
this IInterfaceFieldDescriptor descriptor,
Type type,
string? scope = null)
{
ArgumentNullException.ThrowIfNull(descriptor);
ArgumentNullException.ThrowIfNull(type);

var filterType =
typeof(IFilterInputType).IsAssignableFrom(type)
? type
: typeof(FilterInputType<>).MakeGenericType(type);

return UseFiltering(descriptor, filterType, null, scope);
}

private static IObjectFieldDescriptor UseFiltering(
IObjectFieldDescriptor descriptor,
Type? filterType,
Expand Down Expand Up @@ -181,6 +262,93 @@ private static IObjectFieldDescriptor UseFiltering(
return descriptor;
}

private static bool TryGetTypeInfo(
IDescriptorContext context,
InterfaceFieldConfiguration definition,
[NotNullWhen(true)]
out ITypeInfo? typeInfo)
{
if (definition.ResultType is not null
&& definition.ResultType != typeof(object)
&& context.TypeInspector.TryCreateTypeInfo(definition.ResultType, out typeInfo))
{
return true;
}

if (definition.Member is not null
&& context.TypeInspector.TryCreateTypeInfo(
context.TypeInspector.GetReturnType(definition.Member),
out typeInfo))
{
return true;
}

typeInfo = null;
return false;
}

private static IInterfaceFieldDescriptor UseFiltering(
IInterfaceFieldDescriptor descriptor,
Type? filterType,
ITypeSystemMember? filterTypeInstance,
string? scope)
{
var argumentPlaceholder =
"_" + Guid.NewGuid().ToString("N", CultureInfo.InvariantCulture);

descriptor
.Extend()
.OnBeforeCreate(
(c, definition) =>
{
TypeReference argumentTypeReference;

if (filterTypeInstance is not null)
{
argumentTypeReference = TypeReference.Create(filterTypeInstance, scope);
}
else if (filterType is null)
{
var convention = c.GetFilterConvention(scope);

if (!TryGetTypeInfo(c, definition, out var typeInfo))
{
throw new ArgumentException(
FilterObjectFieldDescriptorExtensions_UseFiltering_CannotHandleType,
nameof(descriptor));
}

argumentTypeReference = convention.GetFieldType(typeInfo.NamedType);
}
else
{
argumentTypeReference = c.TypeInspector.GetTypeRef(
filterType,
TypeContext.Input,
scope);
}

var argumentDefinition = new ArgumentConfiguration
{
Name = argumentPlaceholder,
Type = argumentTypeReference,
Flags = CoreFieldFlags.FilterArgument
};

definition.Arguments.Add(argumentDefinition);

argumentDefinition.Tasks.Add(
new OnCompleteTypeSystemConfigurationTask<ArgumentConfiguration>(
(context, argDef) =>
argDef.Name =
context.GetFilterConvention(scope).GetArgumentName(),
argumentDefinition,
ApplyConfigurationOn.BeforeNaming));
});

return descriptor;
}

private static void CompileMiddleware(
ITypeCompletionContext context,
ObjectFieldConfiguration definition,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,13 @@ namespace HotChocolate.Data;
/// <summary>
/// Registers the middleware and adds the arguments for sorting
/// </summary>
public class UseSortingAttribute : ObjectFieldDescriptorAttribute
[AttributeUsage(
AttributeTargets.Property | AttributeTargets.Method,
Inherited = true,
AllowMultiple = true)]
public class UseSortingAttribute : DescriptorAttribute
{
private static readonly MethodInfo s_generic = typeof(SortingObjectFieldDescriptorExtensions)
private static readonly MethodInfo s_genericObject = typeof(SortingObjectFieldDescriptorExtensions)
.GetMethods(BindingFlags.Public | BindingFlags.Static)
.Single(m => m.Name.Equals(
nameof(SortingObjectFieldDescriptorExtensions.UseSorting),
Expand All @@ -19,6 +23,15 @@ public class UseSortingAttribute : ObjectFieldDescriptorAttribute
&& m.GetParameters().Length == 2
&& m.GetParameters()[0].ParameterType == typeof(IObjectFieldDescriptor));

private static readonly MethodInfo s_genericInterface = typeof(SortingObjectFieldDescriptorExtensions)
.GetMethods(BindingFlags.Public | BindingFlags.Static)
.Single(m => m.Name.Equals(
nameof(SortingObjectFieldDescriptorExtensions.UseSorting),
StringComparison.Ordinal)
&& m.GetGenericArguments().Length == 1
&& m.GetParameters().Length == 2
&& m.GetParameters()[0].ParameterType == typeof(IInterfaceFieldDescriptor));

public UseSortingAttribute(Type? sortingType = null, [CallerLineNumber] int order = 0)
{
Type = sortingType;
Expand All @@ -37,18 +50,35 @@ public UseSortingAttribute(Type? sortingType = null, [CallerLineNumber] int orde
/// <value>The name of the scope</value>
public string? Scope { get; set; }

protected override void OnConfigure(
protected internal override void TryConfigure(
IDescriptorContext context,
IObjectFieldDescriptor descriptor,
MemberInfo? member)
IDescriptor descriptor,
ICustomAttributeProvider? attributeProvider)
{
if (Type is null)
if (descriptor is IObjectFieldDescriptor objectFieldDescriptor)
{
descriptor.UseSorting(Scope);
if (Type is null)
{
objectFieldDescriptor.UseSorting(Scope);
}
else
{
s_genericObject.MakeGenericMethod(Type).Invoke(null, [objectFieldDescriptor, Scope]);
}
}
else

if (descriptor is IInterfaceFieldDescriptor interfaceFieldDescriptor)
{
s_generic.MakeGenericMethod(Type).Invoke(null, [descriptor, Scope]);
if (Type is null)
{
interfaceFieldDescriptor.UseSorting(Scope);
}
else
{
s_genericInterface.MakeGenericMethod(Type).Invoke(
null,
[interfaceFieldDescriptor, Scope]);
}
}
}
}
Expand Down
Loading
Loading