private bool NeedsParens(ODataExpression leftOrRight)
        {
            if (leftOrRight.Kind != ODataExpressionKind.BinaryOp)
            {
                return false;
            }
            var binaryOp = (ODataBinaryOpExpression)leftOrRight;
            switch (binaryOp.Operator)
            {
                case ODataBinaryOp.Or:
                    return this.Operator > ODataBinaryOp.Or;

                case ODataBinaryOp.And:
                case ODataBinaryOp.Equal:
                case ODataBinaryOp.NotEqual:
                case ODataBinaryOp.GreaterThan:
                case ODataBinaryOp.GreaterThanOrEqual:
                case ODataBinaryOp.LessThan:
                case ODataBinaryOp.LessThanOrEqual:
                    return this.Operator > ODataBinaryOp.And;

                case ODataBinaryOp.Add:
                case ODataBinaryOp.Subtract:
                case ODataBinaryOp.Multiply:
                case ODataBinaryOp.Divide:
                case ODataBinaryOp.Modulo:
                    return this.Operator > ODataBinaryOp.Subtract;
                default:
                    throw Throw.UnexpectedCase(binaryOp);
            }
        }
 internal ODataBinaryOpExpression(ODataExpression left, ODataBinaryOp @operator, ODataExpression right, Type clrType)
     : base(ODataExpressionKind.BinaryOp, clrType.ToODataExpressionType(), clrType)
 {
     Throw<ArgumentException>.If(right.Type != left.Type, "right & left: must have equal types");
     this.Right = right;
     this.Operator = @operator;
     this.Left = left;
 }
 protected virtual void Visit(ODataExpression node)
 {
     if (node == null)
     {
         return;
     }
     switch (node.Kind)
     {
         case ODataExpressionKind.Convert:
             this.VisitConvert((ODataConvertExpression)node);
             break;
         case ODataExpressionKind.Constant:
             this.VisitConstant((ODataConstantExpression)node);
             break;
         case ODataExpressionKind.Call:
             this.VisitCall((ODataCallExpression)node);
             break;
         case ODataExpressionKind.BinaryOp:
             this.VisitBinaryOp((ODataBinaryOpExpression)node);
             break;
         case ODataExpressionKind.UnaryOp:
             this.VisitUnaryOp((ODataUnaryOpExpression)node);
             break;
         case ODataExpressionKind.MemberAccess:
             this.VisitMemberAccess((ODataMemberAccessExpression)node);
             break;
         case ODataExpressionKind.Query:
             this.VisitQuery((ODataQueryExpression)node);
             break;
         case ODataExpressionKind.SelectColumn:
             this.VisitSelectColumn((ODataSelectColumnExpression)node);
             break;
         case ODataExpressionKind.SortKey:
             this.VisitSortKey((ODataSortKeyExpression)node);
             break;
         default:
             throw new InvalidOperationException("Unexpected expression kind " + node.Kind);
     }
 }
Esempio n. 4
0
 internal ODataSortKeyExpression(ODataExpression expression, bool descending)
     : base(ODataExpressionKind.SortKey, expression.Type, expression.ClrType)
 {
     this.Expression = expression;
     this.Descending = descending;
 }
            /// <summary>
            /// Attempts to translate the given <see cref="MemberExpression"/> as a special OData member, like <see cref="Nullable{T}.Value"/> or
            /// <see cref="string.Length"/>.
            /// </summary>
            private bool TryTranslateMemberAccessAsSpecialMember(MemberExpression memberAccess, out ODataExpression result)
            {
                // TODO FUTURE null handling?
                Func<IEnumerable<ODataExpression>> translateInstance = () => this._translator.TranslateInternal(memberAccess.Expression).Enumerate();
                if (memberAccess.Member.DeclaringType == typeof(string) && memberAccess.Member.Name == "Length")
                {
                    result = ODataExpression.Call(ODataFunction.Length, translateInstance());
                }
                else if (memberAccess.Member.DeclaringType == typeof(DateTime) && memberAccess.Member.Name == "Year")
                {
                    result = ODataExpression.Call(ODataFunction.Year, translateInstance());
                }
                else if (memberAccess.Member.DeclaringType == typeof(DateTime) && memberAccess.Member.Name == "Month")
                {
                    result = ODataExpression.Call(ODataFunction.Month, translateInstance());
                }
                else if (memberAccess.Member.DeclaringType == typeof(DateTime) && memberAccess.Member.Name == "Day")
                {
                    result = ODataExpression.Call(ODataFunction.Day, translateInstance());
                }
                else if (memberAccess.Member.DeclaringType == typeof(DateTime) && memberAccess.Member.Name == "Hour")
                {
                    result = ODataExpression.Call(ODataFunction.Hour, translateInstance());
                }
                else if (memberAccess.Member.DeclaringType == typeof(DateTime) && memberAccess.Member.Name == "Minute")
                {
                    result = ODataExpression.Call(ODataFunction.Minute, translateInstance());
                }
                else if (memberAccess.Member.DeclaringType == typeof(DateTime) && memberAccess.Member.Name == "Second")
                {
                    result = ODataExpression.Call(ODataFunction.Second, translateInstance());
                }
                // nullable properties
                else if (memberAccess.Member.Name == "HasValue" && memberAccess.Member.DeclaringType.IsGenericOfType(typeof(Nullable<>)))
                {
                    // for HasValue we just re-translate expr != null
                    result = this._translator.TranslateInternal(Expression.NotEqual(memberAccess.Expression, Expression.Constant(null, memberAccess.Expression.Type)));
                }
                else if (memberAccess.Member.Name == "Value" && memberAccess.Member.DeclaringType.IsGenericOfType(typeof(Nullable<>)))
                {
                    // .Value calls can just be ignored, since OData doesn't have the notion of nullable types
                    result = this._translator.TranslateInternal(memberAccess.Expression);
                }
                else
                {
                    result = null;
                    return false;
                }

                return true;
            }
 internal ODataSortKeyExpression(ODataExpression expression, bool descending)
     : base(ODataExpressionKind.SortKey, expression.Type, expression.ClrType)
 {
     this.Expression = expression;
     this.Descending = descending;
 }
 // in general, unary ops don't change the type. If we ever implement one that does, we can change this logic
 internal ODataUnaryOpExpression(ODataExpression operand, ODataUnaryOp @operator)
     : base(ODataExpressionKind.UnaryOp, operand.Type, operand.ClrType)
 {
     this.Operand = operand;
     this.Operator = @operator;
 }
        // TODO VNEXT expand
        internal ODataQueryExpression(
			ODataExpression filter,
			IReadOnlyList<ODataSortKeyExpression> orderBy,
			int? top,
			int skip,
			string format,
			ODataInlineCountOption inlineCount,
			IReadOnlyList<ODataSelectColumnExpression> select)
            : base(ODataExpressionKind.Query, ODataExpressionType.Complex, typeof(IQueryable))
        {
            this.Filter = filter;
            this.OrderBy = orderBy;
            this.Top = top;
            this.Skip = skip;
            this.Format = format;
            this.InlineCount = inlineCount;
            this.Select = select;
        }
 internal ODataQueryExpression Update(ODataExpression filter = null, IEnumerable<ODataSortKeyExpression> orderBy = null, int? top = -1, int? skip = null, string format = null, ODataInlineCountOption? inlineCount = null, IEnumerable<ODataSelectColumnExpression> select = null)
 {
     return Query(
         filter: filter ?? this.Filter,
         orderBy: orderBy.NullSafe(ob => ob.ToArray(), ifNullReturn: this.OrderBy),
         top: top == -1 ? this.Top : top,
         skip: skip ?? this.Skip,
         format: format ?? this.Format,
         inlineCount: inlineCount ?? this.InlineCount,
         select: select.NullSafe(sc => sc.ToArray(), ifNullReturn: this.Select)
     );
 }
Esempio n. 10
0
 internal ODataConvertExpression(ODataExpression expression, Type clrType)
     : base(ODataExpressionKind.Convert, clrType.ToODataExpressionType(), clrType)
 {
     this.Expression = expression;
 }
        internal static ODataQueryExpression Query(
			ODataExpression filter = null,
			IReadOnlyList<ODataSortKeyExpression> orderBy = null,
			int? top = null,
			int skip = 0,
			string format = null,
			ODataInlineCountOption inlineCount = ODataInlineCountOption.None,
			IReadOnlyList<ODataSelectColumnExpression> select = null)
        {
            Throw.If(filter != null && filter.Type != ODataExpressionType.Boolean, "filter: must be boolean-typed");
            if (top.HasValue)
            {
                Throw.IfOutOfRange(top.Value, min: 0, paramName: "top");
            }
            Throw.IfOutOfRange(skip, min: 0, paramName: "skip");

            if (format != null)
            {
                Throw.If(string.IsNullOrWhiteSpace(format), "format: must not be empty or whitespace");
            }

            return new ODataQueryExpression(
                filter: filter,
                orderBy: orderBy != null ? orderBy.ToImmutableList() : Empty<ODataSortKeyExpression>.Array,
                top: top,
                skip: skip,
                format: format,
                inlineCount: inlineCount,
                select: select != null ? select.ToImmutableList() : Empty<ODataSelectColumnExpression>.Array
            );
        }
Esempio n. 12
0
        internal static ODataSortKeyExpression SortKey(ODataExpression expression, bool descending = false)
        {
            Throw.IfNull(expression, "expression");

            return(new ODataSortKeyExpression(expression, descending: descending));
        }
Esempio n. 13
0
        internal static ODataBinaryOpExpression BinaryOp(ODataExpression left, ODataBinaryOp @operator, ODataExpression right)
        {
            Throw.IfNull(left, "left");
            Throw.IfNull(right, "right");

            // add in implicit conversions as needed
            ODataExpression convertedLeft, convertedRight;

            if ((left.Type == ODataExpressionType.Unknown || left.Type == ODataExpressionType.Null) &&
                (right.Type == ODataExpressionType.Unknown || right.Type == ODataExpressionType.Null))
            {
                var canonicalType = GetCanonicalArgumentType(@operator);
                if (canonicalType != typeof(ODataObject))
                {
                    convertedLeft = left.Type == ODataExpressionType.Unknown
                        ? ConvertFromUnknownType(left, canonicalType)
                        : LiftNullToUnknown(left);
                    convertedRight = right.Type == ODataExpressionType.Unknown
                        ? ConvertFromUnknownType(right, canonicalType)
                        : LiftNullToUnknown(right);
                }
                else
                {
                    convertedLeft  = left.Type == ODataExpressionType.Null ? LiftNullToUnknown(left) : left;
                    convertedRight = right.Type == ODataExpressionType.Null ? LiftNullToUnknown(right) : right;
                }
            }
            else if (left.Type == ODataExpressionType.Unknown)
            {
                convertedLeft  = ConvertFromUnknownType(left, right.ClrType);
                convertedRight = right;
            }
            else if (right.Type == ODataExpressionType.Unknown)
            {
                convertedLeft  = left;
                convertedRight = ConvertFromUnknownType(right, left.ClrType);
            }
            else if (left.Type == right.Type)
            {
                convertedLeft  = left;
                convertedRight = right;
            }
            else if (left.Type.IsImplicityCastableTo(right.Type))
            {
                convertedLeft  = Convert(left, right.ClrType);
                convertedRight = right;
            }
            else if (right.Type.IsImplicityCastableTo(left.Type))
            {
                convertedLeft  = left;
                convertedRight = Convert(right, left.ClrType);
            }
            else
            {
                throw new ArgumentException(string.Format("Operator {0} cannot be applied to operands of type '{1}' and '{2}'", @operator, left.Type, right.Type));
            }

            // determine the result type
            var  operandClrType = convertedLeft.ClrType;
            var  operandType    = convertedLeft.Type;
            Type resultClrType;

            switch (@operator)
            {
            case ODataBinaryOp.Add:
            case ODataBinaryOp.Subtract:
            case ODataBinaryOp.Multiply:
            case ODataBinaryOp.Divide:
            case ODataBinaryOp.Modulo:
                Throw.If(!operandType.IsNumeric(), "Operator requires numeric type");
                resultClrType = operandClrType;
                break;

            case ODataBinaryOp.LessThan:
            case ODataBinaryOp.LessThanOrEqual:
            case ODataBinaryOp.GreaterThanOrEqual:
            case ODataBinaryOp.GreaterThan:
                Throw.If(
                    !operandType.IsNumeric() && !NonNumericComparableTypes.Contains(operandType) && operandType != ODataExpressionType.Unknown,
                    "Operator requires a type with comparison operators defined"
                    );
                resultClrType = typeof(bool);
                break;

            case ODataBinaryOp.And:
            case ODataBinaryOp.Or:
                Throw.If(operandClrType != typeof(bool), "Boolean operators require operands with a non-nullable boolean type");
                resultClrType = typeof(bool);
                break;

            case ODataBinaryOp.Equal:
            case ODataBinaryOp.NotEqual:
                resultClrType = typeof(bool);
                break;

            default:
                throw Throw.UnexpectedCase(@operator);
            }

            // construct the expression
            return(new ODataBinaryOpExpression(convertedLeft, @operator, convertedRight, resultClrType));
        }
        internal static ODataBinaryOpExpression BinaryOp(ODataExpression left, ODataBinaryOp @operator, ODataExpression right)
        {
            Throw.IfNull(left, "left");
            Throw.IfNull(right, "right");

            // add in implicit conversions as needed
            ODataExpression convertedLeft, convertedRight;
            if (left.Type == right.Type)
            {
                convertedLeft = left;
                convertedRight = right;
            }
            else if (left.Type.IsImplicityCastableTo(right.Type))
            {
                convertedLeft = Convert(left, right.ClrType);
                convertedRight = right;
            }
            else if (right.Type.IsImplicityCastableTo(left.Type))
            {
                convertedLeft = left;
                convertedRight = Convert(right, left.ClrType);
            }
            else
            {
                throw new ArgumentException(string.Format("Types {0} and {1} cannot be used with operator {2}", left.Type, right.Type, @operator));
            }

            // determine the result type
            var operandClrType = convertedLeft.ClrType;
            var operandType = convertedLeft.Type;
            Type resultClrType;
            switch (@operator)
            {
                case ODataBinaryOp.Add:
                case ODataBinaryOp.Subtract:
                case ODataBinaryOp.Multiply:
                case ODataBinaryOp.Divide:
                case ODataBinaryOp.Modulo:
                    Throw.If(!operandType.IsNumeric(), "Operator requires numeric type");
                    resultClrType = operandClrType;
                    break;
                case ODataBinaryOp.LessThan:
                case ODataBinaryOp.LessThanOrEqual:
                case ODataBinaryOp.GreaterThanOrEqual:
                case ODataBinaryOp.GreaterThan:
                    Throw.If(!operandType.IsNumeric() && !NonNumericComparableTypes.Contains(operandType), "Operator requires a type with comparison operators defined");
                    resultClrType = typeof(bool);
                    break;
                case ODataBinaryOp.And:
                case ODataBinaryOp.Or:
                    Throw.If(operandClrType != typeof(bool), "Boolean operators require operands with a non-nullable boolean type");
                    resultClrType = typeof(bool);
                    break;
                case ODataBinaryOp.Equal:
                case ODataBinaryOp.NotEqual:
                    resultClrType = typeof(bool);
                    break;
                default:
                    throw Throw.UnexpectedCase(@operator);
            }

            // construct the expression
            return new ODataBinaryOpExpression(convertedLeft, @operator, convertedRight, resultClrType);
        }
        internal static ODataUnaryOpExpression UnaryOp(ODataExpression operand, ODataUnaryOp @operator)
        {
            Throw.IfNull(operand, "operand");
            Throw.If(operand.Type != ODataExpressionType.Boolean, "operand: must be a boolean type");

            return new ODataUnaryOpExpression(operand, @operator);
        }
        internal static ODataSortKeyExpression SortKey(ODataExpression expression, bool descending = false)
        {
            Throw.IfNull(expression, "expression");

            return new ODataSortKeyExpression(expression, descending: descending);
        }
 public ISet<MemberPath> FindPaths(ODataExpression node)
 {
     this._paths = new HashSet<MemberPath>();
     this.Visit(node);
     return this._paths;
 }
 internal ODataConvertExpression(ODataExpression expression, Type clrType)
     : base(ODataExpressionKind.Convert, clrType.ToODataExpressionType(), clrType)
 {
     this.Expression = expression;
 }
Esempio n. 19
0
        internal ODataBinaryOpExpression(ODataExpression left, ODataBinaryOp @operator, ODataExpression right, Type clrType)
            : base(ODataExpressionKind.BinaryOp, clrType.ToODataExpressionType(), clrType)
        {
            Throw <ArgumentException> .If(right.Type != left.Type, "right & left: must have equal types");

            this.Right    = right;
            this.Operator = @operator;
            this.Left     = left;
        }
        internal static ODataConvertExpression Convert(ODataExpression expression, Type clrType)
        {
            Throw.IfNull(expression, "expression");
            Throw.IfNull(clrType, "clrType");

            Throw<ArgumentException>.If(
                // can only convert where (1) a cast is valid or (2) a cast might succeed because the target type
                // derives from of the expression type
                !expression.ClrType.IsCastableTo(clrType)
                    && !clrType.IsAssignableFrom(expression.ClrType),
                () => "cannot convert from " + expression.ClrType + " to " + clrType
            );
            return new ODataConvertExpression(expression, clrType);
        }