diff --git a/src/HotChocolate/Data/src/Data/Filters/Convention/FilterTypeInterceptor.cs b/src/HotChocolate/Data/src/Data/Filters/Convention/FilterTypeInterceptor.cs index e2b636284f5..55dc787a254 100644 --- a/src/HotChocolate/Data/src/Data/Filters/Convention/FilterTypeInterceptor.cs +++ b/src/HotChocolate/Data/src/Data/Filters/Convention/FilterTypeInterceptor.cs @@ -167,18 +167,33 @@ public static bool HasIdAttribute(this InputFieldConfiguration? definition) var attributes = member.GetCustomAttributesData(); foreach (var attribute in attributes) { - if (attribute.AttributeType == typeof(IDAttribute)) + if (IsIdAttribute(attribute.AttributeType)) { return true; } + } + + return false; - if (attribute.AttributeType.IsGenericType - && attribute.AttributeType.GetGenericTypeDefinition() == typeof(IDAttribute<>)) + static bool IsIdAttribute(Type? type) + { + while (type is not null) { - return true; + if (type == typeof(IDAttribute)) + { + return true; + } + + if (type.IsGenericType + && type.GetGenericTypeDefinition() == typeof(IDAttribute<>)) + { + return true; + } + + type = type.BaseType; } - } - return false; + return false; + } } } diff --git a/src/HotChocolate/Data/test/Data.Filters.Tests/IdFilterTypeInterceptorTests.cs b/src/HotChocolate/Data/test/Data.Filters.Tests/IdFilterTypeInterceptorTests.cs index b4dd7d78fdc..c0a0084f96d 100644 --- a/src/HotChocolate/Data/test/Data.Filters.Tests/IdFilterTypeInterceptorTests.cs +++ b/src/HotChocolate/Data/test/Data.Filters.Tests/IdFilterTypeInterceptorTests.cs @@ -48,6 +48,38 @@ public async Task Filtering_Should_InferType_When_AnnotatedGeneric() schema.MatchSnapshot(); } + [Fact] + public async Task Filtering_Should_InferType_When_AnnotatedWith_Derived_IDAttribute() + { + var schema = await new ServiceCollection() + .AddGraphQL() + .AddQueryType(x => x.Name("Query").Field("test").Resolve("a")) + .AddType(new FilterInputType()) + .AddFiltering() + .BuildSchemaAsync(); + + var filterType = Assert.IsAssignableFrom(schema.Types["FooIdDerivedFilterInput"]); + var fieldType = filterType.Fields["bar"].Type.NamedType(); + + Assert.Equal("IdOperationFilterInput", fieldType.Name); + } + + [Fact] + public async Task Filtering_Should_InferType_When_AnnotatedWith_Derived_Generic_IDAttribute() + { + var schema = await new ServiceCollection() + .AddGraphQL() + .AddQueryType(x => x.Name("Query").Field("test").Resolve("a")) + .AddType(new FilterInputType()) + .AddFiltering() + .BuildSchemaAsync(); + + var filterType = Assert.IsAssignableFrom(schema.Types["FooIdGenericDerivedFilterInput"]); + var fieldType = filterType.Fields["bar"].Type.NamedType(); + + Assert.Equal("IdOperationFilterInput", fieldType.Name); + } + public class Foo { public string? Bar { get; } @@ -64,4 +96,20 @@ public class FooIdGeneric [ID] public string? Bar { get; } } + + public class FooIdDerived + { + [InheritedId] + public string? Bar { get; } + } + + public class FooIdGenericDerived + { + [InheritedId] + public string? Bar { get; } + } + + public sealed class InheritedId(string? typeName = null) : IDAttribute(typeName); + + public sealed class InheritedId : IDAttribute; }