예제 #1
0
        public static ODataQueryExpression Parse(Type elementType, NameValueCollection parameters)
        {
            Throw.IfNull(elementType, "elementType");
            Throw.IfNull(parameters, "parameters");

            ODataExpression filter       = null;
            var             filterString = parameters["$filter"];

            if (!string.IsNullOrEmpty(filterString))
            {
                var parser = new ODataExpressionLanguageParser(elementType, filterString);
                filter = parser.Parse();
            }

            IReadOnlyList <ODataSortKeyExpression> orderBy = Empty <ODataSortKeyExpression> .Array;
            var orderByString = parameters["$orderby"];

            if (!string.IsNullOrEmpty(orderByString))
            {
                var parser = new ODataExpressionLanguageParser(elementType, orderByString);
                orderBy = parser.ParseSortKeyList();
            }

            int?top       = null;
            var topString = parameters["$top"];

            if (!string.IsNullOrEmpty(topString))
            {
                int topValue;
                if (!int.TryParse(topString, out topValue))
                {
                    throw new ODataParseException("Expected an integer value for $top: " + topString);
                }
                top = topValue;
            }

            var skip       = 0;
            var skipString = parameters["$skip"];

            if (!string.IsNullOrEmpty(skipString))
            {
                if (!int.TryParse(skipString, out skip))
                {
                    throw new ODataParseException("Expected an integer value for $skip: " + skipString);
                }
            }

            IReadOnlyList <ODataSelectColumnExpression> select = Empty <ODataSelectColumnExpression> .Array;
            var selectString = parameters["$select"];

            if (!string.IsNullOrEmpty(selectString))
            {
                var parser = new ODataExpressionLanguageParser(elementType, selectString);
                select = parser.ParseSelectColumnList();
            }

            var    formatParameter = parameters["$format"];
            string format;

            if (!string.IsNullOrEmpty(formatParameter))
            {
                Throw <ODataParseException> .If(string.IsNullOrWhiteSpace(formatParameter), "$format may not be whitespace");

                format = formatParameter;
            }
            else
            {
                format = null;
            }

            var inlineCount       = ODataInlineCountOption.None;
            var inlineCountString = parameters["$inlinecount"];

            if (!string.IsNullOrEmpty(inlineCountString))
            {
                if (!Enum.TryParse(inlineCountString, ignoreCase: true, result: out inlineCount))
                {
                    throw new ODataParseException("Unexpected value " + inlineCountString + " for $inlinecount");
                }
            }

            return(ODataExpression.Query(
                       filter: filter,
                       orderBy: orderBy,
                       top: top,
                       skip: skip,
                       select: select,
                       format: format,
                       inlineCount: inlineCount
                       ));
        }
예제 #2
0
        private ODataExpression TranslateInternal(Expression linq)
        {
            if (linq == null)
            {
                return(null);
            }

            // captured parameters
            object value;

            if (TryGetValueFast(linq, out value))
            {
                // special case the handling of queryable constants, since these can be the "root"
                // of the query expression tree. We check for isInsideQuery since we don't allow multiple
                // roots. An example of a multiply-rooted tree would be: q.Where(x => q.Any(xx => xx.A < x.A))
                if (!this._isInsideQuery && typeof(IQueryable).GetTypeInfo().IsAssignableFrom(linq.Type.GetTypeInfo()))
                {
                    this._rootQuery = (IQueryable)value;
                    return(ODataExpression.Query());
                }
                return(ODataExpression.Constant(value, linq.Type));
            }

            switch (linq.NodeType)
            {
            case ExpressionType.OrElse:
                return(this.TranslateBinary(linq, ODataBinaryOp.Or));

            case ExpressionType.AndAlso:
                return(this.TranslateBinary(linq, ODataBinaryOp.And));

            case ExpressionType.Add:
                if (linq.Type == typeof(string))
                {
                    // special case adding strings, since that's the same as Concat
                    var binary = (BinaryExpression)linq;
                    return(this.TranslateInternal(Expression.Call(Helpers.GetMethod(() => string.Concat(default(string), default(string))), binary.Left, binary.Right)));
                }
                return(this.TranslateBinary(linq, ODataBinaryOp.Add));

            case ExpressionType.Subtract:
                return(this.TranslateBinary(linq, ODataBinaryOp.Subtract));

            case ExpressionType.Multiply:
                return(this.TranslateBinary(linq, ODataBinaryOp.Multiply));

            case ExpressionType.Divide:
                return(this.TranslateBinary(linq, ODataBinaryOp.Divide));

            case ExpressionType.Modulo:
                return(this.TranslateBinary(linq, ODataBinaryOp.Modulo));

            case ExpressionType.Equal:
                return(this.TranslateBinary(linq, ODataBinaryOp.Equal));

            case ExpressionType.NotEqual:
                return(this.TranslateBinary(linq, ODataBinaryOp.NotEqual));

            case ExpressionType.LessThan:
                return(this.TranslateBinary(linq, ODataBinaryOp.LessThan));

            case ExpressionType.LessThanOrEqual:
                return(this.TranslateBinary(linq, ODataBinaryOp.LessThanOrEqual));

            case ExpressionType.GreaterThan:
                return(this.TranslateBinary(linq, ODataBinaryOp.GreaterThan));

            case ExpressionType.GreaterThanOrEqual:
                return(this.TranslateBinary(linq, ODataBinaryOp.GreaterThanOrEqual));

            case ExpressionType.Not:
                return(ODataExpression.UnaryOp(this.TranslateInternal(((UnaryExpression)linq).Operand), ODataUnaryOp.Not));

            case ExpressionType.Negate:
                // we translate -a.B as (-1 * a.B) for numeric types
                var negated = ((UnaryExpression)linq).Operand;
                var underlyingNegatedType = Nullable.GetUnderlyingType(negated.Type) ?? negated.Type;
                if (!underlyingNegatedType.IsNumeric())
                {
                    throw new ODataCompileException("Expression '" + linq + "' could not be translated to OData: only negation of numeric types is supported");
                }
                var multiplyNegate = Expression.Multiply(
                    Expression.Constant(Convert.ChangeType(-1, underlyingNegatedType), negated.Type),
                    negated
                    );
                return(this.TranslateInternal(multiplyNegate));

            case ExpressionType.MemberAccess:
                return(this._memberAndParameterTranslator.TranslateMemberAccess((MemberExpression)linq));

            case ExpressionType.Convert:
            case ExpressionType.ConvertChecked:
            case ExpressionType.TypeAs:
                return(ODataExpression.Convert(this.TranslateInternal(((UnaryExpression)linq).Operand), linq.Type));

            case ExpressionType.Parameter:
                return(this._memberAndParameterTranslator.TranslateParameter((ParameterExpression)linq));

            case ExpressionType.TypeIs:
                var typeBinary     = (TypeBinaryExpression)linq;
                var isArg          = this.TranslateInternal(typeBinary.Expression);
                var isTypeConstant = ODataExpression.Constant(typeBinary.TypeOperand);
                return(isArg != null
                                                ? ODataExpression.Call(ODataFunction.IsOf, new[] { isArg, isTypeConstant })
                                                : ODataExpression.Call(ODataFunction.IsOf, new[] { isTypeConstant }));

            case ExpressionType.Call:
                return(this.TranslateCall((MethodCallExpression)linq));

            case ExpressionType.Quote:
                var quoted = (LambdaExpression)((UnaryExpression)linq).Operand;
                if (!this._isInsideQuery)
                {
                    throw new ODataCompileException("Unexpected placement for lambda expression " + linq);
                }
                return(this.TranslateInternal(quoted.Body));

            default:
                throw new ODataCompileException("Expression '" + linq + "' of type " + linq.NodeType + " could not be translated to OData");
            }
        }