/// <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, geometry.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> /// 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> /// Promotes types of arguments to match signature if possible. /// </summary> /// <param name="signature">The signature to match the types to.</param> /// <param name="argumentNodes">The types to promote.</param> internal static void TypePromoteArguments(FunctionSignatureWithReturnType signature, List <QueryNode> argumentNodes) { // Convert all argument nodes to the best signature argument type Debug.Assert(signature.ArgumentTypes.Length == argumentNodes.Count, "The best signature match doesn't have the same number of arguments."); for (int i = 0; i < argumentNodes.Count; i++) { Debug.Assert(argumentNodes[i] is SingleValueNode, "We should have already verified that all arguments are single values."); SingleValueNode argumentNode = (SingleValueNode)argumentNodes[i]; IEdmTypeReference signatureArgumentType = signature.ArgumentTypes[i]; Debug.Assert(signatureArgumentType.IsODataPrimitiveTypeKind() || signatureArgumentType.IsODataEnumTypeKind(), "Only primitive or enum types should be able to get here."); argumentNodes[i] = MetadataBindingUtils.ConvertToTypeIfNeeded(argumentNode, signatureArgumentType); } }
/// <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> /// Bind this function call token as a Uri function /// </summary> /// <param name="functionCallToken">the function call token to bind</param> /// <param name="argumentNodes">list of semantically bound arguments</param> /// <returns>A function call node bound to this function.</returns> private QueryNode BindAsUriFunction(FunctionCallToken functionCallToken, List <QueryNode> argumentNodes) { if (functionCallToken.Source != null) { // the parent must be null for a Uri function. throw new ODataException(ODataErrorStrings.FunctionCallBinder_UriFunctionMustHaveHaveNullParent(functionCallToken.Name)); } // There are some functions (IsOf and Cast for example) that don't necessarily need to be bound to a function signature, // for these, we just Bind them directly to a SingleValueFunctionCallNode string matchedFunctionCallTokenName = IsUnboundFunction(functionCallToken.Name); if (matchedFunctionCallTokenName != null) { return(CreateUnboundFunctionNode(matchedFunctionCallTokenName, argumentNodes)); } // Do some validation and get potential Uri functions that could match what we saw IList <KeyValuePair <string, FunctionSignatureWithReturnType> > nameSignatures = GetUriFunctionSignatures(functionCallToken.Name, this.state.Configuration.EnableCaseInsensitiveUriFunctionIdentifier); SingleValueNode[] argumentNodeArray = ValidateArgumentsAreSingleValue(functionCallToken.Name, argumentNodes); KeyValuePair <string, FunctionSignatureWithReturnType> nameSignature = MatchSignatureToUriFunction(functionCallToken.Name, argumentNodeArray, nameSignatures); Debug.Assert(nameSignature.Key != null, "nameSignature.Key != null"); string canonicalName = nameSignature.Key; FunctionSignatureWithReturnType signature = nameSignature.Value; if (signature.ReturnType != null) { TypePromoteArguments(signature, argumentNodes); } if (signature.ReturnType != null && signature.ReturnType.IsStructured()) { return(new SingleResourceFunctionCallNode(canonicalName, new ReadOnlyCollection <QueryNode>(argumentNodes), signature.ReturnType.AsStructured(), null)); } return(new SingleValueFunctionCallNode(canonicalName, new ReadOnlyCollection <QueryNode>(argumentNodes), signature.ReturnType)); }
/// <summary> /// Finds the signature that best matches the arguments /// </summary> /// <param name="functionName">The name of the function</param> /// <param name="argumentNodes">The nodes of the arguments, can be new {null,null}.</param> /// <param name="signatures">The signatures to match against</param> /// <returns>Returns the matching signature or throws</returns> internal static FunctionSignatureWithReturnType MatchSignatureToUriFunction(string functionName, SingleValueNode[] argumentNodes, FunctionSignatureWithReturnType[] signatures) { FunctionSignatureWithReturnType signature; IEdmTypeReference[] argumentTypes = argumentNodes.Select(s => s.TypeReference).ToArray(); // Handle the cases where we don't have type information (null literal, open properties) for ANY of the arguments int argumentCount = argumentTypes.Length; if (argumentTypes.All(a => a == null) && argumentCount > 0) { // we specifically want to find just the first function that matches the number of arguments, we don't care about // ambiguity here because we're already in an ambiguous case where we don't know what kind of types // those arguments are. signature = signatures.FirstOrDefault(candidateFunction => candidateFunction.ArgumentTypes.Count() == argumentCount); if (signature == null) { throw new ODataException(ODataErrorStrings.FunctionCallBinder_CannotFindASuitableOverload(functionName, argumentTypes.Count())); } else { // in this case we can't assert the return type, we can only assert that a function exists... so // we need to set the return type to null. signature = new FunctionSignatureWithReturnType(null, signature.ArgumentTypes); } } else { signature = TypePromotionUtils.FindBestFunctionSignature(signatures, argumentNodes); if (signature == null) { throw new ODataException(ODataErrorStrings.MetadataBinder_NoApplicableFunctionFound( functionName, UriFunctionsHelper.BuildFunctionSignatureListDescription(functionName, signatures))); } } return(signature); }
/// <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> /// 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 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); }