/// <summary> /// This is a shortcut of removing the FunctionSignature through 'CustomUriFunctions' class and /// unbinding the function name from it's MethodInfo through 'UriFunctionsBinder' class. /// See these classes documentations. /// </summary> /// <param name="functionName">The uri function name that appears in the OData request uri.</param> /// <param name="functionSignature">The new custom function signature.</param> /// <param name="methodInfo">The MethodInfo to bind the given function name.</param> /// <exception cref="Exception">Any exception thrown by 'CustomUriFunctions.RemoveCustomUriFunction' and 'UriFunctionsBinder.UnbindUriFunctionName' methods.</exception> /// <returns>'True' if the fucntion signature has successfully removed and unbinded. 'False' otherwise.</returns> public static bool RemoveCustomUriFunction(string functionName, FunctionSignatureWithReturnType functionSignature, MethodInfo methodInfo) { return CustomUriFunctions.RemoveCustomUriFunction(functionName, functionSignature) && UriFunctionsBinder.UnbindUriFunctionName(functionName, methodInfo); }
/// <summary> /// Add a custom uri function to extend or override the built-in OData protocol of uri functions. /// In case the function signature already exists as a built-in function, if requested (addAsOverloadToBuiltInFunction = true), the new function signature will be added as another overload. /// In case the function name already exists as a custom function, the signature will be added as an another overload. /// </summary> /// <param name="customFunctionName">The new custom function name</param> /// <param name="newCustomFunctionSignature">The new custom function signature</param> /// <param name="addAsOverloadToBuiltInFunction">If 'True', add as another overload to the existing built-in function in case signature already exists</param> /// <exception cref="ArgumentNullException">Arguments are null, or function signature return type is null</exception> /// <exception cref="ODataException">Throws if built-in function name already exists, and parameter 'addAsOverloadToBuiltInFunction' is not 'True'</exception> /// <exception cref="ODataException">Throws if built-in function signature overload already exists.</exception> /// <exception cref="ODataException">Throws if custom function signature overload already exists</exception> public static void AddCustomUriFunction(string customFunctionName, FunctionSignatureWithReturnType newCustomFunctionSignature, bool addAsOverloadToBuiltInFunction) { // Parameters validation ExceptionUtils.CheckArgumentStringNotNullOrEmpty(customFunctionName, "customFunctionName"); ExceptionUtils.CheckArgumentNotNull(newCustomFunctionSignature, "newCustomFunctionSignature"); ValidateFunctionWithReturnType(newCustomFunctionSignature); // Thread saftey - before using the custom functions dictionary lock (Locker) { // Check if the function does already exists in the Built-In functions // If 'addAsOverloadToBuiltInFunction' parameter is false - throw expection // Else, add as a custom function FunctionSignatureWithReturnType[] existingBuiltInFunctionOverload; if (BuiltInUriFunctions.TryGetBuiltInFunction(customFunctionName, out existingBuiltInFunctionOverload)) { // Built-In function with the same signature already exists, and will not be added as an another overload by user request. if (!addAsOverloadToBuiltInFunction) { throw new ODataException(Strings.CustomUriFunctions_AddCustomUriFunction_BuiltInExistsNotAddingAsOverload(customFunctionName)); } // Function name exists, check if full siganture exists among the overloads. if (existingBuiltInFunctionOverload.Any(builtInFunction => AreFunctionsSignatureEqual(newCustomFunctionSignature, builtInFunction))) { throw new ODataException(Strings.CustomUriFunctions_AddCustomUriFunction_BuiltInExistsFullSignature(customFunctionName)); } } AddCustomFunction(customFunctionName, newCustomFunctionSignature); } }
public void AddCustomFunction_FunctionNameCannotBeEmptyString() { FunctionSignatureWithReturnType customFunctionSignature = new FunctionSignatureWithReturnType(EdmCoreModel.Instance.GetBoolean(false), EdmCoreModel.Instance.GetInt32(false)); Action addCustomFunctionSignature = () => CustomUriFunctions.AddCustomUriFunction(string.Empty, customFunctionSignature); addCustomFunctionSignature.ShouldThrow<ArgumentNullException>(); }
/// <summary> /// Creates all of the spatial functions /// </summary> /// <param name="functions">Dictionary of functions to add to.</param> internal static void CreateSpatialFunctions(IDictionary <string, FunctionSignatureWithReturnType[]> functions) { // double geo.distance(geographyPoint, geographyPoint) // double geo.distance(geometryPoint, geometryPoint) FunctionSignatureWithReturnType[] signatures = new FunctionSignatureWithReturnType[] { new FunctionSignatureWithReturnType( EdmCoreModel.Instance.GetDouble(true), EdmCoreModel.Instance.GetSpatial(EdmPrimitiveTypeKind.GeographyPoint, true), EdmCoreModel.Instance.GetSpatial(EdmPrimitiveTypeKind.GeographyPoint, true)), new FunctionSignatureWithReturnType( EdmCoreModel.Instance.GetDouble(true), EdmCoreModel.Instance.GetSpatial(EdmPrimitiveTypeKind.GeometryPoint, true), EdmCoreModel.Instance.GetSpatial(EdmPrimitiveTypeKind.GeometryPoint, true)) }; functions.Add("geo.distance", signatures); // bool geo.intersects(geometry.Point, geometry.Polygon) // bool geo.intersects(geometry.Polygon, geomtery.Point) // bool geo.intersects(geography.Point, geography.Polygon) // bool geo.intersects(geography.Polygon, geography.Point) signatures = new FunctionSignatureWithReturnType[] { new FunctionSignatureWithReturnType( EdmCoreModel.Instance.GetBoolean(true), EdmCoreModel.Instance.GetSpatial(EdmPrimitiveTypeKind.GeometryPoint, true), EdmCoreModel.Instance.GetSpatial(EdmPrimitiveTypeKind.GeometryPolygon, true)), new FunctionSignatureWithReturnType( EdmCoreModel.Instance.GetBoolean(true), EdmCoreModel.Instance.GetSpatial(EdmPrimitiveTypeKind.GeometryPolygon, true), EdmCoreModel.Instance.GetSpatial(EdmPrimitiveTypeKind.GeometryPoint, true)), new FunctionSignatureWithReturnType( EdmCoreModel.Instance.GetBoolean(true), EdmCoreModel.Instance.GetSpatial(EdmPrimitiveTypeKind.GeographyPoint, true), EdmCoreModel.Instance.GetSpatial(EdmPrimitiveTypeKind.GeographyPolygon, true)), new FunctionSignatureWithReturnType( EdmCoreModel.Instance.GetBoolean(true), EdmCoreModel.Instance.GetSpatial(EdmPrimitiveTypeKind.GeographyPolygon, true), EdmCoreModel.Instance.GetSpatial(EdmPrimitiveTypeKind.GeographyPoint, true)) }; functions.Add("geo.intersects", signatures); // double geo.length(geometryLineString) // double geo.length(geographyLineString) signatures = new FunctionSignatureWithReturnType[] { new FunctionSignatureWithReturnType( EdmCoreModel.Instance.GetDouble(true), EdmCoreModel.Instance.GetSpatial(EdmPrimitiveTypeKind.GeometryLineString, true)), new FunctionSignatureWithReturnType( EdmCoreModel.Instance.GetDouble(true), EdmCoreModel.Instance.GetSpatial(EdmPrimitiveTypeKind.GeographyLineString, true)), }; functions.Add("geo.length", signatures); }
/// <summary> /// Creates all of the spatial functions /// </summary> /// <param name="functions">Dictionary of functions to add to.</param> internal static void CreateSpatialFunctions(IDictionary<string, FunctionSignatureWithReturnType[]> functions) { // double geo.distance(geographyPoint, geographyPoint) // double geo.distance(geometryPoint, geometryPoint) FunctionSignatureWithReturnType[] signatures = new FunctionSignatureWithReturnType[] { new FunctionSignatureWithReturnType( EdmCoreModel.Instance.GetDouble(true), EdmCoreModel.Instance.GetSpatial(EdmPrimitiveTypeKind.GeographyPoint, true), EdmCoreModel.Instance.GetSpatial(EdmPrimitiveTypeKind.GeographyPoint, true)), new FunctionSignatureWithReturnType( EdmCoreModel.Instance.GetDouble(true), EdmCoreModel.Instance.GetSpatial(EdmPrimitiveTypeKind.GeometryPoint, true), EdmCoreModel.Instance.GetSpatial(EdmPrimitiveTypeKind.GeometryPoint, true)) }; functions.Add("geo.distance", signatures); // bool geo.intersects(geometry.Point, geometry.Polygon) // bool geo.intersects(geometry.Polygon, geomtery.Point) // bool geo.intersects(geography.Point, geography.Polygon) // bool geo.intersects(geography.Polygon, geography.Point) signatures = new FunctionSignatureWithReturnType[] { new FunctionSignatureWithReturnType( EdmCoreModel.Instance.GetBoolean(true), EdmCoreModel.Instance.GetSpatial(EdmPrimitiveTypeKind.GeometryPoint, true), EdmCoreModel.Instance.GetSpatial(EdmPrimitiveTypeKind.GeometryPolygon, true)), new FunctionSignatureWithReturnType( EdmCoreModel.Instance.GetBoolean(true), EdmCoreModel.Instance.GetSpatial(EdmPrimitiveTypeKind.GeometryPolygon, true), EdmCoreModel.Instance.GetSpatial(EdmPrimitiveTypeKind.GeometryPoint, true)), new FunctionSignatureWithReturnType( EdmCoreModel.Instance.GetBoolean(true), EdmCoreModel.Instance.GetSpatial(EdmPrimitiveTypeKind.GeographyPoint, true), EdmCoreModel.Instance.GetSpatial(EdmPrimitiveTypeKind.GeographyPolygon, true)), new FunctionSignatureWithReturnType( EdmCoreModel.Instance.GetBoolean(true), EdmCoreModel.Instance.GetSpatial(EdmPrimitiveTypeKind.GeographyPolygon, true), EdmCoreModel.Instance.GetSpatial(EdmPrimitiveTypeKind.GeographyPoint, true)) }; functions.Add("geo.intersects", signatures); // double geo.length(geometryLineString) // double geo.length(geographyLineString) signatures = new FunctionSignatureWithReturnType[] { new FunctionSignatureWithReturnType( EdmCoreModel.Instance.GetDouble(true), EdmCoreModel.Instance.GetSpatial(EdmPrimitiveTypeKind.GeometryLineString, true)), new FunctionSignatureWithReturnType( EdmCoreModel.Instance.GetDouble(true), EdmCoreModel.Instance.GetSpatial(EdmPrimitiveTypeKind.GeographyLineString, true)), }; functions.Add("geo.length", signatures); }
public void AddCustomFunction_CannotAddFunctionSignatureWithNullReturnType() { FunctionSignatureWithReturnType customFunctionSignatureWithNullReturnType = new FunctionSignatureWithReturnType(null, EdmCoreModel.Instance.GetInt32(false)); Action addCustomFunctionSignature = () => CustomUriFunctions.AddCustomUriFunction("my.customFunctionWithNoReturnType", customFunctionSignatureWithNullReturnType); addCustomFunctionSignature.ShouldThrow<ArgumentNullException>(); }
/// <summary> /// Builds an array of signatures for date time functions. /// </summary> /// <returns>The array of signatures for a date time functions.</returns> private static FunctionSignatureWithReturnType[] CreateDateTimeFunctionSignatureArray() { FunctionSignatureWithReturnType dateTimeOffsetNonNullable = new FunctionSignatureWithReturnType( EdmCoreModel.Instance.GetInt32(false), EdmCoreModel.Instance.GetTemporal(EdmPrimitiveTypeKind.DateTimeOffset, false)); FunctionSignatureWithReturnType dateTimeOffsetNullable = new FunctionSignatureWithReturnType( EdmCoreModel.Instance.GetInt32(false), EdmCoreModel.Instance.GetTemporal(EdmPrimitiveTypeKind.DateTimeOffset, true)); return(new[] { dateTimeOffsetNonNullable, dateTimeOffsetNullable }); }
/// <summary> /// Builds an array of signatures for math functions. /// </summary> /// <returns>The array of signatures for math functions.</returns> private static FunctionSignatureWithReturnType[] CreateMathFunctionSignatureArray() { FunctionSignatureWithReturnType doubleSignature = new FunctionSignatureWithReturnType( EdmCoreModel.Instance.GetDouble(false), EdmCoreModel.Instance.GetDouble(false)); FunctionSignatureWithReturnType nullableDoubleSignature = new FunctionSignatureWithReturnType( EdmCoreModel.Instance.GetDouble(false), EdmCoreModel.Instance.GetDouble(true)); FunctionSignatureWithReturnType decimalSignature = new FunctionSignatureWithReturnType( EdmCoreModel.Instance.GetDecimal(false), EdmCoreModel.Instance.GetDecimal(false)); FunctionSignatureWithReturnType nullableDecimalSignature = new FunctionSignatureWithReturnType( EdmCoreModel.Instance.GetDecimal(false), EdmCoreModel.Instance.GetDecimal(true)); return(new FunctionSignatureWithReturnType[] { doubleSignature, decimalSignature, nullableDoubleSignature, nullableDecimalSignature }); }
/// <summary> /// This is a shortcut of adding the custom FunctionSignature through 'CustomUriFunctions' class and /// binding the function name to it's MethodInfo through 'UriFunctionsBinder' class. /// See these classes documentations. /// In case of an excpetion, both operations(adding the signature and binding the function) will be undone. /// </summary> /// <param name="functionName">The uri function name that appears in the OData request uri.</param> /// <param name="functionSignature">The new custom function signature.</param> /// <param name="methodInfo">The MethodInfo to bind the given function name.</param> /// <exception cref="Exception">Any exception thrown by 'CustomUriFunctions.AddCustomUriFunction' and 'UriFunctionBinder.BindUriFunctionName' methods.</exception> public static void AddCustomUriFunction(string functionName, FunctionSignatureWithReturnType functionSignature, MethodInfo methodInfo) { try { // Add to OData.Libs function signature CustomUriFunctions.AddCustomUriFunction(functionName, functionSignature); // Bind the method to it's MethoInfo UriFunctionsBinder.BindUriFunctionName(functionName, methodInfo); } catch { // Clear in case of excpetion RemoveCustomUriFunction(functionName, functionSignature, methodInfo); throw; } }
/// <summary> /// Removes the specific function overload from the custum uri functions. /// </summary> /// <param name="functionName">Custom function name to remove</param> /// <param name="functionSignature">The specific signature overload of the function to remove</param> /// <returns>'False' if custom function signature doesn't exist. 'True' if function has been removed successfully</returns> /// <exception cref="ArgumentNullException">Arguments are null, or function signature return type is null</exception> public static bool RemoveCustomUriFunction(string functionName, FunctionSignatureWithReturnType functionSignature) { ExceptionUtils.CheckArgumentStringNotNullOrEmpty(functionName, "customFunctionName"); ExceptionUtils.CheckArgumentNotNull(functionSignature, "customFunctionSignature"); ValidateFunctionWithReturnType(functionSignature); lock (Locker) { FunctionSignatureWithReturnType[] existingCustomFunctionOverloads; if (!CustomFunctions.TryGetValue(functionName, out existingCustomFunctionOverloads)) { return(false); } // Get all function sigature overloads without the overload which is requested to be removed FunctionSignatureWithReturnType[] customFunctionOverloadsWithoutTheOneToRemove = existingCustomFunctionOverloads.SkipWhile(funcOverload => AreFunctionsSignatureEqual(funcOverload, functionSignature)).ToArray(); // Nothing was removed - Requested overload doesn't exist if (customFunctionOverloadsWithoutTheOneToRemove.Length == existingCustomFunctionOverloads.Length) { return(false); } // No overloads have left in this function name. Delete the function name if (customFunctionOverloadsWithoutTheOneToRemove.Length == 0) { return(CustomFunctions.Remove(functionName)); } else { // Requested overload has been removed. // Update the custom functions to the overloads wihtout that one requested to be removed CustomFunctions[functionName] = customFunctionOverloadsWithoutTheOneToRemove; return(true); } } }
/// <summary> /// Removes the specific function overload from the custum uri functions. /// </summary> /// <param name="functionName">Custom function name to remove</param> /// <param name="functionSignature">The specific signature overload of the function to remove</param> /// <returns>'False' if custom function signature doesn't exist. 'True' if function has been removed successfully</returns> /// <exception cref="ArgumentNullException">Arguments are null, or function signature return type is null</exception> public static bool RemoveCustomUriFunction(string functionName, FunctionSignatureWithReturnType functionSignature) { ExceptionUtils.CheckArgumentStringNotNullOrEmpty(functionName, "customFunctionName"); ExceptionUtils.CheckArgumentNotNull(functionSignature, "customFunctionSignature"); ValidateFunctionWithReturnType(functionSignature); lock (Locker) { FunctionSignatureWithReturnType[] existingCustomFunctionOverloads; if (!CustomFunctions.TryGetValue(functionName, out existingCustomFunctionOverloads)) { return false; } // Get all function sigature overloads without the overload which is requested to be removed FunctionSignatureWithReturnType[] customFunctionOverloadsWithoutTheOneToRemove = existingCustomFunctionOverloads.SkipWhile(funcOverload => AreFunctionsSignatureEqual(funcOverload, functionSignature)).ToArray(); // Nothing was removed - Requested overload doesn't exist if (customFunctionOverloadsWithoutTheOneToRemove.Length == existingCustomFunctionOverloads.Length) { return false; } // No overloads have left in this function name. Delete the function name if (customFunctionOverloadsWithoutTheOneToRemove.Length == 0) { return CustomFunctions.Remove(functionName); } else { // Requested overload has been removed. // Update the custom functions to the overloads wihtout that one requested to be removed CustomFunctions[functionName] = customFunctionOverloadsWithoutTheOneToRemove; return true; } } }
public void RemoveCustomFunction_FunctionSignatureWithoutAReturnType() { FunctionSignatureWithReturnType existingCustomFunctionSignature = new FunctionSignatureWithReturnType(null, EdmCoreModel.Instance.GetBoolean(false)); // Test Action removeFunction = () => CustomUriFunctions.RemoveCustomUriFunction("FunctionName", existingCustomFunctionSignature); // Assert removeFunction.ShouldThrow<ArgumentNullException>(); }
/// <summary> /// Returns a list of signatures for a function name. /// </summary> /// <param name="name">The name of the function to look for.</param> /// <param name="signatures">The list of signatures available for the function name.</param> /// <returns>true if the function was found, or false otherwise.</returns> internal static bool TryGetCustomFunction(string name, out FunctionSignatureWithReturnType[] signatures) { Debug.Assert(name != null, "name != null"); lock (Locker) { return CustomFunctions.TryGetValue(name, out signatures); } }
public void AddCustomFunction_CustomFunctionDoesntExist_ShouldAdd_NoArgumnetsToFunctionSignature() { string customFunctionName = "my.NewCustomFunction"; try { // New not existing custom function - function without any argumnets var newCustomFunctionSignature = new FunctionSignatureWithReturnType(EdmCoreModel.Instance.GetDouble(false)); CustomUriFunctions.AddCustomUriFunction(customFunctionName, newCustomFunctionSignature); // Assert // Make sure both signatures exists FunctionSignatureWithReturnType[] customFunctionSignatures = GetCustomFunctionSignaturesOrNull(customFunctionName); customFunctionSignatures.Length.Should().Be(1); customFunctionSignatures[0].Should().BeSameAs(newCustomFunctionSignature); } finally { // Clean from CustomUriFunctions cache CustomUriFunctions.RemoveCustomUriFunction(customFunctionName); } }
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").Should().BeTrue(); } }
public void AddCustomFunction_CustomFunctionNameExistsButNotFullSignature_ShouldAddAsAnOverload() { string customFunctionName = "my.ExistingCustomFunction"; try { // Prepare FunctionSignatureWithReturnType existingCustomFunctionSignature = new FunctionSignatureWithReturnType(EdmCoreModel.Instance.GetDouble(false), EdmCoreModel.Instance.GetBoolean(false)); CustomUriFunctions.AddCustomUriFunction(customFunctionName, existingCustomFunctionSignature); //Test // Same name, but different signature var newCustomFunctionSignature = new FunctionSignatureWithReturnType(EdmCoreModel.Instance.GetDouble(false), EdmCoreModel.Instance.GetInt32(false), EdmCoreModel.Instance.GetBoolean(false)); CustomUriFunctions.AddCustomUriFunction(customFunctionName, newCustomFunctionSignature); // Assert // Make sure both signatures exists bool areSiganturesAdded = GetCustomFunctionSignaturesOrNull(customFunctionName). All(x => x.Equals(existingCustomFunctionSignature) || x.Equals(newCustomFunctionSignature)); areSiganturesAdded.Should().BeTrue(); } finally { // Clean both signatures from CustomUriFunctions cache CustomUriFunctions.RemoveCustomUriFunction(customFunctionName); } }
/// <summary> /// Builds an array of signatures for date time functions. /// </summary> /// <returns>The array of signatures for a date time functions.</returns> private static FunctionSignatureWithReturnType[] CreateDateTimeFunctionSignatureArray() { FunctionSignatureWithReturnType dateTimeOffsetNonNullable = new FunctionSignatureWithReturnType( EdmCoreModel.Instance.GetInt32(false), EdmCoreModel.Instance.GetTemporal(EdmPrimitiveTypeKind.DateTimeOffset, false)); FunctionSignatureWithReturnType dateTimeOffsetNullable = new FunctionSignatureWithReturnType( EdmCoreModel.Instance.GetInt32(false), EdmCoreModel.Instance.GetTemporal(EdmPrimitiveTypeKind.DateTimeOffset, true)); return new[] { dateTimeOffsetNonNullable, dateTimeOffsetNullable }; }
private static bool AreFunctionsSignatureEqual(FunctionSignatureWithReturnType functionOne, FunctionSignatureWithReturnType functionTwo) { Debug.Assert(functionOne != null, "functionOne != null"); Debug.Assert(functionTwo != null, "functionTwo != null"); // Check if ReturnTypes are equal if (!functionOne.ReturnType.IsEquivalentTo(functionTwo.ReturnType)) { return(false); } // Check the length of the Arguments of the two functions if (functionOne.ArgumentTypes.Length != functionTwo.ArgumentTypes.Length) { return(false); } // Check if the arguments are equal for (int argumentIndex = 0; argumentIndex < functionOne.ArgumentTypes.Length; argumentIndex++) { if (!functionOne.ArgumentTypes[argumentIndex].IsEquivalentTo(functionTwo.ArgumentTypes[argumentIndex])) { return(false); } } return(true); }
/// <summary> /// Check if FunctionSignatureWithReturnType is valid. /// Vaild if the signature has a ReturnType /// </summary> /// <param name="functionSignature">Function signature to validate</param> private static void ValidateFunctionWithReturnType(FunctionSignatureWithReturnType functionSignature) { if (functionSignature == null) { return; } ExceptionUtils.CheckArgumentNotNull(functionSignature.ReturnType, "functionSignatureWithReturnType must contain a return type"); }
/// <summary> /// Creates all string functions. /// </summary> /// <param name="functions">Dictionary of functions to add to.</param> private static void CreateStringFunctions(IDictionary <string, FunctionSignatureWithReturnType[]> functions) { FunctionSignatureWithReturnType signature; FunctionSignatureWithReturnType[] signatures; // bool endswith(string, string) signature = new FunctionSignatureWithReturnType( EdmCoreModel.Instance.GetBoolean(false), EdmCoreModel.Instance.GetString(true), EdmCoreModel.Instance.GetString(true)); functions.Add("endswith", new FunctionSignatureWithReturnType[] { signature }); // int indexof(string, string) signature = new FunctionSignatureWithReturnType( EdmCoreModel.Instance.GetInt32(false), EdmCoreModel.Instance.GetString(true), EdmCoreModel.Instance.GetString(true)); functions.Add("indexof", new FunctionSignatureWithReturnType[] { signature }); // string replace(string, string, string) signature = new FunctionSignatureWithReturnType( EdmCoreModel.Instance.GetString(true), EdmCoreModel.Instance.GetString(true), EdmCoreModel.Instance.GetString(true), EdmCoreModel.Instance.GetString(true)); functions.Add("replace", new FunctionSignatureWithReturnType[] { signature }); // bool startswith(string, string) signature = new FunctionSignatureWithReturnType( EdmCoreModel.Instance.GetBoolean(false), EdmCoreModel.Instance.GetString(true), EdmCoreModel.Instance.GetString(true)); functions.Add("startswith", new FunctionSignatureWithReturnType[] { signature }); // string tolower(string) signature = new FunctionSignatureWithReturnType( EdmCoreModel.Instance.GetString(true), EdmCoreModel.Instance.GetString(true)); functions.Add("tolower", new FunctionSignatureWithReturnType[] { signature }); // string toupper(string) signature = new FunctionSignatureWithReturnType( EdmCoreModel.Instance.GetString(true), EdmCoreModel.Instance.GetString(true)); functions.Add("toupper", new FunctionSignatureWithReturnType[] { signature }); // string trim(string) signature = new FunctionSignatureWithReturnType( EdmCoreModel.Instance.GetString(true), EdmCoreModel.Instance.GetString(true)); functions.Add("trim", new FunctionSignatureWithReturnType[] { signature }); signatures = new FunctionSignatureWithReturnType[] { // string substring(string, int) new FunctionSignatureWithReturnType( EdmCoreModel.Instance.GetString(true), EdmCoreModel.Instance.GetString(true), EdmCoreModel.Instance.GetInt32(false)), // string substring(string, int?) new FunctionSignatureWithReturnType( EdmCoreModel.Instance.GetString(true), EdmCoreModel.Instance.GetString(true), EdmCoreModel.Instance.GetInt32(true)), // string substring(string, int, int) new FunctionSignatureWithReturnType( EdmCoreModel.Instance.GetString(true), EdmCoreModel.Instance.GetString(true), EdmCoreModel.Instance.GetInt32(false), EdmCoreModel.Instance.GetInt32(false)), // string substring(string, int?, int) new FunctionSignatureWithReturnType( EdmCoreModel.Instance.GetString(true), EdmCoreModel.Instance.GetString(true), EdmCoreModel.Instance.GetInt32(true), EdmCoreModel.Instance.GetInt32(false)), // string substring(string, int, int?) new FunctionSignatureWithReturnType( EdmCoreModel.Instance.GetString(true), EdmCoreModel.Instance.GetString(true), EdmCoreModel.Instance.GetInt32(false), EdmCoreModel.Instance.GetInt32(true)), // string substring(string, int?, int?) new FunctionSignatureWithReturnType( EdmCoreModel.Instance.GetString(true), EdmCoreModel.Instance.GetString(true), EdmCoreModel.Instance.GetInt32(true), EdmCoreModel.Instance.GetInt32(true)), }; functions.Add("substring", signatures); // bool contains(string, string) signature = new FunctionSignatureWithReturnType( EdmCoreModel.Instance.GetBoolean(false), EdmCoreModel.Instance.GetString(true), EdmCoreModel.Instance.GetString(true)); functions.Add("contains", new FunctionSignatureWithReturnType[] { signature }); // string concat(string, string) signature = new FunctionSignatureWithReturnType( EdmCoreModel.Instance.GetString(true), EdmCoreModel.Instance.GetString(true), EdmCoreModel.Instance.GetString(true)); functions.Add("concat", new FunctionSignatureWithReturnType[] { signature }); // int length(string) signature = new FunctionSignatureWithReturnType( EdmCoreModel.Instance.GetInt32(false), EdmCoreModel.Instance.GetString(true)); functions.Add("length", new FunctionSignatureWithReturnType[] { signature }); }
public void RemoveCustomFunction_RemoveFunctionWithSameNameAndSignature() { string customFunctionName = "my.ExistingCustomFunction"; try { // Prepare FunctionSignatureWithReturnType existingCustomFunctionSignature = new FunctionSignatureWithReturnType(EdmCoreModel.Instance.GetDouble(false), EdmCoreModel.Instance.GetBoolean(false)); CustomUriFunctions.AddCustomUriFunction(customFunctionName, existingCustomFunctionSignature); GetCustomFunctionSignaturesOrNull(customFunctionName)[0].Equals(existingCustomFunctionSignature).Should().BeTrue(); // Test bool isRemoveSucceeded = CustomUriFunctions.RemoveCustomUriFunction(customFunctionName, existingCustomFunctionSignature); // Assert isRemoveSucceeded.Should().BeTrue(); GetCustomFunctionSignaturesOrNull(customFunctionName).Should().BeNull(); } finally { CustomUriFunctions.RemoveCustomUriFunction(customFunctionName); } }
/// <summary>Finds the best fitting function for the specified arguments.</summary> /// <param name="functions">Functions to consider.</param> /// <param name="argumentNodes">Nodes of the arguments for the function, can be new {null,null}.</param> /// <returns>The best fitting function; null if none found or ambiguous.</returns> internal static FunctionSignatureWithReturnType FindBestFunctionSignature(FunctionSignatureWithReturnType[] functions, SingleValueNode[] argumentNodes) { IEdmTypeReference[] argumentTypes = argumentNodes.Select(s => s.TypeReference).ToArray(); Debug.Assert(functions != null, "functions != null"); Debug.Assert(argumentTypes != null, "argumentTypes != null"); List<FunctionSignatureWithReturnType> applicableFunctions = new List<FunctionSignatureWithReturnType>(functions.Length); // Build a list of applicable functions (and cache their promoted arguments). foreach (FunctionSignatureWithReturnType candidate in functions) { if (candidate.ArgumentTypes.Length != argumentTypes.Length) { continue; } bool argumentsMatch = true; for (int i = 0; i < candidate.ArgumentTypes.Length; i++) { if (!CanPromoteNodeTo(argumentNodes[i], argumentTypes[i], candidate.ArgumentTypes[i])) { argumentsMatch = false; break; } } if (argumentsMatch) { applicableFunctions.Add(candidate); } } // Return the best applicable function. if (applicableFunctions.Count == 0) { // No matching function. return null; } else if (applicableFunctions.Count == 1) { return applicableFunctions[0]; } else { // Find a single function which is better than all others. int bestFunctionIndex = -1; for (int i = 0; i < applicableFunctions.Count; i++) { bool betterThanAllOthers = true; for (int j = 0; j < applicableFunctions.Count; j++) { if (i != j && MatchesArgumentTypesBetterThan(argumentTypes, applicableFunctions[j].ArgumentTypes, applicableFunctions[i].ArgumentTypes)) { betterThanAllOthers = false; break; } } if (betterThanAllOthers) { if (bestFunctionIndex == -1) { bestFunctionIndex = i; } else { // This means there were at least 2 equally matching functions. return null; } } } if (bestFunctionIndex == -1) { return null; } return applicableFunctions[bestFunctionIndex]; } }
public void AddCustomFunction_CannotAddFunctionWithNameAlreadyExistsAsBuildIsFunction_AddAsOverloadFalse_SameNameDifferentArguments() { FunctionSignatureWithReturnType customFunctionSignature = new FunctionSignatureWithReturnType(EdmCoreModel.Instance.GetDouble(false), EdmCoreModel.Instance.GetBoolean(false)); Action addExistingCustomFunctionSignature = () => CustomUriFunctions.AddCustomUriFunction(BUILT_IN_GEODISTANCE_FUNCTION_NAME, customFunctionSignature); addExistingCustomFunctionSignature.ShouldThrow<ODataException>(). WithMessage(Strings.CustomUriFunctions_AddCustomUriFunction_BuiltInExistsNotAddingAsOverload(BUILT_IN_GEODISTANCE_FUNCTION_NAME)); }
public void RemoveCustomFunction_RemoveFunctionWithSameNameAndSignature_OtherOverloadsExists() { string customFunctionName = "my.ExistingCustomFunction"; try { // Prepare FunctionSignatureWithReturnType existingCustomFunctionSignature = new FunctionSignatureWithReturnType(EdmCoreModel.Instance.GetDouble(false), EdmCoreModel.Instance.GetBoolean(false)); CustomUriFunctions.AddCustomUriFunction(customFunctionName, existingCustomFunctionSignature); FunctionSignatureWithReturnType existingCustomFunctionSignatureTwo = new FunctionSignatureWithReturnType(EdmCoreModel.Instance.GetBoolean(false), EdmCoreModel.Instance.GetDate(false)); CustomUriFunctions.AddCustomUriFunction(customFunctionName, existingCustomFunctionSignatureTwo); // Validate that the two overloads as GetCustomFunctionSignaturesOrNull(customFunctionName). All(funcSignature => funcSignature.Equals(existingCustomFunctionSignature) || funcSignature.Equals(existingCustomFunctionSignatureTwo)). Should().BeTrue(); // Remove the first overload, second overload should not be removed bool isRemoveSucceeded = CustomUriFunctions.RemoveCustomUriFunction(customFunctionName, existingCustomFunctionSignature); // Assert isRemoveSucceeded.Should().BeTrue(); FunctionSignatureWithReturnType[] overloads = GetCustomFunctionSignaturesOrNull(customFunctionName); overloads.Length.Should().Be(1); overloads[0].Should().Be(existingCustomFunctionSignatureTwo); } finally { // Clean up cache CustomUriFunctions.RemoveCustomUriFunction(customFunctionName); } }
private static void AddCustomFunction(string customFunctionName, FunctionSignatureWithReturnType newCustomFunctionSignature) { FunctionSignatureWithReturnType[] existingCustomFunctionOverloads; // In case the function doesn't already exist if (!CustomFunctions.TryGetValue(customFunctionName, out existingCustomFunctionOverloads)) { CustomFunctions.Add(customFunctionName, new FunctionSignatureWithReturnType[] { newCustomFunctionSignature }); } else { // Function does already exist as a custom function in cache // Check if the function overload doesn't already exist bool isOverloadAlreadyExist = existingCustomFunctionOverloads.Any(existingFunction => AreFunctionsSignatureEqual(existingFunction, newCustomFunctionSignature)); if (isOverloadAlreadyExist) { // Throw if already exists - User is stupid (inserted the same function twice) throw new ODataException(Strings.CustomUriFunctions_AddCustomUriFunction_CustomFunctionOverloadExists(customFunctionName)); } // Add the custom function as an overload to the same function name CustomFunctions[customFunctionName] = existingCustomFunctionOverloads.Concat(new FunctionSignatureWithReturnType[] { newCustomFunctionSignature }).ToArray(); } }
public void RemoveCustomFunction_CannotRemoveFunctionWithSameNameAndDifferentSignature() { string customFunctionName = "my.ExistingCustomFunction"; try { // Prepare FunctionSignatureWithReturnType existingCustomFunctionSignature = new FunctionSignatureWithReturnType(EdmCoreModel.Instance.GetDouble(false), EdmCoreModel.Instance.GetBoolean(false)); CustomUriFunctions.AddCustomUriFunction(customFunctionName, existingCustomFunctionSignature); GetCustomFunctionSignaturesOrNull(customFunctionName)[0].Equals(existingCustomFunctionSignature).Should().BeTrue(); // Function with different siganture FunctionSignatureWithReturnType customFunctionSignatureToRemove = new FunctionSignatureWithReturnType(EdmCoreModel.Instance.GetInt16(false), EdmCoreModel.Instance.GetBoolean(false)); // Test // Try Remove a function with the same name but different siganture bool isRemoveSucceeded = CustomUriFunctions.RemoveCustomUriFunction(customFunctionName, customFunctionSignatureToRemove); // Assert isRemoveSucceeded.Should().BeFalse(); } finally { // Clean up cahce CustomUriFunctions.RemoveCustomUriFunction(customFunctionName); } }
private static bool AreFunctionsSignatureEqual(FunctionSignatureWithReturnType functionOne, FunctionSignatureWithReturnType functionTwo) { Debug.Assert(functionOne != null, "functionOne != null"); Debug.Assert(functionTwo != null, "functionTwo != null"); // Check if ReturnTypes are equal if (!functionOne.ReturnType.IsEquivalentTo(functionTwo.ReturnType)) { return false; } // Check the length of the Arguments of the two functions if (functionOne.ArgumentTypes.Length != functionTwo.ArgumentTypes.Length) { return false; } // Check if the arguments are equal for (int argumentIndex = 0; argumentIndex < functionOne.ArgumentTypes.Length; argumentIndex++) { if (!functionOne.ArgumentTypes[argumentIndex].IsEquivalentTo(functionTwo.ArgumentTypes[argumentIndex])) { return false; } } return true; }
public void GetUriFunction_CombineCustomFunctionsAndBuiltInFunctions() { const string BUILT_IN_GEODISTANCE_FUNCTION_NAME = "geo.distance"; try { FunctionSignatureWithReturnType customFunctionSignature = new FunctionSignatureWithReturnType(EdmCoreModel.Instance.GetDouble(false), EdmCoreModel.Instance.GetBoolean(false)); // Add with 'addAsOverload' 'true' CustomUriFunctions.AddCustomUriFunction(BUILT_IN_GEODISTANCE_FUNCTION_NAME, customFunctionSignature, true); FunctionSignatureWithReturnType[] resultUriFunctionSignatures = FunctionCallBinder.GetUriFunctionSignatures(BUILT_IN_GEODISTANCE_FUNCTION_NAME); // Assert FunctionSignatureWithReturnType[] existsBuiltInSignature; BuiltInUriFunctions.TryGetBuiltInFunction(BUILT_IN_GEODISTANCE_FUNCTION_NAME, out existsBuiltInSignature).Should().BeTrue(); resultUriFunctionSignatures.Should().NotBeNull(); resultUriFunctionSignatures.Length.Should().Be(existsBuiltInSignature.Length + 1); resultUriFunctionSignatures.All(x => x == customFunctionSignature || existsBuiltInSignature.Any(y => x == y)).Should().BeTrue(); } finally { // Clean from CustomFunctions cache CustomUriFunctions.RemoveCustomUriFunction(BUILT_IN_GEODISTANCE_FUNCTION_NAME); } }
/// <summary> /// Add a custom uri function to extend uri functions. /// In case the function name already exists as a custom function, the signature will be added as an another overload. /// </summary> /// <param name="customFunctionName">The new custom function name</param> /// <param name="newCustomFunctionSignature">The new custom function signature</param> /// <exception cref="ArgumentNullException">Arguments are null, or function signature return type is null</exception> /// <exception cref="ODataException">Throws if built-in function name already exists.</exception> /// <exception cref="ODataException">Throws if built-in function signature overload already exists.</exception> /// <exception cref="ODataException">Throws if custom function signature overload already exists</exception> public static void AddCustomUriFunction(string customFunctionName, FunctionSignatureWithReturnType newCustomFunctionSignature) { AddCustomUriFunction(customFunctionName, newCustomFunctionSignature, false); }
public void GetUriFunction_OnlyCustomFunctionsExist() { const string CUSTOM_FUNCTION_NAME = "myCustomFunction"; try { FunctionSignatureWithReturnType customFunctionSignature = new FunctionSignatureWithReturnType(EdmCoreModel.Instance.GetDouble(false), EdmCoreModel.Instance.GetBoolean(false)); // Add with override 'true' CustomUriFunctions.AddCustomUriFunction(CUSTOM_FUNCTION_NAME, customFunctionSignature); FunctionSignatureWithReturnType[] resultUriFunctionSignatures = FunctionCallBinder.GetUriFunctionSignatures(CUSTOM_FUNCTION_NAME); // Assert resultUriFunctionSignatures.Should().NotBeNull(); resultUriFunctionSignatures.Length.Should().Be(1); resultUriFunctionSignatures.All(x => x == customFunctionSignature).Should().BeTrue(); } finally { // Clean from CustomFunctions cache CustomUriFunctions.RemoveCustomUriFunction(CUSTOM_FUNCTION_NAME); } }
/// <summary> /// Creates all string functions. /// </summary> /// <param name="functions">Dictionary of functions to add to.</param> private static void CreateStringFunctions(IDictionary<string, FunctionSignatureWithReturnType[]> functions) { FunctionSignatureWithReturnType signature; FunctionSignatureWithReturnType[] signatures; // bool endswith(string, string) signature = new FunctionSignatureWithReturnType( EdmCoreModel.Instance.GetBoolean(false), EdmCoreModel.Instance.GetString(true), EdmCoreModel.Instance.GetString(true)); functions.Add("endswith", new FunctionSignatureWithReturnType[] { signature }); // int indexof(string, string) signature = new FunctionSignatureWithReturnType( EdmCoreModel.Instance.GetInt32(false), EdmCoreModel.Instance.GetString(true), EdmCoreModel.Instance.GetString(true)); functions.Add("indexof", new FunctionSignatureWithReturnType[] { signature }); // string replace(string, string, string) signature = new FunctionSignatureWithReturnType( EdmCoreModel.Instance.GetString(true), EdmCoreModel.Instance.GetString(true), EdmCoreModel.Instance.GetString(true), EdmCoreModel.Instance.GetString(true)); functions.Add("replace", new FunctionSignatureWithReturnType[] { signature }); // bool startswith(string, string) signature = new FunctionSignatureWithReturnType( EdmCoreModel.Instance.GetBoolean(false), EdmCoreModel.Instance.GetString(true), EdmCoreModel.Instance.GetString(true)); functions.Add("startswith", new FunctionSignatureWithReturnType[] { signature }); // string tolower(string) signature = new FunctionSignatureWithReturnType( EdmCoreModel.Instance.GetString(true), EdmCoreModel.Instance.GetString(true)); functions.Add("tolower", new FunctionSignatureWithReturnType[] { signature }); // string toupper(string) signature = new FunctionSignatureWithReturnType( EdmCoreModel.Instance.GetString(true), EdmCoreModel.Instance.GetString(true)); functions.Add("toupper", new FunctionSignatureWithReturnType[] { signature }); // string trim(string) signature = new FunctionSignatureWithReturnType( EdmCoreModel.Instance.GetString(true), EdmCoreModel.Instance.GetString(true)); functions.Add("trim", new FunctionSignatureWithReturnType[] { signature }); signatures = new FunctionSignatureWithReturnType[] { // string substring(string, int) new FunctionSignatureWithReturnType( EdmCoreModel.Instance.GetString(true), EdmCoreModel.Instance.GetString(true), EdmCoreModel.Instance.GetInt32(false)), // string substring(string, int?) new FunctionSignatureWithReturnType( EdmCoreModel.Instance.GetString(true), EdmCoreModel.Instance.GetString(true), EdmCoreModel.Instance.GetInt32(true)), // string substring(string, int, int) new FunctionSignatureWithReturnType( EdmCoreModel.Instance.GetString(true), EdmCoreModel.Instance.GetString(true), EdmCoreModel.Instance.GetInt32(false), EdmCoreModel.Instance.GetInt32(false)), // string substring(string, int?, int) new FunctionSignatureWithReturnType( EdmCoreModel.Instance.GetString(true), EdmCoreModel.Instance.GetString(true), EdmCoreModel.Instance.GetInt32(true), EdmCoreModel.Instance.GetInt32(false)), // string substring(string, int, int?) new FunctionSignatureWithReturnType( EdmCoreModel.Instance.GetString(true), EdmCoreModel.Instance.GetString(true), EdmCoreModel.Instance.GetInt32(false), EdmCoreModel.Instance.GetInt32(true)), // string substring(string, int?, int?) new FunctionSignatureWithReturnType( EdmCoreModel.Instance.GetString(true), EdmCoreModel.Instance.GetString(true), EdmCoreModel.Instance.GetInt32(true), EdmCoreModel.Instance.GetInt32(true)), }; functions.Add("substring", signatures); // bool contains(string, string) signature = new FunctionSignatureWithReturnType( EdmCoreModel.Instance.GetBoolean(false), EdmCoreModel.Instance.GetString(true), EdmCoreModel.Instance.GetString(true)); functions.Add("contains", new FunctionSignatureWithReturnType[] { signature }); // string concat(string, string) signature = new FunctionSignatureWithReturnType( EdmCoreModel.Instance.GetString(true), EdmCoreModel.Instance.GetString(true), EdmCoreModel.Instance.GetString(true)); functions.Add("concat", new FunctionSignatureWithReturnType[] { signature }); // int length(string) signature = new FunctionSignatureWithReturnType( EdmCoreModel.Instance.GetInt32(false), EdmCoreModel.Instance.GetString(true)); functions.Add("length", new FunctionSignatureWithReturnType[] { signature }); }
private static void AssertSignatureTypesMatchArguments(FunctionSignatureWithReturnType signature, List<QueryNode> nodes) { for (int i = 0; i < signature.ArgumentTypes.Length; ++i) { signature.ArgumentTypes[i].Definition.Should().Be(MetadataBindingUtils.GetEdmType(nodes[i])); } }
/// <summary> /// Returns a list of signatures for a function name. /// </summary> /// <param name="name">The name of the function to look for.</param> /// <param name="signatures">The list of signatures available for the function name.</param> /// <returns>true if the function was found, or false otherwise.</returns> internal static bool TryGetBuiltInFunction(string name, out FunctionSignatureWithReturnType[] signatures) { Debug.Assert(name != null, "name != null"); return builtInFunctions.TryGetValue(name, out signatures); }
public void RemoveCustomFunction_CannotRemoveFunctionWhichDoesntExist_ByNameAndSignature() { string customFunctionName = "my.ExistingCustomFunction"; FunctionSignatureWithReturnType customFunctionSignature = new FunctionSignatureWithReturnType(EdmCoreModel.Instance.GetDouble(false), EdmCoreModel.Instance.GetBoolean(false)); // Test bool isRemoveSucceeded = CustomUriFunctions.RemoveCustomUriFunction(customFunctionName, customFunctionSignature); // Assert isRemoveSucceeded.Should().BeFalse(); }
/// <summary> /// Builds an array of signatures for math functions. /// </summary> /// <returns>The array of signatures for math functions.</returns> private static FunctionSignatureWithReturnType[] CreateMathFunctionSignatureArray() { FunctionSignatureWithReturnType doubleSignature = new FunctionSignatureWithReturnType( EdmCoreModel.Instance.GetDouble(false), EdmCoreModel.Instance.GetDouble(false)); FunctionSignatureWithReturnType nullableDoubleSignature = new FunctionSignatureWithReturnType( EdmCoreModel.Instance.GetDouble(false), EdmCoreModel.Instance.GetDouble(true)); FunctionSignatureWithReturnType decimalSignature = new FunctionSignatureWithReturnType( EdmCoreModel.Instance.GetDecimal(false), EdmCoreModel.Instance.GetDecimal(false)); FunctionSignatureWithReturnType nullableDecimalSignature = new FunctionSignatureWithReturnType( EdmCoreModel.Instance.GetDecimal(false), EdmCoreModel.Instance.GetDecimal(true)); return new FunctionSignatureWithReturnType[] { doubleSignature, decimalSignature, nullableDoubleSignature, nullableDecimalSignature }; }
public void ParseWithCustomUriFunction_AddAsOverloadToBuiltIn() { FunctionSignatureWithReturnType customStartWithFunctionSignature = new FunctionSignatureWithReturnType(EdmCoreModel.Instance.GetBoolean(true), EdmCoreModel.Instance.GetString(true), EdmCoreModel.Instance.GetInt32(true)); try { // Add with override 'true' CustomUriFunctions.AddCustomUriFunction("startswith", customStartWithFunctionSignature, true); var fullUri = new Uri("http://www.odata.com/OData/People" + "?$filter=startswith(Name, 66)"); ODataUriParser parser = new ODataUriParser(HardCodedTestModel.TestModel, new Uri("http://www.odata.com/OData/"), fullUri); var startsWithArgs = parser.ParseFilter().Expression.ShouldBeSingleValueFunctionCallQueryNode("startswith").And.Parameters.ToList(); startsWithArgs[0].ShouldBeSingleValuePropertyAccessQueryNode(HardCodedTestModel.GetPersonNameProp()); startsWithArgs[1].ShouldBeConstantQueryNode(66); } finally { CustomUriFunctions.RemoveCustomUriFunction("startswith").Should().BeTrue(); } }