/// <summary> /// Finds all signatures for the given function name. /// Search in both BuiltIn uri functions and Custom uri functions. /// Combine and return the signatures overloads of the results. /// </summary> /// <param name="functionName">The function to get the signatures for.</param> /// <returns>The signatures which match the supplied function name.</returns> internal static FunctionSignatureWithReturnType[] GetUriFunctionSignatures(string functionName) { FunctionSignatureWithReturnType[] customUriFunctionsSignatures = null; FunctionSignatureWithReturnType[] builtInUriFunctionsSignatures = null; // Try to find the function in the user custom functions and in our built-in functions bool customFound = CustomUriFunctions.TryGetCustomFunction(functionName, out customUriFunctionsSignatures); bool builtInFound = BuiltInUriFunctions.TryGetBuiltInFunction(functionName, out builtInUriFunctionsSignatures); if (!customFound && !builtInFound) { // Not found in both built-in and custom. throw new ODataException(ODataErrorStrings.MetadataBinder_UnknownFunction(functionName)); } if (!customFound) { Debug.Assert(builtInUriFunctionsSignatures != null, "No Built-in functions found"); return(builtInUriFunctionsSignatures); } if (!builtInFound) { Debug.Assert(customUriFunctionsSignatures != null, "No Custom functions found"); return(customUriFunctionsSignatures); } return(builtInUriFunctionsSignatures.Concat(customUriFunctionsSignatures).ToArray()); }
/// <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="functionName">The new custom function name</param> /// <param name="functionSignature">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 functionName, FunctionSignatureWithReturnType functionSignature) { // Parameters validation ExceptionUtils.CheckArgumentStringNotNullOrEmpty(functionName, "customFunctionName"); ExceptionUtils.CheckArgumentNotNull(functionSignature, "newCustomFunctionSignature"); ValidateFunctionWithReturnType(functionSignature); // 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(functionName, out existingBuiltInFunctionOverload)) { // Function name exists, check if full signature exists among the overloads. if (existingBuiltInFunctionOverload.Any(builtInFunction => AreFunctionsSignatureEqual(functionSignature, builtInFunction))) { throw new ODataException(Strings.CustomUriFunctions_AddCustomUriFunction_BuiltInExistsFullSignature(functionName)); } } AddCustomFunction(functionName, functionSignature); } }
internal static IList <KeyValuePair <string, FunctionSignatureWithReturnType> > GetUriFunctionSignatures(string functionCallToken, bool enableCaseInsensitive = false) { IList <KeyValuePair <string, FunctionSignatureWithReturnType> > customUriFunctionsNameSignatures = null; FunctionSignatureWithReturnType[] builtInUriFunctionsSignatures = null; IList <KeyValuePair <string, FunctionSignatureWithReturnType> > builtInUriFunctionsNameSignatures = null; // Try to find the function in the user custom functions bool customFound = CustomUriFunctions.TryGetCustomFunction(functionCallToken, out customUriFunctionsNameSignatures, enableCaseInsensitive); // And find in our built-in functions // Since list of all built-in functions is a fixed list and is initialized with names in lower case, // such as "endswith", "geo.distance", "maxdatetime" and "round", // => For case-insensitive searching, it is more efficient to convert the search key to lower case first // and then do a case-sensitive match. string nameKey = enableCaseInsensitive ? functionCallToken.ToLowerInvariant() : functionCallToken; bool builtInFound = BuiltInUriFunctions.TryGetBuiltInFunction(nameKey, out builtInUriFunctionsSignatures); // Populate the matched names found for built-in function if (builtInFound) { builtInUriFunctionsNameSignatures = builtInUriFunctionsSignatures.Select(sig => new KeyValuePair <string, FunctionSignatureWithReturnType>(nameKey, sig)).ToList(); } if (!customFound && !builtInFound) { // Not found in both built-in and custom. throw new ODataException(ODataErrorStrings.MetadataBinder_UnknownFunction(functionCallToken)); } if (!customFound) { Debug.Assert(builtInUriFunctionsNameSignatures != null, "No Built-in functions found"); return(builtInUriFunctionsNameSignatures); } if (!builtInFound) { Debug.Assert(customUriFunctionsNameSignatures != null, "No Custom functions found"); return(customUriFunctionsNameSignatures); } return(builtInUriFunctionsNameSignatures.Concat(customUriFunctionsNameSignatures).ToArray()); }