Skip to content

Commit

Permalink
Nullables and other great things
Browse files Browse the repository at this point in the history
  • Loading branch information
StevenThuriot committed Oct 4, 2018
1 parent 0a15a5b commit 1a53a02
Show file tree
Hide file tree
Showing 6 changed files with 73 additions and 4 deletions.
2 changes: 1 addition & 1 deletion src/NQuery.Data/QueryReaderExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ public static DataTable CreateSchemaTable(this QueryReader queryReader)
{
var columnName = queryReader.GetColumnName(i);
var uniqueColumnName = GenerateUniqueColumnName(existingColumnNames, columnName);
var columnType = queryReader.GetColumnType(i);
var columnType = queryReader.GetColumnType(i).GetNonNullableType();
var dataColumn = new DataColumn(uniqueColumnName, columnType);
dataColumn.Caption = columnName;
dataTable.Columns.Add(dataColumn);
Expand Down
27 changes: 26 additions & 1 deletion src/NQuery.Tests/ExpressionTests.Queries.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System;

using NQuery.Data;
using NQuery.Hosting;
using NQuery.Symbols;

using Xunit;
Expand Down Expand Up @@ -63,5 +64,29 @@ public void Expression_Queries_Any()

Assert.True(result);
}

[Fact]
public void Expression_Queries_WorksWithNullableDateTimes()
{
var data = TestData.GetClassesWithNullableField();
var propertyProvider = new ReflectionProvider();
var definition = new EumerableTableDefinition("ClassesWithNullable", data, typeof(TestData.ClassWithNullableField), propertyProvider);
var tableSymbol = new SchemaTableSymbol(definition);

var dataContext = DataContext.Default
.AddTables(tableSymbol);

var query = Query.Create(dataContext, $"Select Name, DateOfDeath from ClassesWithNullable where COALESCE(DateOfDeath, #0001-01-01#) >= #{DateTime.Now.AddYears(-1).ToString("yyyy-MM-dd")}#");

var result = query.ExecuteDataTable();

Assert.NotNull(result);
Assert.Equal(1, result.Rows.Count);

var row = result.Rows[0];

Assert.Equal("John", row["Name"]);
Assert.Equal(DateTime.Today.AddMonths(-1), row["DateOfDeath"]);
}
}
}
21 changes: 21 additions & 0 deletions src/NQuery.Tests/TestData.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;
using System.Data;

namespace NQuery.Tests
Expand All @@ -23,5 +24,25 @@ public static DataTable IdNameBytesDataTable()
table.Columns.Add(new DataColumn("Data", typeof (byte[])));
return table;
}



public class ClassWithNullableField
{
public int Id { get; set; }
public string Name { get; set; }
public DateTime? DateOfDeath { get; set; }
}

public static IReadOnlyList<ClassWithNullableField> GetClassesWithNullableField()
{
return new ClassWithNullableField[]
{
new ClassWithNullableField { Id = 0, Name = "Steven" },
new ClassWithNullableField { Id = 1, Name = "Jack", DateOfDeath = DateTime.Today.AddYears(-10) },
new ClassWithNullableField { Id = 2, Name = "Grace" },
new ClassWithNullableField { Id = 3, Name = "John", DateOfDeath = DateTime.Today.AddMonths(-1) },
};
}
}
}
2 changes: 2 additions & 0 deletions src/NQuery/Binding/BinaryOperator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,8 @@ internal static class BinaryOperator
new BinaryOperatorSignature(BinaryOperatorKind.GreaterOrEqual, typeof(bool), typeof(ulong)),
new BinaryOperatorSignature(BinaryOperatorKind.GreaterOrEqual, typeof(bool), typeof(float)),
new BinaryOperatorSignature(BinaryOperatorKind.GreaterOrEqual, typeof(bool), typeof(double)),
new BinaryOperatorSignature(BinaryOperatorKind.GreaterOrEqual, typeof(bool), typeof(DateTime)),
new BinaryOperatorSignature(BinaryOperatorKind.GreaterOrEqual, BuiltInOperators.NullableDateTimeGreaterOrEqualMethod),
new BinaryOperatorSignature(BinaryOperatorKind.GreaterOrEqual, BuiltInOperators.DecimalGreaterOrEqualMethod)
};

Expand Down
17 changes: 15 additions & 2 deletions src/NQuery/Iterators/ExpressionBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,13 @@ private Expression BuildBinaryExpression(BoundBinaryExpression expression)
var nullableResultType = expression.Type.GetNullableType();
var signature = expression.Result.Best.Signature;

Expression LowerIfNeeded(ParameterExpression parameterExpression, int index)
{
return signature.GetParameterType(index) == parameterExpression.Type
? parameterExpression
: BuildLoweredExpression(parameterExpression);
}

var result = Expression.Condition(
Expression.OrElse(
BuildNullCheck(liftedLeft),
Expand All @@ -243,8 +250,8 @@ private Expression BuildBinaryExpression(BoundBinaryExpression expression)
BuildNullValue(nullableResultType),
BuildLiftedExpression(
BuildBinaryExpression(signature,
BuildLoweredExpression(liftedLeft),
BuildLoweredExpression(liftedRight)
LowerIfNeeded(liftedLeft, 0),
LowerIfNeeded(liftedRight, 1)
)
)
);
Expand Down Expand Up @@ -429,6 +436,12 @@ private Expression BuildConversionExpression(BoundConversionExpression expressio
var input = BuildCachedExpression(expression.Expression);
var targetType = expression.Type;
var conversionMethod = expression.Conversion.ConversionMethods.SingleOrDefault();

if (input.Type == targetType)
{
conversionMethod = null;
}

return
Expression.Condition(
BuildNullCheck(input),
Expand Down
8 changes: 8 additions & 0 deletions src/NQuery/Symbols/BuiltinOperators.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ internal static class BuiltInOperators
public static readonly MethodInfo SoundsLikeMethod = new Func<string, string, bool>(SoundsLike).Method;
public static readonly MethodInfo PowerMethod = new Func<double, double, double>(Math.Pow).Method;

public static readonly MethodInfo NullableDateTimeGreaterOrEqualMethod = new Func<DateTime?, DateTime, bool>(NullableDateTimeGreaterOrEqual).Method;

public static readonly MethodInfo DecimalAddMethod = typeof(decimal).GetMethod("op_Addition", new[] { typeof(decimal), typeof(decimal) });
public static readonly MethodInfo DecimalDivideMethod = typeof(decimal).GetMethod("op_Division", new[] { typeof(decimal), typeof(decimal) });
public static readonly MethodInfo DecimalEqualsMethod = typeof(decimal).GetMethod("op_Equality", new[] { typeof(decimal), typeof(decimal) });
Expand All @@ -31,6 +33,12 @@ internal static class BuiltInOperators
public static readonly MethodInfo DecimalUnaryNegationMethod = typeof(decimal).GetMethod("op_UnaryNegation", new[] { typeof(decimal) });
public static readonly MethodInfo DecimalUnaryIdentityMethod = typeof(decimal).GetMethod("op_UnaryPlus", new[] { typeof(decimal) });


private static bool NullableDateTimeGreaterOrEqual(DateTime? first, DateTime second)
{
return first >= second;
}

private static bool SimilarTo(string str, string regex)
{
var regex1 = new Regex(regex, RegexOptions.Multiline);
Expand Down

0 comments on commit 1a53a02

Please sign in to comment.