Skip to content

Commit

Permalink
Add Translation for to_date and to_timestamp as DBFunctions extensions (
Browse files Browse the repository at this point in the history
#2936)

Closes #2505
  • Loading branch information
WhatzGames authored Mar 20, 2024
1 parent 08f341d commit 533b9d3
Show file tree
Hide file tree
Showing 3 changed files with 78 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -141,4 +141,24 @@ public static int Distance(this DbFunctions _, DateOnly a, DateOnly b)
/// </remarks>
public static TimeSpan Distance(this DbFunctions _, DateTime a, DateTime b)
=> throw new InvalidOperationException(CoreStrings.FunctionOnClient(nameof(Distance)));

/// <summary>
/// Converts string to date according to the given format.
/// </summary>
/// <param name="_">The <see cref="DbFunctions"/> instance.</param>
/// <param name="value">The string to be converted.</param>
/// <param name="format">The format of the input date.</param>
/// <see href="https://www.postgresql.org/docs/current/functions-formatting.html" />
public static DateOnly? ToDate(this DbFunctions _, string? value, string? format)
=> throw new InvalidOperationException(CoreStrings.FunctionOnClient(nameof(ToDate)));

/// <summary>
/// Converts string to time stamp according to the given format.
/// </summary>
/// <param name="_">The <see cref="DbFunctions"/> instance.</param>
/// <param name="value">The string to be converted</param>
/// <param name="format">The format of the input date</param>
/// <see href="https://www.postgresql.org/docs/current/functions-formatting.html" />
public static DateTime? ToTimestamp(this DbFunctions _, string? value, string? format)
=> throw new InvalidOperationException(CoreStrings.FunctionOnClient(nameof(ToTimestamp)));
}
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,12 @@ public class NpgsqlStringMethodTranslator : IMethodCallTranslator
private static readonly MethodInfo StringToArrayNullString = typeof(NpgsqlDbFunctionsExtensions).GetRuntimeMethod(
nameof(NpgsqlDbFunctionsExtensions.StringToArray), [typeof(DbFunctions), typeof(string), typeof(string), typeof(string)])!;

private static readonly MethodInfo ToDate = typeof(NpgsqlDbFunctionsExtensions).GetRuntimeMethod(
nameof(NpgsqlDbFunctionsExtensions.ToDate), [typeof(DbFunctions), typeof(string), typeof(string)])!;

private static readonly MethodInfo ToTimestamp = typeof(NpgsqlDbFunctionsExtensions).GetRuntimeMethod(
nameof(NpgsqlDbFunctionsExtensions.ToTimestamp), [typeof(DbFunctions), typeof(string), typeof(string)])!;

private static readonly MethodInfo FirstOrDefaultMethodInfoWithoutArgs
= typeof(Enumerable).GetRuntimeMethods().Single(
m => m.Name == nameof(Enumerable.FirstOrDefault)
Expand Down Expand Up @@ -425,6 +431,30 @@ public NpgsqlStringMethodTranslator(NpgsqlTypeMappingSource typeMappingSource, I
_typeMappingSource.FindMapping(typeof(string[])));
}

if (method == ToDate)
{
return _sqlExpressionFactory.Function(
"to_date",
new[] { arguments[1], arguments[2] },
nullable: true,
argumentsPropagateNullability: new[] { true, true },
typeof(DateOnly?),
_typeMappingSource.FindMapping(typeof(DateOnly))
);
}

if (method == ToTimestamp)
{
return _sqlExpressionFactory.Function(
"to_timestamp",
new[] { arguments[1], arguments[2] },
nullable: true,
argumentsPropagateNullability: new[] { true, true },
typeof(DateTime?),
_typeMappingSource.FindMapping(typeof(DateTime))
);
}

return null;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,34 @@ WHERE string_to_array(c."ContactName", ' ', 'Maria') = ARRAY[NULL,'Anders']::tex
""");
}

[Fact]
public void ToDate()
{
using var context = CreateContext();
var count = context.Orders.Count(c => EF.Functions.ToDate(c.OrderDate.ToString(), "YYYY-MM-DD") < new DateOnly(2000, 01, 01));
Assert.Equal(830, count);
AssertSql(
"""
SELECT count(*)::int
FROM "Orders" AS o
WHERE to_date(o."OrderDate"::text, 'YYYY-MM-DD') < DATE '2000-01-01'
""");
}

[Fact]
public void ToTimestamp()
{
using var context = CreateContext();
var count = context.Orders.Count(c => EF.Functions.ToTimestamp(c.OrderDate.ToString(), "YYYY-MM-DD") < new DateTime(2000, 01, 01, 0,0,0, DateTimeKind.Utc));
Assert.Equal(830, count);
AssertSql(
"""
SELECT count(*)::int
FROM "Orders" AS o
WHERE to_timestamp(o."OrderDate"::text, 'YYYY-MM-DD') < TIMESTAMPTZ '2000-01-01T00:00:00Z'
""");
}

#endregion

private void AssertSql(params string[] expected)
Expand Down

0 comments on commit 533b9d3

Please sign in to comment.