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.19k stars 739 forks source link

Error in variable coercion when using custom filter in query #7024

Open Mephistofeles opened 6 months ago

Mephistofeles commented 6 months ago

Product

Hot Chocolate

Version

13.9.0

Link to minimal reproduction

https://github.com/Mephistofeles/HotChocolateReproduction

Steps to reproduce

I've included minimal reproduction. When I run query like:

query {
  machines(where: { locks: { any: true } }) {
    id
  }
}

It runs just fine, but when I create a variable for where, like:

query ($filter: MachineFilterInput) {
  machines(where: $filter) {
    id
  }
}

and use it with variables:

{
  "filter": {
    "locks": {
      "any": true
    }
  }
}

I'm getting error HC0016: Variable filter got an invalid value. which when I debug probably comes from trying to convert "locks" to IEnumerable in HotChocolate.Utilities.DictionaryToObjectConverter.VisitObject (in call to Activator.CreateInstance(context.ClrType)) which failes, because of course IEnumerable is an interface and results in "System.MissingMethodException: 'Cannot create an instance of an interface.'"

What is expected?

Query should run the same whether I use variables or not

What is actually happening?

Query fails when I use variable for a filter input

Relevant log output

No response

Additional context

No response

michaelstaib commented 6 months ago

@PascalSenn is this the JSON update issue?

IharYakimush commented 2 months ago

Workaround:

  1. Create a class with a default constructor that implements the IQueryable<T> interface. Implementation is not needed.
    
    using System.Collections;
    using System.Linq.Expressions;

namespace HotChocolateReproduction;

public class QueryWorkaround : IQueryable { public IEnumerator GetEnumerator() { throw new NotImplementedException(); }

IEnumerator IEnumerable.GetEnumerator()
{
    throw new NotImplementedException();
}

pragma warning disable CA1065 // Do not raise exceptions in unexpected locations

public Type ElementType => throw new NotImplementedException();

public Expression Expression => throw new NotImplementedException();

public IQueryProvider Provider => throw new NotImplementedException();

pragma warning restore CA1065 // Do not raise exceptions in unexpected locations

}


2. Configure runtime type 

descriptor.Field(x => x.Locks.Select(y => y.Lock)).Name("locks").ToDefinition().RuntimeType = typeof(QueryWorkaround);