private static string GetBinOpString(ODataBinaryOp op) { switch (op) { case ODataBinaryOp.Add: return("+"); case ODataBinaryOp.And: return("AND"); case ODataBinaryOp.Divide: return("/"); case ODataBinaryOp.Equal: return("="); case ODataBinaryOp.GreaterThan: return(">"); case ODataBinaryOp.GreaterThanOrEqual: return(">="); case ODataBinaryOp.LessThan: return("<"); case ODataBinaryOp.LessThanOrEqual: return("<="); case ODataBinaryOp.Modulo: throw new InvalidOperationException("Modulo is handled separately!"); case ODataBinaryOp.Multiply: return("*"); // ansii standard, see http://blog.sqlauthority.com/2013/07/08/sql-difference-between-and-operator-used-for-not-equal-to-operation/ case ODataBinaryOp.NotEqual: return("<>"); case ODataBinaryOp.Or: return("OR"); case ODataBinaryOp.Subtract: return("-"); default: throw Throw.UnexpectedCase(op); } }
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 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; }
private static Type GetCanonicalArgumentType(ODataBinaryOp @operator) { switch (@operator) { case ODataBinaryOp.Add: case ODataBinaryOp.Subtract: case ODataBinaryOp.Multiply: case ODataBinaryOp.Divide: case ODataBinaryOp.Modulo: // the reason for this is that int can be cast implicitly to most of the other primitive types, // so an expression like substring('foo', A add B) will work if A and B are integers // alternatively, we could return Unknown for these return(typeof(int?)); case ODataBinaryOp.And: case ODataBinaryOp.Or: return(typeof(bool)); default: return(typeof(ODataObject)); } }
private ODataExpression TranslateBinary(Expression linq, ODataBinaryOp op) { var binary = (BinaryExpression)linq; return ODataExpression.BinaryOp(this.TranslateInternal(binary.Left), op, this.TranslateInternal(binary.Right)); }
private ODataExpression TranslateBinary(Expression linq, ODataBinaryOp op) { var binary = (BinaryExpression)linq; return(ODataExpression.BinaryOp(this.TranslateInternal(binary.Left), op, this.TranslateInternal(binary.Right))); }
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); }