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