/// <summary> /// Write the function call token as URI part to this builder. /// </summary> /// <param name="functionQueryToken">To write as URI part.</param> protected virtual void WriteFunctionCall(FunctionCallQueryToken functionQueryToken) { ExceptionUtils.CheckArgumentNotNull(functionQueryToken, "functionQueryToken"); this.builder.Append(functionQueryToken.Name); this.builder.Append(ExpressionConstants.SymbolOpenParen); bool needComma = false; foreach (QueryToken parameter in functionQueryToken.Arguments) { if (needComma) { this.builder.Append(ExpressionConstants.SymbolComma); } else { needComma = true; } this.WriteQuery(parameter); } this.builder.Append(ExpressionConstants.SymbolClosedParen); }
/// <summary> /// Binds a function call token. /// </summary> /// <param name="functionCallToken">The function call token to bind.</param> /// <returns>The bound function call token.</returns> protected virtual QueryNode BindFunctionCall(FunctionCallQueryToken functionCallToken) { ExceptionUtils.CheckArgumentNotNull(functionCallToken, "functionCallToken"); ExceptionUtils.CheckArgumentNotNull(functionCallToken.Name, "functionCallToken.Name"); // Bind all arguments List<QueryNode> argumentNodes = new List<QueryNode>(functionCallToken.Arguments.Select(ar => this.Bind(ar))); // Special case the operators which look like function calls if (functionCallToken.Name == "cast") { // TODO: Implement cast operators throw new NotImplementedException(); } else if (functionCallToken.Name == "isof") { // TODO: Implement cast operators throw new NotImplementedException(); } else { // Try to find the function in our built-in functions BuiltInFunctionSignature[] signatures; if (!BuiltInFunctions.TryGetBuiltInFunction(functionCallToken.Name, out signatures)) { throw new ODataException(Strings.MetadataBinder_UnknownFunction(functionCallToken.Name)); } // Right now all functions take a single value for all arguments IEdmTypeReference[] argumentTypes = new IEdmTypeReference[argumentNodes.Count]; for (int i = 0; i < argumentNodes.Count; i++) { SingleValueQueryNode argumentNode = argumentNodes[i] as SingleValueQueryNode; if (argumentNode == null) { throw new ODataException(Strings.MetadataBinder_FunctionArgumentNotSingleValue(functionCallToken.Name)); } argumentTypes[i] = argumentNode.TypeReference; } BuiltInFunctionSignature signature = (BuiltInFunctionSignature) TypePromotionUtils.FindBestFunctionSignature(signatures, argumentTypes); if (signature == null) { throw new ODataException(Strings.MetadataBinder_NoApplicableFunctionFound( functionCallToken.Name, BuiltInFunctions.BuildFunctionSignatureListDescription(functionCallToken.Name, signatures))); } // 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 SingleValueQueryNode, "We should have already verified that all arguments are single values."); SingleValueQueryNode argumentNode = (SingleValueQueryNode)argumentNodes[i]; IEdmTypeReference signatureArgumentType = signature.ArgumentTypes[i]; if (signatureArgumentType != argumentNode.TypeReference) { argumentNodes[i] = ConvertToType(argumentNode, signatureArgumentType); } } return new SingleValueFunctionCallQueryNode { Name = functionCallToken.Name, Arguments = new ReadOnlyCollection<QueryNode>(argumentNodes), ReturnType = signature.ReturnType }; } }