示例#1
0
        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);
            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);
        }
        public void CanApplyOrderBy_WithNestedParameterAlias()
        {
            // Arrange
            var model = new ODataModelBuilder().Add_Customer_EntityType().Add_Customers_EntitySet().GetServiceModel();

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

            var orderByOption = new OrderByQueryOption("@p1", new ODataQueryContext(model, typeof(Customer)), 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);
        }
        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 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)));

            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 ApplyTo_PropertyAliased_IfEnabled(bool modelAliasing, string propertyName)
        {
            // Arrange
            var builder = new ODataConventionModelBuilder {
                ModelAliasingEnabled = modelAliasing
            };

            builder.EntitySet <PropertyAlias>("PropertyAliases");
            var model = builder.GetEdmModel();

            var context       = new ODataQueryContext(model, typeof(PropertyAlias));
            var orderByOption = new OrderByQueryOption(propertyName, context);
            IEnumerable <PropertyAlias> propertyAliases = FilterQueryOptionTest.PropertyAliasTestData;

            // Act
            IQueryable queryable = orderByOption.ApplyTo(propertyAliases.AsQueryable());

            // Assert
            Assert.NotNull(queryable);
            IEnumerable <PropertyAlias> actualCustomers = Assert.IsAssignableFrom <IEnumerable <PropertyAlias> >(queryable);

            Assert.Equal(
                new[] { "abc", "def", "xyz" },
                actualCustomers.Select(propertyAlias => propertyAlias.FirstName));
        }
示例#6
0
        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 CanApplyOrderBy_WithParameterAlias()
        {
            // Arrange
            var model = new ODataModelBuilder().Add_Customer_EntityType_With_Address().Add_Address_ComplexType().GetServiceModel();

            var parser = new ODataQueryOptionParser(
                model,
                model.FindType("System.Web.OData.Builder.TestModels.Customer"),
                model.FindDeclaredNavigationSource("Default.Container.Customers"),
                new Dictionary <string, string> {
                { "$orderby", "@q desc,@p asc" }, { "@q", "Address/HouseNumber" }, { "@p", "CustomerId" }
            });

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

            var customers = (new List <Customer> {
                new Customer {
                    CustomerId = 1, Address = new Address {
                        HouseNumber = 2
                    }
                },
                new Customer {
                    CustomerId = 2, Address = new Address {
                        HouseNumber = 1
                    }
                },
                new Customer {
                    CustomerId = 3, Address = new Address {
                        HouseNumber = 3
                    }
                },
                new Customer {
                    CustomerId = 4, Address = new Address {
                        HouseNumber = 2
                    }
                },
                new Customer {
                    CustomerId = 5, Address = new Address {
                        HouseNumber = 1
                    }
                },
            }).AsQueryable();

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

            // Assert
            Assert.Equal(3, results[0].CustomerId);
            Assert.Equal(1, results[1].CustomerId);
            Assert.Equal(4, results[2].CustomerId);
            Assert.Equal(2, results[3].CustomerId);
            Assert.Equal(5, results[4].CustomerId);
        }
示例#8
0
        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'.");
        }
示例#9
0
        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.");
        }
示例#10
0
        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 OrderByDuplicatePropertyOfComplexTypeThrows()
        {
            // 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, Address/City", context);

            // Act
            Assert.Throws <ODataException>(
                () => orderbyOption.ApplyTo(Enumerable.Empty <Customer>().AsQueryable()),
                "Duplicate property named 'Address/City' is not supported in '$orderby'.");
        }
示例#12
0
        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);
            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[] { 5, 2, 1, 3, 6 },
                actualCustomers.Select(enumModel => enumModel.Id));
        }
示例#13
0
        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);
        }
示例#14
0
        public void CanApplyOrderByDescending()
        {
            var model         = new ODataModelBuilder().Add_Customer_EntityType().Add_Customers_EntitySet().GetServiceModel();
            var orderByOption = new OrderByQueryOption("Name desc", 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(1, results[0].CustomerId);
            Assert.Equal(3, results[1].CustomerId);
            Assert.Equal(2, results[2].CustomerId);
        }
        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);
        }
示例#16
0
        /// <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 && Request.ODataProperties().TotalCount == null)
            {
                long?count = Count.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 (SelectExpand != null)
            {
                Request.ODataProperties().SelectExpandClause = SelectExpand.SelectExpandClause;
                result = 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);
        }
示例#17
0
        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;

            // First apply $apply
            // Section 3.15 of the spec http://docs.oasis-open.org/odata/odata-data-aggregation-ext/v4.0/cs01/odata-data-aggregation-ext-v4.0-cs01.html#_Toc378326311
            if (IsAvailableODataQueryOption(Apply, AllowedQueryOptions.Apply))
            {
                result = Apply.ApplyTo(result, querySettings, _assembliesResolver);
                Request.ODataProperties().ApplyClause = Apply.ApplyClause;
                this.Context.ElementClrType = Apply.ResultClrType;
            }

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

            if (IsAvailableODataQueryOption(Count, AllowedQueryOptions.Count))
            {
                if (Request.ODataProperties().TotalCountFunc == null)
                {
                    Func <long> countFunc = Count.GetEntityCountFunc(result);
                    if (countFunc != null)
                    {
                        Request.ODataProperties().TotalCountFunc = countFunc;
                    }
                }

                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 &&
                (IsAvailableODataQueryOption(Skip, AllowedQueryOptions.Skip) ||
                 IsAvailableODataQueryOption(Top, AllowedQueryOptions.Top) ||
                 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 (IsAvailableODataQueryOption(orderBy, AllowedQueryOptions.OrderBy))
            {
                result = orderBy.ApplyTo(result, querySettings);
            }

            if (IsAvailableODataQueryOption(Skip, AllowedQueryOptions.Skip))
            {
                result = Skip.ApplyTo(result, querySettings);
            }

            if (IsAvailableODataQueryOption(Top, AllowedQueryOptions.Top))
            {
                result = Top.ApplyTo(result, querySettings);
            }

            AddAutoExpandProperties(querySettings);

            if (SelectExpand != null)
            {
                var tempResult = ApplySelectExpand(result, querySettings);
                if (tempResult != default(IQueryable))
                {
                    result = tempResult;
                }
            }

            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 = Request.GetNextPageLink(querySettings.PageSize.Value);
                    Request.ODataProperties().NextLink = nextPageLink;
                }
            }

            return(result);
        }
示例#18
0
        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("System.Web.OData.Builder.TestModels.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
                {
                    CustomerId = 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
                {
                    CustomerId = 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 {
                    CustomerId = 3, Name = "Alex"
                }
            }).AsQueryable();

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

            // Assert
            Assert.Equal(3, results[0].CustomerId);
            Assert.Equal(2, results[1].CustomerId);
            Assert.Equal(1, results[2].CustomerId);
        }