/// <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");
            }

            // remember the context
            Context = context;

            // Parse the query from request Uri
            RawValues = new ODataRawQueryOptions();
            IEnumerable<KeyValuePair<string, string>> queryParameters = request.GetQueryNameValuePairs();
            foreach (KeyValuePair<string, string> kvp in queryParameters)
            {
                switch (kvp.Key)
                {
                    case "$filter":
                        RawValues.Filter = kvp.Value;
                        ThrowIfEmpty(kvp.Value, "$filter");
                        Filter = new FilterQueryOption(kvp.Value, context);
                        break;
                    case "$orderby":
                        RawValues.OrderBy = kvp.Value;
                        ThrowIfEmpty(kvp.Value, "$orderby");
                        OrderBy = new OrderByQueryOption(kvp.Value, context);
                        break;
                    case "$top":
                        RawValues.Top = kvp.Value;
                        ThrowIfEmpty(kvp.Value, "$top");
                        Top = new TopQueryOption(kvp.Value, context);
                        break;
                    case "$skip":
                        RawValues.Skip = kvp.Value;
                        ThrowIfEmpty(kvp.Value, "$skip");
                        Skip = new SkipQueryOption(kvp.Value, context);
                        break;
                    case "$select":
                        RawValues.Select = kvp.Value;
                        break;
                    case "$inlinecount":
                        RawValues.InlineCount = kvp.Value;
                        break;
                    case "$expand":
                        RawValues.Expand = kvp.Value;
                        break;
                    case "$skiptoken":
                        RawValues.SkipToken = kvp.Value;
                        break;
                    default:
                        // we don't throw if we can't recognize the query
                        break;
                }
            }
        }
        public static string BindOrderByQueryOption(OrderByQueryOption orderByQuery)
        {
            StringBuilder sb = new StringBuilder();

            if (orderByQuery != null)
            {
                sb.Append("order by ");
                foreach (var orderByNode in orderByQuery.OrderByNodes)
                {
                    var orderByPropertyNode = orderByNode as OrderByPropertyNode;

                    if (orderByPropertyNode != null)
                    {
                        sb.Append(orderByPropertyNode.Property.Name);
                        sb.Append(orderByPropertyNode.Direction == OrderByDirection.Ascending ? " asc," : " desc,");
                    }
                    else
                    {
                        throw new ODataException("Only ordering by properties is supported");
                    }
                }
            }

            if (sb[sb.Length - 1] == ',')
            {
                sb.Remove(sb.Length - 1, 1);
            }

            return sb.ToString();
        }
        public virtual void Validate(OrderByQueryOption orderByOption, ODataValidationSettings validationSettings)
        {
            if (orderByOption == null)
            {
                throw Error.ArgumentNull("orderByOption");
            }

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

            if (validationSettings.AllowedOrderByProperties.Count > 0)
            {
                ICollection<OrderByPropertyNode> propertyNodes = orderByOption.PropertyNodes;

                foreach (OrderByPropertyNode property in propertyNodes)
                {
                    if (!validationSettings.AllowedOrderByProperties.Contains(property.Property.Name))
                    {
                        throw new ODataException(Error.Format(SRResources.NotAllowedOrderByProperty, property.Property.Name, "AllowedOrderByProperties"));
                    }
                }
            }
        }
        public void ApplyInValidOrderbyQueryThrows(string orderbyValue)
        {
            var model = new ODataModelBuilder().Add_Customer_EntityType().Add_Customers_EntitySet().GetEdmModel();
            var context = new ODataQueryContext(model, typeof(Customer));
            var orderby = new OrderByQueryOption(orderbyValue, context);

            Assert.Throws<ODataException>(() =>
                orderby.ApplyTo(ODataQueryOptionTest.Customers));
        }
        public void ValidateAllowsOrderByIt()
        {
            // Arrange
            OrderByQueryOption option = new OrderByQueryOption("$it", new ODataQueryContext(EdmCoreModel.Instance, typeof(int)));
            ODataValidationSettings settings = new ODataValidationSettings();

            // Act & Assert
            Assert.DoesNotThrow(() => _validator.Validate(option, settings));
        }
        public void ValidateAllowsOrderByIt_IfExplicitlySpecified()
        {
            // Arrange
            OrderByQueryOption option = new OrderByQueryOption("$it", new ODataQueryContext(EdmCoreModel.Instance, typeof(int)), queryTranslator: null);
            ODataValidationSettings settings = new ODataValidationSettings { AllowedOrderByProperties = { "$it" } };

            // Act & Assert
            Assert.DoesNotThrow(() => _validator.Validate(option, settings));
        }
        public void ValidateAllowsOrderByIt()
        {
            // Arrange
            OrderByQueryOption option = new OrderByQueryOption("$it", _context);
            ODataValidationSettings settings = new ODataValidationSettings();

            // Act & Assert
            Assert.DoesNotThrow(() => _validator.Validate(option, settings));
        }
        public void CanConstructValidFilterQuery(string orderbyValue)
        {
            var model = new ODataModelBuilder().Add_Customer_EntityType().Add_Customers_EntitySet().GetEdmModel();
            var context = new ODataQueryContext(model, typeof(Customer));
            var orderby = new OrderByQueryOption(orderbyValue, context);

            Assert.Same(context, orderby.Context);
            Assert.Equal(orderbyValue, orderby.RawValue);
        }
 // Disallow the 'desc' parameter for $orderby option.
 public override void Validate(OrderByQueryOption orderByOption,
                                 ODataValidationSettings validationSettings)
 {
     if (orderByOption.OrderByNodes.Any(
             node => node.Direction == OrderByDirection.Descending))
     {
         throw new ODataException("The 'desc' option is not supported.");
     }
     base.Validate(orderByOption, validationSettings);
 }
        public void ValidateWillAllowId()
        {
            // Arrange
            OrderByQueryOption option = new OrderByQueryOption("Id", _context);
            ODataValidationSettings settings = new ODataValidationSettings();
            settings.AllowedOrderByProperties.Add("Id");

            // Act & Assert
            Assert.DoesNotThrow(() => _validator.Validate(option, settings));
        }
        public void ValidateWillNotAllowName()
        {
            // Arrange
            OrderByQueryOption option = new OrderByQueryOption("Name", _context);
            ODataValidationSettings settings = new ODataValidationSettings();
            settings.AllowedOrderByProperties.Add("Id");

            // Act & Assert
            Assert.Throws<ODataException>(() => _validator.Validate(option, settings),
                "Order by 'Name' is not allowed. To allow it, set the 'AllowedOrderByProperties' property on QueryableAttribute or QueryValidationSettings.");
        }
        public void ValidateDisallowsOrderByIt_IfTurnedOff()
        {
            // Arrange
            _context = new ODataQueryContext(EdmCoreModel.Instance, typeof(int));
            OrderByQueryOption option = new OrderByQueryOption("$it", _context, queryTranslator: null);
            ODataValidationSettings settings = new ODataValidationSettings();
            settings.AllowedOrderByProperties.Add("dummy");

            // Act & Assert
            Assert.Throws<ODataException>(
                () => _validator.Validate(option, settings),
                "Order by '$it' is not allowed. To allow it, set the 'AllowedOrderByProperties' property on EnableQueryAttribute or QueryValidationSettings.");
        }
Exemple #13
0
        public static HttpRequestMessage BuildCustomRequest(this ODataQueryOptions originalOptions,
            out TopQueryOption top,
            out SkipQueryOption skip, out OrderByQueryOption orderBy)
        {
            top = null;
            skip = null;
            orderBy = null;

            // cuttin out $top and $skip from the request
            HttpRequestMessage customRequest = originalOptions.Request;

            if (customRequest.Properties.ContainsKey(HttpPropertyKeys.RequestQueryNameValuePairsKey))
            {
                Uri uri = originalOptions.Request.RequestUri;
                var pairs =
                    customRequest.Properties[HttpPropertyKeys.RequestQueryNameValuePairsKey] as
                        IEnumerable<KeyValuePair<string, string>>;

                if (pairs != null)
                {
                    IEnumerable<KeyValuePair<string, string>> jQueryNameValuePairs =
                        new FormDataCollection(uri).GetJQueryNameValuePairs();
                    var updatedPairs = new List<KeyValuePair<string, string>>();

                    foreach (var pair in jQueryNameValuePairs)
                    {
                        if (pair.Key.Equals("$top"))
                        {
                            top = originalOptions.Top;
                        }
                        else if (pair.Key.Equals("$skip"))
                        {
                            skip = originalOptions.Skip;
                        }
                        else if (pair.Key.Equals("$orderby"))
                        {
                            orderBy = originalOptions.OrderBy;
                        }
                        else
                        {
                            updatedPairs.Add(pair);
                        }
                    }

                    customRequest.Properties.Remove(HttpPropertyKeys.RequestQueryNameValuePairsKey);
                    customRequest.Properties.Add(HttpPropertyKeys.RequestQueryNameValuePairsKey, updatedPairs);
                }
            }

            return customRequest;
        }
        public void ValidateWillNotAllowMultipleProperties()
        {
            // Arrange
            OrderByQueryOption option = new OrderByQueryOption("Name desc, Id asc", _context);
            ODataValidationSettings settings = new ODataValidationSettings();
            Assert.DoesNotThrow(() => _validator.Validate(option, settings));

            settings.AllowedOrderByProperties.Add("Address");
            settings.AllowedOrderByProperties.Add("Name");

            // Act & Assert
            Assert.Throws<ODataException>(() => _validator.Validate(option, settings),
                "Order by 'Id' is not allowed. To allow it, set the 'AllowedOrderByProperties' property on QueryableAttribute or QueryValidationSettings.");
        }
        public void GetQueryNodeParsesQuery()
        {
            var model = new ODataModelBuilder().Add_Customer_EntityType().Add_Customers_EntitySet().GetEdmModel();
            var context = new ODataQueryContext(model, typeof(Customer), "Customers");
            var orderby = new OrderByQueryOption("Name,Website", context);
            var node = orderby.QueryNode;

            Assert.Equal(QueryNodeKind.PropertyAccess, node.Expression.Kind);
            var websiteNode = node.Expression as PropertyAccessQueryNode;
            Assert.Equal("Website", websiteNode.Property.Name);

            var nameNode = ((OrderByQueryNode)node.Collection).Expression;
            Assert.Equal(QueryNodeKind.PropertyAccess, nameNode.Kind);
            Assert.Equal("Name", ((PropertyAccessQueryNode)nameNode).Property.Name);
        }
        public void ApplyTo_NestedProperties_DoesNotHandleNullPropagation_IfExplicitInSettings()
        {
            // Arrange
            var model = new ODataModelBuilder().Add_Customer_EntityType_With_Address().Add_Customers_EntitySet().GetServiceModel();
            var orderByOption = new OrderByQueryOption("Address/City asc", new ODataQueryContext(model, typeof(Customer)), null);

            var customers = (new List<Customer>{
                new Customer { CustomerId = 1, Address = null },
                new Customer { CustomerId = 2, Address = new Address { City = "B" } },
                new Customer { CustomerId = 3, Address = new Address { City = "A" } }
            }).AsQueryable();
            ODataQuerySettings settings = new ODataQuerySettings { HandleNullPropagation = HandleNullPropagationOption.False };

            // Act & Assert
            Assert.Throws<NullReferenceException>(() => orderByOption.ApplyTo(customers, settings).ToArray());
        }
        public void PropertyNodes_Getter_Parses_Query()
        {
            // Arrange
            var model = new ODataModelBuilder().Add_Customer_EntityType().Add_Customers_EntitySet().GetEdmModel();
            var context = new ODataQueryContext(model, typeof(Customer), "Customers");
            var orderby = new OrderByQueryOption("Name,Website", context);

            // Act
            ICollection<OrderByPropertyNode> nodes = orderby.PropertyNodes;

            // Assert
            Assert.NotNull(nodes);
            Assert.Equal(2, nodes.Count);
            Assert.Equal("Name", nodes.First().Property.Name);
            Assert.Equal("Website", nodes.Last().Property.Name);
        }
        public void PropertyNodes_Getter_Parses_Query()
        {
            // Arrange
            var model = new ODataModelBuilder().Add_Customer_EntityType().Add_Customers_EntitySet().GetEdmModel();
            var context = new ODataQueryContext(model, typeof(Customer));
            var orderby = new OrderByQueryOption("Name,Website", context);

            ICollection<OrderByNode> nodes = orderby.OrderByNodes;

            // Assert
            Assert.False(nodes.OfType<OrderByItNode>().Any());
            IEnumerable<OrderByPropertyNode> propertyNodes = nodes.OfType<OrderByPropertyNode>();
            Assert.NotNull(propertyNodes);
            Assert.Equal(2, propertyNodes.Count());
            Assert.Equal("Name", propertyNodes.First().Property.Name);
            Assert.Equal("Website", propertyNodes.Last().Property.Name);
        }
        /// <summary>
        /// Validates an <see cref="OrderByQueryOption" />.
        /// </summary>
        /// <param name="orderByOption">The $orderby query.</param>
        /// <param name="validationSettings">The validation settings.</param>
        public virtual void Validate(OrderByQueryOption orderByOption, ODataValidationSettings validationSettings)
        {
            if (orderByOption == null)
            {
                throw Error.ArgumentNull("orderByOption");
            }

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

            int nodeCount = 0;
            for (OrderByClause clause = orderByOption.OrderByClause; clause != null; clause = clause.ThenBy)
            {
                nodeCount++;
                if (nodeCount > validationSettings.MaxOrderByNodeCount)
                {
                    throw new ODataException(Error.Format(SRResources.OrderByNodeCountExceeded, validationSettings.MaxOrderByNodeCount));
                }
            }

            if (validationSettings.AllowedOrderByProperties.Count > 0)
            {
                IEnumerable<OrderByNode> orderByNodes = orderByOption.OrderByNodes;

                foreach (OrderByNode node in orderByNodes)
                {
                    string propertyName = null;
                    OrderByPropertyNode property = node as OrderByPropertyNode;
                    if (property != null)
                    {
                        propertyName = property.Property.Name;
                    }
                    else if ((node as OrderByItNode) != null && !validationSettings.AllowedOrderByProperties.Contains("$it"))
                    {
                        propertyName = "$it";
                    }

                    if (propertyName != null && !validationSettings.AllowedOrderByProperties.Contains(propertyName))
                    {
                        throw new ODataException(Error.Format(SRResources.NotAllowedOrderByProperty, propertyName, "AllowedOrderByProperties"));
                    }
                }
            }
        }
        public void Validate_ThrowsIfTheLeafOfThePathIsntWithinTheAllowedProperties()
        {
            // Arrange
            IEdmModel               model    = GetEdmModel();
            IEdmEntityType          edmType  = model.SchemaElements.OfType <IEdmEntityType>().Single(t => t.Name == "LimitedEntity");
            ODataQueryContext       context  = new ODataQueryContext(model, edmType);
            OrderByQueryOption      option   = new OrderByQueryOption("ComplexProperty/Value", context);
            ODataValidationSettings settings = new ODataValidationSettings();

            settings.AllowedOrderByProperties.Add("NotSortableProperty");

            // Act & Assert
            OrderByQueryValidator validator = OrderByQueryValidator.GetOrderByQueryValidator(context);

            ExceptionAssert.Throws <ODataException>(() =>
                                                    validator.Validate(option, settings),
                                                    "Order by 'Value' is not allowed. To allow it, set the 'AllowedOrderByProperties' property on EnableQueryAttribute or QueryValidationSettings.");
        }
        public static Expression <Func <TElement, bool> > ToExpression <TElement>(this OrderByQueryOption orderBy)
        {
            var        param     = Expression.Parameter(typeof(TElement));
            IQueryable queryable = Enumerable.Empty <TElement>().AsQueryable();

            if (orderBy != null)
            {
                queryable = orderBy.ApplyTo(queryable, new ODataQuerySettings());
                var mce = queryable.Expression as MethodCallExpression;
                if (mce != null)
                {
                    var quote = mce.Arguments[1] as UnaryExpression;
                    if (quote != null)
                    {
                        return(quote.Operand as Expression <Func <TElement, bool> >);
                    }
                }
            }
            return(Expression.Lambda <Func <TElement, bool> >(Expression.Constant(true), param));
        }
        public void CanApplySkipOrderby()
        {
            var model = new ODataModelBuilder().Add_Customer_EntityType().Add_Customers_EntitySet().GetServiceModel();
            var context = new ODataQueryContext(model, typeof(Customer));
            var orderbyOption = new OrderByQueryOption("Name", context, queryTranslator: null);
            var skipOption = new SkipQueryOption("1", context);

            var customers = (new List<Customer>{
                new Customer { CustomerId = 1, Name = "Andy" },
                new Customer { CustomerId = 2, Name = "Aaron" },
                new Customer { CustomerId = 3, Name = "Alex" }
            }).AsQueryable();

            IQueryable queryable = orderbyOption.ApplyTo(customers);
            queryable = skipOption.ApplyTo(queryable, new ODataQuerySettings());
            var results = ((IQueryable<Customer>)queryable).ToArray();
            Assert.Equal(2, results.Length);
            Assert.Equal(3, results[0].CustomerId);
            Assert.Equal(1, results[1].CustomerId);
        }
Exemple #23
0
        public ODataQueryOptions(IEnumerable <KeyValuePair <string, string> > queryParameters, ODataQueryContext context, bool aggregate)
        {
            if (queryParameters == null)
            {
                throw new ArgumentNullException(nameof(queryParameters));
            }

            foreach (var queryParameter in queryParameters)
            {
                switch (queryParameter.Key)
                {
                case "$filter":
                    if (!aggregate)
                    {
                        Filter = new FilterQueryOption(queryParameter.Value, context);
                    }
                    break;

                case "$orderby":
                    OrderBy = new OrderByQueryOption(queryParameter.Value, context);
                    break;

                case "$select":
                    if (aggregate)
                    {
                        Select = new SelectExpandQueryOption(queryParameter.Value, string.Empty, context);
                    }
                    break;

                case "$top":
                    Top = new TopQueryOption(queryParameter.Value, context);
                    break;

                case "$format":
                    break;

                default:
                    throw new ArgumentException($"'{queryParameter.Key}' option is not supported");
                }
            }
        }
        public void PropertyNodes_Getter_Parses_Query()
        {
            // Arrange
            var model   = new ODataModelBuilder().Add_Customer_EntityType().Add_Customers_EntitySet().GetEdmModel();
            var context = new ODataQueryContext(model, typeof(Customer))
            {
                RequestContainer = new MockContainer()
            };
            var orderby = new OrderByQueryOption("Name,Website", context);

            ICollection <OrderByNode> nodes = orderby.OrderByNodes;

            // Assert
            Assert.False(nodes.OfType <OrderByItNode>().Any());
            IEnumerable <OrderByPropertyNode> propertyNodes = nodes.OfType <OrderByPropertyNode>();

            Assert.NotNull(propertyNodes);
            Assert.Equal(2, propertyNodes.Count());
            Assert.Equal("Name", propertyNodes.First().Property.Name);
            Assert.Equal("Website", propertyNodes.Last().Property.Name);
        }
        public void ApplyToEnums_ReturnsCorrectQueryable()
        {
            // Arrange
            var builder = new ODataConventionModelBuilder();
            builder.EntitySet<EnumModel>("EnumModels");
            var model = builder.GetEdmModel();

            var context = new ODataQueryContext(model, typeof(EnumModel));
            var orderbyOption = new OrderByQueryOption("Flag", context, null);
            IEnumerable<EnumModel> enumModels = FilterQueryOptionTest.EnumModelTestData;

            // Act
            IQueryable queryable = orderbyOption.ApplyTo(enumModels.AsQueryable());

            // Assert
            Assert.NotNull(queryable);
            IEnumerable<EnumModel> actualCustomers = Assert.IsAssignableFrom<IEnumerable<EnumModel>>(queryable);
            Assert.Equal(
                new int[] { 2, 1, 3 },
                actualCustomers.Select(enumModel => enumModel.Id));
        }
        public void CanApplyOrderBy_WithNestedParameterAlias()
        {
            // Arrange
            var model = new ODataModelBuilder().Add_Customer_EntityType().Add_Customers_EntitySet().GetServiceModel();

            var parser = new ODataQueryOptionParser(
                model,
                model.FindType("Microsoft.AspNet.OData.Test.Builder.TestModels.Customer"),
                model.FindDeclaredNavigationSource("Default.Container.Customers"),
                new Dictionary <string, string> {
                { "$orderby", "@p1" }, { "@p2", "Name" }, { "@p1", "@p2" }
            });

            var context = new ODataQueryContext(model, typeof(Customer))
            {
                RequestContainer = new MockContainer()
            };
            var orderByOption = new OrderByQueryOption("@p1", context, parser);

            var customers = (new List <Customer> {
                new Customer {
                    CustomerId = 1, Name = "Andy"
                },
                new Customer {
                    CustomerId = 2, Name = "Aaron"
                },
                new Customer {
                    CustomerId = 3, Name = "Alex"
                }
            }).AsQueryable();

            // Act
            var results = orderByOption.ApplyTo(customers).ToArray();

            // Assert
            Assert.Equal(2, results[0].CustomerId);
            Assert.Equal(3, results[1].CustomerId);
            Assert.Equal(1, results[2].CustomerId);
        }
Exemple #27
0
        public void CanApplySkipTopOrderby()
        {
            var model   = new ODataModelBuilder().Add_Customer_EntityType().Add_Customers_EntitySet().GetServiceModel();
            var context = new ODataQueryContext(model, typeof(Customer))
            {
                RequestContainer = new MockContainer()
            };
            var orderbyOption = new OrderByQueryOption("Name", context);
            var skipOption    = new SkipQueryOption("2", context);
            var topOption     = new TopQueryOption("2", context);

            var customers = (new List <Customer> {
                new Customer {
                    CustomerId = 1, Name = "Andy"
                },
                new Customer {
                    CustomerId = 2, Name = "Aaron"
                },
                new Customer {
                    CustomerId = 3, Name = "Alex"
                },
                new Customer {
                    CustomerId = 4, Name = "Ace"
                },
                new Customer {
                    CustomerId = 5, Name = "Abner"
                }
            }).AsQueryable();

            IQueryable queryable = orderbyOption.ApplyTo(customers);

            queryable = skipOption.ApplyTo(queryable, new ODataQuerySettings());
            queryable = topOption.ApplyTo(queryable, new ODataQuerySettings());
            var results = ((IQueryable <Customer>)queryable).ToArray();

            Assert.Equal(2, results.Length);
            Assert.Equal(4, results[0].CustomerId);
            Assert.Equal(3, results[1].CustomerId);
        }
Exemple #28
0
        public void CanOrderByMultipleProperties()
        {
            // Arrange
            var query = new List <Product>
            {
                new Product {
                    Id = 2, Price = 1.23m
                },
                new Product {
                    Id = 4, Price = 5.23m
                },
                new Product {
                    Id = 1, Price = 1.23m
                },
                new Product {
                    Id = 3, Price = 0.23m
                }
            }
            .AsQueryable();

            var orderByNodes = new List <OrderByNode>
            {
                new OrderByNode(nameof(Product.Price), OrderByDirection.Descending),
                new OrderByNode(nameof(Product.Id))
            };

            var options = new OrderByQueryOption(orderByNodes);

            // Act
            var results = options.ApplyTo(query).ToList();

            // Assert
            Assert.Collection(
                results,
                o => Assert.Equal(4, o.Id),
                o => Assert.Equal(1, o.Id),
                o => Assert.Equal(2, o.Id),
                o => Assert.Equal(3, o.Id));
        }
        private string BuildOrderClause(EdmEntityType edmEntityType, OrderByQueryOption orderByQueryOption)
        {
            var orderClause = string.Empty;

            if (orderByQueryOption != null)
            {
                var columns        = orderByQueryOption.RawValue.Split(',').AsEnumerable();
                var escapedColumns = columns.Select(
                    s =>
                {
                    var columnToOrder  = s.Trim().Split(' ');
                    string outputOrder = $"[{columnToOrder[0].Replace('/', _objectHierarchySeparator)}]";

                    outputOrder += columnToOrder.Count() > 1 ? $" {columnToOrder[1]}" : string.Empty;

                    return(outputOrder);
                });
                orderClause = string.Join(",", escapedColumns);
            }
            else
            {
                var hasDeclareKey = HasDeclareKey(edmEntityType);
                if (hasDeclareKey)
                {
                    var keys = edmEntityType.DeclaredKey;
                    orderClause = string.Join(",", keys.Select(k => $"[{k.Name}]"));
                }
                else
                {
                    var firstProperty = edmEntityType.DeclaredProperties.FirstOrDefault(w => w.Type.IsComplex() == false);
                    if (firstProperty != null)
                    {
                        orderClause = $"[{firstProperty.Name}]";
                    }
                }
            }

            return(orderClause);
        }
Exemple #30
0
        public void CanOrderByDescending()
        {
            // Arrange
            var query = new List <Product>
            {
                new Product {
                    Id = 2
                },
                new Product {
                    Id = 1
                },
                new Product {
                    Id = 4
                },
                new Product {
                    Id = 3
                }
            }
            .AsQueryable();

            var orderByNodes = new List <OrderByNode>
            {
                new OrderByNode(nameof(Product.Id), OrderByDirection.Descending)
            };

            var options = new OrderByQueryOption(orderByNodes);

            // Act
            var results = options.ApplyTo(query).ToList();

            // Assert
            Assert.Collection(
                results,
                o => Assert.Equal(4, o.Id),
                o => Assert.Equal(3, o.Id),
                o => Assert.Equal(2, o.Id),
                o => Assert.Equal(1, o.Id));
        }
Exemple #31
0
        public SortExpression <T>[] ConvertToSortExpression <T>(OrderByQueryOption orderBy) where T : class
        {
            if (orderBy == null)
            {
                return(null);
            }

            var param           = Expression.Parameter(typeof(T));
            var sortExpressions = new List <SortExpression <T> >();
            var parameters      = orderBy.RawValue.Split(',');

            Expression field   = null;
            var        nodeCtr = 0;

            foreach (var p in parameters)
            {
                var raw   = p.Replace(" asc", "").Replace(" desc", "");
                var props = raw.Split('/');

                if (props.Length < 2)
                {
                    field = Expression.Property(param, raw);
                }
                else
                {
                    field = param;
                    foreach (var sub in props)
                    {
                        field = Expression.Property(field, sub);
                    }
                }
                var converted = Expression.Lambda <Func <T, object> >(Expression.Convert(field, typeof(object)), param);
                sortExpressions.Add(new SortExpression <T>(converted, orderBy.OrderByNodes[nodeCtr].Direction == OrderByDirection.Ascending));
                nodeCtr++;
            }

            return(sortExpressions.ToArray());
        }
Exemple #32
0
        public void OrderByIsCaseInsensitive()
        {
            // Arrange
            var query = new List <Product>
            {
                new Product {
                    Id = 2
                },
                new Product {
                    Id = 1
                },
                new Product {
                    Id = 4
                },
                new Product {
                    Id = 3
                }
            }
            .AsQueryable();

            var orderByNodes = new List <OrderByNode>
            {
                new OrderByNode("iD")
            };

            var options = new OrderByQueryOption(orderByNodes);

            // Act
            var results = options.ApplyTo(query).ToList();

            // Assert
            Assert.Collection(
                results,
                o => Assert.Equal(1, o.Id),
                o => Assert.Equal(2, o.Id),
                o => Assert.Equal(3, o.Id),
                o => Assert.Equal(4, o.Id));
        }
        private static List <Order> ToFetchOrder(OrderByQueryOption orderByQueryOption)
        {
            var orders = new List <Order>();

            if (orderByQueryOption != null)
            {
                foreach (var orderByNode in orderByQueryOption.OrderByNodes)
                {
                    var orderByPropertyNode = orderByNode as OrderByPropertyNode;

                    if (orderByPropertyNode != null)
                    {
                        orders.Add(new Order(orderByPropertyNode.Property.Name, orderByPropertyNode.Direction == OrderByDirection.Descending ? OrderType.Descending : OrderType.Ascending));
                    }
                    else
                    {
                        throw new ODataException("Only ordering by properties is supported.");
                    }
                }
            }

            return(orders);
        }
Exemple #34
0
        public void ApplyTo_NestedProperties_HandlesNullPropagation_Succeeds()
        {
            // Arrange
            var model   = new ODataModelBuilder().Add_Customer_EntityType_With_Address().Add_Customers_EntitySet().GetEdmModel();
            var context = new ODataQueryContext(model, typeof(Customer))
            {
                RequestContainer = new MockServiceProvider()
            };
            var orderByOption = new OrderByQueryOption("Address/City asc", context);

            var customers = (new List <Customer> {
                new Customer {
                    Id = 1, Address = null
                },
                new Customer {
                    Id = 2, Address = new Address {
                        City = "B"
                    }
                },
                new Customer {
                    Id = 3, Address = new Address {
                        City = "A"
                    }
                }
            }).AsQueryable();

            // Act
            ODataQuerySettings settings = new ODataQuerySettings {
                HandleNullPropagation = HandleNullPropagationOption.True
            };
            var results = orderByOption.ApplyTo(customers, settings).ToArray();

            // Assert
            Assert.Equal(1, results[0].Id);
            Assert.Equal(3, results[1].Id);
            Assert.Equal(2, results[2].Id);
        }
Exemple #35
0
        /// <summary>
        /// Validates an <see cref="OrderByQueryOption" />.
        /// </summary>
        /// <param name="orderByOption">The $orderby query.</param>
        /// <param name="validationSettings">The validation settings.</param>
        public virtual void Validate(OrderByQueryOption orderByOption, ODataValidationSettings validationSettings)
        {
            if (orderByOption == null)
            {
                throw Error.ArgumentNull("orderByOption");
            }

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

            if (validationSettings.AllowedOrderByProperties.Count > 0)
            {
                IEnumerable <OrderByNode> orderByNodes = orderByOption.OrderByNodes;

                foreach (OrderByNode node in orderByNodes)
                {
                    string propertyName          = null;
                    OrderByPropertyNode property = node as OrderByPropertyNode;
                    if (property != null)
                    {
                        propertyName = property.Property.Name;
                    }
                    else if ((node as OrderByItNode) != null && !validationSettings.AllowedOrderByProperties.Contains("$it"))
                    {
                        propertyName = "$it";
                    }

                    if (propertyName != null && !validationSettings.AllowedOrderByProperties.Contains(propertyName))
                    {
                        throw new ODataException(Error.Format(SRResources.NotAllowedOrderByProperty, propertyName, "AllowedOrderByProperties"));
                    }
                }
            }
        }
        public void ApplyTo_NestedProperties_WithDuplicateName_Succeeds()
        {
            // Arrange
            var model   = new ODataModelBuilder().Add_Customer_EntityType_With_Address().Add_Customers_EntitySet().GetServiceModel();
            var context = new ODataQueryContext(model, typeof(Customer))
            {
                RequestContainer = new MockContainer()
            };
            var orderByOption = new OrderByQueryOption("Address/City,City", context);

            var customers = (new List <Customer> {
                new Customer {
                    CustomerId = 1, City = "A", Address = new Address {
                        City = "A"
                    }
                },
                new Customer {
                    CustomerId = 2, City = "B", Address = new Address {
                        City = "B"
                    }
                },
                new Customer {
                    CustomerId = 3, City = "A", Address = new Address {
                        City = "B"
                    }
                }
            }).AsQueryable();

            // Act
            var results = orderByOption.ApplyTo(customers).ToArray();

            // Assert
            Assert.Equal(1, results[0].CustomerId);
            Assert.Equal(3, results[1].CustomerId);
            Assert.Equal(2, results[2].CustomerId);
        }
        public void Validate_NoException_ForParameterAlias()
        {
            // Arrange
            IEdmModel         model     = GetEdmModel();
            IEdmEntityType    edmType   = model.SchemaElements.OfType <IEdmEntityType>().Single(t => t.Name == "LimitedEntity");
            IEdmEntitySet     entitySet = model.FindDeclaredEntitySet("Microsoft.AspNet.OData.Query.Validators.LimitedEntities");
            ODataQueryContext context   = new ODataQueryContext(model, edmType);

            OrderByQueryOption option = new OrderByQueryOption(
                "@p,@q desc",
                context,
                new ODataQueryOptionParser(
                    model,
                    edmType,
                    entitySet,
                    new Dictionary <string, string> {
                { "$orderby", "@p,@q desc" }, { "@p", "Id" }, { "@q", "RelatedEntity/Id" }
            }));

            ODataValidationSettings settings = new ODataValidationSettings();

            // Act & Assert
            ExceptionAssert.DoesNotThrow(() => _validator.Validate(option, settings));
        }
        public void Property_OrderByNodes_WorksWithUnTypedContext()
        {
            // Arrange
            CustomersModelWithInheritance model = new CustomersModelWithInheritance();
            ODataQueryContext context = new ODataQueryContext(model.Model, model.Customer);
            OrderByQueryOption orderBy = new OrderByQueryOption("ID desc", context);

            // Act & Assert
            Assert.NotNull(orderBy.OrderByNodes);
        }
        public void ApplyTo_NestedProperties_HandlesNullPropagation_Succeeds()
        {
            // Arrange
            var model = new ODataModelBuilder().Add_Customer_EntityType_With_Address().Add_Customers_EntitySet().GetServiceModel();
            var orderByOption = new OrderByQueryOption("Address/City asc", new ODataQueryContext(model, typeof(Customer)));

            var customers = (new List<Customer>{
                new Customer { CustomerId = 1, Address = null },
                new Customer { CustomerId = 2, Address = new Address { City = "B" } },
                new Customer { CustomerId = 3, Address = new Address { City = "A" } }
            }).AsQueryable();

            // Act
            var results = orderByOption.ApplyTo(customers).ToArray();

            // Assert
            Assert.Equal(1, results[0].CustomerId);
            Assert.Equal(3, results[1].CustomerId);
            Assert.Equal(2, results[2].CustomerId);
        }
        public void OrderByDuplicateItThrows()
        {
            // Arrange
            var context = new ODataQueryContext(EdmCoreModel.Instance, typeof(int));
            var orderbyOption = new OrderByQueryOption("$it, $it", context);

            // Act
            Assert.Throws<ODataException>(
                () => orderbyOption.ApplyTo(Enumerable.Empty<int>().AsQueryable()),
                "Multiple '$it' nodes are not supported in '$orderby'.");
        }
        public void OrderByDuplicatePropertyThrows()
        {
            // Arrange
            var model = new ODataModelBuilder().Add_Customer_EntityType().Add_Customers_EntitySet().GetServiceModel();

            var context = new ODataQueryContext(model, typeof(Customer));
            var orderbyOption = new OrderByQueryOption("Name, Name", context);

            // Act
            Assert.Throws<ODataException>(
                () => orderbyOption.ApplyTo(Enumerable.Empty<Customer>().AsQueryable()),
                "Duplicate property named 'Name' is not supported in '$orderby'.");
        }
        public void CanTurnOffValidationForOrderBy()
        {
            // Arrange
            ODataQueryContext context = ValidationTestHelper.CreateCustomerContext();

            OrderByQueryOption option = new OrderByQueryOption("Name", context);
            ODataValidationSettings settings = new ODataValidationSettings();
            settings.AllowedOrderByProperties.Add("Id");

            // Act & Assert
            Assert.Throws<ODataException>(() => option.Validate(settings),
                "Order by 'Name' is not allowed. To allow it, set the 'AllowedOrderByProperties' property on EnableQueryAttribute or QueryValidationSettings.");

            option.Validator = null;
            Assert.DoesNotThrow(() => option.Validate(settings));
        }
        public void OrderBy_Throws_For_Expressions(string orderByQuery)
        {
            var model = new ODataModelBuilder().Add_Customer_EntityType_With_Address().Add_Customers_EntitySet().GetServiceModel();
            var orderByOption = new OrderByQueryOption(orderByQuery, new ODataQueryContext(model, typeof(Customer)));

            Assert.Throws<ODataException>(
                () => orderByOption.OrderByNodes.Count(),
                "Only ordering by properties is supported for non-primitive collections. Expressions are not supported.");
        }
Exemple #44
0
        public static Func <IQueryable <Creative>, IOrderedQueryable <Creative> > ToExpression <TElement>(this OrderByQueryOption orderBy)
        {
            if (orderBy == null)
            {
                return(null);
            }

            IQueryable queryable = Enumerable.Empty <TElement>().AsQueryable();
            var        param     = Expression.Parameter(typeof(Creative));
            //queryable = orderBy.ApplyTo(queryable, new ODataQuerySettings());

            IOrderedQueryable <Creative> orderQueryable = (IOrderedQueryable <Creative>)orderBy.ApplyTo(queryable, new ODataQuerySettings());
            Func <IQueryable <Creative>, IOrderedQueryable <Creative> > orderingFunc = query => orderQueryable;

            return(orderingFunc);
        }
Exemple #45
0
        public static HttpRequestMessage BuildCustomRequest(this ODataQueryOptions originalOptions,
                                                            out TopQueryOption top,
                                                            out SkipQueryOption skip, out OrderByQueryOption orderBy)
        {
            top     = null;
            skip    = null;
            orderBy = null;

            // cuttin out $top and $skip from the request
            HttpRequestMessage customRequest = originalOptions.Request;

            if (customRequest.Properties.ContainsKey(HttpPropertyKeys.RequestQueryNameValuePairsKey))
            {
                Uri uri   = originalOptions.Request.RequestUri;
                var pairs =
                    customRequest.Properties[HttpPropertyKeys.RequestQueryNameValuePairsKey] as
                    IEnumerable <KeyValuePair <string, string> >;

                if (pairs != null)
                {
                    IEnumerable <KeyValuePair <string, string> > jQueryNameValuePairs =
                        new FormDataCollection(uri).GetJQueryNameValuePairs();
                    var updatedPairs = new List <KeyValuePair <string, string> >();

                    foreach (var pair in jQueryNameValuePairs)
                    {
                        if (pair.Key.Equals("$top"))
                        {
                            top = originalOptions.Top;
                        }
                        else if (pair.Key.Equals("$skip"))
                        {
                            skip = originalOptions.Skip;
                        }
                        else if (pair.Key.Equals("$orderby"))
                        {
                            orderBy = originalOptions.OrderBy;
                        }
                        else
                        {
                            updatedPairs.Add(pair);
                        }
                    }

                    customRequest.Properties.Remove(HttpPropertyKeys.RequestQueryNameValuePairsKey);
                    customRequest.Properties.Add(HttpPropertyKeys.RequestQueryNameValuePairsKey, updatedPairs);
                }
            }

            return(customRequest);
        }
Exemple #46
0
        public override IQueryable ApplyTo(IQueryable query, ODataQuerySettings querySettings)
        {
            if (query == null)
            {
                throw new ArgumentNullException(nameof(query));
            }

            if (querySettings == null)
            {
                throw new ArgumentNullException(nameof(querySettings));
            }

            var 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 (InlineCount != null && Request.ODataProperties().TotalCount == null)
            {
                long?count = InlineCount.GetEntityCount(result);
                if (count.HasValue)
                {
                    Request.ODataProperties().TotalCount = count.Value;
                }
            }

            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 (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);
        }
 private static string ToOrderByQuery(OrderByQueryOption orderByQuery)
 {
     return(NHibernateOrderByBinder.BindOrderByQueryOption(orderByQuery));
 }
        public async Task <IActionResult> OData(ODataQueryOptions <DeveloperDto> oDataQuery)
        {
            var edmModel     = EdmModelConfig.GetEdmModel();
            var edmEntitySet = edmModel.FindDeclaredEntitySet(nameof(Developer));

            var context = new ODataQueryContext(edmModel, typeof(Developer), oDataQuery.Context.Path);
            var edmType = context.ElementType;

            var parameters = new Dictionary <string, string>();

            if (!string.IsNullOrWhiteSpace(oDataQuery.RawValues.Filter))
            {
                parameters.Add("$filter", oDataQuery.RawValues.Filter);
            }

            if (!string.IsNullOrWhiteSpace(oDataQuery.RawValues.Expand))
            {
                parameters.Add("$expand", oDataQuery.RawValues.Expand);
            }

            if (!string.IsNullOrWhiteSpace(oDataQuery.RawValues.OrderBy))
            {
                parameters.Add("$orderby", oDataQuery.RawValues.OrderBy);
            }

            var parser = new ODataQueryOptionParser(edmModel, edmType, edmEntitySet, parameters);

            var queryable = (IQueryable <Developer>)_databaseContext.Developer;

            if (!string.IsNullOrWhiteSpace(oDataQuery.RawValues.Filter))
            {
                var filter = new FilterQueryOption(oDataQuery.RawValues.Filter, context, parser);
                queryable = (IQueryable <Developer>)filter.ApplyTo(queryable, new ODataQuerySettings());
            }

            if (!string.IsNullOrWhiteSpace(oDataQuery.RawValues.OrderBy))
            {
                var orderBy = new OrderByQueryOption(oDataQuery.RawValues.OrderBy, context, parser);
                queryable = orderBy.ApplyTo(queryable, new ODataQuerySettings());
            }

            IQueryable <object> expandableQueryable = null;

            if (!string.IsNullOrWhiteSpace(oDataQuery.RawValues.Expand))
            {
                var expand = new SelectExpandQueryOption(null, oDataQuery.RawValues.Expand, context, parser);
                expandableQueryable = (IQueryable <object>)expand.ApplyTo(queryable, new ODataQuerySettings());
            }

            int pageIndex    = 1;
            var hasPageIndex = oDataQuery.Request.Query.TryGetValue("$pageindex", out StringValues pageIndexRaw);

            if (hasPageIndex)
            {
                var isTrue = int.TryParse(pageIndexRaw, out int _pageIndexRaw);
                pageIndex = (isTrue && _pageIndexRaw > 0) ? _pageIndexRaw : pageIndex;
            }

            int pageSize    = 10;
            var hasPageSize = oDataQuery.Request.Query.TryGetValue("$pagesize", out StringValues pageSizeRaw);

            if (hasPageSize)
            {
                var isTrue = int.TryParse(pageSizeRaw, out int _pageSizeRaw);
                pageSize = (isTrue && _pageSizeRaw > 0) ? _pageSizeRaw : pageSize;
            }

            IQueryable <object> queryToExecute = expandableQueryable ?? queryable;
            var records = await queryToExecute.Skip((pageIndex - 1) *pageSize).Take(pageSize).ToListAsync();

            var count = await queryToExecute.CountAsync();

            var pageList = new PageList <Developer>(MapDomain(records).ToList(), count, pageIndex, pageSize);
            var response = PageListDto <DeveloperDto> .Map(pageList, DeveloperDto.MapDomainToDto);

            return(Ok(response));
        }
Exemple #49
0
        /// <summary>
        /// Validates an <see cref="OrderByQueryOption" />.
        /// </summary>
        /// <param name="orderByOption">The $orderby query.</param>
        /// <param name="validationSettings">The validation settings.</param>
        public virtual void Validate(OrderByQueryOption orderByOption, ODataValidationSettings validationSettings)
        {
            if (orderByOption == null)
            {
                throw Error.ArgumentNull("orderByOption");
            }

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

            int nodeCount = 0;

            for (OrderByClause clause = orderByOption.OrderByClause; clause != null; clause = clause.ThenBy)
            {
                nodeCount++;
                if (nodeCount > validationSettings.MaxOrderByNodeCount)
                {
                    throw new ODataException(Error.Format(SRResources.OrderByNodeCountExceeded,
                                                          validationSettings.MaxOrderByNodeCount));
                }
            }

            bool enableOrderBy = orderByOption.Context.DefaultQuerySettings.EnableOrderBy;
            OrderByModelLimitationsValidator validator = new OrderByModelLimitationsValidator(orderByOption.Context, enableOrderBy);
            bool explicitAllowedProperties             = validationSettings.AllowedOrderByProperties.Count > 0;

            foreach (OrderByNode node in orderByOption.OrderByNodes)
            {
                string propertyName = null;
                OrderByPropertyNode propertyNode = node as OrderByPropertyNode;
                if (propertyNode != null)
                {
                    propertyName = propertyNode.Property.Name;
                    bool isValidPath = !validator.TryValidate(propertyNode.OrderByClause, explicitAllowedProperties);
                    if (propertyName != null && isValidPath && explicitAllowedProperties)
                    {
                        // Explicit allowed properties were specified, but this one isn't within the list of allowed
                        // properties.
                        if (!IsAllowed(validationSettings, propertyName))
                        {
                            throw new ODataException(Error.Format(SRResources.NotAllowedOrderByProperty, propertyName,
                                                                  "AllowedOrderByProperties"));
                        }
                    }
                    else if (propertyName != null)
                    {
                        // The property wasn't limited but it wasn't contained in the set of explicitly allowed
                        // properties.
                        if (!IsAllowed(validationSettings, propertyName))
                        {
                            throw new ODataException(Error.Format(SRResources.NotAllowedOrderByProperty, propertyName,
                                                                  "AllowedOrderByProperties"));
                        }
                    }
                }
                else
                {
                    propertyName = "$it";
                    if (!IsAllowed(validationSettings, propertyName))
                    {
                        throw new ODataException(Error.Format(SRResources.NotAllowedOrderByProperty, propertyName,
                                                              "AllowedOrderByProperties"));
                    }
                }
            }
        }
        // GET: odata/MyEntities
        //[EnableQuery]
        //public IQueryable<MyEntity> GetMyEntities(ODataQueryOptions opts)
        //{
        //    IQueryable results = opts.ApplyTo(db.MyEntities.AsQueryable());
        //    return results as IQueryable<MyEntity>;
        //}

        // GET: odata/MyEntities
        //[EnableQuery]
        public IQueryable <MyEntity> GetMyEntities(ODataQueryOptions opts)
        {
            var settings = new ODataValidationSettings()
            {
                // Initialize settings as needed.
                AllowedFunctions = AllowedFunctions.AllMathFunctions
            };

            opts.Validate(settings);
            //IQueryable results = db.MyEntities.AsQueryable<MyEntity>();
            //if (opts.Filter != null)
            //{
            //    results = opts.Filter.ApplyTo(results, new ODataQuerySettings() { EnableConstantParameterization = false, EnsureStableOrdering = false });
            //}

            //results = results.Decompile();
            //results.Decompile
            //IQueryable results = MyApplyToWithDecompile(db.MyEntities.AsQueryable(), opts);
            //return results as IQueryable<MyEntity>;
            //return db.MyEntities;


            IQueryable         result        = db.MyEntities.AsQueryable();
            ODataQuerySettings querySettings = new ODataQuerySettings()
            {
                EnableConstantParameterization = false, EnsureStableOrdering = false
            };

            // Construct the actual query and apply them in the following order: filter, orderby, skip, top
            if (opts.Filter != null)
            {
                result = opts.Filter.ApplyTo(result, querySettings);
                result = ((result as IQueryable <MyEntity>).Decompile()).AsQueryable();
            }

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

            OrderByQueryOption orderBy = opts.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 &&
                (opts.Skip != null || opts.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(opts.Context)
                            : EnsureStableSortOrderBy(orderBy, opts.Context);
            }

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

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

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

            if (opts.SelectExpand != null)
            {
                Request.ODataProperties().SelectExpandClause = opts.SelectExpand.SelectExpandClause;
                result = opts.SelectExpand.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 as IQueryable <MyEntity>); // this compiles and works in most cases except when using $top with anything else.  Even if no results are found.
            //return result.AsQueryable(); // this doesn't compile, Error: Cannot implicitly convert type 'System.Linq.IQueryable' to 'System.Linq.IQueryable<MyEntity>.  An explicit conversion exists (are you missing a cast?)
        }
        public void ApplyTo_WithUnTypedContext_Throws_InvalidOperation()
        {
            // Arrange
            CustomersModelWithInheritance model = new CustomersModelWithInheritance();
            ODataQueryContext context = new ODataQueryContext(model.Model, model.Customer);
            OrderByQueryOption orderBy = new OrderByQueryOption("ID desc", context);
            IQueryable queryable = new Mock<IQueryable>().Object;

            // Act & Assert
            Assert.Throws<NotSupportedException>(() => orderBy.ApplyTo(queryable),
                "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 CanApplyOrderByDescThenByDesc()
        {
            var model = new ODataModelBuilder().Add_Customer_EntityType().Add_Customers_EntitySet().GetServiceModel();
            var orderByOption = new OrderByQueryOption("Name desc,Website desc", new ODataQueryContext(model, typeof(Customer)));

            var customers = (new List<Customer>{
                new Customer { CustomerId = 1, Name = "ACME", Website = "http://www.acme.net" },
                new Customer { CustomerId = 2, Name = "AAAA", Website = "http://www.aaaa.com" },
                new Customer { CustomerId = 3, Name = "ACME", Website = "http://www.acme.com" }
            }).AsQueryable();

            var results = orderByOption.ApplyTo(customers).ToArray();
            Assert.Equal(1, results[0].CustomerId);
            Assert.Equal(3, results[1].CustomerId);
            Assert.Equal(2, results[2].CustomerId);
        }
        public void CanApplyOrderBy_WithCollectionCount(string orderby)

        {
            // Arrange
            var model = new ODataModelBuilder()
                        .Add_Order_EntityType()
                        .Add_Customer_EntityType_With_Address()
                        .Add_CustomerOrders_Relationship()
                        .Add_Customer_EntityType_With_CollectionProperties()
                        .Add_Customers_EntitySet()
                        .GetEdmModel();

            var parser = new ODataQueryOptionParser(
                model,
                model.FindType("Microsoft.AspNetCore.OData.Tests.Models.Customer"),
                model.FindDeclaredNavigationSource("Default.Container.Customers"),
                new Dictionary <string, string> {
                { "$orderby", orderby }
            });

            var orderByOption = new OrderByQueryOption(orderby, new ODataQueryContext(model, typeof(Customer)), parser);

            var customers = (new List <Customer>
            {
                new Customer
                {
                    Id = 1,
                    Name = "Andy",
                    Orders = new List <Order>
                    {
                        new Order {
                            OrderId = 1
                        },
                        new Order {
                            OrderId = 2
                        }
                    },
                    Addresses = new List <Address>
                    {
                        new Address {
                            City = "1"
                        },
                        new Address {
                            City = "2"
                        }
                    },
                    Aliases = new List <string> {
                        "1", "2"
                    }
                },
                new Customer
                {
                    Id = 2,
                    Name = "Aaron",
                    Orders = new List <Order>
                    {
                        new Order {
                            OrderId = 3
                        }
                    },
                    Addresses = new List <Address>
                    {
                        new Address {
                            City = "3"
                        }
                    },
                    Aliases = new List <string> {
                        "3"
                    }
                },
                new Customer {
                    Id = 3, Name = "Alex"
                }
            }).AsQueryable();

            // Act
            var results = orderByOption.ApplyTo(customers).ToArray();

            // Assert
            Assert.Equal(3, results[0].Id);
            Assert.Equal(2, results[1].Id);
            Assert.Equal(1, results[2].Id);
        }
Exemple #54
0
 /// <summary>
 /// Updates the QueryExpression's sorting options.
 /// </summary>
 /// <param name="orders">The QueryExpression's collection of sorting options.</param>
 /// <param name="orderBy">The OData options for sorting.</param>
 private void UpdateOrdersFromOrderBy(DataCollection <OrderExpression> orders, OrderByQueryOption orderBy)
 {
     if (orderBy != null)
     {
         foreach (var node in orderBy.OrderByNodes.OfType <OrderByPropertyNode>())
         {
             var attributeName = EntityMapper.GetAttributeName(node.Property.Name);
             var direction     = node.Direction == OrderByDirection.Ascending ? OrderType.Ascending : OrderType.Descending;
             orders.Add(new OrderExpression(attributeName, direction));
         }
     }
 }
        public void CanApplyOrderBy()
        {
            var model = new ODataModelBuilder().Add_Customer_EntityType().Add_Customers_EntitySet().GetServiceModel();
            var orderByOption = new OrderByQueryOption("Name", new ODataQueryContext(model, typeof(Customer)));

            var customers = (new List<Customer>{
                new Customer { CustomerId = 1, Name = "Andy" },
                new Customer { CustomerId = 2, Name = "Aaron" },
                new Customer { CustomerId = 3, Name = "Alex" }
            }).AsQueryable();

            var results = orderByOption.ApplyTo(customers).ToArray();
            Assert.Equal(2, results[0].CustomerId);
            Assert.Equal(3, results[1].CustomerId);
            Assert.Equal(1, results[2].CustomerId);
        }
 public static IAsyncEnumerable <T> ApplyTo <T>(this OrderByQueryOption query, IAsyncEnumerable <T> source, ODataQuerySettings settings)
 {
     return(source);            // Not yet implemented.
 }