public void ApplyTo_OnSingleEntity_WithUnTypedContext_Throws_InvalidOperation()
        {
            // Arrange
            CustomersModelWithInheritance model = new CustomersModelWithInheritance();
            ODataQueryContext context = new ODataQueryContext(model.Model, model.Customer);
            SelectExpandQueryOption selectExpand = new SelectExpandQueryOption(select: "ID", expand: null, context: context);
            object entity = new object();

            // Act & Assert
            Assert.Throws<NotSupportedException>(() => selectExpand.ApplyTo(entity, new ODataQuerySettings()),
                "The query option is not bound to any CLR type. 'ApplyTo' is only supported with a query option bound to a CLR type.");
        }
        public void Ctor_SetsProperty_RawExpand()
        {
            // Arrange
            string expandValue = "expand";
            _model.Model.SetAnnotationValue<ClrTypeAnnotation>(_model.Customer, new ClrTypeAnnotation(typeof(Customer)));
            ODataQueryContext context = new ODataQueryContext(_model.Model, typeof(Customer));

            // Act
            SelectExpandQueryOption result = new SelectExpandQueryOption(select: null, expand: expandValue, context: context);

            // Assert
            Assert.Equal(expandValue, result.RawExpand);
        }
        public void Property_SelectExpandClause_WorksWithUnTypedContext()
        {
            // Arrange
            CustomersModelWithInheritance model = new CustomersModelWithInheritance();
            ODataQueryContext context = new ODataQueryContext(model.Model, model.Customer);
            SelectExpandQueryOption selectExpand = new SelectExpandQueryOption(select: "ID", expand: null, context: context);

            // Act & Assert
            Assert.NotNull(selectExpand.SelectExpandClause);
        }
        public void SelectExpandCaluse_ThrowsODataException_InvalidQuery(string select, string expand, string error)
        {
            // Arrange
            IEdmModel model = _model.Model;
            _model.Model.SetAnnotationValue<ClrTypeAnnotation>(_model.Customer, new ClrTypeAnnotation(typeof(Customer)));
            ODataQueryContext context = new ODataQueryContext(model, typeof(Customer));
            SelectExpandQueryOption option = new SelectExpandQueryOption(select, expand, context);

            // Act
            Assert.Throws<ODataException>(
                () => option.SelectExpandClause.ToString(),
                error);
        }
        public void SelectExpandClause_CanParse_ModelBuiltForQueryable(string select, string expand)
        {
            // Arrange
            HttpConfiguration config = new HttpConfiguration();
            config.Services.Replace(typeof(IAssembliesResolver), new TestAssemblyResolver());
            ODataConventionModelBuilder builder = new ODataConventionModelBuilder(new HttpConfiguration(), isQueryCompositionMode: true);
            builder.Entity<Customer>();
            IEdmModel model = builder.GetEdmModel();

            ODataQueryContext context = new ODataQueryContext(model, typeof(Customer));
            SelectExpandQueryOption option = new SelectExpandQueryOption(select, expand, context);

            // Act & Assert
            Assert.DoesNotThrow(() => option.SelectExpandClause.ToString());
        }
        public void ProcessLevelsCorrectly_WithNestedLevels()
        {
            // Arrange
            var model   = ODataLevelsTest.GetEdmModel();
            var context = new ODataQueryContext(
                model,
                model.FindDeclaredType("System.Web.OData.Routing.LevelsEntity"));
            var selectExpand = new SelectExpandQueryOption(
                select: null,
                expand: "Parent($expand=DerivedAncestors($levels=2);$levels=max)",
                context: context);

            selectExpand.LevelsMaxLiteralExpansionDepth = 4;

            // Act
            SelectExpandClause clause = selectExpand.ProcessLevels();

            // Assert
            Assert.True(clause.AllSelected);
            Assert.Equal(1, clause.SelectedItems.Count());

            // Level 1 of Parent.
            var parent = Assert.IsType <ExpandedNavigationSelectItem>(clause.SelectedItems.Single());

            Assert.Equal(
                "Parent",
                ((NavigationPropertySegment)parent.PathToNavigationProperty.FirstSegment).NavigationProperty.Name);
            Assert.Null(parent.LevelsOption);

            var clauseOfParent = parent.SelectAndExpand;

            Assert.True(clauseOfParent.AllSelected);
            Assert.Equal(2, clauseOfParent.SelectedItems.Count());

            // Level 1 of DerivedAncestors.
            var derivedAncestors = Assert.Single(clauseOfParent.SelectedItems.OfType <ExpandedNavigationSelectItem>().Where(
                                                     item => item.PathToNavigationProperty.FirstSegment is NavigationPropertySegment &&
                                                     ((NavigationPropertySegment)item.PathToNavigationProperty.FirstSegment).NavigationProperty.Name == "DerivedAncestors"));

            Assert.Null(derivedAncestors.LevelsOption);

            var clauseOfDerivedAncestors = derivedAncestors.SelectAndExpand;

            Assert.True(clauseOfDerivedAncestors.AllSelected);
            Assert.Equal(1, clauseOfDerivedAncestors.SelectedItems.Count());

            // Level 2 of DerivedAncestors.
            derivedAncestors = Assert.IsType <ExpandedNavigationSelectItem>(clauseOfDerivedAncestors.SelectedItems.Single());
            Assert.Equal(
                "DerivedAncestors",
                ((NavigationPropertySegment)derivedAncestors.PathToNavigationProperty.FirstSegment).NavigationProperty.Name);
            Assert.Null(derivedAncestors.LevelsOption);

            clauseOfDerivedAncestors = derivedAncestors.SelectAndExpand;
            Assert.True(clauseOfDerivedAncestors.AllSelected);
            Assert.Equal(0, clauseOfDerivedAncestors.SelectedItems.Count());

            // Level 2 of Parent.
            parent = Assert.Single(clauseOfParent.SelectedItems.OfType <ExpandedNavigationSelectItem>().Where(
                                       item => item.PathToNavigationProperty.FirstSegment is NavigationPropertySegment &&
                                       ((NavigationPropertySegment)item.PathToNavigationProperty.FirstSegment).NavigationProperty.Name == "Parent"));
            Assert.Null(parent.LevelsOption);

            clauseOfParent = parent.SelectAndExpand;
            Assert.True(clauseOfParent.AllSelected);
            Assert.Equal(1, clauseOfParent.SelectedItems.Count());

            // Level 1 of DerivedAncestors.
            derivedAncestors = Assert.Single(clauseOfParent.SelectedItems.OfType <ExpandedNavigationSelectItem>().Where(
                                                 item => item.PathToNavigationProperty.FirstSegment is NavigationPropertySegment &&
                                                 ((NavigationPropertySegment)item.PathToNavigationProperty.FirstSegment).NavigationProperty.Name == "DerivedAncestors"));
            Assert.Null(derivedAncestors.LevelsOption);

            clauseOfDerivedAncestors = derivedAncestors.SelectAndExpand;
            Assert.True(clauseOfDerivedAncestors.AllSelected);
            Assert.Equal(1, clauseOfDerivedAncestors.SelectedItems.Count());

            // Level 2 of DerivedAncestors.
            derivedAncestors = Assert.IsType <ExpandedNavigationSelectItem>(clauseOfDerivedAncestors.SelectedItems.Single());
            Assert.Equal(
                "DerivedAncestors",
                ((NavigationPropertySegment)derivedAncestors.PathToNavigationProperty.FirstSegment).NavigationProperty.Name);
            Assert.Null(derivedAncestors.LevelsOption);

            clauseOfDerivedAncestors = derivedAncestors.SelectAndExpand;
            Assert.True(clauseOfDerivedAncestors.AllSelected);
            Assert.Equal(0, clauseOfDerivedAncestors.SelectedItems.Count());
        }
        public void ProcessLevelsCorrectly_WithMultipleProperties()
        {
            // Arrange
            var model   = ODataLevelsTest.GetEdmModel();
            var context = new ODataQueryContext(
                model,
                model.FindDeclaredType("System.Web.OData.Routing.LevelsEntity"));
            var selectExpand = new SelectExpandQueryOption(
                select: null,
                expand: "Parent($expand=Parent($levels=max),DerivedAncestors($levels=2;$select=ID)),BaseEntities($levels=2)",
                context: context);

            selectExpand.LevelsMaxLiteralExpansionDepth = 3;

            // Act
            SelectExpandClause clause = selectExpand.ProcessLevels();

            // Assert
            Assert.True(clause.AllSelected);
            Assert.Equal(2, clause.SelectedItems.Count());

            // Top level Parent.
            var parent = Assert.Single(clause.SelectedItems.OfType <ExpandedNavigationSelectItem>().Where(
                                           item => item.PathToNavigationProperty.FirstSegment is NavigationPropertySegment &&
                                           ((NavigationPropertySegment)item.PathToNavigationProperty.FirstSegment).NavigationProperty.Name == "Parent"));

            Assert.Null(parent.LevelsOption);

            var clauseOfParent = parent.SelectAndExpand;

            Assert.True(clauseOfParent.AllSelected);
            Assert.Equal(2, clauseOfParent.SelectedItems.Count());

            // Level 1 of inline Parent.
            var inlineParent = Assert.Single(clauseOfParent.SelectedItems.OfType <ExpandedNavigationSelectItem>().Where(
                                                 item => item.PathToNavigationProperty.FirstSegment is NavigationPropertySegment &&
                                                 ((NavigationPropertySegment)item.PathToNavigationProperty.FirstSegment).NavigationProperty.Name == "Parent"));

            Assert.Null(inlineParent.LevelsOption);

            // Level 2 of inline Parent.
            var inlineParentClause = inlineParent.SelectAndExpand;

            Assert.True(inlineParentClause.AllSelected);
            Assert.Equal(1, inlineParentClause.SelectedItems.Count());

            inlineParent = Assert.IsType <ExpandedNavigationSelectItem>(inlineParentClause.SelectedItems.Single());
            Assert.Equal(
                "Parent",
                ((NavigationPropertySegment)inlineParent.PathToNavigationProperty.FirstSegment).NavigationProperty.Name);
            Assert.Null(inlineParent.LevelsOption);

            inlineParentClause = inlineParent.SelectAndExpand;
            Assert.True(inlineParentClause.AllSelected);
            Assert.Equal(0, inlineParentClause.SelectedItems.Count());

            // Level 1 of inline DerivedAncestors.
            var inlineDerivedAncestors = Assert.Single(clauseOfParent.SelectedItems.OfType <ExpandedNavigationSelectItem>().Where(
                                                           item => item.PathToNavigationProperty.FirstSegment is NavigationPropertySegment &&
                                                           ((NavigationPropertySegment)item.PathToNavigationProperty.FirstSegment).NavigationProperty.Name == "DerivedAncestors"));

            Assert.Null(inlineDerivedAncestors.LevelsOption);

            // Level 2 of inline DerivedAncestors.
            var inlineDerivedAncestorsClause = inlineDerivedAncestors.SelectAndExpand;

            Assert.False(inlineDerivedAncestorsClause.AllSelected);
            Assert.Equal(3, inlineDerivedAncestorsClause.SelectedItems.Count());

            var idItem = Assert.Single(inlineDerivedAncestorsClause.SelectedItems.OfType <PathSelectItem>().Where(
                                           item => item.SelectedPath.FirstSegment is PropertySegment));

            Assert.Equal("ID", ((PropertySegment)idItem.SelectedPath.FirstSegment).Property.Name);

            var derivedAncestorsItem = Assert.Single(inlineDerivedAncestorsClause.SelectedItems.OfType <PathSelectItem>().Where(
                                                         item => item.SelectedPath.FirstSegment is NavigationPropertySegment));

            Assert.Equal(
                "DerivedAncestors",
                ((NavigationPropertySegment)derivedAncestorsItem.SelectedPath.FirstSegment).NavigationProperty.Name);

            inlineDerivedAncestors = Assert.Single(inlineDerivedAncestorsClause.SelectedItems.OfType <ExpandedNavigationSelectItem>());
            Assert.Equal(
                "DerivedAncestors",
                ((NavigationPropertySegment)inlineDerivedAncestors.PathToNavigationProperty.FirstSegment).NavigationProperty.Name);
            Assert.Null(inlineDerivedAncestors.LevelsOption);

            inlineDerivedAncestorsClause = inlineDerivedAncestors.SelectAndExpand;
            Assert.False(inlineDerivedAncestorsClause.AllSelected);
            Assert.Equal(1, inlineDerivedAncestorsClause.SelectedItems.Count());

            idItem = Assert.Single(inlineDerivedAncestorsClause.SelectedItems.OfType <PathSelectItem>());
            Assert.Equal("ID", ((PropertySegment)idItem.SelectedPath.FirstSegment).Property.Name);

            // Level 1 of BaseEntities.
            var baseEntities = Assert.Single(clause.SelectedItems.OfType <ExpandedNavigationSelectItem>().Where(
                                                 item => item.PathToNavigationProperty.FirstSegment is NavigationPropertySegment &&
                                                 ((NavigationPropertySegment)item.PathToNavigationProperty.FirstSegment).NavigationProperty.Name == "BaseEntities"));

            Assert.Null(baseEntities.LevelsOption);

            // Level 2 of BaseEntities.
            var baseEntitiesClause = baseEntities.SelectAndExpand;

            Assert.True(baseEntitiesClause.AllSelected);
            Assert.Equal(1, baseEntitiesClause.SelectedItems.Count());

            baseEntities = Assert.IsType <ExpandedNavigationSelectItem>(baseEntitiesClause.SelectedItems.Single());
            Assert.Equal(
                "BaseEntities",
                ((NavigationPropertySegment)baseEntities.PathToNavigationProperty.FirstSegment).NavigationProperty.Name);
            Assert.Null(baseEntities.LevelsOption);

            baseEntitiesClause = baseEntities.SelectAndExpand;
            Assert.True(baseEntitiesClause.AllSelected);
            Assert.Equal(0, baseEntitiesClause.SelectedItems.Count());
        }
        public void ProcessLevelsCorrectly_NotAllSelected()
        {
            // Arrange
            var model   = ODataLevelsTest.GetEdmModel();
            var context = new ODataQueryContext(
                model,
                model.FindDeclaredType("System.Web.OData.Routing.LevelsEntity"));
            var selectExpand = new SelectExpandQueryOption(
                select: "Name",
                expand: "Parent($select=ID;$levels=max)",
                context: context);

            // Act
            SelectExpandClause clause = selectExpand.ProcessLevels();

            // Assert
            // Level 1.
            Assert.False(clause.AllSelected);
            Assert.Equal(3, clause.SelectedItems.Count());

            var nameSelectItem = Assert.Single(clause.SelectedItems.OfType <PathSelectItem>().Where(
                                                   item => item.SelectedPath.FirstSegment is PropertySegment));

            Assert.Equal("Name", ((PropertySegment)nameSelectItem.SelectedPath.FirstSegment).Property.Name);

            var parentSelectItem = Assert.Single(clause.SelectedItems.OfType <PathSelectItem>().Where(
                                                     item => item.SelectedPath.FirstSegment is NavigationPropertySegment));

            Assert.Equal(
                "Parent",
                ((NavigationPropertySegment)parentSelectItem.SelectedPath.FirstSegment).NavigationProperty.Name);

            var expandedItem = Assert.Single(clause.SelectedItems.OfType <ExpandedNavigationSelectItem>());

            Assert.Equal(
                "Parent",
                ((NavigationPropertySegment)expandedItem.PathToNavigationProperty.FirstSegment).NavigationProperty.Name);
            Assert.Null(expandedItem.LevelsOption);

            // Level 2.
            clause = expandedItem.SelectAndExpand;
            Assert.False(clause.AllSelected);
            Assert.Equal(3, clause.SelectedItems.Count());

            var idSelectItem = Assert.Single(clause.SelectedItems.OfType <PathSelectItem>().Where(
                                                 item => item.SelectedPath.FirstSegment is PropertySegment));

            Assert.Equal("ID", ((PropertySegment)idSelectItem.SelectedPath.FirstSegment).Property.Name);

            parentSelectItem = Assert.Single(clause.SelectedItems.OfType <PathSelectItem>().Where(
                                                 item => item.SelectedPath.FirstSegment is NavigationPropertySegment));
            Assert.Equal(
                "Parent",
                ((NavigationPropertySegment)parentSelectItem.SelectedPath.FirstSegment).NavigationProperty.Name);

            expandedItem = Assert.Single(clause.SelectedItems.OfType <ExpandedNavigationSelectItem>());
            Assert.Equal(
                "Parent",
                ((NavigationPropertySegment)expandedItem.PathToNavigationProperty.FirstSegment).NavigationProperty.Name);
            Assert.Null(expandedItem.LevelsOption);

            clause = expandedItem.SelectAndExpand;
            Assert.False(clause.AllSelected);
            Assert.Equal(1, clause.SelectedItems.Count());

            idSelectItem = Assert.IsType <PathSelectItem>(clause.SelectedItems.Single());
            Assert.Equal("ID", ((PropertySegment)idSelectItem.SelectedPath.FirstSegment).Property.Name);
        }
        public void ProcessLevelsCorrectly_AllSelected()
        {
            // Arrange
            var model = ODataLevelsTest.GetEdmModel();
            var context = new ODataQueryContext(
                model,
                model.FindDeclaredType("System.Web.OData.Routing.LevelsEntity"));
            var selectExpand = new SelectExpandQueryOption(
                select: null,
                expand: "Parent($expand=Parent($levels=2))",
                context: context);
            selectExpand.LevelsMaxLiteralExpansionDepth = 3;

            // Act
            SelectExpandClause clause = selectExpand.ProcessLevels();

            // Assert
            // Level 1.
            Assert.True(clause.AllSelected);
            Assert.Equal(1, clause.SelectedItems.Count());

            var item = Assert.IsType<ExpandedNavigationSelectItem>(clause.SelectedItems.Single());
            Assert.Equal(
                "Parent",
                ((NavigationPropertySegment)item.PathToNavigationProperty.FirstSegment).NavigationProperty.Name);
            Assert.Null(item.LevelsOption);

            // Level 2.
            clause = item.SelectAndExpand;
            Assert.True(clause.AllSelected);
            Assert.Equal(1, clause.SelectedItems.Count());

            item = Assert.IsType<ExpandedNavigationSelectItem>(clause.SelectedItems.Single());
            Assert.Equal(
                "Parent",
                ((NavigationPropertySegment)item.PathToNavigationProperty.FirstSegment).NavigationProperty.Name);
            Assert.Null(item.LevelsOption);

            // Level 3.
            clause = item.SelectAndExpand;
            Assert.True(clause.AllSelected);
            Assert.Equal(1, clause.SelectedItems.Count());

            item = Assert.IsType<ExpandedNavigationSelectItem>(clause.SelectedItems.Single());
            Assert.Equal(
                "Parent",
                ((NavigationPropertySegment)item.PathToNavigationProperty.FirstSegment).NavigationProperty.Name);
            Assert.Null(item.LevelsOption);

            clause = item.SelectAndExpand;
            Assert.True(clause.AllSelected);
            Assert.Equal(0, clause.SelectedItems.Count());
        }
Exemple #10
0
        private void BuildQueryOptions(IDictionary <string, string> queryParameters)
        {
            foreach (KeyValuePair <string, string> kvp in queryParameters)
            {
                switch (kvp.Key.ToLowerInvariant())
                {
                case "$filter":
                    ThrowIfEmpty(kvp.Value, "$filter");
                    RawValues.Filter = kvp.Value;
                    Filter           = new FilterQueryOption(kvp.Value, Context, _queryOptionParser);
                    break;

                case "$orderby":
                    ThrowIfEmpty(kvp.Value, "$orderby");
                    RawValues.OrderBy = kvp.Value;
                    OrderBy           = new OrderByQueryOption(kvp.Value, Context, _queryOptionParser);
                    break;

                case "$top":
                    ThrowIfEmpty(kvp.Value, "$top");
                    RawValues.Top = kvp.Value;
                    Top           = new TopQueryOption(kvp.Value, Context, _queryOptionParser);
                    break;

                case "$skip":
                    ThrowIfEmpty(kvp.Value, "$skip");
                    RawValues.Skip = kvp.Value;
                    Skip           = new SkipQueryOption(kvp.Value, Context, _queryOptionParser);
                    break;

                case "$select":
                    RawValues.Select = kvp.Value;
                    break;

                case "$count":
                    ThrowIfEmpty(kvp.Value, "$count");
                    RawValues.Count = kvp.Value;
                    Count           = new CountQueryOption(kvp.Value, Context, _queryOptionParser);
                    break;

                case "$expand":
                    RawValues.Expand = kvp.Value;
                    break;

                case "$format":
                    RawValues.Format = kvp.Value;
                    break;

                case "$skiptoken":
                    RawValues.SkipToken = kvp.Value;
                    break;

                case "$deltatoken":
                    RawValues.DeltaToken = kvp.Value;
                    break;

                case "$apply":
                    ThrowIfEmpty(kvp.Value, "$apply");
                    RawValues.Apply = kvp.Value;
                    Apply           = new ApplyQueryOption(kvp.Value, Context, _queryOptionParser);
                    break;

                default:
                    // we don't throw if we can't recognize the query
                    break;
                }
            }

            if (RawValues.Select != null || RawValues.Expand != null)
            {
                SelectExpand = new SelectExpandQueryOption(RawValues.Select, RawValues.Expand,
                                                           Context, _queryOptionParser);
            }

            if (ODataCountMediaTypeMapping.IsCountRequest(Request))
            {
                Count = new CountQueryOption(
                    "true",
                    Context,
                    new ODataQueryOptionParser(
                        Context.Model,
                        Context.ElementType,
                        Context.NavigationSource,
                        new Dictionary <string, string> {
                    { "$count", "true" }
                }));
            }
        }
Exemple #11
0
        /// <summary>
        /// Initializes a new instance of the <see cref="ODataQueryOptions"/> class based on the incoming request and some metadata information from
        /// the <see cref="ODataQueryContext"/>.
        /// </summary>
        /// <param name="context">The <see cref="ODataQueryContext"/> which contains the <see cref="IEdmModel"/> and some type information.</param>
        /// <param name="request">The incoming request message.</param>
        public ODataQueryOptions(ODataQueryContext context, HttpRequestMessage request)
        {
            if (context == null)
            {
                throw Error.ArgumentNull("context");
            }

            if (request == null)
            {
                throw Error.ArgumentNull("request");
            }

            if (request.GetConfiguration() != null)
            {
                _assembliesResolver = request.GetConfiguration().Services.GetAssembliesResolver();
            }

            // fallback to the default assemblies resolver if none available.
            _assembliesResolver = _assembliesResolver ?? new DefaultAssembliesResolver();

            // remember the context and request
            Context = context;
            Request = request;

            // Parse the query from request Uri
            RawValues = new ODataRawQueryOptions();
            IEnumerable <KeyValuePair <string, string> > queryParameters = request.GetQueryNameValuePairs();

            IDictionary <string, string> queryOptions = queryParameters.ToDictionary(p => p.Key, p => p.Value);

            _queryOptionParser = new ODataQueryOptionParser(context.Model, context.ElementType,
                                                            context.NavigationSource, queryOptions);

            foreach (KeyValuePair <string, string> kvp in queryParameters)
            {
                switch (kvp.Key)
                {
                case "$apply":
                    ThrowIfEmpty(kvp.Value, "$apply");
                    RawValues.Apply = kvp.Value;
                    Apply           = new ApplyQueryOption(context, _queryOptionParser);
                    break;

                case "aggregationWindowSize":
                    _aggregationWindowSize = int.Parse(kvp.Value);
                    break;

                case "$filter":
                    ThrowIfEmpty(kvp.Value, "$filter");
                    RawValues.Filter = kvp.Value;
                    Filter           = new FilterQueryOption(kvp.Value, context, _queryOptionParser);
                    break;

                case "$orderby":
                    ThrowIfEmpty(kvp.Value, "$orderby");
                    RawValues.OrderBy = kvp.Value;
                    OrderBy           = new OrderByQueryOption(kvp.Value, context, _queryOptionParser);
                    break;

                case "$top":
                    ThrowIfEmpty(kvp.Value, "$top");
                    RawValues.Top = kvp.Value;
                    Top           = new TopQueryOption(kvp.Value, context, _queryOptionParser);
                    break;

                case "$skip":
                    ThrowIfEmpty(kvp.Value, "$skip");
                    RawValues.Skip = kvp.Value;
                    Skip           = new SkipQueryOption(kvp.Value, context, _queryOptionParser);
                    break;

                case "$select":
                    RawValues.Select = kvp.Value;
                    break;

                case "$count":
                    ThrowIfEmpty(kvp.Value, "$count");
                    RawValues.Count = kvp.Value;
                    Count           = new CountQueryOption(kvp.Value, context, _queryOptionParser);
                    break;

                case "$expand":
                    RawValues.Expand = kvp.Value;
                    break;

                case "$format":
                    RawValues.Format = kvp.Value;
                    break;

                case "$skiptoken":
                    RawValues.SkipToken = kvp.Value;
                    break;

                default:
                    // we don't throw if we can't recognize the query
                    break;
                }
            }

            if (RawValues.Select != null || RawValues.Expand != null)
            {
                SelectExpand = new SelectExpandQueryOption(RawValues.Select, RawValues.Expand,
                                                           context, _queryOptionParser);
            }

            Validator = new ODataQueryValidator();
        }
        /// <summary>
        /// Apply the individual query to the given IQueryable in the right order.
        /// </summary>
        /// <param name="query">The original <see cref="IQueryable"/>.</param>
        /// <param name="querySettings">The settings to use in query composition.</param>
        /// <returns>The new <see cref="IQueryable"/> after the query has been applied to.</returns>
        public virtual IQueryable ApplyTo(IQueryable query, ODataQuerySettings querySettings)
        {
            if (query == null)
            {
                throw Error.ArgumentNull("query");
            }

            if (querySettings == null)
            {
                throw Error.ArgumentNull("querySettings");
            }

            IQueryable result = query;

            // Construct the actual query and apply them in the following order: filter, orderby, skip, top
            if (Filter != null)
            {
                result = Filter.ApplyTo(result, querySettings, _assembliesResolver);
            }

            if (Count != null)
            {
                if (Request.ODataProperties().TotalCount == null)
                {
                    long?count = Count.GetEntityCount(result);
                    if (count.HasValue)
                    {
                        Request.ODataProperties().TotalCount = count.Value;
                    }
                }

                if (ODataCountMediaTypeMapping.IsCountRequest(Request))
                {
                    return(result);
                }
            }

            OrderByQueryOption orderBy = OrderBy;

            // $skip or $top require a stable sort for predictable results.
            // Result limits require a stable sort to be able to generate a next page link.
            // If either is present in the query and we have permission,
            // generate an $orderby that will produce a stable sort.
            if (querySettings.EnsureStableOrdering &&
                (Skip != null || Top != null || querySettings.PageSize.HasValue))
            {
                // If there is no OrderBy present, we manufacture a default.
                // If an OrderBy is already present, we add any missing
                // properties necessary to make a stable sort.
                // Instead of failing early here if we cannot generate the OrderBy,
                // let the IQueryable backend fail (if it has to).
                orderBy = orderBy == null
                            ? GenerateDefaultOrderBy(Context)
                            : EnsureStableSortOrderBy(orderBy, Context);
            }

            if (orderBy != null)
            {
                result = orderBy.ApplyTo(result, querySettings);
            }

            if (Skip != null)
            {
                result = Skip.ApplyTo(result, querySettings);
            }

            if (Top != null)
            {
                result = Top.ApplyTo(result, querySettings);
            }

            if (SelectExpand != null)
            {
                SelectExpandClause      processedClause = SelectExpand.ProcessLevels();
                SelectExpandQueryOption newSelectExpand = new SelectExpandQueryOption(
                    SelectExpand.RawSelect,
                    SelectExpand.RawExpand,
                    SelectExpand.Context,
                    processedClause);

                Request.ODataProperties().SelectExpandClause = processedClause;
                result = newSelectExpand.ApplyTo(result, querySettings);
            }

            if (querySettings.PageSize.HasValue)
            {
                bool resultsLimited;
                result = LimitResults(result, querySettings.PageSize.Value, out resultsLimited);
                if (resultsLimited && Request.RequestUri != null && Request.RequestUri.IsAbsoluteUri && Request.ODataProperties().NextLink == null)
                {
                    Uri nextPageLink = GetNextPageLink(Request, querySettings.PageSize.Value);
                    Request.ODataProperties().NextLink = nextPageLink;
                }
            }

            return(result);
        }
        public void ProcessLevelsCorrectly_WithMaxNestedLevels()
        {
            // Arrange
            var model = ODataLevelsTest.GetEdmModel();
            var context = new ODataQueryContext(
                model,
                model.FindDeclaredType("System.Web.OData.Routing.LevelsEntity"));
            var selectExpand = new SelectExpandQueryOption(
                select: null,
                expand: "Parent($expand=DerivedAncestors($levels=max);$levels=2)",
                context: context);

            // Act
            SelectExpandClause clause = selectExpand.ProcessLevels();

            // Assert
            Assert.True(clause.AllSelected);
            Assert.Equal(1, clause.SelectedItems.Count());

            // Level 1 of Parent.
            var parent = Assert.IsType<ExpandedNavigationSelectItem>(clause.SelectedItems.Single());
            Assert.Equal(
                "Parent",
                ((NavigationPropertySegment)parent.PathToNavigationProperty.FirstSegment).NavigationProperty.Name);
            Assert.Null(parent.LevelsOption);

            var clauseOfParent = parent.SelectAndExpand;
            Assert.True(clauseOfParent.AllSelected);
            Assert.Equal(2, clauseOfParent.SelectedItems.Count());

            // Level 1 of DerivedAncestors.
            var derivedAncestors = Assert.Single(
                clauseOfParent.SelectedItems.OfType<ExpandedNavigationSelectItem>().Where(
                    item => item.PathToNavigationProperty.FirstSegment is NavigationPropertySegment &&
                    ((NavigationPropertySegment)item.PathToNavigationProperty.FirstSegment).NavigationProperty.Name == "DerivedAncestors")
                );
            Assert.Null(derivedAncestors.LevelsOption);

            var clauseOfDerivedAncestors = derivedAncestors.SelectAndExpand;
            Assert.True(clauseOfDerivedAncestors.AllSelected);
            Assert.Equal(0, clauseOfDerivedAncestors.SelectedItems.Count());

            // Level 2 of Parent.
            parent = Assert.Single(
                clauseOfParent.SelectedItems.OfType<ExpandedNavigationSelectItem>().Where(
                    item => item.PathToNavigationProperty.FirstSegment is NavigationPropertySegment &&
                    ((NavigationPropertySegment)item.PathToNavigationProperty.FirstSegment).NavigationProperty.Name == "Parent")
                );
            Assert.Null(parent.LevelsOption);

            clauseOfParent = parent.SelectAndExpand;
            Assert.True(clauseOfParent.AllSelected);
            Assert.Equal(0, clauseOfParent.SelectedItems.Count());
        }
        public void ProcessLevelsCorrectly_WithMultipleProperties()
        {
            // Arrange
            var model = ODataLevelsTest.GetEdmModel();
            var context = new ODataQueryContext(
                model,
                model.FindDeclaredType("System.Web.OData.Routing.LevelsEntity"));
            var selectExpand = new SelectExpandQueryOption(
                select: null,
                expand: "Parent($expand=Parent($levels=max),DerivedAncestors($levels=2;$select=ID)),BaseEntities($levels=2)",
                context: context);
            selectExpand.LevelsMaxLiteralExpansionDepth = 3;

            // Act
            SelectExpandClause clause = selectExpand.ProcessLevels();

            // Assert
            Assert.True(clause.AllSelected);
            Assert.Equal(2, clause.SelectedItems.Count());

            // Top level Parent.
            var parent = Assert.Single(clause.SelectedItems.OfType<ExpandedNavigationSelectItem>().Where(
                item => item.PathToNavigationProperty.FirstSegment is NavigationPropertySegment &&
                ((NavigationPropertySegment)item.PathToNavigationProperty.FirstSegment).NavigationProperty.Name == "Parent"));
            Assert.Null(parent.LevelsOption);

            var clauseOfParent = parent.SelectAndExpand;
            Assert.True(clauseOfParent.AllSelected);
            Assert.Equal(2, clauseOfParent.SelectedItems.Count());

            // Level 1 of inline Parent.
            var inlineParent = Assert.Single(clauseOfParent.SelectedItems.OfType<ExpandedNavigationSelectItem>().Where(
                item => item.PathToNavigationProperty.FirstSegment is NavigationPropertySegment &&
                ((NavigationPropertySegment)item.PathToNavigationProperty.FirstSegment).NavigationProperty.Name == "Parent"));
            Assert.Null(inlineParent.LevelsOption);

            // Level 2 of inline Parent.
            var inlineParentClause = inlineParent.SelectAndExpand;
            Assert.True(inlineParentClause.AllSelected);
            Assert.Equal(1, inlineParentClause.SelectedItems.Count());

            inlineParent = Assert.IsType<ExpandedNavigationSelectItem>(inlineParentClause.SelectedItems.Single());
            Assert.Equal(
                "Parent",
                ((NavigationPropertySegment)inlineParent.PathToNavigationProperty.FirstSegment).NavigationProperty.Name);
            Assert.Null(inlineParent.LevelsOption);

            inlineParentClause = inlineParent.SelectAndExpand;
            Assert.True(inlineParentClause.AllSelected);
            Assert.Equal(0, inlineParentClause.SelectedItems.Count());

            // Level 1 of inline DerivedAncestors.
            var inlineDerivedAncestors = Assert.Single(clauseOfParent.SelectedItems.OfType<ExpandedNavigationSelectItem>().Where(
                item => item.PathToNavigationProperty.FirstSegment is NavigationPropertySegment &&
                ((NavigationPropertySegment)item.PathToNavigationProperty.FirstSegment).NavigationProperty.Name == "DerivedAncestors"));
            Assert.Null(inlineDerivedAncestors.LevelsOption);

            // Level 2 of inline DerivedAncestors.
            var inlineDerivedAncestorsClause = inlineDerivedAncestors.SelectAndExpand;
            Assert.False(inlineDerivedAncestorsClause.AllSelected);
            Assert.Equal(3, inlineDerivedAncestorsClause.SelectedItems.Count());

            var idItem = Assert.Single(inlineDerivedAncestorsClause.SelectedItems.OfType<PathSelectItem>().Where(
               item => item.SelectedPath.FirstSegment is PropertySegment));
            Assert.Equal("ID", ((PropertySegment)idItem.SelectedPath.FirstSegment).Property.Name);

            var derivedAncestorsItem = Assert.Single(inlineDerivedAncestorsClause.SelectedItems.OfType<PathSelectItem>().Where(
               item => item.SelectedPath.FirstSegment is NavigationPropertySegment));
            Assert.Equal(
                "DerivedAncestors",
                ((NavigationPropertySegment)derivedAncestorsItem.SelectedPath.FirstSegment).NavigationProperty.Name);

            inlineDerivedAncestors = Assert.Single(inlineDerivedAncestorsClause.SelectedItems.OfType<ExpandedNavigationSelectItem>());
            Assert.Equal(
                "DerivedAncestors",
                ((NavigationPropertySegment)inlineDerivedAncestors.PathToNavigationProperty.FirstSegment).NavigationProperty.Name);
            Assert.Null(inlineDerivedAncestors.LevelsOption);

            inlineDerivedAncestorsClause = inlineDerivedAncestors.SelectAndExpand;
            Assert.False(inlineDerivedAncestorsClause.AllSelected);
            Assert.Equal(1, inlineDerivedAncestorsClause.SelectedItems.Count());

            idItem = Assert.Single(inlineDerivedAncestorsClause.SelectedItems.OfType<PathSelectItem>());
            Assert.Equal("ID", ((PropertySegment)idItem.SelectedPath.FirstSegment).Property.Name);

            // Level 1 of BaseEntities.
            var baseEntities = Assert.Single(clause.SelectedItems.OfType<ExpandedNavigationSelectItem>().Where(
                item => item.PathToNavigationProperty.FirstSegment is NavigationPropertySegment &&
                ((NavigationPropertySegment)item.PathToNavigationProperty.FirstSegment).NavigationProperty.Name == "BaseEntities"));
            Assert.Null(baseEntities.LevelsOption);

            // Level 2 of BaseEntities.
            var baseEntitiesClause = baseEntities.SelectAndExpand;
            Assert.True(baseEntitiesClause.AllSelected);
            Assert.Equal(1, baseEntitiesClause.SelectedItems.Count());

            baseEntities = Assert.IsType<ExpandedNavigationSelectItem>(baseEntitiesClause.SelectedItems.Single());
            Assert.Equal(
                "BaseEntities",
                ((NavigationPropertySegment)baseEntities.PathToNavigationProperty.FirstSegment).NavigationProperty.Name);
            Assert.Null(baseEntities.LevelsOption);

            baseEntitiesClause = baseEntities.SelectAndExpand;
            Assert.True(baseEntitiesClause.AllSelected);
            Assert.Equal(0, baseEntitiesClause.SelectedItems.Count());
        }
        public void ProcessLevelsCorrectly_NotAllSelected()
        {
            // Arrange
            var model = ODataLevelsTest.GetEdmModel();
            var context = new ODataQueryContext(
                model,
                model.FindDeclaredType("System.Web.OData.Routing.LevelsEntity"));
            var selectExpand = new SelectExpandQueryOption(
                select: "Name",
                expand: "Parent($select=ID;$levels=max)",
                context: context);

            // Act
            SelectExpandClause clause = selectExpand.ProcessLevels();

            // Assert
            // Level 1.
            Assert.False(clause.AllSelected);
            Assert.Equal(3, clause.SelectedItems.Count());

            var nameSelectItem = Assert.Single(clause.SelectedItems.OfType<PathSelectItem>().Where(
                item => item.SelectedPath.FirstSegment is PropertySegment));
            Assert.Equal("Name", ((PropertySegment)nameSelectItem.SelectedPath.FirstSegment).Property.Name);

            var parentSelectItem = Assert.Single(clause.SelectedItems.OfType<PathSelectItem>().Where(
                item => item.SelectedPath.FirstSegment is NavigationPropertySegment));
            Assert.Equal(
                "Parent",
                ((NavigationPropertySegment)parentSelectItem.SelectedPath.FirstSegment).NavigationProperty.Name);

            var expandedItem = Assert.Single(clause.SelectedItems.OfType<ExpandedNavigationSelectItem>());
            Assert.Equal(
                "Parent",
                ((NavigationPropertySegment)expandedItem.PathToNavigationProperty.FirstSegment).NavigationProperty.Name);
            Assert.Null(expandedItem.LevelsOption);

            // Level 2.
            clause = expandedItem.SelectAndExpand;
            Assert.False(clause.AllSelected);
            Assert.Equal(3, clause.SelectedItems.Count());

            var idSelectItem = Assert.Single(clause.SelectedItems.OfType<PathSelectItem>().Where(
                item => item.SelectedPath.FirstSegment is PropertySegment));
            Assert.Equal("ID", ((PropertySegment)idSelectItem.SelectedPath.FirstSegment).Property.Name);

            parentSelectItem = Assert.Single(clause.SelectedItems.OfType<PathSelectItem>().Where(
                item => item.SelectedPath.FirstSegment is NavigationPropertySegment));
            Assert.Equal(
                "Parent",
                ((NavigationPropertySegment)parentSelectItem.SelectedPath.FirstSegment).NavigationProperty.Name);

            expandedItem = Assert.Single(clause.SelectedItems.OfType<ExpandedNavigationSelectItem>());
            Assert.Equal(
                "Parent",
                ((NavigationPropertySegment)expandedItem.PathToNavigationProperty.FirstSegment).NavigationProperty.Name);
            Assert.Null(expandedItem.LevelsOption);

            clause = expandedItem.SelectAndExpand;
            Assert.False(clause.AllSelected);
            Assert.Equal(1, clause.SelectedItems.Count());

            idSelectItem = Assert.IsType<PathSelectItem>(clause.SelectedItems.Single());
            Assert.Equal("ID", ((PropertySegment)idSelectItem.SelectedPath.FirstSegment).Property.Name);
        }
        public void SelectExpandClause_Property_ParsesRawSelectAndRawExpand()
        {
            // Arrange
            IEdmModel model = _model.Model;
            _model.Model.SetAnnotationValue<ClrTypeAnnotation>(_model.Customer, new ClrTypeAnnotation(typeof(Customer)));
            ODataQueryContext context = new ODataQueryContext(model, typeof(Customer));
            SelectExpandQueryOption option = new SelectExpandQueryOption("ID,Name,SimpleEnum,Orders", "Orders", context);

            // Act
            SelectExpandClause selectExpandClause = option.SelectExpandClause;

            // Assert
            Assert.NotEmpty(selectExpandClause.SelectedItems.OfType<PathSelectItem>());
            Assert.NotEmpty(selectExpandClause.SelectedItems.OfType<ExpandedNavigationSelectItem>());
        }
        public void SelectExpandClause_Property_ParsesWithEdmTypeAndNavigationSource()
        {
            // Arrange
            IEdmModel model = _model.Model;
            _model.Model.SetAnnotationValue(_model.Customer, new ClrTypeAnnotation(typeof(Customer)));
            ODataPath odataPath = new ODataPath(new EntitySetPathSegment(_model.Customers));
            ODataQueryContext context = new ODataQueryContext(model, _model.Customer, odataPath);
            SelectExpandQueryOption option = new SelectExpandQueryOption("ID,Name,SimpleEnum,Orders", "Orders", context);

            // Act
            SelectExpandClause selectExpandClause = option.SelectExpandClause;

            // Assert
            Assert.NotEmpty(selectExpandClause.SelectedItems.OfType<PathSelectItem>());
            Assert.NotEmpty(selectExpandClause.SelectedItems.OfType<ExpandedNavigationSelectItem>());
        }