diff --git a/src/Microsoft.OData.Core/UriParser/Binders/FunctionCallBinder.cs b/src/Microsoft.OData.Core/UriParser/Binders/FunctionCallBinder.cs index 49cf0da4ab..de4ff7da72 100644 --- a/src/Microsoft.OData.Core/UriParser/Binders/FunctionCallBinder.cs +++ b/src/Microsoft.OData.Core/UriParser/Binders/FunctionCallBinder.cs @@ -100,7 +100,7 @@ internal static SingleValueNode[] ValidateArgumentsAreSingleValue(string functio /// The nodes of the arguments, can be new {null,null}. /// The signatures to match against /// Returns the matching signature or throws - internal static FunctionSignatureWithReturnType MatchSignatureToBuiltInFunction(string functionName, SingleValueNode[] argumentNodes, FunctionSignatureWithReturnType[] signatures) + internal static FunctionSignatureWithReturnType MatchSignatureToUriFunction(string functionName, SingleValueNode[] argumentNodes, FunctionSignatureWithReturnType[] signatures) { FunctionSignatureWithReturnType signature; IEdmTypeReference[] argumentTypes = argumentNodes.Select(s => s.TypeReference).ToArray(); @@ -202,7 +202,7 @@ internal QueryNode BindFunctionCall(FunctionCallToken functionCallToken) // If there isn't, bind as built-in function // Bind all arguments List argumentNodes = new List(functionCallToken.Arguments.Select(ar => this.bindMethod(ar))); - return BindAsBuiltInFunction(functionCallToken, argumentNodes); + return BindAsUriFunction(functionCallToken, argumentNodes); } /// @@ -250,7 +250,7 @@ internal bool TryBindDottedIdentifierAsFunctionCall(DottedIdentifierToken dotted /// the function call token to bind /// list of semantically bound arguments /// A function call node bound to this function. - private QueryNode BindAsBuiltInFunction(FunctionCallToken functionCallToken, List argumentNodes) + private QueryNode BindAsUriFunction(FunctionCallToken functionCallToken, List argumentNodes) { if (functionCallToken.Source != null) { @@ -270,7 +270,7 @@ private QueryNode BindAsBuiltInFunction(FunctionCallToken functionCallToken, Lis // Do some validation and get potential built-in functions that could match what we saw FunctionSignatureWithReturnType[] signatures = GetUriFunctionSignatures(functionCallTokenName); SingleValueNode[] argumentNodeArray = ValidateArgumentsAreSingleValue(functionCallTokenName, argumentNodes); - FunctionSignatureWithReturnType signature = MatchSignatureToBuiltInFunction(functionCallTokenName, argumentNodeArray, signatures); + FunctionSignatureWithReturnType signature = MatchSignatureToUriFunction(functionCallTokenName, argumentNodeArray, signatures); if (signature.ReturnType != null) { TypePromoteArguments(signature, argumentNodes); diff --git a/test/FunctionalTests/Microsoft.OData.Core.Tests/ScenarioTests/UriParser/CustomUriFunctionsTests.cs b/test/FunctionalTests/Microsoft.OData.Core.Tests/ScenarioTests/UriParser/CustomUriFunctionsTests.cs index 050e6ad28a..db42186c75 100644 --- a/test/FunctionalTests/Microsoft.OData.Core.Tests/ScenarioTests/UriParser/CustomUriFunctionsTests.cs +++ b/test/FunctionalTests/Microsoft.OData.Core.Tests/ScenarioTests/UriParser/CustomUriFunctionsTests.cs @@ -9,6 +9,7 @@ using System.Linq; using System.Text; using System.Threading.Tasks; +using Microsoft.OData.Core.Tests.UriParser; namespace Microsoft.OData.Core.Tests.ScenarioTests.UriParser { @@ -513,6 +514,34 @@ public void RemoveCustomFunction_RemoveFunctionWithSameNameAndSignature_OtherOve #endregion + #region ODataUriParser + + [Fact] + public void ParseWithCustomUriFunction() + { + try + { + FunctionSignatureWithReturnType myStringFunction + = new FunctionSignatureWithReturnType(EdmCoreModel.Instance.GetBoolean(true), EdmCoreModel.Instance.GetString(true), EdmCoreModel.Instance.GetString(true)); + + // Add a custom uri function + CustomUriFunctions.AddCustomUriFunction("mystringfunction", myStringFunction); + + var fullUri = new Uri("http://www.odata.com/OData/People" + "?$filter=mystringfunction(Name, 'BlaBla')"); + ODataUriParser parser = new ODataUriParser(HardCodedTestModel.TestModel, new Uri("http://www.odata.com/OData/"), fullUri); + + var startsWithArgs = parser.ParseFilter().Expression.ShouldBeSingleValueFunctionCallQueryNode("mystringfunction").And.Parameters.ToList(); + startsWithArgs[0].ShouldBeSingleValuePropertyAccessQueryNode(HardCodedTestModel.GetPersonNameProp()); + startsWithArgs[1].ShouldBeConstantQueryNode("BlaBla"); + } + finally + { + CustomUriFunctions.RemoveCustomUriFunction("mystringfunction"); + } + } + + #endregion + #region Private Methods private FunctionSignatureWithReturnType[] GetCustomFunctionSignaturesOrNull(string customFunctionName) diff --git a/test/FunctionalTests/Microsoft.OData.Core.Tests/UriParser/Binders/FunctionCallBinderTests.cs b/test/FunctionalTests/Microsoft.OData.Core.Tests/UriParser/Binders/FunctionCallBinderTests.cs index 0f111af705..4c5db49a57 100644 --- a/test/FunctionalTests/Microsoft.OData.Core.Tests/UriParser/Binders/FunctionCallBinderTests.cs +++ b/test/FunctionalTests/Microsoft.OData.Core.Tests/UriParser/Binders/FunctionCallBinderTests.cs @@ -296,7 +296,7 @@ public void MatchArgumentsToSignatureDuplicateSignature() }; var signatures = this.GetDuplicateIndexOfFunctionSignatureForTest(); - Action bind = () => FunctionCallBinder.MatchSignatureToBuiltInFunction( + Action bind = () => FunctionCallBinder.MatchSignatureToUriFunction( "IndexOf", new SingleValueNode[] { new SingleValuePropertyAccessNode(new ConstantNode(null)/*parent*/, new EdmStructuralProperty(new EdmEntityType("MyNamespace", "MyEntityType"), "myPropertyName", argumentNodes[0].GetEdmTypeReference())), @@ -318,7 +318,7 @@ public void MatchArgumentsToSignature() }; var signatures = this.GetHardCodedYearFunctionSignatureForTest(); - var result = FunctionCallBinder.MatchSignatureToBuiltInFunction( + var result = FunctionCallBinder.MatchSignatureToUriFunction( "year", argumentNodes.Select(s => (SingleValueNode)s).ToArray(), signatures); @@ -336,7 +336,7 @@ public void MatchArgumentsToSignatureNoMatchEmpty() new ConstantNode(4) }; - Action bind = () => FunctionCallBinder.MatchSignatureToBuiltInFunction( + Action bind = () => FunctionCallBinder.MatchSignatureToUriFunction( "year", new SingleValueNode[] { new SingleValuePropertyAccessNode(new ConstantNode(null)/*parent*/, new EdmStructuralProperty(new EdmEntityType("MyNamespace", "MyEntityType"), "myPropertyName", argumentNodes[0].GetEdmTypeReference()))}, @@ -356,7 +356,7 @@ public void MatchArgumentsToSignatureNoMatchContainsSignatures() new ConstantNode(4) }; - Action bind = () => FunctionCallBinder.MatchSignatureToBuiltInFunction( + Action bind = () => FunctionCallBinder.MatchSignatureToUriFunction( "year", new SingleValueNode[] { new SingleValuePropertyAccessNode(new ConstantNode(null)/*parent*/, new EdmStructuralProperty(new EdmEntityType("MyNamespace", "MyEntityType"), "myPropertyName", argumentNodes[0].GetEdmTypeReference()))}, @@ -370,7 +370,7 @@ public void MatchArgumentsToSignatureNoMatchContainsSignatures() [Fact] public void MatchArgumentsToSignatureWillPickRightSignatureForSomeNullArgumentTypes() { - var result = FunctionCallBinder.MatchSignatureToBuiltInFunction( + var result = FunctionCallBinder.MatchSignatureToUriFunction( "substring", new SingleValueNode[] { new SingleValuePropertyAccessNode(new ConstantNode(null)/*parent*/, new EdmStructuralProperty(new EdmEntityType("MyNamespace", "MyEntityType"), "myPropertyName", EdmCoreModel.Instance.GetString(true))),