示例#1
0
 /// <summary>
 /// Binds a collection of <paramref name="segments"/> to metadata, creating a semantic ODataPath object.
 /// </summary>
 /// <param name="segments">Collection of path segments.</param>
 /// <param name="configuration">The configuration to use when binding the path.</param>
 /// <returns>A semantic <see cref="ODataPath"/> object to describe the path.</returns>
 internal static ODataPath BindPath(ICollection<string> segments, ODataUriParserConfiguration configuration)
 {
     ODataPathParser semanticPathParser = new ODataPathParser(configuration);
     var intermediateSegments = semanticPathParser.ParsePath(segments);
     ODataPath path = new ODataPath(intermediateSegments);
     return path;
 }
示例#2
0
        /// <summary>
        /// Build the ExpandOption variant of an SelectExpandBinder
        /// </summary>
        /// <param name="configuration">The configuration used for binding.</param>
        /// <param name="edmType">The type of the top level expand item.</param>
        /// <param name="navigationSource">The navigation source of the top level expand item.</param>
        public SelectExpandBinder(ODataUriParserConfiguration configuration, IEdmStructuredType edmType, IEdmNavigationSource navigationSource)
        {
            ExceptionUtils.CheckArgumentNotNull(configuration, "configuration");
            ExceptionUtils.CheckArgumentNotNull(edmType, "edmType");

            this.configuration = configuration;
            this.edmType = edmType;
            this.navigationSource = navigationSource;
        }
        /// <summary>
        /// Tries to parse a collection of function parameters for path.
        /// </summary>     
        /// <param name="parenthesisExpression">The contents of the parentheses portion of the current path segment.</param>
        /// <param name="configuration">The ODataUriParserConfiguration to create a UriQueryExpressionParser.</param>
        /// <param name="splitParameters">The parameters if they were successfully split.</param>
        /// <returns>Whether the parameters could be split.</returns>
        internal static bool TrySplitOperationParameters(string parenthesisExpression, ODataUriParserConfiguration configuration, out ICollection<FunctionParameterToken> splitParameters)
        {
            ExpressionLexer lexer = new ExpressionLexer(parenthesisExpression, true /*moveToFirstToken*/, false /*useSemicolonDelimeter*/, true /*parsingFunctionParameters*/);
            UriQueryExpressionParser parser = new UriQueryExpressionParser(configuration.Settings.FilterLimit, lexer);
            var ret = parser.TrySplitOperationParameters(ExpressionTokenKind.End, out splitParameters);

            // check duplicate names
            if (splitParameters.Select(t => t.ParameterName).Distinct().Count() != splitParameters.Count)
            {
                throw new ODataException(ODataErrorStrings.FunctionCallParser_DuplicateParameterOrEntityKeyName);
            }

            return ret;
        }
示例#4
0
        public void ParseMultipleTransformations(string query)
        {
            var model =
                Common.TestModelBuilder.CreateModel(new Type[] { typeof(Category), typeof(Product), typeof(Sales) });
            IEdmType edmType = model.FindDeclaredType(typeof(Sales).FullName);
            var      config  = new ODataUriParserConfiguration(model);
            var      result  = default(ApplyClause);

            "Given a message to parse {0}".Given(() => { });
            "When I try to parse".When(
                () =>
            {
                result = ApplyParser.ParseApplyImplementation(query, config, edmType, null);
            });
            "we should find 4 transformations".Then(() => result.Transformations.Count.Should().Be(4));
            "the first transformation is aggregate".Then(() => result.Transformations.First().Item2.Should().BeOfType <ApplyAggregateClause>());
            "the last transformation is groupby".Then(() => result.Transformations.Last().Item2.Should().BeOfType <ApplyGroupbyClause>());
        }
示例#5
0
        private static bool TryParseOperationParameters(string functionName, string parenthesisExpression, ParameterAliasValueAccessor paramAliasAccessor, IEdmOperation operation, out ICollection <OperationSegmentParameter> parsedSegementParameters)
        {
            ICollection <FunctionParameterToken> splitParameters;

            parsedSegementParameters = null;
            ODataUriParserConfiguration configuration = new ODataUriParserConfiguration(HardCodedTestModel.TestModel)
            {
                ParameterAliasValueAccessor = paramAliasAccessor, EnableCaseInsensitiveUriFunctionIdentifier = false
            };

            if (FunctionParameterParser.TrySplitOperationParameters(parenthesisExpression, configuration, out splitParameters))
            {
                parsedSegementParameters = FunctionCallBinder.BindSegmentParameters(configuration, operation, splitParameters);
                return(true);
            }

            return(false);
        }
示例#6
0
        private static bool TryParseOperationParameters(string functionName, string parenthesisExpression, IEdmOperation operation, out ICollection <OperationSegmentParameter> parsedSegementParameters, bool enableUriTemplateParsing = false)
        {
            ICollection <FunctionParameterToken> splitParameters;

            parsedSegementParameters = null;
            ODataUriParserConfiguration configuration = new ODataUriParserConfiguration(HardCodedTestModel.TestModel)
            {
                EnableUriTemplateParsing = enableUriTemplateParsing
            };

            if (FunctionParameterParser.TrySplitOperationParameters(parenthesisExpression, configuration, out splitParameters))
            {
                parsedSegementParameters = FunctionCallBinder.BindSegmentParameters(configuration, operation, splitParameters);
                return(true);
            }

            return(false);
        }
示例#7
0
        /// <summary>
        /// Parse an apply query
        /// </summary>
        /// <param name="applyQuery">The apply query</param>
        /// <param name="oDataUriParserConfiguration"></param>
        /// <param name="edmType">the EDM type of the entity set</param>
        /// <param name="edmNavigationSource"></param>
        /// <returns>an <see cref="ApplyClause"/> that contains a list of transformation clause objects as a List of Tuples
        /// where item1 is the transformation name and item2 is the relevant Clause object as <see cref="AggregationTransformationBase"/></returns>
        internal static ApplyClause ParseApplyImplementation(string applyQuery, ODataUriParserConfiguration oDataUriParserConfiguration, IEdmType edmType, IEdmNavigationSource edmNavigationSource)
        {
            var res = new ApplyClause();

            if (applyQuery.StartsWith(UriQueryConstants.ApplyQueryOption))
            {
                applyQuery = applyQuery.Substring(7);
            }

            var trasformations = new List <Tuple <string, AggregationTransformationBase> >();
            List <Tuple <string, string> > trasformationsToParse = GetTransformations(applyQuery);

            foreach (var transformationPair in trasformationsToParse)
            {
                var trasformationName  = transformationPair.Item2;
                var trasformationQuery = transformationPair.Item1;
                switch (trasformationName)
                {
                case UriQueryConstants.AggregateTransformation:
                    trasformations.Add(new Tuple <string, AggregationTransformationBase>(
                                           UriQueryConstants.AggregateTransformation,
                                           ParseAggregate(res, trasformationQuery, oDataUriParserConfiguration, edmType, edmNavigationSource)));
                    break;

                case UriQueryConstants.GroupbyTransformation:
                    trasformations.Add(new Tuple <string, AggregationTransformationBase>(
                                           UriQueryConstants.GroupbyTransformation,
                                           ParseGroupBy(res, trasformationQuery, oDataUriParserConfiguration, edmType, edmNavigationSource)));
                    break;

                case UriQueryConstants.FilterTransformation:
                    trasformations.Add(new Tuple <string, AggregationTransformationBase>(
                                           UriQueryConstants.FilterTransformation,
                                           ParseFilter(res, trasformationQuery, oDataUriParserConfiguration, edmType, edmNavigationSource)));
                    break;

                default:
                    throw new ODataException("Unsupported aggregation transformation");
                }
            }
            res.Transformations = trasformations;

            return(res);
        }
        private ExpandToken StarExpandTesting(string expand, String entitySetType)
        {
            IEdmModel model = Microsoft.Test.OData.Utils.Metadata.TestModels.BuildTestModel();

            ODataUriParserConfiguration configuration = new ODataUriParserConfiguration(EdmCoreModel.Instance)
            {
                Settings = { PathLimit = 10, FilterLimit = 10, OrderByLimit = 10, SearchLimit = 10, SelectExpandLimit = 10 }
            };
            var parentEntityType            = configuration.Resolver.ResolveNavigationSource(model, entitySetType).EntityType();
            SelectExpandParser expandParser = new SelectExpandParser(configuration.Resolver, expand, parentEntityType, configuration.Settings.SelectExpandLimit, configuration.EnableCaseInsensitiveUriFunctionIdentifier)
            {
                MaxPathDepth    = configuration.Settings.PathLimit,
                MaxFilterDepth  = configuration.Settings.FilterLimit,
                MaxOrderByDepth = configuration.Settings.OrderByLimit,
                MaxSearchDepth  = configuration.Settings.SearchLimit
            };

            return(expandParser.ParseExpand());
        }
示例#9
0
        public void ParseAggregate(string query)
        {
            var model =
                Common.TestModelBuilder.CreateModel(new Type[] { typeof(Category), typeof(Product), typeof(Sales) });
            IEdmType edmType = model.FindDeclaredType(typeof(Sales).FullName);
            var      config  = new ODataUriParserConfiguration(model);
            var      result  = default(ApplyClause);

            "Given a message to parse {0}".Given(() => { });
            "When I try to parse".When(
                () =>
            {
                result = ApplyParser.ParseApplyImplementation(query, config, edmType, null);
            });
            "The transformation is aggregate".Then(() => result.Transformations.First().Item2.Should().BeOfType <ApplyAggregateClause>());
            "The Alias is Total".Then(() => ((ApplyAggregateClause)result.Transformations.First().Item2).Alias.Should().Be("Total"));
            "The aggregation method is Sum".Then(() => ((ApplyAggregateClause)result.Transformations.First().Item2).AggregationMethod.Should().Be("sum"));
            "The aggregation expression exist".Then(() => ((ApplyAggregateClause)result.Transformations.First().Item2).AggregatablePropertyExpression.Expression.Should().NotBeNull());
            "The aggregation expression type exist".Then(() => ((ApplyAggregateClause)result.Transformations.First().Item2).AggregatablePropertyExpression.ItemType.Should().NotBeNull());
        }
        public void ParentEntityTypeIsNullForExpandStar()
        {
            var expand = "*";

            ODataUriParserConfiguration configuration = new ODataUriParserConfiguration(EdmCoreModel.Instance)
            {
                Settings = { PathLimit = 10, FilterLimit = 10, OrderByLimit = 10, SearchLimit = 10, SelectExpandLimit = 10 }
            };

            SelectExpandParser expandParser = new SelectExpandParser(configuration.Resolver, expand, null, configuration.Settings.SelectExpandLimit, configuration.EnableCaseInsensitiveUriFunctionIdentifier)
            {
                MaxPathDepth    = configuration.Settings.PathLimit,
                MaxFilterDepth  = configuration.Settings.FilterLimit,
                MaxOrderByDepth = configuration.Settings.OrderByLimit,
                MaxSearchDepth  = configuration.Settings.SearchLimit
            };

            Action action = () => expandParser.ParseExpand();

            action.ShouldThrow <ODataException>().WithMessage(Strings.UriExpandParser_ParentEntityIsNull(""));
        }
示例#11
0
        /// <summary>
        /// Add semantic meaning to a Select or Expand Token
        /// </summary>
        /// <param name="elementType">the top level entity type.</param>
        /// <param name="navigationSource">the top level navigation source</param>
        /// <param name="expandToken">the syntactically parsed expand token</param>
        /// <param name="selectToken">the syntactically parsed select token</param>
        /// <param name="configuration">The configuration to use for parsing.</param>
        /// <returns>A select expand clause bound to metadata.</returns>
        public SelectExpandClause Bind(
            IEdmStructuredType elementType,
            IEdmNavigationSource navigationSource,
            ExpandToken expandToken,
            SelectToken selectToken,
            ODataUriParserConfiguration configuration)
        {
            ExpandToken unifiedSelectExpandToken = SelectExpandSyntacticUnifier.Combine(expandToken, selectToken);

            ExpandTreeNormalizer expandTreeNormalizer        = new ExpandTreeNormalizer();
            ExpandToken          normalizedSelectExpandToken = expandTreeNormalizer.NormalizeExpandTree(unifiedSelectExpandToken);

            SelectExpandBinder selectExpandBinder = new SelectExpandBinder(configuration, elementType, navigationSource);
            SelectExpandClause clause             = selectExpandBinder.Bind(normalizedSelectExpandToken);

            SelectExpandClauseFinisher.AddExplicitNavPropLinksWhereNecessary(clause);

            new ExpandDepthAndCountValidator(configuration.Settings.MaximumExpansionDepth, configuration.Settings.MaximumExpansionCount).Validate(clause);

            return(clause);
        }
        /// <summary>
        /// Add semantic meaning to a Select or Expand Token
        /// </summary>
        /// <param name="elementType">the top level entity type.</param>
        /// <param name="navigationSource">the top level navigation source</param>
        /// <param name="expandToken">the syntactically parsed expand token</param>
        /// <param name="selectToken">the syntactically parsed select token</param>
        /// <param name="configuration">The configuration to use for parsing.</param>
        /// <returns>A select expand clause bound to metadata.</returns>
        public SelectExpandClause Bind(
            IEdmStructuredType elementType, 
            IEdmNavigationSource navigationSource,
            ExpandToken expandToken, 
            SelectToken selectToken, 
            ODataUriParserConfiguration configuration)
        {
            ExpandToken unifiedSelectExpandToken = SelectExpandSyntacticUnifier.Combine(expandToken, selectToken);

            ExpandTreeNormalizer expandTreeNormalizer = new ExpandTreeNormalizer();
            ExpandToken normalizedSelectExpandToken = expandTreeNormalizer.NormalizeExpandTree(unifiedSelectExpandToken);

            SelectExpandBinder selectExpandBinder = new SelectExpandBinder(configuration, elementType, navigationSource);
            SelectExpandClause clause = selectExpandBinder.Bind(normalizedSelectExpandToken);

            SelectExpandClauseFinisher.AddExplicitNavPropLinksWhereNecessary(clause);

            new ExpandDepthAndCountValidator(configuration.Settings.MaximumExpansionDepth, configuration.Settings.MaximumExpansionCount).Validate(clause);

            return clause;
        }
        /// <summary>
        /// Parse the raw select and expand strings into Abstract Syntax Trees
        /// </summary>
        /// <param name="selectClause">The raw select string</param>
        /// <param name="expandClause">the raw expand string</param>
        /// <param name="configuration">Configuration parameters</param>
        /// <param name="expandTree">the resulting expand AST</param>
        /// <param name="selectTree">the resulting select AST</param>
        public static void Parse(
            string selectClause, 
            string expandClause, 
            ODataUriParserConfiguration configuration, 
            out ExpandToken expandTree, 
            out SelectToken selectTree)
        {
            SelectExpandParser selectParser = new SelectExpandParser(selectClause, configuration.Settings.SelectExpandLimit, configuration.EnableCaseInsensitiveBuiltinIdentifier)
            {
                MaxPathDepth = configuration.Settings.PathLimit
            };
            selectTree = selectParser.ParseSelect();

            SelectExpandParser expandParser = new SelectExpandParser(expandClause, configuration.Settings.SelectExpandLimit, configuration.EnableCaseInsensitiveBuiltinIdentifier)
            {
                MaxPathDepth = configuration.Settings.PathLimit,
                MaxFilterDepth = configuration.Settings.FilterLimit,
                MaxOrderByDepth = configuration.Settings.OrderByLimit,
                MaxSearchDepth = configuration.Settings.SearchLimit
            };
            expandTree = expandParser.ParseExpand();
        }
        /// <summary>
        /// Parse the raw select and expand strings into Abstract Syntax Trees
        /// </summary>
        /// <param name="selectClause">the raw select string</param>
        /// <param name="expandClause">the raw expand string</param>
        /// <param name="parentEntityType">the parent entity type for expand option</param>
        /// <param name="configuration">the OData URI parser configuration</param>
        /// <param name="expandTree">the resulting expand AST</param>
        /// <param name="selectTree">the resulting select AST</param>
        public static void Parse(
            string selectClause, 
            string expandClause,
            IEdmStructuredType parentEntityType,
            ODataUriParserConfiguration configuration, 
            out ExpandToken expandTree, 
            out SelectToken selectTree)
        {
            SelectExpandParser selectParser = new SelectExpandParser(selectClause, configuration.Settings.SelectExpandLimit, configuration.EnableCaseInsensitiveUriFunctionIdentifier)
            {
                MaxPathDepth = configuration.Settings.PathLimit
            };
            selectTree = selectParser.ParseSelect();

            SelectExpandParser expandParser = new SelectExpandParser(configuration.Resolver, expandClause, parentEntityType, configuration.Settings.SelectExpandLimit, configuration.EnableCaseInsensitiveUriFunctionIdentifier)
            {
                MaxPathDepth = configuration.Settings.PathLimit,
                MaxFilterDepth = configuration.Settings.FilterLimit,
                MaxOrderByDepth = configuration.Settings.OrderByLimit,
                MaxSearchDepth = configuration.Settings.SearchLimit
            };
            expandTree = expandParser.ParseExpand();
        }
示例#15
0
        private ExpandToken StarExpandTesting(string expand, string typeName, IEdmModel model = null)
        {
            if (model == null)
            {
                model = Test.OData.Utils.Metadata.TestModels.BuildTestModel();
            }

            ODataUriParserConfiguration configuration = new ODataUriParserConfiguration(EdmCoreModel.Instance)
            {
                Settings = { PathLimit = 10, FilterLimit = 10, OrderByLimit = 10, SearchLimit = 10, SelectExpandLimit = 10 }
            };

            var parentStructuredType        = configuration.Resolver.ResolveType(model, "TestModel." + typeName) as IEdmStructuredType;
            SelectExpandParser expandParser = new SelectExpandParser(configuration.Resolver, expand, parentStructuredType, configuration.Settings.SelectExpandLimit, configuration.EnableCaseInsensitiveUriFunctionIdentifier)
            {
                MaxPathDepth    = configuration.Settings.PathLimit,
                MaxFilterDepth  = configuration.Settings.FilterLimit,
                MaxOrderByDepth = configuration.Settings.OrderByLimit,
                MaxSearchDepth  = configuration.Settings.SearchLimit
            };

            return(expandParser.ParseExpand());
        }
        /// <summary>
        /// Parse the raw select and expand strings into Abstract Syntax Trees
        /// </summary>
        /// <param name="selectClause">The raw select string</param>
        /// <param name="expandClause">the raw expand string</param>
        /// <param name="configuration">Configuration parameters</param>
        /// <param name="expandTree">the resulting expand AST</param>
        /// <param name="selectTree">the resulting select AST</param>
        public static void Parse(
            string selectClause,
            string expandClause,
            ODataUriParserConfiguration configuration,
            out ExpandToken expandTree,
            out SelectToken selectTree)
        {
            SelectExpandParser selectParser = new SelectExpandParser(selectClause, configuration.Settings.SelectExpandLimit, configuration.EnableCaseInsensitiveBuiltinIdentifier)
            {
                MaxPathDepth = configuration.Settings.PathLimit
            };

            selectTree = selectParser.ParseSelect();

            SelectExpandParser expandParser = new SelectExpandParser(expandClause, configuration.Settings.SelectExpandLimit, configuration.EnableCaseInsensitiveBuiltinIdentifier)
            {
                MaxPathDepth    = configuration.Settings.PathLimit,
                MaxFilterDepth  = configuration.Settings.FilterLimit,
                MaxOrderByDepth = configuration.Settings.OrderByLimit,
                MaxSearchDepth  = configuration.Settings.SearchLimit
            };

            expandTree = expandParser.ParseExpand();
        }
示例#17
0
 /// <summary>
 /// Constructs a <see cref="BindingState"/> with the given <paramref name="configuration"/>.
 /// </summary>
 /// <param name="configuration">The configuration used for binding.</param>
 internal BindingState(ODataUriParserConfiguration configuration)
 {
     ExceptionUtils.CheckArgumentNotNull(configuration, "configuration");
     this.configuration = configuration;
     this.BindingRecursionDepth = 0;
 }
示例#18
0
        /// <summary>
        /// Initializes a new instance of <see cref="ODataPathParser"/>.
        /// </summary>
        /// <param name="configuration">The parser's current configuration.</param>
        internal ODataPathParser(ODataUriParserConfiguration configuration)
        {
            Debug.Assert(configuration != null, "configuration != null");

            this.configuration = configuration;
        }
示例#19
0
        /// <summary>
        /// Tries to find a single matching operation import for the given identifier, parametes, and binding type.
        /// </summary>
        /// <param name="identifier">The identifier from the URI.</param>
        /// <param name="parenthesisExpression">The parenthesis expression contianing parameters, if any.</param>
        /// <param name="bindingType">The current binding type or null if there isn't one.</param>
        /// <param name="configuration">The configuration of the parser.</param>
        /// <param name="boundParameters">The parsed parameters from the parenthesis expression.</param>
        /// <param name="matchingOperation">The single matching operation import if one could be determined.</param>
        /// <returns>Whether or not a matching operation import could be found.</returns>
        private static bool TryBindingParametersAndMatchingOperation(string identifier, string parenthesisExpression, IEdmType bindingType, ODataUriParserConfiguration configuration, out ICollection<OperationSegmentParameter> boundParameters, out IEdmOperation matchingOperation)
        {
            // If the name isn't fully qualified then it can't be a function or action.
            // When using extension, there may be function call with unqualified name. So loose the restriction here.
            if (identifier != null && identifier.IndexOf(".", StringComparison.Ordinal) == -1 && configuration.Resolver.GetType() == typeof(ODataUriResolver))
            {
                boundParameters = null;
                matchingOperation = null;
                return false;
            }

            // TODO: update code that is duplicate between operation and operation import, add more tests.
            matchingOperation = null;
            ICollection<FunctionParameterToken> splitParameters;
            if (!String.IsNullOrEmpty(parenthesisExpression))
            {
                if (!FunctionParameterParser.TrySplitOperationParameters(parenthesisExpression, configuration, out splitParameters))
                {
                    IEdmOperation possibleMatchingOperation = null;

                    // Look for an overload that returns an entity collection by the specified name. If so parthensis is just key parameters.
                    if (FunctionOverloadResolver.ResolveOperationFromList(identifier, new List<string>(), bindingType, configuration.Model, out possibleMatchingOperation, configuration.Resolver))
                    {
                        IEdmCollectionTypeReference collectionReturnType = possibleMatchingOperation.ReturnType as IEdmCollectionTypeReference;
                        if (collectionReturnType != null && collectionReturnType.ElementType().IsEntity())
                        {
                            matchingOperation = possibleMatchingOperation;
                            boundParameters = null;
                            return true;
                        }
                        else
                        {
                            throw ExceptionUtil.CreateBadRequestError(ODataErrorStrings.RequestUriProcessor_SegmentDoesNotSupportKeyPredicates(identifier));
                        }
                    }

                    boundParameters = null;
                    return false;
                }
            }
            else
            {
                splitParameters = new Collection<FunctionParameterToken>();
            }

            // Resolve the specific overload.
            if (FunctionOverloadResolver.ResolveOperationFromList(identifier, splitParameters.Select(k => k.ParameterName).ToList(), bindingType, configuration.Model, out matchingOperation, configuration.Resolver))
            {
                boundParameters = FunctionCallBinder.BindSegmentParameters(configuration, matchingOperation, splitParameters);
                return true;
            }

            boundParameters = null;
            return false;
        }
示例#20
0
        /// <summary>
        /// Tries to find a single matching operation import for the given identifier, and parameters.
        /// </summary>
        /// <param name="identifier">The identifier from the URI.</param>
        /// <param name="parenthesisExpression">The parenthesis expression contianing parameters, if any.</param>
        /// <param name="configuration">The configuration of the parser.</param>
        /// <param name="boundParameters">The parsed parameters from the parenthesis expression.</param>
        /// <param name="matchingFunctionImport">The single matching operation import if one could be determined.</param>
        /// <returns>Whether or not a matching operation import could be found.</returns>
        private static bool TryBindingParametersAndMatchingOperationImport(string identifier, string parenthesisExpression, ODataUriParserConfiguration configuration, out ICollection<OperationSegmentParameter> boundParameters, out IEdmOperationImport matchingFunctionImport)
        {
            matchingFunctionImport = null;
            ICollection<FunctionParameterToken> splitParameters = null;
            if (!String.IsNullOrEmpty(parenthesisExpression))
            {
                if (!FunctionParameterParser.TrySplitOperationParameters(parenthesisExpression, configuration, out splitParameters))
                {
                    IEdmOperationImport possibleMatchingOperationImport = null;

                    // Look for an overload that returns an entity collection by the specified name. If so parthensis is just key parameters.
                    if (FunctionOverloadResolver.ResolveOperationImportFromList(identifier, EmptyList, configuration.Model, out possibleMatchingOperationImport, configuration.Resolver))
                    {
                        IEdmCollectionTypeReference collectionReturnType = possibleMatchingOperationImport.Operation.ReturnType as IEdmCollectionTypeReference;
                        if (collectionReturnType != null && collectionReturnType.ElementType().IsEntity())
                        {
                            matchingFunctionImport = possibleMatchingOperationImport;
                            boundParameters = null;
                            return true;
                        }
                        else
                        {
                            throw ExceptionUtil.CreateBadRequestError(ODataErrorStrings.RequestUriProcessor_SegmentDoesNotSupportKeyPredicates(identifier));
                        }
                    }

                    boundParameters = null;
                    return false;
                }
            }
            else
            {
                splitParameters = new Collection<FunctionParameterToken>();
            }

            // Resolve the specific overload.
            if (FunctionOverloadResolver.ResolveOperationImportFromList(identifier, splitParameters.Select(k => k.ParameterName).ToList(), configuration.Model, out matchingFunctionImport, configuration.Resolver))
            {
                var matchingOperation = matchingFunctionImport.Operation;
                boundParameters = FunctionCallBinder.BindSegmentParameters(configuration, matchingOperation, splitParameters);
                return true;
            }

            boundParameters = null;
            return false;
        }
示例#21
0
        internal static List<OperationSegmentParameter> BindSegmentParameters(ODataUriParserConfiguration configuration, IEdmOperation functionOrOpertion, ICollection<FunctionParameterToken> segmentParameterTokens)
        {
            // TODO: HandleComplexOrCollectionParameterValueIfExists is temp work around for single copmlex or colleciton type, it can't handle nested complex or collection value.
            ICollection<FunctionParameterToken> parametersParsed = FunctionCallBinder.HandleComplexOrCollectionParameterValueIfExists(configuration.Model, functionOrOpertion, segmentParameterTokens, configuration.Resolver.EnableCaseInsensitive, configuration.EnableUriTemplateParsing);

            // Bind it to metadata
            BindingState state = new BindingState(configuration);
            state.ImplicitRangeVariable = null;
            state.RangeVariables.Clear();
            MetadataBinder binder = new MetadataBinder(state);
            List<OperationSegmentParameter> boundParameters = new List<OperationSegmentParameter>();

            IDictionary<string, SingleValueNode> input = new Dictionary<string, SingleValueNode>(StringComparer.Ordinal);
            foreach (var paraToken in parametersParsed)
            {
                // TODO: considering another better exception
                if (paraToken.ValueToken is EndPathToken)
                {
                    throw new ODataException(Strings.MetadataBinder_ParameterNotInScope(
                        string.Format(CultureInfo.InvariantCulture, "{0}={1}", paraToken.ParameterName, (paraToken.ValueToken as EndPathToken).Identifier)));
                }

                SingleValueNode boundNode = (SingleValueNode)binder.Bind(paraToken.ValueToken);

                if (!input.ContainsKey(paraToken.ParameterName))
                {
                    input.Add(paraToken.ParameterName, boundNode);
                }
            }

            IDictionary<IEdmOperationParameter, SingleValueNode> result = configuration.Resolver.ResolveOperationParameters(functionOrOpertion, input);

            foreach (var item in result)
            {
                SingleValueNode boundNode = item.Value;

                // ensure node type is compatible with parameter type.
                var sourceTypeReference = boundNode.GetEdmTypeReference();
                bool sourceIsNullOrOpenType = (sourceTypeReference == null);
                if (!sourceIsNullOrOpenType)
                {
                    // if the node has been rewritten, no further conversion is needed.
                    if (!TryRewriteIntegralConstantNode(ref boundNode, item.Key.Type))
                    {
                        boundNode = MetadataBindingUtils.ConvertToTypeIfNeeded(boundNode, item.Key.Type);
                    }
                }

                OperationSegmentParameter boundParamer = new OperationSegmentParameter(item.Key.Name, boundNode);
                boundParameters.Add(boundParamer);
            }

            return boundParameters;
        }
示例#22
0
        /// <summary>
        /// Parse queries such as : "groupby(Customer/Name,Customer/ID,Product/Name,Account)" or "groupby((Customer/Country,Product/Name), aggregate(Amount with sum as Total))"
        /// </summary>
        /// <param name="apply"></param>
        /// <param name="query"></param>
        /// <param name="oDataUriParserConfiguration"></param>
        /// <param name="edmType"></param>
        /// <param name="edmNavigationSource"></param>
        /// <returns></returns>
        private static ApplyGroupbyClause ParseGroupBy(ApplyClause apply, string query,
                                                       ODataUriParserConfiguration oDataUriParserConfiguration, IEdmType edmType, IEdmNavigationSource edmNavigationSource)
        {
            string selectQuery;
            ApplyAggregateClause aggregateClause = null;

            query = IsolateQuery(query, UriQueryConstants.GroupbyTransformation);
            if (query.StartsWith("(") && query.EndsWith(")"))
            {
                query = query.TrimOne('(', ')');
            }
            var p = query.IndexOf(UriQueryConstants.AggregateTransformation + '(');

            if (p == -1)
            {
                if (query.StartsWith("(") && query.EndsWith(")"))
                {
                    query = query.TrimOne('(', ')');
                }
                selectQuery = query;
            }
            else
            {
                selectQuery     = query.Substring(0, p).Trim().Trim(',').TrimOne('(', ')');
                aggregateClause = ParseAggregate(apply, query.Substring(p), oDataUriParserConfiguration, edmType, edmNavigationSource);
            }

            var selectedStatements = selectQuery.Split(',');
            var withIndex          = selectQuery.IndexOf("with");

            if (withIndex > 0)
            {
                selectedStatements = selectQuery.Substring(0, withIndex).Split(',');
                var withStatement = selectQuery.Substring(withIndex, selectQuery.Length - withIndex);
                selectedStatements[selectedStatements.Count() - 1] =
                    selectedStatements[selectedStatements.Count() - 1] + withStatement;
            }

            string aggregationMethod, alias;
            List <ExpressionClause> aggregatablePropertyExpressions = null;

            try
            {
                aggregatablePropertyExpressions =
                    selectedStatements.Select(statement => ODataQueryOptionParser.ParseExpressionImplementation(
                                                  GetAggregatableProperty(statement, false, out alias, out aggregationMethod),
                                                  oDataUriParserConfiguration,
                                                  edmType,
                                                  edmNavigationSource)).ToList();
            }
            catch (Exception)
            {
                //parsing of some expressions (like property on enum such as DateTimeOffset/Minute) are not supported so ODataQueryOptionParser.ParseExpressionImplementation will fail
                aggregatablePropertyExpressions = null;
            }


            return(new ApplyGroupbyClause()
            {
                SelectedStatements = selectedStatements,
                SelectedPropertiesExpressions = aggregatablePropertyExpressions,
                Aggregate = aggregateClause,
                Apply = apply
            });
        }
示例#23
0
        /// <summary>
        /// Parse queries such as:
        /// "aggregate(Amount with sum as Total)" and "aggregate(Amount mul Product/TaxRate with sum as Tax)"
        /// </summary>
        /// <param name="apply"></param>
        /// <param name="query"></param>
        /// <param name="oDataUriParserConfiguration"></param>
        /// <param name="edmType"></param>
        /// <param name="edmNavigationSource"></param>
        /// <returns></returns>
        private static ApplyAggregateClause ParseAggregate(ApplyClause apply, string query, ODataUriParserConfiguration oDataUriParserConfiguration, IEdmType edmType, IEdmNavigationSource edmNavigationSource)
        {
            query = IsolateQuery(query, UriQueryConstants.AggregateTransformation);
            string aggregatableProperty;
            string aggregationMethod;
            string alias;

            aggregatableProperty = GetAggregatableProperty(query, true, out alias, out aggregationMethod);

            //create an projection Expression to the property
            var AggregatablePropertyExpression = ODataQueryOptionParser.ParseExpressionImplementation(
                aggregatableProperty,
                oDataUriParserConfiguration,
                edmType,
                edmNavigationSource);

            return(new ApplyAggregateClause()
            {
                AggregatablePropertyExpression = AggregatablePropertyExpression,
                Alias = alias,
                AggregationMethod = aggregationMethod,
                AggregatableProperty = aggregatableProperty,
                Apply = apply
            });
        }
示例#24
0
 public ApplyBinder(MetadataBinder.QueryTokenVisitor bindMethod, BindingState state, ODataUriParserConfiguration configuration, ODataPathInfo odataPathInfo)
 {
     this.bindMethod    = bindMethod;
     this.state         = state;
     this.filterBinder  = new FilterBinder(bindMethod, state);
     this.configuration = configuration;
     this.odataPathInfo = odataPathInfo;
 }
        /// <summary>
        /// Bind a select and expand option.
        /// </summary>
        /// <param name="syntax">A syntax tree containing the select and expand options to bind</param>
        /// <param name="path">the top level path</param>
        /// <param name="configuration">The configuration to use for binding.</param>
        /// <returns>a select expand clause bound to metadata</returns>
        public static SelectExpandClause BindSelectExpand(SyntacticTree syntax, ODataPath path, ODataUriParserConfiguration configuration)
        {
            if (syntax.Select != null || syntax.Expand != null)
            {
                if (!path.EdmType().IsEntityCollection() && !path.EdmType().IsEntity())
                {
                    throw new ODataException(ODataErrorStrings.MetadataBinder_QueryOptionNotApplicable("$select or $expand"));
                }

                SelectExpandSemanticBinder semanticBinder = new SelectExpandSemanticBinder();

                return(semanticBinder.Bind((IEdmEntityType)((IEdmCollectionTypeReference)path.EdmType()).ElementType().Definition, path.NavigationSource(), syntax.Expand, syntax.Select, configuration));
            }

            return(null);
        }
示例#26
0
 /// <summary>
 /// Constructs a <see cref="BindingState"/> with the given <paramref name="configuration"/>.
 /// </summary>
 /// <param name="configuration">The configuration used for binding.</param>
 internal BindingState(ODataUriParserConfiguration configuration)
 {
     ExceptionUtils.CheckArgumentNotNull(configuration, "configuration");
     this.configuration         = configuration;
     this.BindingRecursionDepth = 0;
 }
示例#27
0
 /// <summary>
 /// Build an ExpandBinder based on global settings
 /// </summary>
 /// <param name="elementType">The entity type of the top level expand item.</param>
 /// <param name="entitySet">The entity set of the top level expand item.</param>
 /// <param name="configuration">The configuration to use for binding.</param>
 /// <returns>An ExpandBinder strategy based on the global settings</returns>
 public static ExpandBinder Create(IEdmEntityType elementType, IEdmEntitySet entitySet, ODataUriParserConfiguration configuration)
 {
     Debug.Assert(configuration != null, "configuration != null");
     Debug.Assert(configuration.Settings != null, "configuration.Settings != null");
     if (configuration.Settings.SupportExpandOptions)
     {
         return(new ExpandOptionExpandBinder(configuration, elementType, entitySet));
     }
     else
     {
         return(new NonOptionExpandBinder(configuration, elementType, entitySet));
     }
 }
示例#28
0
        /// <summary>
        /// Tries to parse a collection of function parameters for path.
        /// </summary>
        /// <param name="functionName">The function name to use in error messages.</param>
        /// <param name="parenthesisExpression">The contents of the parentheses portion of the current path segment.</param>
        /// <param name="configuration">The ODataUriParserConfiguration to create a UriQueryExpressionParser.</param>
        /// <param name="splitParameters">The parameters if they were successfully split.</param>
        /// <returns>Whether the parameters could be split.</returns>
        internal static bool TrySplitOperationParameters(string functionName, string parenthesisExpression, ODataUriParserConfiguration configuration, out ICollection <FunctionParameterToken> splitParameters)
        {
            ExpressionLexer          lexer  = new ExpressionLexer(parenthesisExpression, true /*moveToFirstToken*/, false /*useSemicolonDelimeter*/, true /*parsingFunctionParameters*/);
            UriQueryExpressionParser parser = new UriQueryExpressionParser(configuration.Settings.FilterLimit, lexer);
            var ret = parser.TrySplitOperationParameters(ExpressionTokenKind.End, out splitParameters);

            // check duplicate names
            if (splitParameters.Select(t => t.ParameterName).Distinct().Count() != splitParameters.Count)
            {
                throw new ODataException(ODataErrorStrings.FunctionCallParser_DuplicateParameterName);
            }

            return(ret);
        }
示例#29
0
 /// <summary>
 /// Build the NonOption variant of an ExpandBinder
 /// </summary>
 /// <param name="configuration">The configuration used for binding.</param>
 /// <param name="entityType">The entity type of the top level expand item.</param>
 /// <param name="entitySet">The entity set of the top level expand item.</param>
 public NonOptionExpandBinder(ODataUriParserConfiguration configuration, IEdmEntityType entityType, IEdmEntitySet entitySet)
     : base(configuration, entityType, entitySet)
 {
 }
示例#30
0
 /// <summary>
 /// Create a ApplyFilterClause from a parse transformation query
 /// </summary>
 /// <param name="apply"></param>
 /// <param name="query"></param>
 /// <param name="oDataUriParserConfiguration"></param>
 /// <param name="edmType"></param>
 /// <param name="edmNavigationSource"></param>
 /// <returns></returns>
 private static ApplyFilterClause ParseFilter(ApplyClause apply, string query, ODataUriParserConfiguration oDataUriParserConfiguration, IEdmType edmType, IEdmNavigationSource edmNavigationSource)
 {
     query = IsolateQuery(query, UriQueryConstants.FilterTransformation);
     return(new ApplyFilterClause()
     {
         Apply = apply,
         Filter = ODataQueryOptionParser.ParseFilterImplementation(
             query,
             oDataUriParserConfiguration,
             edmType,
             edmNavigationSource),
         RawQueryString = query
     });
 }