public static IQueryable Bind(IQueryable queryable, ODataQuerySettings settings, SelectExpandQueryOption selectExpandQuery)
        {
            Contract.Assert(queryable != null);

            SelectExpandBinder binder = new SelectExpandBinder(settings, selectExpandQuery);
            return binder.Bind(queryable);
        }
        public static object Bind(object entity, ODataQuerySettings settings, SelectExpandQueryOption selectExpandQuery)
        {
            Contract.Assert(entity != null);

            SelectExpandBinder binder = new SelectExpandBinder(settings, selectExpandQuery);
            return binder.Bind(entity);
        }
 /// <summary>
 /// Initialize a new instance of the <see cref="ODataQuerySettings"/> class based on an existing one. 
 /// </summary>
 /// <param name="settings">The setting to copy from.</param>
 public ODataQuerySettings(ODataQuerySettings settings)
 {
     EnsureStableOrdering = settings.EnsureStableOrdering;
     EnableConstantParameterization = settings.EnableConstantParameterization;
     HandleNullPropagation = settings.HandleNullPropagation;
     PageSize = settings.PageSize;
 }
        public SelectExpandBinder(ODataQuerySettings settings, SelectExpandQueryOption selectExpandQuery)
        {
            Contract.Assert(settings != null);
            Contract.Assert(selectExpandQuery != null);
            Contract.Assert(selectExpandQuery.Context != null);
            Contract.Assert(selectExpandQuery.Context.Model != null);
            Contract.Assert(settings.HandleNullPropagation != HandleNullPropagationOption.Default);

            _selectExpandQuery = selectExpandQuery;
            _context = selectExpandQuery.Context;
            _model = _context.Model;
            _modelID = ModelContainer.GetModelID(_model);
            _settings = settings;
        }
        public SelectExpandBinderTest()
        {
            _settings = new ODataQuerySettings { HandleNullPropagation = HandleNullPropagationOption.False };
            _model = new CustomersModelWithInheritance();
            _model.Model.SetAnnotationValue<ClrTypeAnnotation>(_model.Customer, new ClrTypeAnnotation(typeof(Customer)));
            _model.Model.SetAnnotationValue<ClrTypeAnnotation>(_model.SpecialCustomer, new ClrTypeAnnotation(typeof(SpecialCustomer)));
            _context = new ODataQueryContext(_model.Model, typeof(Customer));
            _binder = new SelectExpandBinder(_settings, new SelectExpandQueryOption("*", "", _context));

            Customer customer = new Customer();
            Order order = new Order { Customer = customer };
            customer.Orders.Add(order);

            _queryable = new[] { customer }.AsQueryable();
        }
        internal AggregationBinder(ODataQuerySettings settings, IAssembliesResolver assembliesResolver, Type elementType,
            IEdmModel model, TransformationNode transformation)
            : base(model, assembliesResolver, settings)
        {
            Contract.Assert(elementType != null);
            Contract.Assert(transformation != null);

            _elementType = elementType;
            _transformation = transformation;

            this._lambdaParameter = Expression.Parameter(this._elementType, "$it");

            switch (transformation.Kind)
            {
                case TransformationNodeKind.Aggregate:
                    var aggregateClause = this._transformation as AggregateTransformationNode;
                    _aggregateExpressions = aggregateClause.Expressions;
                    ResultClrType = AggregationDynamicTypeProvider.GetResultType<DynamicTypeWrapper>(_model, null,
                        _aggregateExpressions);
                    break;
                case TransformationNodeKind.GroupBy:
                    var groupByClause = this._transformation as GroupByTransformationNode;
                    _groupingProperties = groupByClause.GroupingProperties;
                    if (groupByClause.ChildTransformations != null)
                    {
                        if (groupByClause.ChildTransformations.Kind == TransformationNodeKind.Aggregate)
                        {
                            _aggregateExpressions =
                                ((AggregateTransformationNode)groupByClause.ChildTransformations).Expressions;
                        }
                        else
                        {
                            throw new NotImplementedException();
                        }
                    }

                    _groupByClrType = AggregationDynamicTypeProvider.GetResultType<DynamicTypeWrapper>(_model,
                        _groupingProperties, null);
                    ResultClrType = AggregationDynamicTypeProvider.GetResultType<DynamicTypeWrapper>(_model,
                        _groupingProperties, _aggregateExpressions);
                    break;
                default:
                    throw new NotSupportedException(String.Format(CultureInfo.InvariantCulture,
                        SRResources.NotSupportedTransformationKind, transformation.Kind));
            }

            _groupByClrType = _groupByClrType ?? typeof(DynamicTypeWrapper);
        }
 /// <summary>
 /// Enables a controller action to support OData query parameters.
 /// </summary>
 public EnableQueryAttribute()
 {
     _validationSettings = new ODataValidationSettings();
     _querySettings      = new ODataQuerySettings();
 }
        public static ODataQuerySettings UpdateQuerySettings(this ODataQueryContext context, ODataQuerySettings querySettings, IQueryable query)
        {
            ODataQuerySettings updatedSettings = context.RequestContainer.GetRequiredService <ODataQuerySettings>();

            updatedSettings.CopyFrom(querySettings);

            if (updatedSettings.HandleNullPropagation == HandleNullPropagationOption.Default)
            {
                updatedSettings.HandleNullPropagation = query != null
                    ? HandleNullPropagationOptionHelper.GetDefaultHandleNullPropagationOption(query)
                    : HandleNullPropagationOption.True;
            }

            return(updatedSettings);
        }
Exemple #9
0
 internal AggregationBinderEFFake(ODataQuerySettings settings, IWebApiAssembliesResolver assembliesResolver, Type elementType, IEdmModel model, TransformationNode transformation)
     : base(settings, assembliesResolver, elementType, model, transformation)
 {
 }
        /// <summary>
        /// Creates a new instance of <see cref="StorageDomainManager{TData}"/>
        /// </summary>
        /// <param name="connectionStringName">
        /// Name of the storage connection string
        /// </param>
        /// <param name="tableName">
        /// Name of table
        /// </param>
        /// <param name="request">
        /// An instance of <see cref="HttpRequestMessage"/>
        /// </param>
        /// <param name="querySettings">
        /// An instance of <see cref="ODataQuerySettings"/>
        /// </param>
        /// <param name="validationSettings">
        /// An instance of <see cref="ODataValidationSettings"/>
        /// </param>
        /// <param name="enableSoftDelete">
        /// Determines whether rows are hard deleted or marked as deleted.
        /// </param>
        public StorageDomainManager(string connectionStringName, string tableName, HttpRequestMessage request, ODataValidationSettings validationSettings, ODataQuerySettings querySettings, bool enableSoftDelete)
            : base(request, enableSoftDelete)
        {
            if (connectionStringName == null)
            {
                throw new ArgumentNullException("connectionStringName");
            }

            if (tableName == null)
            {
                throw new ArgumentNullException("tableName");
            }

            if (validationSettings == null)
            {
                throw new ArgumentNullException("validationSettings");
            }

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

            this.validationSettings = validationSettings;
            this.querySettings      = querySettings;

            this.StorageAccount    = CloudStorageAccounts.GetOrAdd(connectionStringName, this.GetCloudStorageAccount);
            this.TableName         = tableName;
            this.TableClient       = this.StorageAccount.CreateCloudTableClient();
            this.Table             = this.TableClient.GetTableReference(this.TableName);
            this.systemPropertyMap = typeof(StorageData).IsAssignableFrom(typeof(TData)) ? StorageDataSystemPropertyMap : null;
        }
        private static IQueryable AddOrderByQueryForProperty <T>(ODataQuery <T> query, ODataQuerySettings querySettings,
                                                                 OrderByClause orderbyClause, IQueryable querySoFar, OrderByDirection direction, bool alreadyOrdered)
        {
            //Context.UpdateQuerySettings(querySettings, query);

            LambdaExpression orderByExpression =
                FilterBinder.Bind(query, orderbyClause, typeof(T), query.ServiceProvider);

            querySoFar = ExpressionHelpers.OrderBy(querySoFar, orderByExpression, direction, typeof(T),
                                                   alreadyOrdered);
            return(querySoFar);
        }
Exemple #12
0
        public static IQueryable <object> ApplyQuery(this IQueryable query, int recordLimit, IDictionary <string, string> queryString)
        {
            Check.NotNull(query, nameof(query));
            Check.NotNull(queryString, nameof(queryString));

            var defaultOdataQuerySettings = new ODataQuerySettings();
            var settings = new ODataValidationSettings
            {
                MaxTop = recordLimit
            };

            //Build odata context

            var modelBuilder = ODataQueryExtensions.ConfigureConventionBuilder();

            modelBuilder.AddEntityType(query.ElementType);
            modelBuilder.OnModelCreating += builder => AddCompoundKeyConvention(builder);

            var edmModel         = modelBuilder.GetEdmModel();
            var odataPath        = new ODataPath();
            var odataQueryConext = new ODataQueryContext(edmModel, query.ElementType, odataPath);

            var options = odataQueryConext.CreateOptionsFromQueryString(queryString);

            //set default record top limit
            if (options.Top == null && options.Count?.Value != true)
            {
                queryString.Add("$top", recordLimit.ToString(CultureInfo.InvariantCulture));
                options = odataQueryConext.CreateOptionsFromQueryString(queryString);
            }

            options.Validate(settings);

            IQueryable <dynamic> retList;

            if (options.OrderBy == null)
            {
                //Optimize odata filter ordering
                IQueryable results = options.ApplyTo(query, defaultOdataQuerySettings, AllowedQueryOptions.OrderBy);
                retList = results as IQueryable <dynamic>;
            }
            else
            {
                //Optimize odata filter ordering
                IQueryable results = options.OrderBy.ApplyTo(query, defaultOdataQuerySettings);
                results = options.ApplyTo(results, defaultOdataQuerySettings, AllowedQueryOptions.OrderBy);
                retList = results as IQueryable <dynamic>;
            }

            if (options.Count?.Value == true)
            {
                IList <dynamic> count    = new List <dynamic>();
                CountTotal      countObj = new CountTotal
                {
                    Count = retList.Count()
                };
                count.Add(countObj);
                return(count.AsQueryable());
            }

            return(retList);
        }
Exemple #13
0
 protected ExpressionBinderBase(IEdmModel model, IAssembliesResolver assembliesResolver, ODataQuerySettings querySettings)
     : this(model, querySettings)
 {
     _assembliesResolver = assembliesResolver;
 }
Exemple #14
0
        /// <summary>
        /// Apply the queryOptions to the query.
        /// This method handles nested order-by statements the the current ASP.NET web api does not yet support.
        /// </summary>
        /// <param name="queryable"></param>
        /// <param name="queryOptions"></param>
        /// <param name="querySettings"></param>
        /// <returns></returns>
        public static IQueryable ApplyQuery(IQueryable queryable, ODataQueryOptions queryOptions, ODataQuerySettings querySettings)
        {
            // HACK: this is a hack because on a bug in querySettings.EnsureStableOrdering = true that overrides
            // any existing order by clauses, instead of appending to them.
            querySettings.EnsureStableOrdering = false;

            // Basic idea here is the current WebApi OData cannot support the following operations
            // 1) "orderby" with  nested properties
            // 2) "select" with complex types
            // 3) "selects" of "nested" properties unless accompanied by the appropriate "expand".
            //     i.e. can't do Customers.select("orders") unless we also add expand("orders")

            // The workaround here is to bypass "select" and "orderBy" processing under these conditions
            // This involves removing the "offending" queryOptions before asking the WebApi2 OData processing to do its thing
            // and then post processing the resulting IQueryable.
            // We actually do this with all selects because it's easier than trying to determine if they are actually problematic.

            // Another approach that DOESN'T work is to let WebApi2 OData try to do it stuff and then only handle the cases where it throws an exception.
            // This doesn't work because WebApi2 OData will actually just skip the portions of the query that it can't process and return what it can ( under some conditions).

            var expandQueryString  = queryOptions.RawValues.Expand;
            var orderByQueryString = queryOptions.RawValues.OrderBy;
            var selectQueryString  = queryOptions.RawValues.Select;

            ODataQueryOptions newQueryOptions = queryOptions;

            if (selectQueryString != null)
            {
                newQueryOptions = QueryHelper.RemoveSelectAndExpand(newQueryOptions);
            }

            if (orderByQueryString != null && orderByQueryString.IndexOf('/') >= 0)
            {
                newQueryOptions = QueryHelper.RemoveSelectAndExpand(newQueryOptions);
                newQueryOptions = QueryHelper.RemoveExtendedOps(newQueryOptions);
            }

            if (newQueryOptions == queryOptions)
            {
                return(queryOptions.ApplyTo(queryable, querySettings));
            }
            else
            {
                // apply default processing first with "unsupported" stuff removed.
                var q = newQueryOptions.ApplyTo(queryable, querySettings);
                // then apply unsupported stuff.
                var qh = new QueryHelper(querySettings);

                if (orderByQueryString != null && orderByQueryString.IndexOf('/') >= 0)
                {
                    q = qh.ApplyNestedOrderBy(q, queryOptions);
                }

                if (selectQueryString != null)
                {
                    q = qh.ApplySelect(q, selectQueryString);
                }
                else if (expandQueryString != null)
                {
                    // don't bother doing an expand if there was already a select ( this code doesn't need it)
                    q = qh.ApplyExpand(q, queryOptions.RawValues.Expand);
                }


                return(q);
            }
        }
Exemple #15
0
 internal static Expression <Func <TEntityType, bool> > Bind <TEntityType>(FilterClause filterClause, IEdmModel model,
                                                                           IWebApiAssembliesResolver assembliesResolver, ODataQuerySettings querySettings)
 {
     return(Bind(filterClause, typeof(TEntityType), model, assembliesResolver, querySettings) as Expression <Func <TEntityType, bool> >);
 }
        internal Expression CreatePropertyValueExpressionWithFilter(IEdmEntityType elementType, IEdmProperty property,
                                                                    Expression source, FilterClause filterClause)
        {
            Contract.Assert(elementType != null);
            Contract.Assert(property != null);
            Contract.Assert(source != null);

            IEdmEntityType declaringType = property.DeclaringType as IEdmEntityType;

            Contract.Assert(declaringType != null, "only entity types are projected.");

            // derived property using cast
            if (elementType != declaringType)
            {
                Type castType = EdmLibHelpers.GetClrType(declaringType, _model);
                if (castType == null)
                {
                    throw new ODataException(Error.Format(SRResources.MappingDoesNotContainResourceType,
                                                          declaringType.FullName()));
                }

                source = Expression.TypeAs(source, castType);
            }

            string     propertyName          = EdmLibHelpers.GetClrPropertyName(property, _model);
            Expression propertyValue         = Expression.Property(source, propertyName);
            Type       nullablePropertyType  = TypeHelper.ToNullable(propertyValue.Type);
            Expression nullablePropertyValue = ExpressionHelpers.ToNullable(propertyValue);

            if (filterClause != null)
            {
                bool isCollection = property.Type.IsCollection();

                IEdmTypeReference edmElementType = (isCollection ? property.Type.AsCollection().ElementType() : property.Type);
                Type clrElementType = EdmLibHelpers.GetClrType(edmElementType, _model);
                if (clrElementType == null)
                {
                    throw new ODataException(Error.Format(SRResources.MappingDoesNotContainResourceType,
                                                          edmElementType.FullName()));
                }

                Expression filterResult = nullablePropertyValue;

                ODataQuerySettings querySettings = new ODataQuerySettings()
                {
                    HandleNullPropagation = HandleNullPropagationOption.True,
                };

                if (isCollection)
                {
                    Expression filterSource =
                        typeof(IEnumerable).IsAssignableFrom(source.Type.GetProperty(propertyName).PropertyType)
                            ? Expression.Call(
                            ExpressionHelperMethods.QueryableAsQueryable.MakeGenericMethod(clrElementType),
                            nullablePropertyValue)
                            : nullablePropertyValue;

                    // TODO: Implement proper support for $select/$expand after $apply
                    Expression filterPredicate = FilterBinder.Bind(null, filterClause, clrElementType, _context, querySettings);
                    filterResult = Expression.Call(
                        ExpressionHelperMethods.QueryableWhereGeneric.MakeGenericMethod(clrElementType),
                        filterSource,
                        filterPredicate);

                    nullablePropertyType = filterResult.Type;
                }
                else if (_settings.HandleReferenceNavigationPropertyExpandFilter)
                {
                    LambdaExpression filterLambdaExpression = FilterBinder.Bind(null, filterClause, clrElementType, _context, querySettings) as LambdaExpression;
                    if (filterLambdaExpression == null)
                    {
                        throw new ODataException(Error.Format(SRResources.ExpandFilterExpressionNotLambdaExpression,
                                                              property.Name, "LambdaExpression"));
                    }

                    ParameterExpression filterParameter     = filterLambdaExpression.Parameters.First();
                    Expression          predicateExpression = new ReferenceNavigationPropertyExpandFilterVisitor(filterParameter, nullablePropertyValue).Visit(filterLambdaExpression.Body);

                    // create expression similar to: 'predicateExpression == true ? nullablePropertyValue : null'
                    filterResult = Expression.Condition(
                        test: predicateExpression,
                        ifTrue: nullablePropertyValue,
                        ifFalse: Expression.Constant(value: null, type: nullablePropertyType));
                }

                if (_settings.HandleNullPropagation == HandleNullPropagationOption.True)
                {
                    // create expression similar to: 'nullablePropertyValue == null ? null : filterResult'
                    nullablePropertyValue = Expression.Condition(
                        test: Expression.Equal(nullablePropertyValue, Expression.Constant(value: null)),
                        ifTrue: Expression.Constant(value: null, type: nullablePropertyType),
                        ifFalse: filterResult);
                }
                else
                {
                    nullablePropertyValue = filterResult;
                }
            }

            if (_settings.HandleNullPropagation == HandleNullPropagationOption.True)
            {
                // create expression similar to: 'source == null ? null : propertyValue'
                propertyValue = Expression.Condition(
                    test: Expression.Equal(source, Expression.Constant(value: null)),
                    ifTrue: Expression.Constant(value: null, type: nullablePropertyType),
                    ifFalse: nullablePropertyValue);
            }
            else
            {
                // need to cast this to nullable as EF would fail while materializing if the property is not nullable and source is null.
                propertyValue = nullablePropertyValue;
            }

            return(propertyValue);
        }
        /// <summary>
        /// Apply the queryOptions to the query.
        /// This method handles nested order-by statements the the current ASP.NET web api does not yet support.
        /// </summary>
        /// <param name="queryable"></param>
        /// <param name="queryOptions"></param>
        /// <param name="querySettings"></param>
        /// <returns></returns>
        public IQueryable ApplyQuery(IQueryable queryable, ODataQueryOptions queryOptions, ODataQuerySettings querySettings)
        {
            // HACK: this is a hack because on a bug in querySettings.EnsureStableOrdering = true that overrides
            // any existing order by clauses, instead of appending to them.
            querySettings.EnsureStableOrdering = false;

            // Basic idea here is the current WebApi OData cannot support the following operations
            // 1) "orderby" with  nested properties
            // 2) "select" with complex types
            // 3) "selects" of "nested" properties unless accompanied by the appropriate "expand".
            //     i.e. can't do Customers.select("orders") unless we also add expand("orders")

            // The workaround here is to bypass "select" and "orderBy" processing under these conditions
            // This involves removing the "offending" queryOptions before asking the WebApi2 OData processing to do its thing
            // and then post processing the resulting IQueryable.
            // We actually do this with all selects because it's easier than trying to determine if they are actually problematic.

            // Another approach that DOESN'T work is to let WebApi2 OData try to do it stuff and then only handle the cases where it throws an exception.
            // This doesn't work because WebApi2 OData will actually just skip the portions of the query that it can't process and return what it can ( under some conditions).

            var expandQueryString  = queryOptions.RawValues.Expand;
            var orderByQueryString = queryOptions.RawValues.OrderBy;
            var selectQueryString  = queryOptions.RawValues.Select;

            ODataQueryOptions newQueryOptions = queryOptions;

            if (!string.IsNullOrWhiteSpace(selectQueryString))
            {
                newQueryOptions = QueryHelper.RemoveSelectExpandOrderBy(newQueryOptions);
            }
            else if ((!string.IsNullOrWhiteSpace(orderByQueryString)) && orderByQueryString.IndexOf('/') >= 0)
            {
                newQueryOptions = QueryHelper.RemoveSelectExpandOrderBy(newQueryOptions);
            }
            else if (ManuallyExpand && !string.IsNullOrWhiteSpace(expandQueryString))
            {
                newQueryOptions = QueryHelper.RemoveSelectExpandOrderBy(newQueryOptions);
            }


            if (newQueryOptions == queryOptions)
            {
                return(queryOptions.ApplyTo(queryable, querySettings));
            }
            else
            {
                // remove inlinecount or it will be executed two times
                if (newQueryOptions.InlineCount != null)
                {
                    newQueryOptions = QueryHelper.RemoveInlineCount(newQueryOptions);
                }

                // apply default processing first with "unsupported" stuff removed.
                var q = newQueryOptions.ApplyTo(queryable, querySettings);
                // then apply unsupported stuff.

                string inlinecountString = queryOptions.RawValues.InlineCount;
                if (!string.IsNullOrWhiteSpace(inlinecountString))
                {
                    if (inlinecountString == "allpages")
                    {
                        var inlineCount = (Int64)Queryable.Count((dynamic)q);
                        queryOptions.Request.SetInlineCount(inlineCount);
                    }
                }

                q = ApplyOrderBy(q, queryOptions);
                var q2 = ApplySelect(q, queryOptions);
                if (q2 == q)
                {
                    q2 = ApplyExpand(q, queryOptions);
                }

                return(q2);
            }
        }
        protected EntitySetController(IContainerMetadata containerMetadata, ODataValidationSettings queryValidationSettings, ODataQuerySettings querySettings)
        {
            Contract.Requires<ArgumentNullException>(containerMetadata != null);
            Contract.Requires<ArgumentNullException>(queryValidationSettings != null);
            Contract.Requires<ArgumentNullException>(querySettings != null);

            _entitySetMetadata = containerMetadata.GetEntitySetFor(typeof(TEntity));
            if (_entitySetMetadata == null)
            {
                throw new InvalidOperationException("EntitySet not found in containerMetadata for type " + typeof(TEntity));
            }

            _queryValidationSettings = queryValidationSettings;
            _querySettings = querySettings;
        }
Exemple #19
0
        private static FilterBinder GetOrCreateFilterBinder(ODataQueryContext context, ODataQuerySettings querySettings)
        {
            FilterBinder binder = null;

            if (context.RequestContainer != null)
            {
                binder = context.RequestContainer.GetRequiredService <FilterBinder>();
                if (binder != null && binder.Model != context.Model && binder.Model == EdmCoreModel.Instance)
                {
                    binder.Model = context.Model;
                }
            }

            return(binder ?? new FilterBinder(querySettings, WebApiAssembliesResolver.Default, context.Model));
        }
Exemple #20
0
 internal FilterBinder(ODataQuerySettings settings, IWebApiAssembliesResolver assembliesResolver, IEdmModel model)
     : base(model, assembliesResolver, settings)
 {
 }
Exemple #21
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("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
            ODataQuerySettings settings = new ODataQuerySettings {
                HandleNullPropagation = HandleNullPropagationOption.True
            };
            var results = orderByOption.ApplyTo(customers, settings).ToArray();

            // Assert
            Assert.Equal(3, results[0].Id);
            Assert.Equal(2, results[1].Id);
            Assert.Equal(1, results[2].Id);
        }
 internal ExpressionBinderBase(IEdmModel model, IAssemblyProvider assemblyProvider, ODataQuerySettings querySettings)
     : this(model, querySettings)
 {
     AssemblyProvider = assemblyProvider;
 }
Exemple #23
0
 internal TransformationBinderBase(ODataQuerySettings settings, IAssemblyResolver assembliesResolver, Type elementType,
                                   IEdmModel model) : base(model, assembliesResolver, settings)
 {
     Contract.Assert(elementType != null);
     LambdaParameter = Expression.Parameter(elementType, "$it");
 }
Exemple #24
0
 public QueryHelper(ODataQuerySettings querySettings)
 {
     this.querySettings = querySettings;
 }
        public static IOrderedQueryable OrderApplyToCore <T>(ODataQuery <T> query, ODataQuerySettings querySettings, ICollection <OrderByNode> nodes, IEdmModel model)
        {
            bool       alreadyOrdered = false;
            IQueryable querySoFar     = query;

            HashSet <object> propertiesSoFar     = new HashSet <object>();
            HashSet <string> openPropertiesSoFar = new HashSet <string>();
            bool             orderByItSeen       = false;

            foreach (OrderByNode node in nodes)
            {
                OrderByPropertyNode     propertyNode     = node as OrderByPropertyNode;
                OrderByOpenPropertyNode openPropertyNode = node as OrderByOpenPropertyNode;

                if (propertyNode != null)
                {
                    // Use autonomy class to achieve value equality for HasSet.
                    var edmPropertyWithPath    = new { propertyNode.Property, propertyNode.PropertyPath };
                    OrderByDirection direction = propertyNode.Direction;

                    // This check prevents queries with duplicate properties (e.g. $orderby=Id,Id,Id,Id...) from causing stack overflows
                    if (propertiesSoFar.Contains(edmPropertyWithPath))
                    {
                        throw new ODataException(Error.Format(SRResources.OrderByDuplicateProperty, edmPropertyWithPath.PropertyPath));
                    }

                    propertiesSoFar.Add(edmPropertyWithPath);

                    if (propertyNode.OrderByClause != null)
                    {
                        querySoFar = AddOrderByQueryForProperty(query, querySettings, propertyNode.OrderByClause, querySoFar, direction, alreadyOrdered);
                    }
                    else
                    {
                        querySoFar = ExpressionHelpers.OrderByProperty(querySoFar, model, edmPropertyWithPath.Property, direction, typeof(T), alreadyOrdered);
                    }

                    alreadyOrdered = true;
                }
                else if (openPropertyNode != null)
                {
                    // This check prevents queries with duplicate properties (e.g. $orderby=Id,Id,Id,Id...) from causing stack overflows
                    if (openPropertiesSoFar.Contains(openPropertyNode.PropertyName))
                    {
                        throw new ODataException(Error.Format(SRResources.OrderByDuplicateProperty, openPropertyNode.PropertyPath));
                    }

                    openPropertiesSoFar.Add(openPropertyNode.PropertyName);
                    Contract.Assert(openPropertyNode.OrderByClause != null);
                    querySoFar     = AddOrderByQueryForProperty(query, querySettings, openPropertyNode.OrderByClause, querySoFar, openPropertyNode.Direction, alreadyOrdered);
                    alreadyOrdered = true;
                }
                else
                {
                    // This check prevents queries with duplicate nodes (e.g. $orderby=$it,$it,$it,$it...) from causing stack overflows
                    if (orderByItSeen)
                    {
                        throw new ODataException(Error.Format(SRResources.OrderByDuplicateIt));
                    }

                    querySoFar     = ExpressionHelpers.OrderByIt(querySoFar, node.Direction, typeof(T), alreadyOrdered);
                    alreadyOrdered = true;
                    orderByItSeen  = true;
                }
            }

            return(querySoFar as IOrderedQueryable);
        }
Exemple #26
0
 public QueryHelper(bool enableConstantParameterization, bool ensureStableOrdering, HandleNullPropagationOption handleNullPropagation, int?pageSize)
 {
     this.querySettings = NewODataQuerySettings(enableConstantParameterization, ensureStableOrdering, handleNullPropagation, pageSize);
 }
 /// <summary>
 /// Creates a new instance of <see cref="StorageDomainManager{TData}"/>
 /// </summary>
 /// <param name="connectionStringName">
 /// Name of the storage connection string
 /// </param>
 /// <param name="tableName">
 /// Name of table
 /// </param>
 /// <param name="request">
 /// An instance of <see cref="HttpRequestMessage"/>
 /// </param>
 /// <param name="querySettings">
 /// An instance of <see cref="ODataQuerySettings"/>
 /// </param>
 /// <param name="validationSettings">
 /// An instance of <see cref="ODataValidationSettings"/>
 /// </param>
 public StorageDomainManager(string connectionStringName, string tableName, HttpRequestMessage request, ODataValidationSettings validationSettings, ODataQuerySettings querySettings)
     : this(connectionStringName, tableName, request, validationSettings, querySettings, enableSoftDelete : false)
 {
 }
Exemple #28
0
        /// <summary>
        /// Apply the queryOptions to the query.
        /// This method handles nested order-by statements the the current ASP.NET web api does not yet support.
        /// </summary>
        /// <param name="queryable"></param>
        /// <param name="queryOptions"></param>
        /// <param name="querySettings"></param>
        /// <returns></returns>
        public static IQueryable ApplyQuery(IQueryable queryable, ODataQueryOptions queryOptions, ODataQuerySettings querySettings)
        {
            // if we see an extended order by we also need to process any skip/take operators as well.
            var orderByQueryString = queryOptions.RawValues.OrderBy;

            if (orderByQueryString == null || orderByQueryString.IndexOf('/') < 0)
            {
                // Just let the default implementation handle it.
                return(queryOptions.ApplyTo(queryable, querySettings));
            }

            var newQueryOptions = QueryHelper.RemoveExtendedOps(queryOptions);

            var result = QueryHelper.ApplyQuery(queryable, newQueryOptions, querySettings);

            var elementType = TypeFns.GetElementType(queryable.GetType());

            var orderByClauses = orderByQueryString.Split(',').ToList();
            var isThenBy       = false;

            orderByClauses.ForEach(obc =>
            {
                var func = QueryBuilder.BuildOrderByFunc(isThenBy, elementType, obc);
                result   = func(result);
                isThenBy = true;
            });

            var skipQueryString = queryOptions.RawValues.Skip;

            if (!string.IsNullOrWhiteSpace(skipQueryString))
            {
                var count  = int.Parse(skipQueryString);
                var method = TypeFns.GetMethodByExample((IQueryable <String> q) => Queryable.Skip <String>(q, 999), elementType);
                var func   = BuildIQueryableFunc(elementType, method, count);
                result = func(result);
            }

            var topQueryString = queryOptions.RawValues.Top;

            if (!string.IsNullOrWhiteSpace(topQueryString))
            {
                var count  = int.Parse(topQueryString);
                var method = TypeFns.GetMethodByExample((IQueryable <String> q) => Queryable.Take <String>(q, 999), elementType);
                var func   = BuildIQueryableFunc(elementType, method, count);
                result = func(result);
            }
            return(result);
        }
Exemple #29
0
 public NHQueryHelper(ODataQuerySettings querySettings) : base(querySettings)
 {
 }
 internal ExpressionBinderBase(IEdmModel model, IAssembliesResolver assembliesResolver, ODataQuerySettings querySettings)
     : this(model, querySettings)
 {
     this.AssembliesResolver = assembliesResolver;
 }
        public ReadOnlyDbSetController(Lazy <TDbContext> lazyDbContext, IContainerMetadata <TDbContext> containerMetadata, ODataValidationSettings queryValidationSettings, ODataQuerySettings querySettings)
            : base(containerMetadata, queryValidationSettings, querySettings)
        {
            Contract.Requires <ArgumentNullException>(lazyDbContext != null);

            _lazyDb = lazyDbContext;
        }
 public static IQueryable <T> ApplyOptions <T>(this IQueryable <T> queryable, ODataQueryOptions <T> options, ODataQuerySettings querySettings)
 {
     return((IQueryable <T>)options.ApplyTo(queryable, querySettings));
 }
        public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
        {
            if (actionExecutedContext == null)
            {
                throw Error.ArgumentNull("actionExecutedContext");
            }

            HttpRequestMessage request = actionExecutedContext.Request;

            if (request == null)
            {
                throw Error.Argument("actionExecutedContext", SRResources.ActionExecutedContextMustHaveRequest);
            }

            HttpConfiguration configuration = request.GetConfiguration();

            if (configuration == null)
            {
                throw Error.Argument("actionExecutedContext", SRResources.RequestMustContainConfiguration);
            }

            if (actionExecutedContext.ActionContext == null)
            {
                throw Error.Argument("actionExecutedContext", SRResources.ActionExecutedContextMustHaveActionContext);
            }

            HttpActionDescriptor actionDescriptor = actionExecutedContext.ActionContext.ActionDescriptor;

            if (actionDescriptor == null)
            {
                throw Error.Argument("actionExecutedContext", SRResources.ActionContextMustHaveDescriptor);
            }

            HttpResponseMessage response = actionExecutedContext.Response;

            IEnumerable query;
            IQueryable  queryable = null;

            if (response != null && response.IsSuccessStatusCode && response.TryGetContentValue(out query))
            {
                if (request.RequestUri != null && !String.IsNullOrWhiteSpace(request.RequestUri.Query))
                {
                    ValidateQuery(request);

                    try
                    {
                        ODataQueryContext queryContext;

                        Type originalQueryType = query.GetType();
                        Type entityClrType     = TypeHelper.GetImplementedIEnumerableType(originalQueryType);

                        if (entityClrType == null)
                        {
                            // The element type cannot be determined because the type of the content
                            // is not IEnumerable<T> or IQueryable<T>.
                            throw Error.InvalidOperation(
                                      SRResources.FailedToRetrieveTypeToBuildEdmModel,
                                      this.GetType().Name,
                                      actionDescriptor.ActionName,
                                      actionDescriptor.ControllerDescriptor.ControllerName,
                                      originalQueryType.FullName);
                        }

                        // Primitive types do not construct an EDM model and deal only with the CLR Type
                        if (TypeHelper.IsQueryPrimitiveType(entityClrType))
                        {
                            queryContext = new ODataQueryContext(entityClrType);
                        }
                        else
                        {
                            // Get model for the entire app
                            IEdmModel model = configuration.GetEdmModel();

                            if (model == null)
                            {
                                // user has not configured anything, now let's create one just for this type
                                // and cache it in the action descriptor
                                model = actionDescriptor.GetEdmModel(entityClrType);
                                Contract.Assert(model != null);
                            }

                            // parses the query from request uri
                            queryContext = new ODataQueryContext(model, entityClrType);
                        }

                        ODataQueryOptions queryOptions = new ODataQueryOptions(queryContext, request);

                        // Filter and OrderBy require entity sets.  Top and Skip may accept primitives.
                        if (queryContext.IsPrimitiveClrType && (queryOptions.Filter != null || queryOptions.OrderBy != null))
                        {
                            // An attempt to use a query option not allowed for primitive types
                            // generates a BadRequest with a general message that avoids information disclosure.
                            actionExecutedContext.Response = request.CreateErrorResponse(
                                HttpStatusCode.BadRequest,
                                SRResources.OnlySkipAndTopSupported);
                            return;
                        }

                        // apply the query
                        queryable = query as IQueryable;
                        if (queryable == null)
                        {
                            queryable = query.AsQueryable();
                        }

                        ODataQuerySettings querySettings = new ODataQuerySettings
                        {
                            EnsureStableOrdering  = EnsureStableOrdering,
                            HandleNullPropagation = HandleNullPropagation
                        };

                        queryable = queryOptions.ApplyTo(queryable, querySettings);

                        Contract.Assert(queryable != null);

                        // we don't support shape changing query composition
                        ((ObjectContent)response.Content).Value = queryable;
                    }
                    catch (ODataException e)
                    {
                        actionExecutedContext.Response = request.CreateErrorResponse(
                            HttpStatusCode.BadRequest,
                            SRResources.UriQueryStringInvalid,
                            e);
                        return;
                    }
                }
            }
        }
        public static Uri GetNextLink(Uri currentRequestUri, long?totalResultCount, object queryParameters, ODataQueryOptions options, ODataQuerySettings settings, int?semVerLevelKey = null)
        {
            if (!totalResultCount.HasValue || totalResultCount.Value <= MaxPageSize || totalResultCount.Value == 0)
            {
                return(null); // no need for a next link if there are no additional results on this page
            }

            var skipCount = (options.Skip != null ? options.Skip.Value : 0) + Math.Min(totalResultCount.Value, (settings.PageSize != null ? settings.PageSize.Value : SearchAdaptor.MaxPageSize));

            if (totalResultCount.Value <= skipCount)
            {
                return(null); // no need for a next link if there are no additional results in the result set
            }

            var queryBuilder = new StringBuilder();

            var queryParametersCollection = new RouteValueDictionary(queryParameters);

            foreach (var queryParameter in queryParametersCollection)
            {
                queryBuilder.Append(Uri.EscapeDataString(queryParameter.Key));
                queryBuilder.Append("=");
                if (queryParameter.Value != null)
                {
                    if (queryParameter.Value is string)
                    {
                        queryBuilder.Append(Uri.EscapeDataString("'" + queryParameter.Value + "'"));
                    }
                    else if (queryParameter.Value is bool)
                    {
                        queryBuilder.Append(queryParameter.Value.ToString().ToLowerInvariant());
                    }
                    else
                    {
                        queryBuilder.Append(queryParameter.Value.ToString().ToLowerInvariant());
                    }
                }
                queryBuilder.Append("&");
            }

            if (options.SelectExpand != null)
            {
                if (!string.IsNullOrEmpty(options.SelectExpand.RawSelect))
                {
                    queryBuilder.Append("$select=");
                    queryBuilder.Append(options.SelectExpand.RawSelect);
                    queryBuilder.Append("&");
                }
                if (!string.IsNullOrEmpty(options.SelectExpand.RawExpand))
                {
                    queryBuilder.Append("$expand=");
                    queryBuilder.Append(options.SelectExpand.RawExpand);
                    queryBuilder.Append("&");
                }
            }

            if (options.Filter != null)
            {
                queryBuilder.Append("$filter=");
                queryBuilder.Append(options.Filter.RawValue);
                queryBuilder.Append("&");
            }

            if (options.OrderBy != null)
            {
                queryBuilder.Append("$orderby=");
                queryBuilder.Append(options.OrderBy.RawValue);
                queryBuilder.Append("&");
            }

            if (skipCount > 0)
            {
                queryBuilder.Append("$skip=");
                queryBuilder.Append(skipCount);
                queryBuilder.Append("&");
            }

            if (options.Top != null)
            {
                queryBuilder.Append("$top=");
                queryBuilder.Append(options.Top.RawValue);
                queryBuilder.Append("&");
            }

            if (semVerLevelKey != null)
            {
                if (semVerLevelKey == SemVerLevelKey.SemVer2)
                {
                    queryBuilder.Append("semVerLevel=");
                    queryBuilder.Append(SemVerLevelKey.SemVerLevel2);
                    queryBuilder.Append("&");
                }
            }

            var queryString = queryBuilder.ToString().TrimEnd('&');

            var builder = new UriBuilder(currentRequestUri);

            builder.Query = queryString;
            return(builder.Uri);
        }
Exemple #35
0
        public void SelectExpandBinder_BindsComputedPropertyInExpand_FromDollarCompute()
        {
            // Arrange
            QueryClause clause = CreateQueryClause("$expand=Orders($select=Title,Tax;$compute=Amount mul TaxRate as Tax)", _model, typeof(ComputeCustomer));

            ODataQuerySettings querySettings = new ODataQuerySettings();
            SelectExpandBinder binder        = new SelectExpandBinder();
            QueryBinderContext context       = new QueryBinderContext(_model, querySettings, typeof(ComputeCustomer));

            if (clause.Compute != null)
            {
                context.AddComputedProperties(clause.Compute.ComputedItems);
            }

            // Act
            Expression selectExp = binder.BindSelectExpand(clause.SelectExpand, context);

            // Assert
            Assert.NotNull(selectExp);
            string resultExpression = ExpressionStringBuilder.ToString(selectExp);

            Assert.Equal("$it => new SelectAllAndExpand`1() {Model = Microsoft.OData.Edm.EdmModel, " +
                         "Instance = $it, UseInstanceForProperties = True, " +
                         "Container = new NamedPropertyWithNext0`1() " +
                         "{" +
                         "Name = Orders, " +
                         "Value = $it.Orders.Select($it => new SelectSome`1() " +
                         "{" +
                         "Model = Microsoft.OData.Edm.EdmModel, " +
                         "Container = new NamedPropertyWithNext1`1() " +
                         "{" +
                         "Name = Title, " +
                         "Value = $it.Title, " +
                         "Next0 = new NamedProperty`1() {Name = Tax, Value = (Convert($it.Amount) * $it.TaxRate), }, " +
                         "Next1 = new AutoSelectedNamedProperty`1() " +
                         "{" +
                         "Name = Id, Value = Convert($it.Id), " +
                         "}, " +
                         "}, " +
                         "}), " +
                         "Next0 = new NamedProperty`1() {Name = Dynamics, Value = $it.Dynamics, }, }, }", resultExpression);

            ComputeCustomer customer = new ComputeCustomer
            {
                Orders = new List <ComputeOrder>
                {
                    new ComputeOrder {
                        Title = "Kerry", Amount = 4, TaxRate = 0.35
                    },
                    new ComputeOrder {
                        Title = "WU", Amount = 6, TaxRate = 0.5
                    },
                    new ComputeOrder {
                        Title = "XU", Amount = 5, TaxRate = 0.12
                    },
                }
            };
            IDictionary <string, object> result = SelectExpandBinderTest.InvokeSelectExpand(customer, selectExp);

            Assert.Equal(8, result.Count); // Because it's select-all

            int idx         = 0;
            var ordersValue = result["Orders"] as IEnumerable;

            foreach (var order in ordersValue)
            {
                SelectExpandWrapper itemWrapper = order as SelectExpandWrapper;

                var orderDic = itemWrapper.ToDictionary();
                Assert.Equal(customer.Orders[idx].Title, orderDic["Title"]);
                Assert.Equal(customer.Orders[idx].Amount * customer.Orders[idx].TaxRate, orderDic["Tax"]);
                idx++;
            }
        }
Exemple #36
0
        internal static Expression Bind(FilterClause filterClause, Type filterType, IEdmModel model,
                                        IWebApiAssembliesResolver assembliesResolver, ODataQuerySettings querySettings)
        {
            if (filterClause == null)
            {
                throw Error.ArgumentNull("filterClause");
            }
            if (filterType == null)
            {
                throw Error.ArgumentNull("filterType");
            }
            if (model == null)
            {
                throw Error.ArgumentNull("model");
            }
            if (assembliesResolver == null)
            {
                throw Error.ArgumentNull("assembliesResolver");
            }

            FilterBinder binder = new FilterBinder(model, assembliesResolver, querySettings, filterType);

            return(BindFilterClause(binder, filterClause, filterType));
        }