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

Fix type casting exceptions in 'isof' and 'cast' calls. #3117

Open
wants to merge 6 commits into
base: main
Choose a base branch
from

Conversation

WanjohiSammy
Copy link
Contributor

Issues

This pull request fixes #1744.

Description

When using unquoted type parameters in isof and cast, the operations perform as expected provided that the source type can be cast to the target type. Issues arise when casting is not possible, resulting in the following exception:

Encountered invalid type cast. '{source type}' is not assignable from '{target type}'.

Lets say you have the following data model:

namespace NS;

public class Product
{
    public int ProductID { get; set; }
    // Others properties
    public Address SupplierAddress { get; set; }
}

public class DerivedProduct : Product
{
   public string AnotherProperty { get; set; }
    // Others properties
}

public class Address
{
    // Others properties
    public string City { get; set; }
}

Executing the query isof(NS.DerivedCategory) will throw the exception:

"Encountered invalid type cast. 'NS.Category' is not assignable from 'NS.Product'."

This occurs because ODL checks if NS.Product is related to NS.Category using the CheckRelatedTo function and since the types are not related or one is not a derivative of the other, the exception is thrown.

Main changes

According to the spec_cast and spec_isof specifications, there is no indication that an exception should be thrown if casting fails. This pull request introduces the TryBindDottedIdentifierForIsOfOrCastFunctionCall method, which handles the binding of DottedIdentifierToken specifically for the isof and cast function calls without performing the CheckRelatedTo validation, thereby preventing exceptions when type casting is not possible.

Checklist (Uncheck if it is not completed)

  • Test cases added
  • Build and test with one-click build and test script passed

Additional work necessary

If documentation update is needed, please add "Docs Needed" label to the issue and provide details about the required document change in the issue.

xuzhg
xuzhg previously approved these changes Nov 12, 2024
@@ -234,7 +234,22 @@ internal QueryNode BindFunctionCall(FunctionCallToken functionCallToken)

// If there isn't, bind as Uri function
// Bind all arguments
List<QueryNode> argumentNodes = new List<QueryNode>(functionCallToken.Arguments.Select(ar => this.bindMethod(ar)));
List<QueryNode> argumentNodes = new List<QueryNode>(functionCallToken.Arguments.Select(argument =>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It may be better to call functionCallToken.Arguments.Select(...).ToList() than new List(...). If Arguments has a known collection size, then using ToList() could use an optimized path that avoids resizing. See:
dotnet/runtime#107560

[InlineData("cast(MyAddress,Fully.Qualified.Namespace.Employee)/WorkID eq 345")]
[InlineData("cast(null,Fully.Qualified.Namespace.Employee)/WorkID eq 345")]
[InlineData("cast('',Fully.Qualified.Namespace.Employee)/WorkID eq 345")]
public void CastFunctionWithUnquotedTypeParameter_WithIncorrectType_DoesNotThrowException(string filterQuery)
Copy link
Contributor

@habbes habbes Nov 13, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the expected behaviour of cast() when the types are incorrect? If it doesn't throw an exception, what will happen? How is this scenario expected to be handled? How will a library like AspNetCore know that the cast is not possible? And would this be a breaking change?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is what is happening currently with cast with quoted type parameter

For cast with unquoted type parameter

[InlineData("cast(MyAddress,Fully.Qualified.Namespace.Employee)/WorkID eq 345")]
[InlineData("cast(null,Fully.Qualified.Namespace.Employee)/WorkID eq 345")]
[InlineData("cast('',Fully.Qualified.Namespace.Employee)/WorkID eq 345")]
public void CastFunctionWithUnquotedTypeParameter_WithIncorrectType_DoesNotThrowException(string filterQuery)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this behaviour consistent with how cast is handled when the type param is quoted?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[InlineData("isof(MyAddress,Fully.Qualified.Namespace.Pet1)")]
[InlineData("isof(null,Fully.Qualified.Namespace.Person)")]
[InlineData("isof('',Fully.Qualified.Namespace.Person)")]
public void IsOfFunctionsWithUnquotedTypeParameter_WithIncorrectType_DoesNotThrowException(string filterQuery)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this behaviour consistent with how isof is handled when the type param is quoted?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same applied to isof as discussed in #3117 (comment), however, the method in AspNetCore that is responsible to create LINQ is different. Here is the method Expression BindIsOf(SingleValueFunctionCallNode node, QueryBinderContext context). I will also update this method to allow cast to SingleResourceCastNode as it currently only support cast to ConstantNode

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

Successfully merging this pull request may close these issues.

Isof type parameter quotes
3 participants