/// <summary>
        /// Applies the query to the given entity using the given <see cref="ODataQuerySettings"/>.
        /// </summary>
        /// <param name="entity">The original entity.</param>
        /// <param name="querySettings">The <see cref="ODataQuerySettings"/> that contains all the query application related settings.</param>
        /// <returns>The new entity after the $select and $expand query has been applied to.</returns>
        /// <remarks>Only $select and $expand query options can be applied on single entities. This method throws if the query contains any other
        /// query options.</remarks>
        public virtual object ApplyTo(object entity, ODataQuerySettings querySettings)
        {
            if (entity == null)
            {
                throw Error.ArgumentNull("entity");
            }
            if (querySettings == null)
            {
                throw Error.ArgumentNull("querySettings");
            }

            if (Filter != null || OrderBy != null || Top != null || Skip != null || Count != null)
            {
                throw Error.InvalidOperation(SRResources.NonSelectExpandOnSingleEntity);
            }

            if (SelectExpand != null)
            {
                SelectExpandClause      processedClause = SelectExpand.ProcessLevels();
                SelectExpandQueryOption newSelectExpand = new SelectExpandQueryOption(
                    SelectExpand.RawSelect,
                    SelectExpand.RawExpand,
                    SelectExpand.Context,
                    processedClause);

                Request.ODataProperties().SelectExpandClause = processedClause;
                return(newSelectExpand.ApplyTo(entity, querySettings));
            }

            return(entity);
        }
Example #2
0
        public void ApplyTo_OnSingleEntity_WithUnTypedContext_Throws_InvalidOperation()
        {
            // Arrange
            CustomersModelWithInheritance model        = new CustomersModelWithInheritance();
            ODataQueryContext             context      = new ODataQueryContext(model.Model, model.Customer);
            SelectExpandQueryOption       selectExpand = new SelectExpandQueryOption(select: "ID", expand: null, context: context);
            object entity = new object();

            // Act & Assert
            Assert.Throws <NotSupportedException>(() => selectExpand.ApplyTo(entity, new ODataQuerySettings()),
                                                  "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 ApplyTo_OnSingleEntity_WithUnTypedContext_Throws_InvalidOperation()
        {
            // Arrange
            CustomersModelWithInheritance model = new CustomersModelWithInheritance();
            ODataQueryContext context = new ODataQueryContext(model.Model, model.Customer);
            SelectExpandQueryOption selectExpand = new SelectExpandQueryOption(select: "ID", expand: null, context: context);
            object entity = new object();

            // Act & Assert
            Assert.Throws<NotSupportedException>(() => selectExpand.ApplyTo(entity, new ODataQuerySettings()),
                "The query option is not bound to any CLR type. 'ApplyTo' is only supported with a query option bound to a CLR type.");
        }
Example #4
0
        private T ApplySelectExpand <T>(T entity, ODataQuerySettings querySettings)
        {
            var  result          = default(T);
            bool selectAvailable = IsAvailableODataQueryOption(SelectExpand.RawSelect, AllowedQueryOptions.Select);
            bool expandAvailable = IsAvailableODataQueryOption(SelectExpand.RawExpand, AllowedQueryOptions.Expand);

            if (selectAvailable || expandAvailable)
            {
                if ((!selectAvailable && SelectExpand.RawSelect != null) ||
                    (!expandAvailable && SelectExpand.RawExpand != null))
                {
                    SelectExpand = new SelectExpandQueryOption(
                        selectAvailable ? RawValues.Select : null,
                        expandAvailable ? RawValues.Expand : null,
                        SelectExpand.Context);
                }

                SelectExpandClause      processedClause = SelectExpand.ProcessLevels();
                SelectExpandQueryOption newSelectExpand = new SelectExpandQueryOption(
                    SelectExpand.RawSelect,
                    SelectExpand.RawExpand,
                    SelectExpand.Context,
                    processedClause);

                Request.ODataProperties().SelectExpandClause = processedClause;

                var type = typeof(T);
                if (type == typeof(IQueryable))
                {
                    result = (T)newSelectExpand.ApplyTo((IQueryable)entity, querySettings);
                }
                else if (type == typeof(object))
                {
                    result = (T)newSelectExpand.ApplyTo(entity, querySettings);
                }
            }

            return(result);
        }
Example #5
0
        public void ApplyTo_OnQueryable_WithUnTypedContext_Throws_InvalidOperation()
        {
            // Arrange
            CustomersModelWithInheritance model   = new CustomersModelWithInheritance();
            ODataQueryContext             context = new ODataQueryContext(model.Model, model.Customer);

            context.RequestContainer = new MockContainer();
            SelectExpandQueryOption selectExpand = new SelectExpandQueryOption(select: "ID", expand: null, context: context);
            IQueryable queryable = new Mock <IQueryable>().Object;

            // Act & Assert
            Assert.Throws <NotSupportedException>(() => selectExpand.ApplyTo(queryable, new ODataQuerySettings()),
                                                  "The query option is not bound to any CLR type. 'ApplyTo' is only supported with a query option bound to a CLR type.");
        }
        /// <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)
            {
                if (Request.ODataProperties().TotalCount == null)
                {
                    long?count = Count.GetEntityCount(result);
                    if (count.HasValue)
                    {
                        Request.ODataProperties().TotalCount = count.Value;
                    }
                }

                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 &&
                (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)
            {
                SelectExpandClause      processedClause = SelectExpand.ProcessLevels();
                SelectExpandQueryOption newSelectExpand = new SelectExpandQueryOption(
                    SelectExpand.RawSelect,
                    SelectExpand.RawExpand,
                    SelectExpand.Context,
                    processedClause);

                Request.ODataProperties().SelectExpandClause = processedClause;
                result = newSelectExpand.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);
        }