Skip to content

Commit

Permalink
Code literal support for DateOnly/TimeOnly (#26159)
Browse files Browse the repository at this point in the history
Fixes #26156
  • Loading branch information
roji authored Sep 23, 2021
1 parent 2bec43f commit 059433e
Show file tree
Hide file tree
Showing 2 changed files with 83 additions and 0 deletions.
42 changes: 42 additions & 0 deletions src/EFCore.Design/Design/Internal/CSharpHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@ public CSharpHelper(ITypeMappingSource typeMappingSource)
{ typeof(byte), (c, v) => c.Literal((byte)v) },
{ typeof(byte[]), (c, v) => c.Literal((byte[])v) },
{ typeof(char), (c, v) => c.Literal((char)v) },
{ typeof(DateOnly), (c, v) => c.Literal((DateOnly)v) },
{ typeof(DateTime), (c, v) => c.Literal((DateTime)v) },
{ typeof(DateTimeOffset), (c, v) => c.Literal((DateTimeOffset)v) },
{ typeof(decimal), (c, v) => c.Literal((decimal)v) },
Expand All @@ -144,6 +145,7 @@ public CSharpHelper(ITypeMappingSource typeMappingSource)
{ typeof(sbyte), (c, v) => c.Literal((sbyte)v) },
{ typeof(short), (c, v) => c.Literal((short)v) },
{ typeof(string), (c, v) => c.Literal((string)v) },
{ typeof(TimeOnly), (c, v) => c.Literal((TimeOnly)v) },
{ typeof(TimeSpan), (c, v) => c.Literal((TimeSpan)v) },
{ typeof(uint), (c, v) => c.Literal((uint)v) },
{ typeof(ulong), (c, v) => c.Literal((ulong)v) },
Expand Down Expand Up @@ -358,6 +360,20 @@ public virtual string Literal(byte value)
public virtual string Literal(char value)
=> "\'" + (value == '\'' ? "\\'" : value.ToString()) + "\'";

/// <summary>
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
/// the same compatibility standards as public APIs. It may be changed or removed without notice in
/// any release. You should only use it directly in your code with extreme caution and knowing that
/// doing so can result in application failures when updating to a new Entity Framework Core release.
/// </summary>
public virtual string Literal(DateOnly value)
=> string.Format(
CultureInfo.InvariantCulture,
"new DateOnly({0}, {1}, {2})",
value.Year,
value.Month,
value.Day);

/// <summary>
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
/// the same compatibility standards as public APIs. It may be changed or removed without notice in
Expand Down Expand Up @@ -490,6 +506,32 @@ public virtual string Literal(sbyte value)
public virtual string Literal(short value)
=> "(short)" + value;

/// <summary>
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
/// the same compatibility standards as public APIs. It may be changed or removed without notice in
/// any release. You should only use it directly in your code with extreme caution and knowing that
/// doing so can result in application failures when updating to a new Entity Framework Core release.
/// </summary>
public virtual string Literal(TimeOnly value)
{
var result = value.Millisecond == 0
? string.Format(
CultureInfo.InvariantCulture, "new TimeOnly({0}, {1}, {2})", value.Hour, value.Minute, value.Second)
: string.Format(
CultureInfo.InvariantCulture, "new TimeOnly({0}, {1}, {2}, {3})", value.Hour, value.Minute, value.Second,
value.Millisecond);

if (value.Ticks % 10000 > 0)
{
result += string.Format(
CultureInfo.InvariantCulture,
".Add(TimeSpan.FromTicks({0}))",
value.Ticks % 10000);
}

return result;
}

/// <summary>
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
/// the same compatibility standards as public APIs. It may be changed or removed without notice in
Expand Down
41 changes: 41 additions & 0 deletions test/EFCore.SqlServer.Tests/Storage/SqlServerTypeMappingTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
using System.Reflection;
using Microsoft.Data.SqlClient;
using Microsoft.EntityFrameworkCore.ChangeTracking;
using Microsoft.EntityFrameworkCore.Design.Internal;
using Microsoft.EntityFrameworkCore.SqlServer.Storage.Internal;
using Microsoft.EntityFrameworkCore.TestUtilities;
using Xunit;
Expand Down Expand Up @@ -275,12 +276,52 @@ public override void String_literal_generated_correctly()
Test_GenerateSqlLiteral_helper(GetMapping("varchar(max)"), "Text", "'Text'");
}

[ConditionalFact]
public virtual void DateOnly_code_literal_generated_correctly()
{
var typeMapping = new DateOnlyTypeMapping("date", DbType.Date);

Test_GenerateCodeLiteral_helper(typeMapping, new DateOnly(2020, 3, 5), "new DateOnly(2020, 3, 5)");
}

[ConditionalFact]
public virtual void TimeOnly_code_literal_generated_correctly()
{
var typeMapping = new TimeOnlyTypeMapping("time", DbType.Time);

Test_GenerateCodeLiteral_helper(typeMapping, new TimeOnly(12, 30, 10), "new TimeOnly(12, 30, 10)");
Test_GenerateCodeLiteral_helper(typeMapping, new TimeOnly(12, 30, 10, 500), "new TimeOnly(12, 30, 10, 500)");

Test_GenerateCodeLiteral_helper(
typeMapping,
new TimeOnly(12, 30, 10).Add(TimeSpan.FromTicks(10)),
"new TimeOnly(12, 30, 10).Add(TimeSpan.FromTicks(10))");
Test_GenerateCodeLiteral_helper(
typeMapping,
new TimeOnly(12, 30, 10, 500).Add(TimeSpan.FromTicks(10)),
"new TimeOnly(12, 30, 10, 500).Add(TimeSpan.FromTicks(10))");
}

public static RelationalTypeMapping GetMapping(string type)
=> new SqlServerTypeMappingSource(
TestServiceFactory.Instance.Create<TypeMappingSourceDependencies>(),
TestServiceFactory.Instance.Create<RelationalTypeMappingSourceDependencies>())
.FindMapping(type);

protected virtual void Test_GenerateCodeLiteral_helper(
RelationalTypeMapping typeMapping,
object value,
string expectedCode)
{
var typeMappingSource = new SqlServerTypeMappingSource(
TestServiceFactory.Instance.Create<TypeMappingSourceDependencies>(),
TestServiceFactory.Instance.Create<RelationalTypeMappingSourceDependencies>());

var csharpHelper = new CSharpHelper(typeMappingSource);

Assert.Equal(expectedCode, csharpHelper.UnknownLiteral(value));
}

private class FakeType : Type
{
public FakeType(string fullName)
Expand Down

0 comments on commit 059433e

Please sign in to comment.