graphql-platform icon indicating copy to clipboard operation
graphql-platform copied to clipboard

Error in variable coercion when using custom filter in query

Open Mephistofeles opened this issue 10 months ago • 2 comments

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<LockType> 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

Mephistofeles avatar Mar 27 '24 14:03 Mephistofeles

@PascalSenn is this the JSON update issue?

michaelstaib avatar Mar 28 '24 07:03 michaelstaib

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<T> : IQueryable<T>
{
    public IEnumerator<T> 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
}
  1. Configure runtime type
descriptor.Field(x => x.Locks.Select(y => y.Lock)).Name("locks").ToDefinition().RuntimeType = typeof(QueryWorkaround<LockType>);

IharYakimush avatar Jul 08 '24 11:07 IharYakimush