Skip to content
Draft
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 @@ -297,9 +297,29 @@ protected bool TryCreateFilterType(
return true;
}

// try to match open generic types if runtime type is a generic type
if (runtimeType.Source is { IsGenericType: true, IsGenericTypeDefinition: false })
{
var genericTypeDefinition = runtimeType.Source.GetGenericTypeDefinition();
if (_bindings.TryGetValue(genericTypeDefinition, out var genericFilterType))
{
// if the filter type is a generic type definition, make it concrete
if (genericFilterType.IsGenericTypeDefinition)
{
var typeArguments = runtimeType.Source.GetGenericArguments();
type = genericFilterType.MakeGenericType(typeArguments);
return true;
}

// use the non-generic filter type directly
type = genericFilterType;
return true;
}
}

if (runtimeType.IsArrayOrList)
{
if (runtimeType.ElementType is { }
if (runtimeType.ElementType is not null
&& TryCreateFilterType(runtimeType.ElementType, out var elementType))
{
type = typeof(ListFilterInputType<>).MakeGenericType(elementType);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ public void FilterConvention_Should_Work_When_ConfigurationIsComplete()
var value = Utf8GraphQLParser.Syntax.ParseValueLiteral("{ bar: { eq:\"a\" }}");
var type = new FooFilterInput();

//act
// act
CreateSchemaWith(type, convention);
var executor = new ExecutorBuilder(type);

Expand Down Expand Up @@ -87,7 +87,7 @@ public void FilterConvention_Should_Fail_When_FieldHandlerIsNotRegistered()

var type = new FooFilterInput();

//act
// act
var error = Assert.Throws<SchemaException>(() => CreateSchemaWith(type, convention));

// assert
Expand All @@ -96,7 +96,7 @@ public void FilterConvention_Should_Fail_When_FieldHandlerIsNotRegistered()
}

[Fact]
public void FilterConvention_Should_Fail_When_OperationsInUknown()
public void FilterConvention_Should_Fail_When_OperationsInUnknown()
{
// arrange
var provider = new QueryableFilterProvider(
Expand All @@ -115,7 +115,7 @@ public void FilterConvention_Should_Fail_When_OperationsInUknown()

var type = new FooFilterInput();

//act
// act
var error = Assert.Throws<SchemaException>(() => CreateSchemaWith(type, convention));

// assert
Expand Down Expand Up @@ -144,7 +144,7 @@ public void FilterConvention_Should_Fail_When_OperationsIsNotNamed()

var type = new FooFilterInput();

//act
// act
Assert.Throws<SchemaException>(() => CreateSchemaWith(type, convention));
}

Expand All @@ -161,7 +161,7 @@ public void FilterConvention_Should_Fail_When_NoProviderWasRegistered()

var type = new FooFilterInput();

//act
// act
var error = Assert.Throws<SchemaException>(() => CreateSchemaWith(type, convention));

Assert.Single(error.Errors);
Expand All @@ -188,7 +188,7 @@ public void FilterConvention_Should_Fail_When_NoMatchingBindingWasFound()

var type = new FooFilterInput();

//act
// act
var error = Assert.Throws<SchemaException>(() => CreateSchemaWith(type, convention));

// assert
Expand All @@ -208,7 +208,7 @@ public void FilterConvention_Should_Work_With_Extensions()
});

var convention = new FilterConvention(
descriptor =>
_ =>
{
});

Expand All @@ -225,7 +225,7 @@ public void FilterConvention_Should_Work_With_Extensions()
var value = Utf8GraphQLParser.Syntax.ParseValueLiteral("{ bar: { eq:\"a\" }}");
var type = new FooFilterInput();

//act
// act
CreateSchemaWith(type, convention, extension1, extension2);
var executor = new ExecutorBuilder(type);

Expand Down Expand Up @@ -260,7 +260,7 @@ public void FilterConvention_Should_Work_With_ExtensionsType()
var value = Utf8GraphQLParser.Syntax.ParseValueLiteral("{ bar: { eq:\"a\" }}");
var type = new FooFilterInput();

//act
// act
CreateSchemaWithTypes(
type,
convention,
Expand Down Expand Up @@ -301,7 +301,7 @@ public void FilterConvention_Should_Work_With_ProviderExtensionsType()
var value = Utf8GraphQLParser.Syntax.ParseValueLiteral("{ bar: { eq:\"a\" }}");
var type = new FooFilterInput();

//act
// act
CreateSchemaWith(type, convention, extension1);
var executor = new ExecutorBuilder(type);

Expand Down Expand Up @@ -334,7 +334,7 @@ public async Task FilterConvention_Should_UseBoundFilterType()
.AddQueryType(
x => x.Name("Query").Field("foos").UseFiltering().Resolve(new List<Foo>()));

//act
// act
var schema = await builder.BuildSchemaAsync();

// assert
Expand Down Expand Up @@ -379,7 +379,7 @@ public async Task FilterConvention_Should_NotAddAnd()
.AddQueryType(
x => x.Name("Query").Field("foos").UseFiltering().Resolve(new List<Foo>()));

//act
// act
var schema = await builder.BuildSchemaAsync();

// assert
Expand All @@ -404,7 +404,32 @@ public async Task FilterConvention_Should_NotAddOr()
.AddQueryType(
x => x.Name("Query").Field("foos").UseFiltering().Resolve(new List<Foo>()));

//act
// act
var schema = await builder.BuildSchemaAsync();

// assert
schema.MatchSnapshot();
}

[Fact]
public async Task FilterConvention_Should_Support_OpenGeneric_RuntimeType_Binding()
{
// arrange
var convention = new FilterConvention(
descriptor =>
{
descriptor.AddDefaults();
descriptor.BindRuntimeType(typeof(GenericFoo<>), typeof(GenericFooOperationFilterInput));
});

var builder = new ServiceCollection()
.AddGraphQL()
.AddConvention<IFilterConvention>(convention)
.AddFiltering()
.AddQueryType(
x => x.Name("Query").Field("foos").UseFiltering().Resolve(new List<UsingGenericFoo>()));

// act
var schema = await builder.BuildSchemaAsync();

// assert
Expand Down Expand Up @@ -461,8 +486,7 @@ protected Schema CreateSchemaWith(

public class MockFilterProviderExtensionConvention : QueryableFilterProviderExtension
{
protected override void Configure(
IFilterProviderDescriptor<QueryableFilterContext> descriptor)
protected override void Configure(IFilterProviderDescriptor<QueryableFilterContext> descriptor)
{
descriptor.AddFieldHandler<QueryableStringEqualsHandler>();
}
Expand All @@ -485,8 +509,7 @@ protected override void Configure(IFilterInputTypeDescriptor descriptor)
}
}

public class FailingCombinator
: FilterOperationCombinator<FilterVisitorContext<string>, string>
public class FailingCombinator : FilterOperationCombinator<FilterVisitorContext<string>, string>
{
public override bool TryCombineOperations(
FilterVisitorContext<string> context,
Expand All @@ -503,16 +526,33 @@ public class Foo
public string Bar { get; set; } = null!;
}

public class FooFilterInput
: FilterInputType<Foo>
public class GenericFoo<T>
{
protected override void Configure(
IFilterInputTypeDescriptor<Foo> descriptor)
public string Bar { get; set; } = null!;
}

public class UsingGenericFoo
{
public GenericFoo<Foo> Bar { get; set; } = null!;
}

public class FooFilterInput : FilterInputType<Foo>
{
protected override void Configure(IFilterInputTypeDescriptor<Foo> descriptor)
{
descriptor.Field(t => t.Bar);
descriptor.AllowAnd(false).AllowOr(false);
}
}

public class CustomFooFilterInput : FilterInputType<Foo>;

public class GenericFooOperationFilterInput : StringOperationFilterInputType
{
protected override void Configure(IFilterInputTypeDescriptor descriptor)
{
descriptor.Operation(DefaultFilterOperations.Equals).Type<StringType>();
descriptor.AllowAnd(false).AllowOr(false);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
schema {
query: Query
}

type GenericFooOfFoo {
bar: String!
}

type Query {
foos(where: UsingGenericFooFilterInput): [UsingGenericFoo]
}

type UsingGenericFoo {
bar: GenericFooOfFoo!
}

input GenericFooOperationFilterInput {
eq: String
}

input UsingGenericFooFilterInput {
and: [UsingGenericFooFilterInput!]
or: [UsingGenericFooFilterInput!]
bar: GenericFooOperationFilterInput
}