예제 #1
0
        // coerce fromExpr to toExpr type
        // but also convert both to nonnullable types.
        private void ConvertExpr(ref Expression fromExpr, ref Expression toExpr)
        {
            var constExpr = fromExpr as ConstantExpression;

            var toType = TypeFns.GetNonNullableType(toExpr.Type);

            if (constExpr != null)
            {
                if (constExpr.Value == null)
                {
                    return;
                }
                var newValue = Convert.ChangeType(constExpr.Value, toType);
                fromExpr = Expression.Constant(newValue);
            }
            else
            {
                fromExpr = Expression.Convert(fromExpr, toType);
            }
            if (TypeFns.IsNullableType(toExpr.Type))
            {
                toExpr = Expression.Convert(toExpr, toType);
            }
        }
예제 #2
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;

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

            string inlinecountString = queryOptions.RawValues.InlineCount;

            if (!string.IsNullOrWhiteSpace(inlinecountString))
            {
                if (inlinecountString == "allpages")
                {
                    if (result is IQueryable)
                    {
                        var inlineCount = (Int64)Queryable.Count((dynamic)result);
                        queryOptions.Request.SetInlineCount(inlineCount);
                    }
                }
            }

            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);
        }
예제 #3
0
 /// <summary>
 /// Constructs a generic list.
 /// </summary>
 /// <param name="type"></param>
 /// <returns></returns>
 public static IList MakeGenericList(Type type)
 {
     return((IList)TypeFns.ConstructGenericInstance(typeof(List <>), type));
 }
예제 #4
0
        /// <summary>
        /// Called when the action is executed.
        /// </summary>
        /// <param name="actionExecutedContext">The action executed context.</param>
        public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
        {
            if (actionExecutedContext.Response == null)
            {
                return;
            }

            if (!actionExecutedContext.Response.IsSuccessStatusCode)
            {
                return;
            }

            object responseObject;

            if (!actionExecutedContext.Response.TryGetContentValue(out responseObject))
            {
                return;
            }

            var dQuery = ((dynamic)responseObject);

            if (dQuery.GetType().IsInstanceOfType(typeof(IQueryable)))
            {
                return;
            }

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

            NameValueCollection querystringParams =
                HttpUtility.ParseQueryString(actionExecutedContext.Request.RequestUri.Query);

            string filterQueryString = querystringParams["$filter"];

            if (!string.IsNullOrWhiteSpace(filterQueryString))
            {
                var func = BuildFilterFunc(filterQueryString, elementType);
                dQuery = func(dQuery as IQueryable);
            }

            int?   inlineCount       = null;
            string inlinecountString = querystringParams["$inlinecount"];

            if (!string.IsNullOrWhiteSpace(inlinecountString))
            {
                if (inlinecountString == "allpages")
                {
                    if (dQuery is IQueryable)
                    {
                        inlineCount = Queryable.Count(dQuery);
                    }
                }
            }


            string orderByQueryString = querystringParams["$orderby"];

            if (!string.IsNullOrWhiteSpace(orderByQueryString))
            {
                var orderByClauses = orderByQueryString.Split(',').ToList();
                var isThenBy       = false;
                orderByClauses.ForEach(obc => {
                    var func = BuildOrderByFunc(isThenBy, elementType, obc);
                    dQuery   = func(dQuery as IQueryable);
                    isThenBy = true;
                });
            }

            string skipQueryString = querystringParams["$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);
                dQuery = func(dQuery as IQueryable);
            }

            string topQueryString = querystringParams["$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);
                dQuery = func(dQuery as IQueryable);
            }

            string selectQueryString = querystringParams["$select"];

            if (!string.IsNullOrWhiteSpace(selectQueryString))
            {
                var selectClauses = selectQueryString.Split(',').Select(sc => sc.Replace('/', '.')).ToList();
                var func          = BuildSelectFunc(elementType, selectClauses);
                dQuery = func(dQuery as IQueryable);
            }

            string expandsQueryString = querystringParams["$expand"];

            if (!string.IsNullOrWhiteSpace(expandsQueryString))
            {
                if (!string.IsNullOrWhiteSpace(selectQueryString))
                {
                    throw new Exception("Use of both 'expand' and 'select' in the same query is not currently supported");
                }
                expandsQueryString.Split(',').Select(s => s.Trim()).ToList().ForEach(expand => {
                    dQuery = dQuery.Include(expand.Replace('/', '.'));
                });
            }

            // execute any DbQueries here, so that any exceptions thrown can be properly returned.
            // if we wait to have the query executed within the serializer, some exceptions will not
            // serialize properly.
            Object rQuery;

            if (dQuery is IQueryable)
            {
                rQuery = System.Linq.Enumerable.ToList((dynamic)dQuery);
            }
            else
            {
                rQuery = dQuery;
            }

            var formatter = ((dynamic)actionExecutedContext.Response.Content).Formatter;
            var oc        = new System.Net.Http.ObjectContent(rQuery.GetType(), rQuery, formatter);

            actionExecutedContext.Response.Content = oc;

            if (inlineCount.HasValue)
            {
                actionExecutedContext.Response.Headers.Add("X-InlineCount", inlineCount.ToString());
            }
        }
예제 #5
0
        private IQueryable ApplyExtendedOrderBy(IQueryable queryable, ODataQueryOptions queryOptions)
        {
            // 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("/") == -1)
            {
                return(null);
            }

            var request  = queryOptions.Request;
            var oldUri   = request.RequestUri;
            var map      = oldUri.ParseQueryString();
            var newQuery = map.Keys.Cast <String>()
                           .Where(k => (k != "$orderby") && (k != "$top") && (k != "$skip"))
                           .Select(k => k + "=" + map[k])
                           .ToAggregateString("&");

            var newUrl = oldUri.Scheme + "://" + oldUri.Authority + oldUri.AbsolutePath + "?" + newQuery;

            var newRequest = new HttpRequestMessage(request.Method, new Uri(newUrl));
            var newQo      = new ODataQueryOptions(queryOptions.Context, newRequest);
            var result     = base.ApplyQuery(queryable, newQo);

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


            if (!string.IsNullOrWhiteSpace(orderByQueryString))
            {
                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);
            }

            request.Properties.Add("breeze_orderBy", true);
            return(result);
        }
예제 #6
0
        protected virtual Expression VisitNode(ParseTreeNode node)
        {
            if (node == null)
            {
                return(null);
            }
            var        nodes = node.ChildNodes;
            Expression targetExpr, searchExpr, startExpr, lengthExpr;
            String     methodName;

            switch (node.Term.Name)
            {
            case "BinaryExpr": {
                var leftExpr     = VisitNode(nodes[0]);
                var operatorName = nodes[1].Token.ValueString;
                var rightExpr    = VisitNode(nodes[2]);
                return(VisitBinary(node, operatorName, leftExpr, rightExpr));
            }

            case "UnaryExpr": {
                var operatorName = nodes[0].Token.ValueString.ToLower();
                targetExpr = VisitNode(nodes[1]);
                return(VisitUnary(node, targetExpr, operatorName));
            }

            case "MemberExpr": {
                targetExpr = _paramExpr;
                ParameterExpression paramExpr;
                nodes[0].ChildNodes.ForEach(n => {
                        var name = n.Term.Name;
                        if (name == "Identifier")
                        {
                            if (_lambdaVarMap.TryGetValue(n.Token.ValueString, out paramExpr))
                            {
                                targetExpr = paramExpr;
                            }
                            else
                            {
                                targetExpr = VisitMemberExpr(n, targetExpr, n.Token.ValueString);
                            }
                        }
                        else if (name == "AnyMethodCallExpr" || name == "AllMethodCallExpr")
                        {
                            methodName             = n.ChildNodes[0].Token.ValueString;
                            var lambdaExprNode     = n.ChildNodes[1];
                            var lambdaVariableName = lambdaExprNode.ChildNodes[0].Token.ValueString;
                            var exprNode           = lambdaExprNode.ChildNodes[1];
                            var itemType           = TypeFns.GetElementType(targetExpr.Type);
                            paramExpr = Expression.Parameter(itemType, lambdaVariableName);
                            _lambdaVarMap.Add(lambdaVariableName, paramExpr);
                            var lambdaSubExpr = VisitNode(exprNode);
                            var lambdaExpr    = Expression.Lambda(lambdaSubExpr, paramExpr);
                            targetExpr        = VisitAnyAll(n, targetExpr, methodName, lambdaExpr);
                        }
                        else
                        {
                            throw new Exception("Unable to process node: " + n.Term.Name);
                        }
                    });
                return(targetExpr);
            }

            case "StringLiteral":
            case "NumberLiteral": {
                return(VisitSimpleLiteral(node, node.Token.Value));
            }

            case "Constant": {
                return(VisitConstant(node, node.Token.ValueString));
            }

            case "DateTimeLiteral": {
                return(VisitDateTimeLiteral(node, node.Token.ValueString));
            }

            case "TimeLiteral": {
                return(VisitTimeLiteral(node, node.Token.ValueString));
            }

            case "GuidLiteral": {
                return(VisitGuidLiteral(node, node.Token.ValueString));
            }

            case "DateTimeOffsetLiteral": {
                return(VisitDateTimeOffsetLiteral(node, node.Token.ValueString));
            }

            case "SubstringOfMethodCallExpr": {
                searchExpr = VisitNode(nodes[1]);
                targetExpr = VisitNode(nodes[2]);
                return(VisitSubstringOf(node, targetExpr, searchExpr));
            }

            case "StartsWithMethodCallExpr": {
                targetExpr = VisitNode(nodes[1]);
                searchExpr = VisitNode(nodes[2]);
                return(VisitStartsWith(node, targetExpr, searchExpr));
            }

            case "EndsWithMethodCallExpr": {
                targetExpr = VisitNode(nodes[1]);
                searchExpr = VisitNode(nodes[2]);
                return(VisitEndsWith(node, targetExpr, searchExpr));
            }

            case "IndexOfMethodCallExpr": {
                targetExpr = VisitNode(nodes[1]);
                searchExpr = VisitNode(nodes[2]);
                return(VisitIndexOf(node, targetExpr, searchExpr));
            }

            case "Substring1MethodCallExpr": {
                targetExpr = VisitNode(nodes[1]);
                startExpr  = VisitNode(nodes[2]);
                return(VisitSubstring1(node, targetExpr, startExpr));
            }

            case "Substring2MethodCallExpr": {
                targetExpr = VisitNode(nodes[1]);
                startExpr  = VisitNode(nodes[2]);
                lengthExpr = VisitNode(nodes[3]);
                return(VisitSubstring2(node, targetExpr, startExpr, lengthExpr));
            }

            case "ConcatMethodCallExpr": {
                var expr1 = VisitNode(nodes[1]);
                var expr2 = VisitNode(nodes[2]);
                return(VisitConcat(node, expr1, expr2));
            }

            case "ReplaceMethodCallExpr": {
                targetExpr = VisitNode(nodes[1]);
                var findExpr    = VisitNode(nodes[2]);
                var replaceExpr = VisitNode(nodes[3]);
                return(VisitReplace(node, targetExpr, findExpr, replaceExpr));
            }

            case "LengthMethodCallExpr": {
                targetExpr = VisitNode(nodes[1]);
                return(VisitLength(node, targetExpr));
            }

            case "TrimMethodCallExpr": {
                targetExpr = VisitNode(nodes[1]);
                return(VisitTrim(node, targetExpr));
            }

            case "ToLowerMethodCallExpr": {
                targetExpr = VisitNode(nodes[1]);
                return(VisitToLower(node, targetExpr));
            }

            case "ToUpperMethodCallExpr": {
                targetExpr = VisitNode(nodes[1]);
                return(VisitToUpper(node, targetExpr));
            }

            case "SecondMethodCallExpr":
            case "MinuteMethodCallExpr":
            case "HourMethodCallExpr":
            case "DayMethodCallExpr":
            case "MonthMethodCallExpr":
            case "YearMethodCallExpr": {
                methodName = nodes[0].Token.ValueString.ToLower();
                targetExpr = VisitNode(nodes[1]);
                return(VisitDatePart(node, targetExpr, methodName));
            }

            case "RoundMethodCallExpr":
            case "FloorMethodCallExpr":
            case "CeilingMethodCallExpr": {
                methodName = nodes[0].Token.ValueString.ToLower();
                targetExpr = VisitNode(nodes[1]);
                return(VisitMath(node, targetExpr, methodName));
            }

            default: throw new Exception("Unknown Expression type: " + node.Term.Name);
            }
        }
예제 #7
0
 private void CoerceTypes(string operatorName, ref Expression leftExpr, ref Expression rightExpr)
 {
     if (leftExpr.Type != rightExpr.Type)
     {
         var leftType  = TypeFns.GetNonNullableType(leftExpr.Type);
         var rightType = TypeFns.GetNonNullableType(rightExpr.Type);
         if (leftType == typeof(String))
         {
             ConvertExpr(ref rightExpr, ref leftExpr);
         }
         else if (rightType == typeof(String))
         {
             ConvertExpr(ref leftExpr, ref rightExpr);
         }
         else if ((TypeFns.IsNumericType(leftType) || TypeFns.IsEnumType(leftType)) && (TypeFns.IsNumericType(rightType) || TypeFns.IsEnumType(rightType)))
         {
             var leftIx  = NumericTypes.IndexOf(leftType);
             var rightIx = NumericTypes.IndexOf(rightType);
             if (leftIx < rightIx)
             {
                 ConvertExpr(ref leftExpr, ref rightExpr);
             }
             else
             {
                 ConvertExpr(ref rightExpr, ref leftExpr);
             }
         }
         else if (leftType == typeof(Guid) ||
                  leftType == typeof(DateTime) ||
                  leftType == typeof(Boolean) ||
                  leftType == typeof(TimeSpan) ||
                  TypeFns.IsNumericType(leftType) ||
                  TypeFns.IsEnumType(leftType))
         {
             ConvertExpr(ref rightExpr, ref leftExpr);
         }
         else
         {
             throw new Exception("Unable to perform operation: " + operatorName + "on types:"
                                 + leftExpr.Type + ", " + rightExpr.Type);
         }
     }
 }