Skip to content

Commit 72232d9

Browse files
authored
Supporting System.DateOnly and System.TimeOnly types. (#141)
1 parent ae04b35 commit 72232d9

File tree

7 files changed

+112
-17
lines changed

7 files changed

+112
-17
lines changed

AutoMapper.AspNetCore.OData.EF6/AutoMapper.AspNetCore.OData.EF6.csproj

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
<PackageId>AutoMapper.AspNetCore.OData.EF6</PackageId>
77
<Description>Creates LINQ expressions from ODataQueryOptions and executes the query.</Description>
88
<PackageRequireLicenseAcceptance>false</PackageRequireLicenseAcceptance>
9-
<PackageReleaseNotes>1. Returning expansions not specified in $select. 2. Bugfix: Inherited members ignored.</PackageReleaseNotes>
9+
<PackageReleaseNotes>Supporting System.DateOnly and System.TimeOnly types.</PackageReleaseNotes>
1010
<PackageTags>linq expressions odata efcore</PackageTags>
1111
<PackageIcon>icon.png</PackageIcon>
1212
<RepositoryUrl>https://github.com/AutoMapper/AutoMapper.Extensions.OData</RepositoryUrl>
@@ -55,9 +55,9 @@
5555
</ItemGroup>
5656

5757
<ItemGroup>
58-
<PackageReference Include="AutoMapper.Extensions.ExpressionMapping" Version="[5.0.2,6.0.0)" />
58+
<PackageReference Include="AutoMapper.Extensions.ExpressionMapping" Version="[5.0.3,6.0.0)" />
5959
<PackageReference Include="EntityFramework" Version="6.3.0" />
60-
<PackageReference Include="LogicBuilder.Expressions.Utils" Version="[5.0.4,6.0.0)" />
60+
<PackageReference Include="LogicBuilder.Expressions.Utils" Version="[5.0.6,6.0.0)" />
6161
<PackageReference Include="Microsoft.AspNetCore.OData" Version="8.0.6" />
6262
<PackageReference Include="MinVer" Version="2.5.0">
6363
<PrivateAssets>all</PrivateAssets>

AutoMapper.AspNetCore.OData.EFCore/AutoMapper.AspNetCore.OData.EFCore.csproj

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
<PackageId>AutoMapper.AspNetCore.OData.EFCore</PackageId>
77
<Description>Creates LINQ expressions from ODataQueryOptions and executes the query.</Description>
88
<PackageRequireLicenseAcceptance>false</PackageRequireLicenseAcceptance>
9-
<PackageReleaseNotes>1. Returning expansions not specified in $select. 2. Bugfix: Inherited members ignored.</PackageReleaseNotes>
9+
<PackageReleaseNotes>Supporting System.DateOnly and System.TimeOnly types.</PackageReleaseNotes>
1010
<PackageTags>linq expressions odata efcore</PackageTags>
1111
<PackageIcon>icon.png</PackageIcon>
1212
<RepositoryUrl>https://github.com/AutoMapper/AutoMapper.Extensions.OData</RepositoryUrl>
@@ -28,8 +28,8 @@
2828
</ItemGroup>
2929

3030
<ItemGroup>
31-
<PackageReference Include="AutoMapper.Extensions.ExpressionMapping" Version="[5.0.2,6.0.0)" />
32-
<PackageReference Include="LogicBuilder.Expressions.Utils" Version="[5.0.4,6.0.0)" />
31+
<PackageReference Include="AutoMapper.Extensions.ExpressionMapping" Version="[5.0.3,6.0.0)" />
32+
<PackageReference Include="LogicBuilder.Expressions.Utils" Version="[5.0.6,6.0.0)" />
3333
<PackageReference Include="Microsoft.AspNetCore.OData" Version="8.0.6" />
3434
<PackageReference Include="MinVer" Version="2.5.0">
3535
<PrivateAssets>all</PrivateAssets>

AutoMapper.AspNetCore.OData.EFCore/Constants.cs

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,19 +8,26 @@ namespace AutoMapper.AspNet.OData
88
{
99
internal static class Constants
1010
{
11-
public static HashSet<Type> DateRelatedTypes = new HashSet<Type>
11+
public static HashSet<Type> DateRelatedTypes = new()
1212
{
1313
typeof(DateTimeOffset),
1414
typeof(DateTime),
15-
typeof(Date)
15+
typeof(Date),
16+
#if NET6_0
17+
typeof(DateOnly)
18+
#endif
1619
};
1720

18-
public static HashSet<Type> DateTimeRelatedTypes = new HashSet<Type>
21+
public static HashSet<Type> DateTimeRelatedTypes = new()
1922
{
2023
typeof(DateTimeOffset),
2124
typeof(DateTime),
2225
typeof(TimeSpan),
2326
typeof(TimeOfDay),
27+
#if NET6_0
28+
typeof(TimeOnly),
29+
typeof(DateOnly),
30+
#endif
2431
typeof(Date)
2532
};
2633

AutoMapper.AspNetCore.OData.EFCore/FilterHelper.cs

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -589,8 +589,7 @@ public IExpressionPart GetBinaryOperatorFilterPart(BinaryOperatorNode binaryOper
589589
left = new ConvertToNumericDateOperator(left);
590590
right = new ConvertToNumericDateOperator(right);
591591
}
592-
593-
if (ShouldConvertToNumericTime(binaryOperatorNode))
592+
else if (ShouldConvertToNumericTime(binaryOperatorNode))
594593
{
595594
left = new ConvertToNumericTimeOperator(left);
596595
right = new ConvertToNumericTimeOperator(right);
@@ -709,7 +708,17 @@ private bool ShouldConvertToNumericDate(BinaryOperatorNode binaryOperatorNode)
709708
);
710709

711710
static bool ShouldConvert(Type leftType, Type rightType)
712-
=> BothTypesDateRelated(leftType, rightType) && (leftType == typeof(Date) || rightType == typeof(Date));
711+
=> BothTypesDateRelated(leftType, rightType)
712+
#if NET6_0
713+
&& (
714+
leftType == typeof(Date)
715+
|| rightType == typeof(Date)
716+
|| leftType == typeof(DateOnly)
717+
|| rightType == typeof(DateOnly)
718+
);
719+
#else
720+
&& (leftType == typeof(Date) || rightType == typeof(Date));
721+
#endif
713722
}
714723

715724
private bool ShouldConvertToNumericTime(BinaryOperatorNode binaryOperatorNode)
@@ -724,7 +733,17 @@ private bool ShouldConvertToNumericTime(BinaryOperatorNode binaryOperatorNode)
724733
);
725734

726735
static bool ShouldConvert(Type leftType, Type rightType)
727-
=> BothTypesDateTimeRelated(leftType, rightType) && (leftType == typeof(TimeOfDay) || rightType == typeof(TimeOfDay));
736+
=> BothTypesDateTimeRelated(leftType, rightType)
737+
#if NET6_0
738+
&& (
739+
leftType == typeof(TimeOfDay)
740+
|| rightType == typeof(TimeOfDay)
741+
|| leftType == typeof(TimeOnly)
742+
|| rightType == typeof(TimeOnly)
743+
);
744+
#else
745+
&& (leftType == typeof(TimeOfDay) || rightType == typeof(TimeOfDay));
746+
#endif
728747
}
729748

730749
public IExpressionPart GetConstantOperandFilterPart(ConstantNode constantNode)

ExpressionBuilder.Tests/Data/DataClasses.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,9 +39,15 @@ public class Product
3939
public Guid GuidProperty { get; set; }
4040
public Guid? NullableGuidProperty { get; set; }
4141

42+
public DateOnly DateOnlyProperty { get; set; }
43+
public DateOnly? NullableDateOnlyProperty { get; set; }
44+
4245
public TimeOfDay TimeOfDayProperty { get; set; }
4346
public TimeOfDay? NullableTimeOfDayProperty { get; set; }
4447

48+
public TimeOnly TimeOnlyProperty { get; set; }
49+
public TimeOnly? NullableTimeOnlyProperty { get; set; }
50+
4551
public ushort? UnsignedReorderLevel { get; set; }
4652

4753
public SimpleEnum Ranking { get; set; }

ExpressionBuilder.Tests/ExpressionStringBuilder.cs

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -93,9 +93,19 @@ object GetConstantValue()
9393
: node.Value;
9494

9595
string GetOutString(object constant)
96-
=> constant.GetType() == typeof(string)
97-
? string.Format(CultureInfo.InvariantCulture, "\"{0}\"", constant)
98-
: string.Format(CultureInfo.InvariantCulture, "{0}", constant);
96+
{
97+
Type constanType = constant.GetType();
98+
if (constanType == typeof(string))
99+
return string.Format(CultureInfo.InvariantCulture, "\"{0}\"", constant);
100+
101+
if (constanType == typeof(Microsoft.OData.Edm.Date) || constanType == typeof(DateOnly))
102+
return string.Format(CultureInfo.InvariantCulture, "{0:yyyy-MM-dd}", constant);
103+
104+
if (constanType == typeof(Microsoft.OData.Edm.TimeOfDay) || constanType == typeof(TimeOnly))
105+
return string.Format(CultureInfo.InvariantCulture, "{0:HH:mm:ss.fffffff}", constant);
106+
107+
return string.Format(CultureInfo.InvariantCulture, "{0}", constant);
108+
}
99109

100110
return node;
101111
}

ExpressionBuilder.Tests/FilterTests.cs

Lines changed: 54 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
using AutoMapper.AspNet.OData;
33
using ExpressionBuilder.Tests.Data;
44
using Microsoft.AspNetCore.Builder;
5-
using Microsoft.AspNetCore.OData;
65
using Microsoft.AspNetCore.Routing;
76
using Microsoft.Extensions.DependencyInjection;
87
using Microsoft.OData;
@@ -1202,6 +1201,19 @@ public void DateFunctions_Nullable(string filterString, string expression)
12021201
AssertFilterStringIsCorrect(filter, expression);
12031202
}
12041203

1204+
[Theory]
1205+
[InlineData("year(NullableDateOnlyProperty) eq 2015", "$it => ($it.NullableDateOnlyProperty.Value.Year == 2015)")]
1206+
[InlineData("month(NullableDateOnlyProperty) eq 12", "$it => ($it.NullableDateOnlyProperty.Value.Month == 12)")]
1207+
[InlineData("day(NullableDateOnlyProperty) eq 23", "$it => ($it.NullableDateOnlyProperty.Value.Day == 23)")]
1208+
public void DateOnlyFunctions_Nullable(string filterString, string expression)
1209+
{
1210+
//act
1211+
var filter = GetFilter<Product>(filterString);
1212+
1213+
//assert
1214+
AssertFilterStringIsCorrect(filter, expression);
1215+
}
1216+
12051217
[Theory]
12061218
[InlineData("year(DateProperty) eq 2015", "$it => ($it.DateProperty.Year == 2015)")]
12071219
[InlineData("month(DateProperty) eq 12", "$it => ($it.DateProperty.Month == 12)")]
@@ -1215,6 +1227,19 @@ public void DateFunctions_NonNullable(string filterString, string expression)
12151227
AssertFilterStringIsCorrect(filter, expression);
12161228
}
12171229

1230+
[Theory]
1231+
[InlineData("year(DateOnlyProperty) eq 2015", "$it => ($it.DateOnlyProperty.Year == 2015)")]
1232+
[InlineData("month(DateOnlyProperty) eq 12", "$it => ($it.DateOnlyProperty.Month == 12)")]
1233+
[InlineData("day(DateOnlyProperty) eq 23", "$it => ($it.DateOnlyProperty.Day == 23)")]
1234+
public void DateOnlyFunctions_NonNullable(string filterString, string expression)
1235+
{
1236+
//act
1237+
var filter = GetFilter<Product>(filterString);
1238+
1239+
//assert
1240+
AssertFilterStringIsCorrect(filter, expression);
1241+
}
1242+
12181243
[Theory]
12191244
[InlineData("hour(NullableTimeOfDayProperty) eq 10", "$it => ($it.NullableTimeOfDayProperty.Value.Hours == 10)")]
12201245
[InlineData("minute(NullableTimeOfDayProperty) eq 20", "$it => ($it.NullableTimeOfDayProperty.Value.Minutes == 20)")]
@@ -1228,6 +1253,19 @@ public void TimeOfDayFunctions_Nullable(string filterString, string expression)
12281253
AssertFilterStringIsCorrect(filter, expression);
12291254
}
12301255

1256+
[Theory]
1257+
[InlineData("hour(NullableTimeOnlyProperty) eq 10", "$it => ($it.NullableTimeOnlyProperty.Value.Hour == 10)")]
1258+
[InlineData("minute(NullableTimeOnlyProperty) eq 20", "$it => ($it.NullableTimeOnlyProperty.Value.Minute == 20)")]
1259+
[InlineData("second(NullableTimeOnlyProperty) eq 30", "$it => ($it.NullableTimeOnlyProperty.Value.Second == 30)")]
1260+
public void TimeOnlyFunctions_Nullable(string filterString, string expression)
1261+
{
1262+
//act
1263+
var filter = GetFilter<Product>(filterString);
1264+
1265+
//assert
1266+
AssertFilterStringIsCorrect(filter, expression);
1267+
}
1268+
12311269
[Theory]
12321270
[InlineData("hour(TimeOfDayProperty) eq 10", "$it => ($it.TimeOfDayProperty.Hours == 10)")]
12331271
[InlineData("minute(TimeOfDayProperty) eq 20", "$it => ($it.TimeOfDayProperty.Minutes == 20)")]
@@ -1241,9 +1279,23 @@ public void TimeOfDayFunctions_NonNullable(string filterString, string expressio
12411279
AssertFilterStringIsCorrect(filter, expression);
12421280
}
12431281

1282+
[Theory]
1283+
[InlineData("hour(TimeOnlyProperty) eq 10", "$it => ($it.TimeOnlyProperty.Hour == 10)")]
1284+
[InlineData("minute(TimeOnlyProperty) eq 20", "$it => ($it.TimeOnlyProperty.Minute == 20)")]
1285+
[InlineData("second(TimeOnlyProperty) eq 30", "$it => ($it.TimeOnlyProperty.Second == 30)")]
1286+
public void TimeOnlyFunctions_NonNullable(string filterString, string expression)
1287+
{
1288+
//act
1289+
var filter = GetFilter<Product>(filterString);
1290+
1291+
//assert
1292+
AssertFilterStringIsCorrect(filter, expression);
1293+
}
1294+
12441295
[Theory]
12451296
[InlineData("fractionalseconds(DiscontinuedDate) eq 0.2", "$it => ((Convert($it.DiscontinuedDate.Value.Millisecond) / 1000) == 0.2)")]
12461297
[InlineData("fractionalseconds(NullableTimeOfDayProperty) eq 0.2", "$it => ((Convert($it.NullableTimeOfDayProperty.Value.Milliseconds) / 1000) == 0.2)")]
1298+
[InlineData("fractionalseconds(NullableTimeOnlyProperty) eq 0.2", "$it => ((Convert($it.NullableTimeOnlyProperty.Value.Millisecond) / 1000) == 0.2)")]
12471299
public void FractionalsecondsFunction_Nullable(string filterString, string expression)
12481300
{
12491301
//act
@@ -1256,6 +1308,7 @@ public void FractionalsecondsFunction_Nullable(string filterString, string expre
12561308
[Theory]
12571309
[InlineData("fractionalseconds(NonNullableDiscontinuedDate) eq 0.2", "$it => ((Convert($it.NonNullableDiscontinuedDate.Millisecond) / 1000) == 0.2)")]
12581310
[InlineData("fractionalseconds(TimeOfDayProperty) eq 0.2", "$it => ((Convert($it.TimeOfDayProperty.Milliseconds) / 1000) == 0.2)")]
1311+
[InlineData("fractionalseconds(TimeOnlyProperty) eq 0.2", "$it => ((Convert($it.TimeOnlyProperty.Millisecond) / 1000) == 0.2)")]
12591312
public void FractionalsecondsFunction_NonNullable(string filterString, string expression)
12601313
{
12611314
//act

0 commit comments

Comments
 (0)