Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Fix] Fixed null in Parameter and added functionality Binary And and Or with different Types #86

Merged
merged 6 commits into from
Jun 1, 2017
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 50 additions & 1 deletion src/System.Linq.Dynamic.Core/ExpressionParser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -606,11 +606,13 @@ Expression ParseLogicalAndOrOperator()
}
else
{
ConvertNumericTypeToBiggestCommonTypeForBinaryOperator(ref left, ref right);
left = Expression.And(left, right);
}
break;

case TokenId.Bar:
ConvertNumericTypeToBiggestCommonTypeForBinaryOperator(ref left, ref right);
left = Expression.Or(left, right);
break;
}
Expand Down Expand Up @@ -2019,7 +2021,7 @@ Expression PromoteExpression(Expression expr, Type type, bool exact, bool conver

if (ce != null)
{
if (ce == NullLiteral)
if (ce == NullLiteral || ce.Value == null)
{
if (!type.GetTypeInfo().IsValueType || IsNullableType(type))
return Expression.Constant(null, type);
Expand Down Expand Up @@ -2678,5 +2680,52 @@ internal static void ResetDynamicLinqTypes()
{
_keywords = null;
}

static void ConvertNumericTypeToBiggestCommonTypeForBinaryOperator(ref Expression left, ref Expression right)
{
if (left.Type == right.Type)
return;

if (left.Type == typeof(UInt64) || right.Type == typeof(UInt64))
{
right = right.Type != typeof(UInt64) ? Expression.Convert(right, typeof(UInt64)) : right;
left = left.Type != typeof(UInt64) ? Expression.Convert(left, typeof(UInt64)) : left;
}
else if (left.Type == typeof(Int64) || right.Type == typeof(Int64))
{
right = right.Type != typeof(Int64) ? Expression.Convert(right, typeof(Int64)) : right;
left = left.Type != typeof(Int64) ? Expression.Convert(left, typeof(Int64)) : left;
}
else if (left.Type == typeof(UInt32) || right.Type == typeof(UInt32))
{
right = right.Type != typeof(UInt32) ? Expression.Convert(right, typeof(UInt32)) : right;
left = left.Type != typeof(UInt32) ? Expression.Convert(left, typeof(UInt32)) : left;
}
else if (left.Type == typeof(Int32) || right.Type == typeof(Int32))
{
right = right.Type != typeof(Int32) ? Expression.Convert(right, typeof(Int32)) : right;
left = left.Type != typeof(Int32) ? Expression.Convert(left, typeof(Int32)) : left;
}
else if (left.Type == typeof(UInt16) || right.Type == typeof(UInt16))
{
right = right.Type != typeof(UInt16) ? Expression.Convert(right, typeof(UInt16)) : right;
left = left.Type != typeof(UInt16) ? Expression.Convert(left, typeof(UInt16)) : left;
}
else if (left.Type == typeof(Int16) || right.Type == typeof(Int16))
{
right = right.Type != typeof(Int16) ? Expression.Convert(right, typeof(Int16)) : right;
left = left.Type != typeof(Int16) ? Expression.Convert(left, typeof(Int16)) : left;
}
else if (left.Type == typeof(Byte) || right.Type == typeof(Byte))
{
right = right.Type != typeof(Byte) ? Expression.Convert(right, typeof(Byte)) : right;
left = left.Type != typeof(Byte) ? Expression.Convert(left, typeof(Byte)) : left;
}
else if (left.Type == typeof(SByte) || right.Type == typeof(SByte))
{
right = right.Type != typeof(SByte) ? Expression.Convert(right, typeof(SByte)) : right;
left = left.Type != typeof(SByte) ? Expression.Convert(left, typeof(SByte)) : left;
}
}
}
}
51 changes: 46 additions & 5 deletions test/System.Linq.Dynamic.Core.Tests/ExpressionTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -580,16 +580,57 @@ public void ExpressionTests_Guid_CompareTo_Null()
// Act
var result2a = qry.FirstOrDefault("it.GuidNull = null");
var result2b = qry.FirstOrDefault("null = it.GuidNull");
// var result1a = qry.FirstOrDefault("it.GuidNull = @0", null); TODO: fails?
// var result1b = qry.FirstOrDefault("@0 = it.GuidNull", null); TODO: fails?
var result1a = qry.FirstOrDefault("it.GuidNull = @0", new object[] { null });
var result1b = qry.FirstOrDefault("@0 = it.GuidNull", new object[] { null });

// Assert
// Assert.Equal(1, result1a.Id);
// Assert.Equal(1, result1b.Id);
Assert.Equal(1, result1a.Id);
Assert.Equal(1, result1b.Id);
Assert.Equal(1, result2a.Id);
Assert.Equal(1, result2b.Id);
}

public enum TestEnum2 : sbyte
{
Var2 = 1
}

public class TestEnumClass
{
public TestEnum A { get; set; }

public TestEnum2 B { get; set; }

public int Id { get; set; }
}

[Fact]
public void ExpressionTests_Test_BinaryAndOr()
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some remarks:

  1. Does this method also test OR ? Because I only see & ?
  2. Rename this method to ExpressionTests_BinaryAnd and also ExpressionTests_BinaryOr ?
  3. Move this method to the correct location (I try to keep a A-Z sorting applied to this test class to keep things organized)
  4. Also check the result (result0, result1, ...) using Assert, else the unit-test is not complete.

{
// Arrange
var lst = new List<TestEnumClass> { new TestEnumClass { A = TestEnum.Var2, Id = 1 } };
var qry = lst.AsQueryable();

// Act
var result0 = qry.FirstOrDefault("(it.A & @0) == 0", 1);
var result1 = qry.FirstOrDefault("(it.A & @0) == 0", (uint)1);
var result2 = qry.FirstOrDefault("(it.A & @0) == 0", (long)1);
var result3 = qry.FirstOrDefault("(it.A & @0) == 0", (ulong)1);
var result4 = qry.FirstOrDefault("(it.A & @0) == 0", (byte)1);
var result5 = qry.FirstOrDefault("(it.A & @0) == 0", (sbyte)1);
var result6 = qry.FirstOrDefault("(it.A & @0) == 0", (ushort)1);
var result7 = qry.FirstOrDefault("(it.A & @0) == 0", (short)1);

var result10 = qry.FirstOrDefault("(it.B & @0) == 0", 1);
var result11 = qry.FirstOrDefault("(it.B & @0) == 0", (uint)1);
var result12 = qry.FirstOrDefault("(it.B & @0) == 0", (long)1);
var result13 = qry.FirstOrDefault("(it.B & @0) == 0", (ulong)1);
var result14 = qry.FirstOrDefault("(it.B & @0) == 0", (byte)1);
var result15 = qry.FirstOrDefault("(it.B & @0) == 0", (sbyte)1);
var result16 = qry.FirstOrDefault("(it.B & @0) == 0", (ushort)1);
var result17 = qry.FirstOrDefault("(it.B & @0) == 0", (short)1);
}

[Fact]
public void ExpressionTests_HexadecimalInteger()
{
Expand Down Expand Up @@ -1307,4 +1348,4 @@ public void ExpressionTests_Where_WithCachedLambda()
Assert.Equal(res9, list[1]);
}
}
}
}