Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Error occurs when you check whether a string literal is in an enum collection #2371

Closed
habbes opened this issue Apr 5, 2022 · 0 comments · Fixed by #3023
Closed

Error occurs when you check whether a string literal is in an enum collection #2371

habbes opened this issue Apr 5, 2022 · 0 comments · Fixed by #3023
Assignees
Labels

Comments

@habbes
Copy link
Contributor

habbes commented Apr 5, 2022

Related to OData/AspNetCoreOData#536

The in operator does not allow you to use a string literal as an operand when comparing against a collection of enums.
For example, let's assume WorkingDays property is a collection of enums, the following would fail with an error:

$filter='Monday' in WorkingDays

For it to work, you have to use the fully qualified enum literal:

$filter=ODataRoutingSample.Models.WorkingDay'Monday' in WorkingDays

However, binary operators like eq do allow comparisons between string literals and enums, so the following does work:

$filter=WorkingDays/any(t:t eq 'Monday')

I think both approaches should work. According to the spec:

  Enumeration literals in OData 4.0 required prefixing with the qualified type name of the enumeration.

  In OData 4.01, services MUST support duration and enumeration literals with or without the type prefix.
  OData clients that want to operate across OData 4.0 and OData 4.01 services should always include the prefix for duration and enumeration types.

Assemblies affected

Microsoft.OData.Core 7.10.0

Reproduce steps

Create a service that exposes an entity set with a property that contains a collection of enums, e.g.: WorkingDays that contains enum values: WorkingDay.Monday, WorkingDay.Tueday, etc.

Make a query against the service with the filter expression: $filter='Monday' in WorkingDays.

See this related issue for a more detailed repro example.

Expected result

The request should return the expected filtered data, same to what you would get with: $filter=WorkingDays/any(t:t eq 'Monday')

Actual result

The following error is thrown:

System.ArgumentException: An instance of InNode can only be created where the item types of the right operand 'ODataRoutingSample.Models.WorkingDay' and the left operand 'Edm.String' can be compared.

Additional detail

For binary operators, the BinaryOperatorBinder promotes the operands to compatible types, specifically, strings are promoted to enums where applicable:

internal QueryNode BindBinaryOperator(BinaryOperatorToken binaryOperatorToken)
{
    ExceptionUtils.CheckArgumentNotNull(binaryOperatorToken, "binaryOperatorToken");

    SingleValueNode left = this.GetOperandFromToken(binaryOperatorToken.OperatorKind, binaryOperatorToken.Left);
    SingleValueNode right = this.GetOperandFromToken(binaryOperatorToken.OperatorKind, binaryOperatorToken.Right);

    IEdmTypeReference typeReference;
    this.resolver.PromoteBinaryOperandTypes(binaryOperatorToken.OperatorKind, ref left, ref right, out typeReference);

    return new BinaryOperatorNode(binaryOperatorToken.OperatorKind, left, right, typeReference);
}

The InBinder does not promote types. The InNode throws an exception if the type of one operand is not assignable to the other.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
3 participants