/// <summary> /// Bind a parameter alias which is inside another alias value. /// </summary> /// <param name="bindingState">The alias name which is inside another alias value.</param> /// <param name="aliasToken">The cache of alias value nodes</param> /// <returns>The semantics node tree for alias (the @p1 in "@p1=...", not alias value expression)</returns> internal ParameterAliasNode BindParameterAlias(BindingState bindingState, FunctionParameterAliasToken aliasToken) { ExceptionUtils.CheckArgumentNotNull(bindingState, "bindingState"); ExceptionUtils.CheckArgumentNotNull(aliasToken, "aliasToken"); string alias = aliasToken.Alias; ParameterAliasValueAccessor aliasValueAccessor = bindingState.Configuration.ParameterAliasValueAccessor; if (aliasValueAccessor == null) { return(new ParameterAliasNode(alias, null)); } // in cache? SingleValueNode aliasValueNode = null; if (!aliasValueAccessor.ParameterAliasValueNodesCached.TryGetValue(alias, out aliasValueNode)) { // has value expression? string aliasValueExpression = aliasValueAccessor.GetAliasValueExpression(alias); if (aliasValueExpression == null) { aliasValueAccessor.ParameterAliasValueNodesCached[alias] = null; } else { aliasValueNode = this.ParseAndBindParameterAliasValueExpression(bindingState, aliasValueExpression, aliasToken.ExpectedParameterType); aliasValueAccessor.ParameterAliasValueNodesCached[alias] = aliasValueNode; } } return(new ParameterAliasNode(alias, aliasValueNode.GetEdmTypeReference())); }
/// <summary> /// Parses parameter alias into token. /// </summary> /// <param name="lexer">The lexer to use.</param> /// <returns>The parameter alias token.</returns> private static FunctionParameterAliasToken ParseParameterAlias(ExpressionLexer lexer) { Debug.Assert(lexer != null, "lexer != null"); FunctionParameterAliasToken ret = new FunctionParameterAliasToken(lexer.CurrentToken.Text); lexer.NextToken(); return(ret); }
/// <summary> /// This is temp work around for $filter $orderby parameter expression which contains complex or collection /// like "Fully.Qualified.Namespace.CanMoveToAddresses(addresses=[{\"Street\":\"NE 24th St.\",\"City\":\"Redmond\"},{\"Street\":\"Pine St.\",\"City\":\"Seattle\"}])"; /// TODO: $filter $orderby parameter expression which contains nested complex or collection should NOT be supported in this way /// but should be parsed into token tree, and binded to node tree: parsedParameters.Select(p => this.bindMethod(p)); /// </summary> /// <param name="model">The model.</param> /// <param name="operation">IEdmFunction or IEdmOperation</param> /// <param name="parameterTokens">The tokens to bind.</param> /// <param name="enableCaseInsensitive">Whether to enable case-insensitive when resolving parameter name.</param> /// <param name="enableUriTemplateParsing">Whether Uri template parsing is enabled.</param> /// <returns>The FunctionParameterTokens with complex or collection values converted from string like "{...}", or "[..,..,..]".</returns> private static ICollection <FunctionParameterToken> HandleComplexOrCollectionParameterValueIfExists(IEdmModel model, IEdmOperation operation, ICollection <FunctionParameterToken> parameterTokens, bool enableCaseInsensitive, bool enableUriTemplateParsing = false) { ICollection <FunctionParameterToken> partiallyParsedParametersWithComplexOrCollection = new Collection <FunctionParameterToken>(); foreach (FunctionParameterToken paraToken in parameterTokens) { FunctionParameterToken funcParaToken; IEdmOperationParameter functionParameter = operation.FindParameter(paraToken.ParameterName); if (enableCaseInsensitive && functionParameter == null) { functionParameter = ODataUriResolver.ResolveOperationParameterNameCaseInsensitive(operation, paraToken.ParameterName); // The functionParameter can not be null here, else this method won't be called. funcParaToken = new FunctionParameterToken(functionParameter.Name, paraToken.ValueToken); } else { funcParaToken = paraToken; } FunctionParameterAliasToken aliasToken = funcParaToken.ValueToken as FunctionParameterAliasToken; if (aliasToken != null) { aliasToken.ExpectedParameterType = functionParameter.Type; } LiteralToken valueToken = funcParaToken.ValueToken as LiteralToken; string valueStr = null; if (valueToken != null && (valueStr = valueToken.Value as string) != null && !string.IsNullOrEmpty(valueToken.OriginalText)) { ExpressionLexer lexer = new ExpressionLexer(valueToken.OriginalText, true /*moveToFirstToken*/, false /*useSemicolonDelimiter*/, true /*parsingFunctionParameters*/); if (lexer.CurrentToken.Kind == ExpressionTokenKind.BracketedExpression || lexer.CurrentToken.Kind == ExpressionTokenKind.BracedExpression) { object result; UriTemplateExpression expression; if (enableUriTemplateParsing && UriTemplateParser.TryParseLiteral(lexer.CurrentToken.Text, functionParameter.Type, out expression)) { result = expression; } else if (!functionParameter.Type.IsStructured() && !functionParameter.Type.IsStructuredCollectionType()) { // ExpressionTokenKind.BracketedExpression means text like [1,2] // so now try convert it to collection type value: result = ODataUriUtils.ConvertFromUriLiteral(valueStr, ODataVersion.V4, model, functionParameter.Type); } else { // For complex & colleciton of complex directly return the raw string. partiallyParsedParametersWithComplexOrCollection.Add(funcParaToken); continue; } LiteralToken newValueToken = new LiteralToken(result, valueToken.OriginalText); FunctionParameterToken newFuncParaToken = new FunctionParameterToken(funcParaToken.ParameterName, newValueToken); partiallyParsedParametersWithComplexOrCollection.Add(newFuncParaToken); continue; } } partiallyParsedParametersWithComplexOrCollection.Add(funcParaToken); } return(partiallyParsedParametersWithComplexOrCollection); }
/// <summary> /// Bind parameter alias (figuring out its type by first parsing and binding its value expression). /// </summary> /// <param name="functionParameterAliasToken">The alias syntactics token.</param> /// <returns>The semantics node for parameter alias.</returns> protected virtual SingleValueNode BindParameterAlias(FunctionParameterAliasToken functionParameterAliasToken) { ParameterAliasBinder binder = new ParameterAliasBinder(this.Bind); return(binder.BindParameterAlias(this.BindingState, functionParameterAliasToken)); }