/// <summary>
        /// Apply the individual query to the given IQueryable in the right order.
        /// </summary>
        /// <param name="query">The IQueryable that we are applying query against.</param>
        /// <param name="handleNullPropagation">Specifies if we need to handle null propagation. Pass false if the underlying query provider handles null propagation. Otherwise pass true.</param>
        /// <param name="canUseDefaultOrderBy">If a default ordering can be used if the query doesn't specify one and has a $skip or $top.</param>
        /// <returns>The query that the query has been applied to.</returns>
        public IQueryable ApplyTo(IQueryable query, bool handleNullPropagation, bool canUseDefaultOrderBy)
        {
            if (query == null)
            {
                throw Error.ArgumentNull("query");
            }

            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, handleNullPropagation);
            }

            OrderByQueryOption orderBy = OrderBy;

            if (orderBy == null && (Skip != null || Top != null) && canUseDefaultOrderBy && !Context.IsPrimitiveClrType)
            {
                // Instead of failing early here if we cannot generate a default OrderBy,
                // let the IQueryable backend fail (if it has to).
                string orderByRaw = GenerateDefaultOrderBy(Context);
                if (!String.IsNullOrEmpty(orderByRaw))
                {
                    orderBy = new OrderByQueryOption(orderByRaw, Context);
                }
            }

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

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

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

            return(result);
        }
예제 #2
0
        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);
        }
        public void ApplyTo_Does_Not_Replace_Original_OrderBy_With_Missing_Keys()
        {
            // Arrange
            var model = new ODataModelBuilder()
                        .Add_Customers_No_Keys_EntitySet().GetEdmModel();

            var message = new HttpRequestMessage(
                HttpMethod.Get,
                new Uri("http://server/service/Customers?$orderby=Name")
                );

            // Act
            var queryOptions = new ODataQueryOptions(new ODataQueryContext(model, typeof(Customer)), message);
            OrderByQueryOption originalOption = queryOptions.OrderBy;
            ODataQuerySettings querySettings  = new ODataQuerySettings();

            IQueryable finalQuery = queryOptions.ApplyTo(new Customer[0].AsQueryable(), querySettings);

            // Assert
            Assert.ReferenceEquals(originalOption, queryOptions.OrderBy);
        }
예제 #4
0
        public void CanApplyOrderBy()
        {
            var model         = new ODataModelBuilder().Add_Customer_EntityType().Add_Customers_EntitySet().GetServiceModel();
            var orderByOption = new OrderByQueryOption("Name", new ODataQueryContext(model, typeof(Customer), "Customers"));

            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);
        }
예제 #5
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), "Customers"));

            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);
        }
예제 #6
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), "EnumModels");
            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[] { 2, 1, 3 },
                actualCustomers.Select(enumModel => enumModel.Id));
        }
예제 #7
0
        public void CanApplySkipTopOrderby()
        {
            var model         = new ODataModelBuilder().Add_Customer_EntityType().Add_Customers_EntitySet().GetServiceModel();
            var context       = new ODataQueryContext(model, typeof(Customer), "Customers");
            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);
            queryable = topOption.ApplyTo(queryable);
            var results = ((IQueryable <Customer>)queryable).ToArray();

            Assert.Equal(2, results.Length);
            Assert.Equal(4, results[0].CustomerId);
            Assert.Equal(3, results[1].CustomerId);
        }
예제 #8
0
        /// <summary>
        /// Initializes a new instance of the <see cref="ODataQueryOptions"/> class based on the incoming request and some metadata information from
        /// the <see cref="ODataQueryContext"/>.
        /// </summary>
        /// <param name="context">The <see cref="ODataQueryContext"/> which contains the <see cref="IEdmModel"/> and some type information.</param>
        /// <param name="request">The incoming request message.</param>
        public ODataQueryOptions(ODataQueryContext context, HttpRequestMessage request)
        {
            if (context == null)
            {
                throw Error.ArgumentNull("context");
            }

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

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

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

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

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

            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;
                    ThrowIfEmpty(kvp.Value, "$inlinecount");
                    InlineCount = new InlineCountQueryOption(kvp.Value, context);
                    break;

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

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

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

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

            Validator = new ODataQueryValidator();
        }
예제 #9
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 (InlineCount != null)
            {
                long?count = InlineCount.GetEntityCount(result);
                if (count.HasValue)
                {
                    Request.SetInlineCount(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);
            }

            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, Context, out resultsLimited);
                if (resultsLimited && Request.RequestUri != null && Request.RequestUri.IsAbsoluteUri)
                {
                    Uri nextPageLink = GetNextPageLink(Request, querySettings.PageSize.Value);
                    Request.SetNextPageLink(nextPageLink);
                }
            }

            return(result);
        }
        /// <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;
                }
            }
        }