Skip to content

Commit

Permalink
feat: Add utc conversion.
Browse files Browse the repository at this point in the history
  • Loading branch information
bugrakosen committed Oct 31, 2024
1 parent 13c6c39 commit c77d6d1
Show file tree
Hide file tree
Showing 15 changed files with 95 additions and 35 deletions.
6 changes: 4 additions & 2 deletions ExpressionBuilder.Test.NetCore/Unit/Helpers/TestData.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,10 @@ public TestData()
new Person { Name = "Jane Jones", Gender = PersonGender.Female, Salary=3500, Birth = new Person.BirthData { Date = new DateTime(1980, 12, 20), Country = "AUS" } },
new Person { Name = "Fulano Silva", Gender = PersonGender.Male, Salary=3322, Birth = new Person.BirthData { Date = new DateTime(1983, 5, 10), Country = "BRA" }, Employer = company, Manager = manager2, EmployeeReferenceNumber = 986543434323 },
new Person { Name = "John Hancock", Gender = PersonGender.Male, Employer = company },
new Person { Name = "Jack Luffy 30-21", SalaryDate = new DateTime(2024, 10, 30, 21, 10, 10, DateTimeKind.Utc), Gender = PersonGender.Male, Employer = company },
new Person { Name = "Jack Luffy Offset 30-21", SalaryDateOffset = new DateTimeOffset(2024, 10, 30, 21, 10, 10, TimeSpan.Zero), Gender = PersonGender.Male, Employer = company },
new Person { Name = "Jack Luffy UTC 30-21", SalaryDate = new DateTime(2024, 10, 30, 21, 10, 10, DateTimeKind.Utc), Gender = PersonGender.Male, Employer = company },
new Person { Name = "Jack Luffy UTC Offset 30-21", SalaryDateOffset = new DateTimeOffset(2024, 10, 30, 21, 10, 10, TimeSpan.Zero), Gender = PersonGender.Male, Employer = company },
new Person { Name = "Jack Luffy Local 28-21", SalaryDate = new DateTime(2024, 10, 28, 21, 10, 10, DateTimeKind.Local), Gender = PersonGender.Male, Employer = company },
new Person { Name = "Jack Luffy Local Offset 28-21", SalaryDateOffset = new DateTimeOffset(2024, 10, 28, 21, 10, 10, new TimeSpan(3,0,0)), Gender = PersonGender.Male, Employer = company },
];
var id = 1;
foreach (var person in People)
Expand Down
25 changes: 16 additions & 9 deletions ExpressionBuilder.Test.NetCore/Unit/Operations/DateEqualToTests.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using ExpressionBuilder.Operations;
using ExpressionBuilder.Configuration;
using ExpressionBuilder.Operations;
using ExpressionBuilder.Test.Models;
using ExpressionBuilder.Test.Unit.Helpers;
using FluentAssertions;
Expand All @@ -20,12 +21,15 @@ public DateEqualToTests()
TestData = new TestData();
}

[TestCase("SalaryDate", "2024-10-31", TestName = "'DateEqualTo' operation - Get expression (DateTime? value)")]
[TestCase("SalaryDate", "2024-10-30", TestName = "'DateEqualTo' operation - Get expression (DateTime? value)")]
public void GetExpressionDateTimeValueTest(string propertyName, object value)
[TestCase("SalaryDate", "2024-10-31", true, TestName = "'DateEqualTo UTC 31' operation - Get expression (DateTime? value)")]
[TestCase("SalaryDate", "2024-10-30", true, TestName = "'DateEqualTo UTC 30' operation - Get expression (DateTime? value)")]
[TestCase("SalaryDate", "2024-10-29", false, TestName = "'DateEqualTo 29' operation - Get expression (DateTime? value)")]
[TestCase("SalaryDate", "2024-10-28", false, TestName = "'DateEqualTo 28' operation - Get expression (DateTime? value)")]
public void GetExpressionDateTimeValueTest(string propertyName, object value, bool useUtcConversionInDateTypes)
{
Settings.UseUtcConversionInDateTypes = useUtcConversionInDateTypes;
var dateValue = DateTime.Parse(value.ToString());
var startDate = dateValue.ToUniversalTime();
var startDate = Settings.UseUtcConversionInDateTypes ? dateValue.ToUniversalTime() : dateValue;
var endDate = startDate.AddDays(1).AddTicks(-1);
var operation = new DateEqualTo();
var param = Expression.Parameter(typeof(Person), "x");
Expand Down Expand Up @@ -63,12 +67,15 @@ public void GetExpressionDateTimeValueTest(string propertyName, object value)

public static Func<Person, bool> SalaryDate(DateTime startDate, DateTime endDate) => x => x.SalaryDate != null && (x.SalaryDate.Value >= startDate && x.SalaryDate.Value <= endDate);

[TestCase("SalaryDateOffset", "2024-10-31", TestName = "'DateEqualTo Offset' operation - Get expression (DateTimeOffset? value)")]
[TestCase("SalaryDateOffset", "2024-10-30", TestName = "'DateEqualTo Offset' operation - Get expression (DateTimeOffset? value)")]
public void GetExpressionDateTimeOffsetValueTest(string propertyName, object value)
[TestCase("SalaryDateOffset", "2024-10-31", true, TestName = "'DateEqualTo Offset UTC 31' operation - Get expression (DateTimeOffset? value)")]
[TestCase("SalaryDateOffset", "2024-10-30", true, TestName = "'DateEqualTo Offset UTC 30' operation - Get expression (DateTimeOffset? value)")]
[TestCase("SalaryDateOffset", "2024-10-29", false, TestName = "'DateEqualTo Offset 29' operation - Get expression (DateTimeOffset? value)")]
[TestCase("SalaryDateOffset", "2024-10-28", false, TestName = "'DateEqualTo Offset 28' operation - Get expression (DateTimeOffset? value)")]
public void GetExpressionDateTimeOffsetValueTest(string propertyName, object value, bool useUtcConversionInDateTypes)
{
Settings.UseUtcConversionInDateTypes = useUtcConversionInDateTypes;
var dateValue = DateTimeOffset.Parse(value.ToString());
var startDate = dateValue.ToUniversalTime();
var startDate = Settings.UseUtcConversionInDateTypes ? dateValue.ToUniversalTime() : dateValue;
var endDate = dateValue.AddDays(1).AddTicks(-1);
var operation = new DateEqualTo();
var param = Expression.Parameter(typeof(Person), "x");
Expand Down
36 changes: 35 additions & 1 deletion ExpressionBuilder/Common/CommonExtensionMethods.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.Linq.Expressions;
using ExpressionBuilder.Configuration;
using System.Linq.Expressions;
using System.Reflection;

namespace ExpressionBuilder.Common;
Expand Down Expand Up @@ -72,4 +73,37 @@ public static bool IsGenericList(this object o)
var oType = o.GetType();
return oType.IsGenericType && oType.GetGenericTypeDefinition() == typeof(List<>);
}

/// <summary>
/// If constant type is date tyep it will converts constant value to utc if requested in the <see cref="Settings"/>.
/// </summary>
/// <param name="constant"></param>
/// <returns></returns>
public static ConstantExpression ConvertUtcIfRequested(this ConstantExpression constant)
{
if (constant.Type == typeof(DateTime) || constant.Type == typeof(DateTime?))
{
var valueAsDateTime = (DateTime)constant.Value;

DateTime dateValue = new(valueAsDateTime.Year, valueAsDateTime.Month, valueAsDateTime.Day, 0, 0, 0, DateTimeKind.Local);

if (Settings.UseUtcConversionInDateTypes)
dateValue = dateValue.ToUniversalTime();

constant = Expression.Constant(dateValue);
}
else if (constant.Type == typeof(DateTimeOffset) || constant.Type == typeof(DateTimeOffset?))
{
var valueAsDateTimeOffset = (DateTimeOffset)constant.Value;

DateTimeOffset dateValue = new(valueAsDateTimeOffset.Year, valueAsDateTimeOffset.Month, valueAsDateTimeOffset.Day, 0, 0, 0, valueAsDateTimeOffset.Offset);

if (Settings.UseUtcConversionInDateTypes)
dateValue = dateValue.ToOffset(TimeSpan.Zero);

constant = Expression.Constant(dateValue);
}

return constant;
}
}
15 changes: 13 additions & 2 deletions ExpressionBuilder/Configuration/Settings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,18 @@ namespace ExpressionBuilder.Configuration;

public static class Settings
{
public const string SectionName = "Milvasoft:ExpressionBuilder";

/// <summary>
/// Uses utc conversion in date types searchs. Default is true.
/// </summary>
public static bool UseUtcConversionInDateTypes { get; set; } = true;

public static void LoadSettingsFromConfigurationFile(IConfigurationManager configurationManager)
{
foreach (var supportedType in configurationManager.GetSection("supportedTypes").GetChildren())
UseUtcConversionInDateTypes = configurationManager.GetSection($"{SectionName}:UseUtcConversionInDateTypes").Get<bool>();

foreach (var supportedType in configurationManager.GetSection($"{SectionName}:SupportedTypes").GetChildren())
{
var typeGroup = supportedType.GetValue<TypeGroup>("typeGroup");

Expand All @@ -19,8 +28,10 @@ public static void LoadSettingsFromConfigurationFile(IConfigurationManager confi
}
}

public static void LoadSettings(List<SupportedType> supportedTypes)
public static void LoadSettings(List<SupportedType> supportedTypes, bool useUtcConversionInDateTypes = true)
{
UseUtcConversionInDateTypes = useUtcConversionInDateTypes;

foreach (var supportedType in supportedTypes)
{
if (supportedType.Type != null)
Expand Down
2 changes: 1 addition & 1 deletion ExpressionBuilder/ExpressionBuilder.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
</Description>
<AssemblyVersion>1.0.0.0</AssemblyVersion>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
<Version>1.0.11</Version>
<Version>1.0.12</Version>
<GeneratePackageOnBuild>false</GeneratePackageOnBuild>
<PackageId>Milvasoft.ExpressionBuilder</PackageId>
</PropertyGroup>
Expand Down
27 changes: 16 additions & 11 deletions ExpressionBuilder/Operations/DateEqualTo.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using ExpressionBuilder.Common;
using ExpressionBuilder.Configuration;
using System.Linq.Expressions;

namespace ExpressionBuilder.Operations;
Expand Down Expand Up @@ -43,13 +44,14 @@ private static (ConstantExpression, ConstantExpression) GetStartAndEndDates(Cons
{
var valueAsDateTime = (DateTime)constant.Value;

// Kullanıcının tarihine göre günün başı ve sonu
DateTime startDateLocal = new DateTime(valueAsDateTime.Year, valueAsDateTime.Month, valueAsDateTime.Day, 0, 0, 0, DateTimeKind.Local);
DateTime endDateLocal = startDateLocal.AddDays(1).AddTicks(-1);
DateTime startDate = new(valueAsDateTime.Year, valueAsDateTime.Month, valueAsDateTime.Day, 0, 0, 0, DateTimeKind.Local);
DateTime endDate = startDate.AddDays(1).AddTicks(-1);

// UTC'ye dönüştürme
DateTime startDate = startDateLocal.ToUniversalTime();
DateTime endDate = endDateLocal.ToUniversalTime();
if (Settings.UseUtcConversionInDateTypes)
{
startDate = startDate.ToUniversalTime();
endDate = endDate.ToUniversalTime();
}

startDateExpression = Expression.Constant(startDate);
endDateExpression = Expression.Constant(endDate);
Expand All @@ -59,12 +61,15 @@ private static (ConstantExpression, ConstantExpression) GetStartAndEndDates(Cons
var valueAsDateTimeOffset = (DateTimeOffset)constant.Value;

// Kullanıcının saat dilimine göre gün başlangıcı ve sonu
DateTimeOffset startDateLocal = new(valueAsDateTimeOffset.Year, valueAsDateTimeOffset.Month, valueAsDateTimeOffset.Day, 0, 0, 0, valueAsDateTimeOffset.Offset);
DateTimeOffset endDateLocal = startDateLocal.AddDays(1).AddTicks(-1);

DateTimeOffset startDate = new(valueAsDateTimeOffset.Year, valueAsDateTimeOffset.Month, valueAsDateTimeOffset.Day, 0, 0, 0, valueAsDateTimeOffset.Offset);
DateTimeOffset endDate = startDate.AddDays(1).AddTicks(-1);

if (Settings.UseUtcConversionInDateTypes)
{
startDate = startDate.ToOffset(TimeSpan.Zero);
endDate = endDate.ToOffset(TimeSpan.Zero);
}
// UTC'ye dönüştürme
DateTimeOffset startDate = startDateLocal.ToOffset(TimeSpan.Zero);
DateTimeOffset endDate = endDateLocal.ToOffset(TimeSpan.Zero);

startDateExpression = Expression.Constant(startDate);
endDateExpression = Expression.Constant(endDate);
Expand Down
3 changes: 1 addition & 2 deletions ExpressionBuilder/Operations/EndsWith.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ public override Expression GetExpression(MemberExpression member, ConstantExpres
{
var constant = constant1.TrimToLower();

return Expression.Call(member.TrimToLower(), _endsWithMethod, constant)
.AddNullCheck(member);
return Expression.Call(member.TrimToLower(), _endsWithMethod, constant).AddNullCheck(member);
}
}
2 changes: 1 addition & 1 deletion ExpressionBuilder/Operations/EqualTo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ public EqualTo() : base(nameof(EqualTo), ValueCount, TypeGroup.Default | TypeGro
/// <inheritdoc />
public override Expression GetExpression(MemberExpression member, ConstantExpression constant1, ConstantExpression constant2)
{
Expression constant = constant1;
Expression constant = constant1.ConvertUtcIfRequested();

if (member.Type != typeof(string))
return Expression.Equal(member, constant);
Expand Down
2 changes: 1 addition & 1 deletion ExpressionBuilder/Operations/GreaterThan.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,5 @@ public class GreaterThan : OperationBase
public GreaterThan() : base(nameof(GreaterThan), ValueCount, TypeGroup.Number | TypeGroup.Date) { }

/// <inheritdoc />
public override Expression GetExpression(MemberExpression member, ConstantExpression constant1, ConstantExpression constant2) => Expression.GreaterThan(member, constant1);
public override Expression GetExpression(MemberExpression member, ConstantExpression constant1, ConstantExpression constant2) => Expression.GreaterThan(member, constant1.ConvertUtcIfRequested());
}
2 changes: 1 addition & 1 deletion ExpressionBuilder/Operations/GreaterThanOrEqualTo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,5 @@ public class GreaterThanOrEqualTo : OperationBase
public GreaterThanOrEqualTo() : base(nameof(GreaterThanOrEqualTo), ValueCount, TypeGroup.Number | TypeGroup.Date) { }

/// <inheritdoc />
public override Expression GetExpression(MemberExpression member, ConstantExpression constant1, ConstantExpression constant2) => Expression.GreaterThanOrEqual(member, constant1);
public override Expression GetExpression(MemberExpression member, ConstantExpression constant1, ConstantExpression constant2) => Expression.GreaterThanOrEqual(member, constant1.ConvertUtcIfRequested());
}
2 changes: 2 additions & 0 deletions ExpressionBuilder/Operations/In.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ public override MethodCallExpression GetExpression(MemberExpression member, Cons
var type = constant1.Value.GetType();
var inInfo = type.GetMethod("Contains", [type.GetGenericArguments()[0]]);

constant1 = constant1.ConvertUtcIfRequested();

return GetExpressionHandlingNullables(member, constant1, type, inInfo) ?? Expression.Call(constant1, inInfo, member);
}

Expand Down
2 changes: 1 addition & 1 deletion ExpressionBuilder/Operations/LessThan.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,5 @@ public class LessThan : OperationBase
public LessThan() : base(nameof(LessThan), ValueCount, TypeGroup.Number | TypeGroup.Date) { }

/// <inheritdoc />
public override Expression GetExpression(MemberExpression member, ConstantExpression constant1, ConstantExpression constant2) => Expression.LessThan(member, constant1);
public override Expression GetExpression(MemberExpression member, ConstantExpression constant1, ConstantExpression constant2) => Expression.LessThan(member, constant1.ConvertUtcIfRequested());
}
2 changes: 1 addition & 1 deletion ExpressionBuilder/Operations/LessThanOrEqualTo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,5 @@ public class LessThanOrEqualTo : OperationBase
public LessThanOrEqualTo() : base(nameof(LessThanOrEqualTo), ValueCount, TypeGroup.Number | TypeGroup.Date) { }

/// <inheritdoc />
public override Expression GetExpression(MemberExpression member, ConstantExpression constant1, ConstantExpression constant2) => Expression.LessThanOrEqual(member, constant1);
public override Expression GetExpression(MemberExpression member, ConstantExpression constant1, ConstantExpression constant2) => Expression.LessThanOrEqual(member, constant1.ConvertUtcIfRequested());
}
2 changes: 1 addition & 1 deletion ExpressionBuilder/Operations/NotEqualTo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ public NotEqualTo() : base(nameof(NotEqualTo), ValueCount, TypeGroup.Default | T
/// <inheritdoc />
public override Expression GetExpression(MemberExpression member, ConstantExpression constant1, ConstantExpression constant2)
{
Expression constant = constant1;
Expression constant = constant1.ConvertUtcIfRequested();

if (member.Type != typeof(string))
return Expression.NotEqual(member, constant);
Expand Down
2 changes: 1 addition & 1 deletion ExpressionBuilder/Operations/NotIn.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ public override Expression GetExpression(MemberExpression member, ConstantExpres

var type = constant1.Value.GetType();
var inInfo = type.GetMethod("Contains", [type.GetGenericArguments()[0]]);
var contains = Expression.Call(constant1, inInfo, member);
var contains = Expression.Call(constant1.ConvertUtcIfRequested(), inInfo, member);
return Expression.Not(contains);
}
}

0 comments on commit c77d6d1

Please sign in to comment.