Beispiel #1
0
        private void ParseUriAndVerify(
            Uri uri,
            Action <ODataPath, FilterClause, OrderByClause, SelectExpandClause, IDictionary <string, SingleValueNode> > verifyAction)
        {
            // run 2 test passes:
            // 1. low level api - ODataUriParser instance methods
            {
                List <CustomQueryOptionToken> queries = UriUtils.ParseQueryOptions(uri);
                ODataUriParser parser = new ODataUriParser(HardCodedTestModel.TestModel, new Uri("http://gobbledygook/"), uri);

                ODataPath            path         = parser.ParsePath();
                IEdmNavigationSource entitySource = ResolveEntitySource(path);
                IEdmEntitySet        entitySet    = entitySource as IEdmEntitySet;

                var dic = queries.ToDictionary(customQueryOptionToken => customQueryOptionToken.Name, customQueryOptionToken => queries.GetQueryOptionValue(customQueryOptionToken.Name));
                ODataQueryOptionParser queryOptionParser = new ODataQueryOptionParser(HardCodedTestModel.TestModel, entitySet.EntityType(), entitySet, dic)
                {
                    Configuration = { ParameterAliasValueAccessor = parser.ParameterAliasValueAccessor }
                };

                FilterClause       filterClause       = queryOptionParser.ParseFilter();
                SelectExpandClause selectExpandClause = queryOptionParser.ParseSelectAndExpand();
                OrderByClause      orderByClause      = queryOptionParser.ParseOrderBy();

                // Two parser should share same ParameterAliasNodes
                verifyAction(path, filterClause, orderByClause, selectExpandClause, parser.ParameterAliasNodes);
                verifyAction(path, filterClause, orderByClause, selectExpandClause, queryOptionParser.ParameterAliasNodes);
            }

            //2. high level api - ParseUri
            {
                ODataUriParser parser = new ODataUriParser(HardCodedTestModel.TestModel, new Uri("http://gobbledygook/"), uri);
                verifyAction(parser.ParsePath(), parser.ParseFilter(), parser.ParseOrderBy(), parser.ParseSelectAndExpand(), parser.ParameterAliasNodes);
            }
        }
        public void QueryOptionWithNullValueShouldWork()
        {
            var uriParser = new ODataQueryOptionParser(HardCodedTestModel.TestModel, HardCodedTestModel.GetPersonType(), HardCodedTestModel.GetPeopleSet(), new Dictionary <string, string>()
            {
                { "$filter", null },
                { "$expand", null },
                { "$select", null },
                { "$orderby", null },
                { "$top", null },
                { "$skip", null },
                { "index", null },
                { "$count", null },
                { "$search", null },
                { "$compute", null },
                { "$unknow", null },
            });

            uriParser.ParseFilter().Should().BeNull();
            uriParser.ParseSelectAndExpand().Should().BeNull();
            uriParser.ParseOrderBy().Should().BeNull();
            uriParser.ParseTop().Should().Be(null);
            uriParser.ParseSkip().Should().Be(null);
            uriParser.ParseIndex().Should().Be(null);
            uriParser.ParseCount().Should().Be(null);
            uriParser.ParseSearch().Should().BeNull();
            uriParser.ParseCompute().Should().BeNull();
        }
Beispiel #3
0
        public void CreatePropertyValueExpressionWithFilter_Single_Works_IfSettingIsOff()
        {
            // Arrange
            _settings.HandleReferenceNavigationPropertyExpandFilter = false;
            var order = Expression.Constant(
                new Order
            {
                Customer = new Customer
                {
                    ID = 1
                }
            }
                );
            var customerProperty = _model.Order.NavigationProperties().Single(p => p.Name == "Customer");

            var parser = new ODataQueryOptionParser(
                _model.Model,
                _model.Customer,
                _model.Customers,
                new Dictionary <string, string> {
                { "$filter", "ID ne 1" }
            });
            var filterCaluse = parser.ParseFilter();

            // Act
            var filterInExpand = _binder.CreatePropertyValueExpressionWithFilter(_model.Order, customerProperty, order, filterCaluse);

            // Assert
            var customer = Expression.Lambda(filterInExpand).Compile().DynamicInvoke() as Customer;

            Assert.NotNull(customer);
            Assert.Equal(1, customer.ID);
        }
        public void QueryOptionWithEmptyValueShouldWork()
        {
            var uriParser = new ODataQueryOptionParser(HardCodedTestModel.TestModel, HardCodedTestModel.GetPersonType(), HardCodedTestModel.GetPeopleSet(), new Dictionary <string, string>()
            {
                { "$filter", "" },
                { "$expand", "" },
                { "$select", "" },
                { "$orderby", "" },
                { "$top", "" },
                { "$skip", "" },
                { "$count", "" },
                { "$search", "" },
                { "$unknow", "" },
            });

            uriParser.ParseFilter().Should().BeNull();
            var results = uriParser.ParseSelectAndExpand();

            results.AllSelected.Should().BeTrue();
            results.SelectedItems.Should().HaveCount(0);
            uriParser.ParseOrderBy().Should().BeNull();
            Action action = () => uriParser.ParseTop();

            action.ShouldThrow <ODataException>().WithMessage(Strings.SyntacticTree_InvalidTopQueryOptionValue(""));
            action = () => uriParser.ParseSkip();
            action.ShouldThrow <ODataException>().WithMessage(Strings.SyntacticTree_InvalidSkipQueryOptionValue(""));
            action = () => uriParser.ParseCount();
            action.ShouldThrow <ODataException>().WithMessage(Strings.ODataUriParser_InvalidCount(""));
            action = () => uriParser.ParseSearch();
            action.ShouldThrow <ODataException>().WithMessage(Strings.UriQueryExpressionParser_ExpressionExpected(0, ""));
        }
Beispiel #5
0
        public void CreatePropertyValueExpressionWithFilter_Collection_ThrowsODataException_IfMappingTypeIsNotFoundInModel()
        {
            // Arrange
            _model.Model.SetAnnotationValue <ClrTypeAnnotation>(_model.Order, value: null);
            var customer       = Expression.Constant(new Customer());
            var ordersProperty = _model.Customer.NavigationProperties().Single(p => p.Name == "Orders");
            var parser         = new ODataQueryOptionParser(
                _model.Model,
                _model.Order,
                _model.Orders,
                new Dictionary <string, string> {
                { "$filter", "ID eq 1" }
            });
            var filterCaluse = parser.ParseFilter();

            // Act & Assert
            ExceptionAssert.Throws <ODataException>(
                () => _binder.CreatePropertyValueExpressionWithFilter(_model.Customer, ordersProperty, customer, filterCaluse),
                "The provided mapping does not contain a resource for the resource type 'NS.Order'.");

            // NetFx and NetCore differ in the way Expression is converted to a string.
            //Assert.Equal(ExpressionType.Convert, property.NodeType);
            //var unaryExpression = (property as UnaryExpression);
            //Assert.NotNull(unaryExpression);
            //Assert.Equal(String.Format("{0}.ID", customer.ToString()), unaryExpression.Operand.ToString());
            //Assert.Equal(typeof(int?), unaryExpression.Type);
        }
        public static FilterClause GetFilterClause <T>(IDictionary <string, string> queryOptions, IServiceProvider serviceProvider, bool useFilterOption = false) where T : class
        {
            IEdmModel      model       = GetModel <T>(serviceProvider);
            IEdmEntityType productType = model.SchemaElements.OfType <IEdmEntityType>().Single(t => t.Name == typeof(T).Name);
            IEdmEntitySet  entitySet   = model.EntityContainer.FindEntitySet(typeof(T).Name);

            ODataQueryOptionParser parser = new ODataQueryOptionParser
                                            (
                model,
                productType,
                entitySet,
                queryOptions
                                            );

            if (useFilterOption)
            {
                return(GetFilterClauseFromFilterOption
                       (
                           model,
                           entitySet,
                           parser,
                           queryOptions["$filter"]
                       ));
            }

            return(parser.ParseFilter());
        }
        public void EmptyQueryOptionDictionaryShouldWork()
        {
            var uriParser = new ODataQueryOptionParser(HardCodedTestModel.TestModel, HardCodedTestModel.GetPersonType(), HardCodedTestModel.GetPeopleSet(), new Dictionary <string, string>());

            uriParser.ParseFilter().Should().BeNull();
            uriParser.ParseSelectAndExpand().Should().BeNull();
            uriParser.ParseOrderBy().Should().BeNull();
            uriParser.ParseTop().Should().Be(null);
            uriParser.ParseSkip().Should().Be(null);
            uriParser.ParseCount().Should().Be(null);
            uriParser.ParseSearch().Should().BeNull();
        }
        private QueryNode TranslateFilterExpression(string filter)
        {
            var parser = new ODataQueryOptionParser(_model, _customerEntityType, _customersEntitySet,
                                                    new Dictionary <string, string> {
                { "$filter", filter }
            });
            FilterClause filterClause = parser.ParseFilter();
            var          translator   = new ParameterAliasNodeTranslator(
                new Dictionary <string, SingleValueNode> {
                { "@p", _parameterAliasMappedNode }
            });
            QueryNode translatedNode = filterClause.Expression.Accept(translator);

            return(translatedNode);
        }
Beispiel #9
0
        private static QueryClause CreateQueryClause(string query, IEdmModel model, Type type)
        {
            IEdmEntityType entityType = model.SchemaElements.OfType <IEdmEntityType>().Single(t => t.Name == type.Name);

            Assert.NotNull(entityType); // Guard

            IEdmEntitySet entitySet = model.EntityContainer.FindEntitySet("Customers");

            Assert.NotNull(entitySet); // Guard

            string[] queryItems = query.Split('&');

            Dictionary <string, string> queries = new Dictionary <string, string>();

            foreach (string item in queryItems)
            {
                if (item.StartsWith("$select=", StringComparison.Ordinal))
                {
                    queries["$select"] = item.Substring(8);
                }
                else if (item.StartsWith("$expand=", StringComparison.Ordinal))
                {
                    queries["$expand"] = item.Substring(8);
                }
                else if (item.StartsWith("$filter=", StringComparison.Ordinal))
                {
                    queries["$filter"] = item.Substring(8);
                }
                else if (item.StartsWith("$orderby=", StringComparison.Ordinal))
                {
                    queries["$orderby"] = item.Substring(9);
                }
                else if (item.StartsWith("$compute=", StringComparison.Ordinal))
                {
                    queries["$compute"] = item.Substring(9);
                }
            }

            ODataQueryOptionParser parser = new ODataQueryOptionParser(model, entityType, entitySet, queries);

            return(new QueryClause
            {
                Filter = parser.ParseFilter(),
                OrderBy = parser.ParseOrderBy(),
                SelectExpand = parser.ParseSelectAndExpand(),
                Compute = parser.ParseCompute()
            });
        }
Beispiel #10
0
        private static FilterClause CreateFilterClause(string filter, IEdmModel model, Type type)
        {
            IEdmEntityType entityType = model.SchemaElements.OfType <IEdmEntityType>().Single(t => t.Name == type.Name);

            Assert.NotNull(entityType); // Guard

            IEdmEntitySet entitySet = model.EntityContainer.FindEntitySet("Products");

            Assert.NotNull(entitySet); // Guard

            ODataQueryOptionParser parser = new ODataQueryOptionParser(model, entityType, entitySet,
                                                                       new Dictionary <string, string> {
                { "$filter", filter }
            });

            return(parser.ParseFilter());
        }
Beispiel #11
0
        public void CreatePropertyValueExpressionWithFilter_Collection_Works_HandleNullPropagationOptionIsTrue()
        {
            // Arrange
            _model.Model.SetAnnotationValue(_model.Order, new ClrTypeAnnotation(typeof(Order)));
            _settings.HandleNullPropagation = HandleNullPropagationOption.True;
            var customer =
                Expression.Constant(new Customer {
                Orders = new[] { new Order {
                                     ID = 1
                                 }, new Order {
                                     ID = 2
                                 } }
            });
            var ordersProperty = _model.Customer.NavigationProperties().Single(p => p.Name == "Orders");
            var parser         = new ODataQueryOptionParser(
                _model.Model,
                _model.Order,
                _model.Orders,
                new Dictionary <string, string> {
                { "$filter", "ID eq 1" }
            });
            var filterCaluse = parser.ParseFilter();

            // Act
            var filterInExpand = _binder.CreatePropertyValueExpressionWithFilter(
                _model.Customer,
                ordersProperty,
                customer,
                filterCaluse);

            // Assert
            Assert.Equal(
                string.Format(
                    "IIF((value({0}) == null), null, IIF((value({0}).Orders == null), null, " +
                    "value({0}).Orders.AsQueryable().Where($it => ($it.ID == value({1}).TypedProperty))))",
                    customer.Type,
                    "Microsoft.AspNet.OData.Query.Expressions.LinqParameterContainer+TypedLinqParameterContainer`1[System.Int32]"),
                filterInExpand.ToString());
            var orders = Expression.Lambda(filterInExpand).Compile().DynamicInvoke() as IEnumerable <Order>;

            Assert.Single(orders);
            Assert.Equal(1, orders.ToList()[0].ID);
        }
Beispiel #12
0
        private FilterClause CreateFilterClause(string filterExpression)
        {
            const string uriBase = "http://service/";

            Uri            uri       = new Uri(uriBase + "Pet1Set?$filter=" + filterExpression);
            ODataUriParser parser    = new ODataUriParser(HardCodedTestModel.TestModel, new Uri(uriBase), uri);
            IEdmEntitySet  entitySet = HardCodedTestModel.GetPet1Set();

            Dictionary <string, string> queryOptions = new Dictionary <string, string>()
            {
                { "$filter", filterExpression }
            };

            // Use query option parser to help create the filter because it takes care of a bunch of instantiations
            ODataQueryOptionParser queryOptionParser =
                new ODataQueryOptionParser(HardCodedTestModel.TestModel, entitySet.EntityType(), entitySet, queryOptions);

            return(queryOptionParser.ParseFilter());
        }
        public void CreatePropertyValueExpressionWithFilter_ThrowsODataException_IfMappingTypeIsNotFoundInModel()
        {
            // Arrange
            _model.Model.SetAnnotationValue <ClrTypeAnnotation>(_model.Order, value: null);
            var customer       = Expression.Constant(new Customer());
            var ordersProperty = _model.Customer.NavigationProperties().Single(p => p.Name == "Orders");
            var parser         = new ODataQueryOptionParser(
                _model.Model,
                _model.Order,
                _model.Orders,
                new Dictionary <string, string> {
                { "$filter", "ID eq 1" }
            });
            var filterCaluse = parser.ParseFilter();

            // Act & Assert
            Assert.Throws <ODataException>(
                () => _binder.CreatePropertyValueExpressionWithFilter(_model.Customer, ordersProperty, customer, filterCaluse),
                "The provided mapping does not contain an entry for the entity type 'NS.Order'.");
        }
Beispiel #14
0
        public void CreatePropertyValueExpressionWithFilter_Single_Works_HandleNullPropagationOptionIsTrue()
        {
            // Arrange
            _settings.HandleReferenceNavigationPropertyExpandFilter = true;
            _settings.HandleNullPropagation = HandleNullPropagationOption.True;
            var order = Expression.Constant(
                new Order
            {
                Customer = new Customer
                {
                    ID = 1
                }
            }
                );
            var customerProperty = _model.Order.NavigationProperties().Single(p => p.Name == "Customer");

            var parser = new ODataQueryOptionParser(
                _model.Model,
                _model.Customer,
                _model.Customers,
                new Dictionary <string, string> {
                { "$filter", "ID ne 1" }
            });
            var filterCaluse = parser.ParseFilter();

            // Act
            var filterInExpand = _binder.CreatePropertyValueExpressionWithFilter(_model.Order, customerProperty, order, filterCaluse);

            // Assert
            Assert.Equal(
                string.Format(
                    "IIF((value({0}) == null), null, IIF((value({0}).Customer == null), null, " +
                    "IIF((value({0}).Customer.ID != value(Microsoft.AspNet.OData.Query.Expressions.LinqParameterContainer+TypedLinqParameterContainer`1[System.Int32]).TypedProperty), " +
                    "value({0}).Customer, null)))",
                    order.Type),
                filterInExpand.ToString());
            var customer = Expression.Lambda(filterInExpand).Compile().DynamicInvoke() as Customer;

            Assert.Null(customer);
        }
        /// <summary>
        /// Apply $filter parameter to query.
        /// </summary>
        /// <param name="query">
        /// The OData aware query.
        /// </param>
        /// <param name="filterText">
        /// The $filter parameter text.
        /// </param>
        /// <param name="entitySetName">
        /// The entity set name.
        /// </param>
        /// <typeparam name="T">
        /// The query type param
        /// </typeparam>
        /// <returns>
        /// The <see cref="ODataQuery{T}"/> query with applied filter parameter.
        /// </returns>
        /// <exception cref="ArgumentNullException">
        /// Argument Null Exception
        /// </exception>
        public static ODataQuery <T> Filter <T>(this ODataQuery <T> query, string filterText, string entitySetName = null)
        {
            if (query == null)
            {
                throw new ArgumentNullException(nameof(query));
            }
            if (filterText == null)
            {
                throw new ArgumentNullException(nameof(filterText));
            }

            IEdmModel edmModel = query.EdmModel;

            ODataQueryOptionParser queryOptionParser = GetParser(
                query,
                entitySetName,
                new Dictionary <string, string> {
                { "$filter", filterText }
            });

            ODataSettings settings = query.ServiceProvider.GetRequiredService <ODataSettings>();

            FilterClause    filterClause     = queryOptionParser.ParseFilter();
            SingleValueNode filterExpression = filterClause.Expression.Accept(
                new ParameterAliasNodeTranslator(queryOptionParser.ParameterAliasNodes)) as SingleValueNode;

            filterExpression = filterExpression ?? new ConstantNode(null);
            filterClause     = new FilterClause(filterExpression, filterClause.RangeVariable);
            Contract.Assert(filterClause != null);

            var validator = new FilterQueryValidator(settings.DefaultQuerySettings);

            validator.Validate(filterClause, settings.ValidationSettings, edmModel);

            Expression filter = FilterBinder.Bind(query, filterClause, typeof(T), query.ServiceProvider);
            var        result = ExpressionHelpers.Where(query, filter, typeof(T));

            return(new ODataQuery <T>(result, query.ServiceProvider));
        }
        public QueryDescription <T> Parse <T>()
        {
            var model    = GetCachedEdmModel(typeof(T));
            var entities = model.FindDeclaredNavigationSource("Entities");
            var parser   = new ODataQueryOptionParser(model, entities.EntityType(),
                                                      entities, Dictionary);

            var filter  = Filter == null ? null : parser.ParseFilter();
            var orderby = OrderBy == null ? null : parser.ParseOrderBy();
            var search  = Search == null ? null : parser.ParseSearch();
            var apply   = Apply == null ? null : parser.ParseApply();

            var result = new QueryDescription <T>()
            {
                Skip     = Skip == null ? 0 : parser.ParseSkip() ?? 0,
                Take     = Top == null ? null : parser.ParseTop(),
                Filter   = ParseFilter(filter),
                Sorting  = ParseOrderBy(orderby),
                Search   = ParseSearch(search),
                Grouping = ParseApply(apply)
            };

            if (result.Take == null)
            {
                result.Page = result.Skip == 0 ? 1 : 2;
            }
            else
            {
                result.Page = (result.Skip / result.Take.Value) + 1;
                if (result.Skip % result.Take.Value > 0)
                {
                    result.Page++;
                }
            }
            return(result);
        }