ChilliCream / graphql-platform

Welcome to the home of the Hot Chocolate GraphQL server for .NET, the Strawberry Shake GraphQL client for .NET and Banana Cake Pop the awesome Monaco based GraphQL IDE.
https://chillicream.com
MIT License
5.25k stars 744 forks source link

Custom Filtering is not working for null values #4822

Open Sangeetha-Murugesan opened 2 years ago

Sangeetha-Murugesan commented 2 years ago

Is there an existing issue for this?

Describe the bug

I was trying to implement case insensitive filtering and found this example on your documentation.

It is working fine if the resultant field has values. If the resultant field has value as null,it throws Object Reference error.

In my case, api return an array of data(shiptoCust) in which some might have value and some might be null. while applyig filter to this field,I am getting object reference not set to an instance.

query Query {
    getpartSaleOrder{
      data(skip:0,take:5,where: {shiptoCust:{eq:"4001"}}) {
            shiptoCust
      }
    }
  }

Steps to reproduce

 public class CustomConvention : FilterConvention
        {
            protected override void Configure(IFilterConventionDescriptor descriptor)
            {
                descriptor.AddDefaults();
                descriptor.Provider(
                    new QueryableFilterProvider(
                        x => x
                            .AddDefaultFieldHandlers().AddFieldHandler<QueryableStringInvariantContainsHandler>()
                            .AddFieldHandler< QueryableStringInvariantEqualsHandler>()));
            }
        }

 public class QueryableStringInvariantEqualsHandler : QueryableStringOperationHandler
        {

            public QueryableStringInvariantEqualsHandler(InputParser inputParser) : base(inputParser){ }

            private static readonly MethodInfo _toLower = typeof(string).GetMethods().Single(
                 x => x.Name == nameof(string.ToLower) && x.GetParameters().Length == 0);

            protected override int Operation => DefaultFilterOperations.Equals;

            public override Expression HandleOperation(QueryableFilterContext context, IFilterOperationField field, IValueNode value, object? parsedValue)
            {

                Expression property = context.GetInstance();

                if (parsedValue != null && parsedValue is string str)
                {

                    return Expression.Equal(
                        Expression.Call(property, _toLower),
                        Expression.Constant(str.ToLower()));
                }

                throw new InvalidOperationException();

            }

        }

In Configure Method:

services.AddGraphQLServer(component)
                   .AddFiltering<CustomConvention>()
                   .AddConvention<IFilterConvention>(new FilterConventionExtension(
                        x => x.AddProviderExtension(new QueryableFilterProviderExtension(
                        y => y.AddFieldHandler<QueryableStringInvariantEqualsHandler>().AddFieldHandler<QueryableStringInvariantContainsHandler>())
                   )));

Relevant log output

No response

Additional Context?

No response

Product

Hot Chocolate

Version

12.6.1

PascalSenn commented 2 years ago

I guess something like this should work

 public class QueryableStringInvariantEqualsHandler : QueryableStringOperationHandler
        {

            public QueryableStringInvariantEqualsHandler(InputParser inputParser) : base(inputParser){ }

            private static readonly MethodInfo _toLower = typeof(string).GetMethods().Single(
                 x => x.Name == nameof(string.ToLower) && x.GetParameters().Length == 0);

            protected override int Operation => DefaultFilterOperations.Equals;

            public override Expression HandleOperation(QueryableFilterContext context, IFilterOperationField field, IValueNode value, object? parsedValue)
            {

                Expression property = context.GetInstance();
                if ( parsedValue is null)
                { 
                    return Expression.Equal(property, Expression.Constant(null));
                }

                if ( parsedValue is string str)
                {

                    return Expression.Equal(
                        Expression.Call(property, _toLower),
                        Expression.Constant(str.ToLower()));
                }

                throw new InvalidOperationException();

            }

        }
Sangeetha-Murugesan commented 2 years ago

@PascalSenn , adding the null condition in QueryableStringInvariantEqualsHandler class also not works,getting the same error

PS: I am getting object reference error in this line await next.Invoke(context); in useField Middleware.

PascalSenn commented 2 years ago

@Sangeetha-Murugesan can you push a reproduction into a simple example project?

Sangeetha-Murugesan commented 2 years ago

@PascalSenn , Source code is available in Source Code - Custom Filtering

Sangeetha-Murugesan commented 2 years ago

@PascalSenn any update on this issue?

PascalSenn commented 2 years ago

@Sangeetha-Murugesan I do not know what should not work in your example project

PascalSenn commented 2 years ago

can you provide an example query or something similar?

Sangeetha-Murugesan commented 2 years ago

PFB. Sample query to simulate the issue. On query execution, you will get object reference error because in response,one of the field value for which I have applied filter is null. If the response doesnt have any null value,it works fine. you can refer the sample response data in source file.

{ getpartSaleOrderInquiry{ data{ items{ partDetails(where:{mrstatusArr:{eq:"Pend"}}){ items{ mrstatusArr } } saleOrderNo saleOrderStatus } } } }

Sangeetha-Murugesan commented 2 years ago

@PascalSenn @tobias-tengler , any update on this?

lucas-garrido commented 1 year ago

https://github.com/ChilliCream/hotchocolate/issues/4822#issuecomment-1061826600

this worked for me